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:
¿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.
Usando la imagen de umbral, detectamos contornos usando las aproximaciones completas y simples. Esto se almacena en dos listas, contours1
y contours2
.
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)
.
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:
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:
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
.
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()