Manejo de contornos y rectángulo delimitador en OpenCV 2.4-python 2.7
python-2.7 image-processing (1)
Estoy trabajando con openCv y python y estoy tratando con análisis estructural y descriptores de formas. He encontrado este blog: http://opencvpython.blogspot.it/2012/06/contours-2-brotherhood.html que es muy útil y he intentado con una imagen en blanco y negro dibujar un rectángulo delimitador y funciona. Pero ahora de una imagen extraigo, por ejemplo, el color amarillo y sobre eso me gustaría dibujar un rectángulo delimitador. El problema es que la imagen en blanco y negro no es uniforme, tiene algo de ruido y al igual que el código no reconoce toda la forma.
Y este es el código:
import numpy as np
import cv2
im = cv2.imread(''shot.bmp'')
hsv_img = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
COLOR_MIN = np.array([20, 80, 80],np.uint8)
COLOR_MAX = np.array([40, 255, 255],np.uint8)
frame_threshed = cv2.inRange(hsv_img, COLOR_MIN, COLOR_MAX)
imgray = frame_threshed
ret,thresh = cv2.threshold(frame_threshed,127,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt=contours[0]
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow("Show",im)
cv2.waitKey()
cv2.destroyAllWindows()
Debido a que su imagen original es bastante ruidosa, una solución simple es eliminar parte del ruido usando cv2.medianBlur()
Esto eliminará las áreas de ruido pequeño en su imagen original y lo dejará con un solo contorno. Las primeras líneas de tu código se verían así:
im = cv2.imread(''shot.bmp'')
im = cv2.medianBlur(im,5) # 5 is a fairly small kernel size
hsv_img = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
Sin embargo, este método no es el más robusto porque debe especificar manualmente un tamaño de kernel, y la línea cnt=contours[0]
en su código asume que el contorno de interés es el primero en la lista de contornos, que solo es cierto si Solo hay un contorno. Un método más robusto es asumir que está interesado en el contorno más grande , lo que le permitirá compensar incluso el ruido moderado.
Para ello, añade las líneas:
# Find the index of the largest contour
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]
después de la línea:
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
Resultando en este código:
import numpy as np
import cv2
im = cv2.imread(''shot.bmp'')
hsv_img = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
COLOR_MIN = np.array([20, 80, 80],np.uint8)
COLOR_MAX = np.array([40, 255, 255],np.uint8)
frame_threshed = cv2.inRange(hsv_img, COLOR_MIN, COLOR_MAX)
imgray = frame_threshed
ret,thresh = cv2.threshold(frame_threshed,127,255,0)
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# Find the index of the largest contour
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow("Show",im)
cv2.waitKey()
cv2.destroyAllWindows()
Ambos métodos dan un resultado con un cuadro delimitador correcto:
nótese bien
A partir de OpenCV
3.x, el método findContours()
devuelve 3 resultados (como se puede ver here ), por lo que el valor de retorno adicional se debe capturar como:
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)