Detectando el borde más externo de la imagen y graficando en base a ella.

Estoy trabajando en un proyecto que puede calcular el ángulo de una articulación del codo por imagen. La parte en la que estoy luchando es el procesamiento de imágenes.

Actualmente estoy haciendo esto en Python usando un Intel RealSense R200 (aunque se puede considerar que estoy usando una entrada de imagen).

Estoy intentando detectar los bordes de la imagen izquierda , de modo que pueda obtener la imagen central , con el objective de extraer el contorno exterior ( imagen derecha ):

Sabiendo que los lados de los dos tubos que salen del ángulo serán paralelos (dos lados naranjas y dos lados verdes son paralelos al mismo color) …

… Estoy tratando de construir 2 loci de puntos equidistantes de los dos pares de colores y luego ‘extrapolar al medio’ para calcular el ángulo:

He llegado hasta la segunda imagen y, poco fidedignamente, hasta la tercera imagen. Estoy muy abierto a las sugerencias y agradecería enormemente cualquier ayuda.

Usaría el siguiente enfoque para tratar de encontrar las cuatro líneas proporcionadas en la pregunta.

1. Lee la imagen, y conviértela en escala de grises.

import cv2 import numpy as np rgb_img = cv2.imread('pipe.jpg') height, width = gray_img.shape gray_img = cv2.cvtColor(rgb_img, cv2.COLOR_BGR2GRAY) 

2. Agregue un poco de relleno blanco en la parte superior de la imagen (solo para tener un fondo adicional)

 white_padding = np.zeros((50, width, 3)) white_padding[:, :] = [255, 255, 255] rgb_img = np.row_stack((white_padding, rgb_img)) 

Imagen resultante – imagen acolchada blanca 3. Invierta la imagen en escala de grises y aplique un relleno negro en la parte superior

 gray_img = 255 - gray_img gray_img[gray_img > 100] = 255 gray_img[gray_img <= 100] = 0 black_padding = np.zeros((50, width)) gray_img = np.row_stack((black_padding, gray_img)) 

Imagen acolchada negra

4.Utilice cierre morfológico para rellenar los agujeros en la imagen -

 kernel = np.ones((30, 30), np.uint8) closing = cv2.morphologyEx(gray_img, cv2.MORPH_CLOSE, kernel) 

imagen cerrada 5. Encuentre bordes en la imagen usando la detección de bordes Canny -

 edges = cv2.Canny(closing, 100, 200) 

imagen de bordes de tubería 6. Ahora, podemos usar la función HoughLinesP de HoughLinesP para encontrar líneas en la imagen dada -

 minLineLength = 500 maxLineGap = 10 lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 50, None, 50, 100) all_lines = lines[0] for x1,y1,x2,y2 in lines[0]: cv2.line(rgb_img,(x1,y1),(x2,y2),(0,0,255),2) 

introduzca la descripción de la imagen aquí 7. Ahora, tenemos que encontrar las dos líneas horizontales más a la derecha y las dos líneas verticales más bajas. Para las líneas horizontales, ordenaremos las líneas usando ambos (x2, x1), en orden descendente. La primera línea en esta lista ordenada será la línea vertical más a la derecha. Si saltamos eso, si tomamos las siguientes dos líneas, serán las líneas horizontales más a la derecha.

 all_lines_x_sorted = sorted(all_lines, key=lambda k: (-k[2], -k[0])) for x1,y1,x2,y2 in all_lines_x_sorted[1:3]: cv2.line(rgb_img,(x1,y1),(x2,y2),(0,0,255),2) 

imagen de líneas horizontales 8. De manera similar, las líneas pueden ordenarse usando la coordenada y1, en orden descendente, y las dos primeras líneas en la lista ordenada serán las líneas verticales más bajas.

 all_lines_y_sorted = sorted(all_lines, key=lambda k: (-k[1])) for x1,y1,x2,y2 in all_lines_y_sorted[:2]: cv2.line(rgb_img,(x1,y1),(x2,y2),(0,0,255),2) 

imagen de líneas verticales 9. Imagen con ambas líneas.

 final_lines = all_lines_x_sorted[1:3] + all_lines_y_sorted[:2] 

líneas finales

Por lo tanto, obtener estas 4 líneas puede ayudarlo a terminar el rest de su tarea.

Como puede ver, la línea en la imagen binaria no es tan recta, también hay muchas líneas similares. Por lo tanto, hacer HoughLine directamente en una imagen de este tipo es a bad choice , no responsabilidad.


Intento binario la imagen, suelto la región superior izquierda (3*w/4, h*2/3) , luego obtengo las dos regiones separadas:

introduzca la descripción de la imagen aquí

 img = cv2.imread("img04.jpg", 0) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) th, threshed = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY_INV|cv2.THRESH_OTSU) H,W = img.shape[:2] threshed[:H*2//3,:W*3//4] = 0 cv2.imwrite("regions.png", threshed) 

Entonces puedes hacer otros pasos de post como quieras.

Parece que la transformada de Hough para la segunda imagen debe dar dos grupos verticales fuertes (en el espacio Theta-Rho), que corresponden a los haces de líneas paralelas. Así que puedes determinar las direcciones principales.

Aquí está el resultado de mi prueba rápida utilizando la segunda imagen y la función OpenCV HoughLines

introduzca la descripción de la imagen aquí

Luego conté las líneas con todas las direcciones (redondeadas a grados enteros) en el rango 0..180 e 0..180 los resultados con count>1 . Aparentemente podemos ver recuentos más grandes en 86-87 y 175-176 grados (note la diferencia de casi 90 grados)

 line angle : count 84: 3 85: 3 86: 8 87: 12 88: 3 102: 3 135: 3 140: 2 141: 2 165: 2 171: 4 172: 2 173: 2 175: 7 176: 17 177: 3 

Nota: He utilizado el ejemplo de Delphi arbitrario del uso de la función HoughLines y el recuento de direcciones agregado. Puedes obtener este ejemplo de Python y construir un histogtwig para los valores theta.

No está claro si esta geometría es fija o si son posibles otros diseños.

Como tiene un excelente contraste entre el objeto y el fondo, puede detectar algunos puntos al encontrar las primeras y últimas transiciones a lo largo de una línea de prueba.

Los pares de puntos te dan una dirección. Más puntos le permiten hacer ajuste de línea, y puede usar todos los puntos en sus áreas naranja y verde. Incluso es posible realizar el ajuste simultáneo de dos líneas paralelas.

Tenga en cuenta que si solo necesita un ángulo, no es necesario encontrar el eje de los tubos.

introduzca la descripción de la imagen aquí

Esto ya tiene muchas buenas respuestas, aunque ninguna es aceptada. Intenté algo un poco diferente, así que pensé en publicarlo incluso si la pregunta es antigua. Al menos alguien más podría encontrar esto útil. Esto funciona solo si hay un fondo uniforme agradable como en la imagen de muestra.

  • detectar puntos de interés (pruebe diferentes detectores de puntos de interés. Usé FAST)
  • encuentra el triángulo-mínimo-encerrador de estos puntos
  • encuentra el ángulo más grande (¿verdad?) de este triángulo

Esto le dará una estimación aproximada.

Para la imagen de muestra, el código da

 90.868604 42.180990 46.950407 

El código está en c++ . Puede portarlo fácilmente si lo encuentra útil.

triángulo

 // helper function: // finds a cosine of angle between vectors // from pt0->pt1 and from pt0->pt2 static double angle( Point2f pt1, Point2f pt2, Point2f pt0 ) { double dx1 = pt1.x - pt0.x; double dy1 = pt1.y - pt0.y; double dx2 = pt2.x - pt0.x; double dy2 = pt2.y - pt0.y; return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); } int _tmain(int argc, _TCHAR* argv[]) { Mat rgb = imread("GmHqQ.jpg"); Mat im; cvtColor(rgb, im, CV_BGR2GRAY); Ptr detector = FastFeatureDetector::create(); vector keypoints; detector->detect(im, keypoints); drawKeypoints(im, keypoints, rgb, Scalar(0, 0, 255)); vector points; for (KeyPoint& kp: keypoints) { points.push_back(kp.pt); } vector triangle(3); minEnclosingTriangle(points, triangle); for (size_t i = 0; i < triangle.size(); i++) { line(rgb, triangle[i], triangle[(i + 1) % triangle.size()], Scalar(255, 0, 0), 2); printf("%f\n", acosf( angle(triangle[i], triangle[(i + 1) % triangle.size()], triangle[(i + 2) % triangle.size()]) ) * 180 / CV_PI); } return 0; } 

Lamentablemente, su método no funcionará porque el ángulo que calcula con este método es solo el ángulo real si la cámara se mantiene exactamente perpendicular al plano de la junta. Necesitas un cuadrado de referencia en tus imágenes para poder calcular el ángulo en el que se sostiene la cámara para poder corregir el ángulo de la cámara. Y el cuadrado de referencia debe colocarse en la misma superficie plana que la junta de la tubería.