¿Cómo muestro los contornos de una imagen usando OpenCV Python?

Seguí este tutorial desde la documentación oficial. Yo corro su código:

import numpy as np import cv2 im = cv2.imread('test.jpg') imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) ret,thresh = cv2.threshold(imgray,127,255,0) contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img, contours, -1, (0,255,0), 3) 

Eso está bien: no hay errores, pero no se muestra nada. Quiero mostrar el resultado que obtuvieron tal como lo mostraron en la imagen:

introduzca la descripción de la imagen aquí

¿Cómo puedo mostrar el resultado de los contadores así (solo el resultado izquierdo o el derecho)? Sé que debo usar cv2.imshow(something) pero, ¿cómo en este caso específico?

En primer lugar, ese ejemplo solo muestra cómo dibujar contornos con la aproximación simple. Tenga en cuenta que incluso si dibuja los contornos con la aproximación simple, se visualizará con un contorno azul dibujado alrededor del rectángulo como se ve en la imagen de la izquierda. No podrá obtener la imagen correcta simplemente dibujando los contornos en la imagen. Además, desea comparar dos conjuntos de contornos: la versión simplificada a la derecha con su representación completa a la izquierda. Específicamente, debe reemplazar el indicador cv2.CHAIN_APPROX_NONE con cv2.CHAIN_APPROX_NONE para obtener la representación completa. Eche un vistazo al documento de OpenCV en findContours para obtener más detalles: http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html#findcontours

Además, aunque dibuje los contornos en la imagen, no muestra los resultados. Tendrás que llamar a cv2.imshow para eso. Sin embargo, dibujar los contornos por sí mismos no le mostrará la diferencia entre la versión completa y la simplificada. El tutorial menciona que necesita dibujar círculos en cada punto de contorno, por lo que no debemos usar cv2.drawContours para esta tarea. Lo que debes hacer es extraer los puntos de contorno y dibujar círculos en cada punto.

Como tal, crea dos imágenes así:

 # Your code import numpy as np import cv2 im = cv2.imread('test.jpg') imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) ret,thresh = cv2.threshold(imgray,127,255,0) ## Step #1 - Detect contours using both methods on the same image contours1, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) contours2, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) ### Step #2 - Reshape to 2D matrices contours1 = contours1[0].reshape(-1,2) contours2 = contours2[0].reshape(-1,2) ### Step #3 - Draw the points as individual circles in the image img1 = im.copy() img2 = im.copy() for (x, y) in contours1: cv2.circle(img1, (x, y), 1, (255, 0, 0), 3) for (x, y) in contours2: cv2.circle(img2, (x, y), 1, (255, 0, 0), 3) 

Tenga en cuenta que el código anterior es para OpenCV 2. Para OpenCV 3, hay una salida adicional para cv2.findContours que es la primera salida que puede ignorar en este caso:

 _, contours1, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) _, contours2, _ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) 

Ahora vamos a caminar a través del código lentamente. La primera parte del código es lo que usted proporcionó. Ahora pasamos a lo nuevo.

Paso # 1 – Detectar contornos usando ambos métodos

Usando la imagen de umbral, detectamos contornos usando las aproximaciones completas y simples. Esto se almacena en dos listas, contours1 y contours2 .

Paso # 2 – remodelar a matrices 2D

Los contornos se almacenan como una lista de matrices NumPy. Para la imagen simple proporcionada, solo se debe detectar un contorno, así que extraiga el primer elemento de la lista, luego use numpy.reshape para remodelar las matrices 3D en sus formas 2D donde cada fila es un punto (x, y) .

Paso # 3 – Dibuja los puntos como círculos individuales en la imagen

El siguiente paso sería tomar cada punto (x, y) de cada conjunto de contornos y dibujarlos en la imagen. Hacemos dos copias de la imagen original en forma de color, luego usamos cv2.circle e cv2.circle través de cada par de puntos (x, y) para ambos conjuntos de contornos y llenamos dos imágenes diferentes, una para cada conjunto de contornos.


Ahora, para obtener la figura que ves arriba, hay dos maneras de hacer esto:

  1. Cree una imagen que almacene ambos resultados juntos y luego muestre esta imagen combinada.
  2. Use matplotlib , combinado con imshow e imshow para que pueda mostrar dos imágenes en una ventana.

Te mostraré cómo hacerlo usando ambos métodos:

Método 1

Simplemente apile las dos imágenes una al lado de la otra, luego muestre la imagen después de:

 out = np.hstack([img1, img2]) # Now show the image cv2.imshow('Output', out) cv2.waitKey(0) cv2.destroyAllWindows() 

Los apilo horizontalmente para que sean una imagen combinada, luego muestro esto con cv2.imshow .

Método # 2

Puedes usar matplotlib :

 import matplotlib.pyplot as plt # Spawn a new figure plt.figure() # Show the first image on the left column plt.subplot(1,2,1) plt.imshow(img1[:,:,::-1]) # Turn off axis numbering plt.axis('off') # Show the second image on the right column plt.subplot(1,2,2) plt.imshow(img2[:,:,::-1]) # Turn off the axis numbering plt.axis('off') # Show the figure plt.show() 

Esto debería mostrar ambas imágenes en subfiguras separadas dentro de una ventana de figura general. Si echa un vistazo a cómo lo estoy llamando en este momento, verá que estoy cambiando los canales RGB porque OpenCV lee las imágenes en formato BGR. Si desea mostrar imágenes con matplotlib , deberá invertir los canales ya que las imágenes están en formato RGB (como deberían ser).


Para abordar su pregunta en sus comentarios, debe tomar la estructura de contorno que desee ( contours1 o contours2 ) y buscar los puntos de contorno. contours es una lista de todos los contornos posibles, y dentro de cada contorno hay una matriz 3D que tiene la forma de un formato N x 1 x 2 . N sería el número total de puntos que representan el contorno. Voy a eliminar la segunda dimensión de Singleton para que podamos obtener una matriz N x 2 . También, usemos la representación completa de los contornos por ahora:

 points = contours1[0].reshape(-1,2) 

Asumiré que su imagen solo tiene un objeto, por lo tanto mi indexación en contours1 con índice 0. Desenredo la matriz para que se convierta en un vector de una sola fila, luego remodela la matriz para que se convierta en N x 2 . A continuación, podemos encontrar el punto mínimo por:

 min_x = np.argmin(points[:,0]) min_point = points[min_x,:] 

np.argmin encuentra la ubicación del valor más pequeño en una matriz que proporcione. En este caso, queremos operar a lo largo de la coordenada x , o las columnas. Una vez que encontramos esta ubicación, simplemente indexamos nuestra matriz de puntos de contorno 2D y extraemos el punto de contorno.

Agrega estas 2 líneas al final:

 cv2.imshow("title", im) cv2.waitKey() 

Además, tenga en cuenta que tiene img lugar de im en su última línea.

Debería agregar cv2.imshow (“Título”, img) al final de su código. Debe tener un aspecto como este:

 import numpy as np import cv2 im = cv2.imread('test.jpg') imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) ret,thresh = cv2.threshold(imgray,127,255,0) contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(im, contours, -1, (0,255,0), 3) cv2.imshow("title", im) cv2.waitKey()