Consulta código - Tratamiento de imagen en Python

opencv
python

#1

Hola!

Os comento una duda que tengo con mi código en Python, por si alguno pudiera ayudarme.

Tengo una imagen de un ala de mosca tal que así:

y quiero cuantificar cuánto del área del ala está ocupado por la mancha, así que he escrito esto:

    # Independent estimations of the contours - the whole wing and the wing spot
    # Then, identification of the areas corresponding to the whole wing and the wing spot
    # Finally, the areas of each contours are estimated and the ratio is inferred

    # Packages loading. Remember the install needs to be done from the command line

    import cv2
    import numpy as np;

    # Import of the image

    im = cv2.imread('.\\M1D_Bar.jpg')

    # Image blurring
     
    blurred = cv2.pyrMeanShiftFiltering(im, 31,91)

    # Blurred image turned to gray scale

    gray = cv2.cvtColor(blurred, cv2.COLOR_BGR2GRAY)

    ##### Here's where the part corresponding to the WHOLE WING starts
    # Colour threshold is applied, so the background of the wing is separated

    ret , thresh = cv2.threshold(gray, 0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

    # Estimation of all the contours (wing vs background and others!)

    _ , cont, _ = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

    # Representation of the 6th contour (wing vs background)

    cv2.drawContours(im, cont, 6, (255,255,0),6)

    cv2.namedWindow('Wing contour', cv2.WINDOW_NORMAL)
    cv2.imshow('Wing contour', im)

    ##### Here there's the part belonging to the spot
    # A hardcore colour threshold is applied, so the spot is identified

    retval, threshold = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)

    # Estimation of all the contours (spot vs rest and others!)

    _ , contours, _ = cv2.findContours(threshold, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)

    # Representation of the 105th contour (spot vs rest)

    cv2.drawContours(im, contours, 105, (255,255,0),6)

    cv2.namedWindow('Spot area', cv2.WINDOW_NORMAL)
    cv2.imshow('Spot area', im)

    ###### Estimation of the ratio spot area / wing area

    ratio = cv2.contourArea(contours[105]) / cv2.contourArea(cont[6])

Creo que el trabajo me lo hace, pero no entiendo por qué al intentar representar sólo el área de la mancha también me representa el contorno del ala y me da miedo, porque me preocupa entonces que al estimar el ratio mancha/ala también esté cogiendo áreas que no son. ¿Alguna idea/observación?


#2

Qué versiones estás usando de opencv y python? Cuando intento ejecutar el código me sale esto:

Traceback (most recent call last):
  File "code.py", line 30, in <module>
    _ , cont, _ = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
ValueError: need more than 2 values to unpack

Edit: uso python 2.7.5, opencv 2.4.5


#3

Hola!

Por lo que he entendido quieres saber el tamaño de la mancha grande que tiene el ala.

No he compilado el codigo pero te explico lo siguiente:

“contours” es una lista de todos los contornos que tiene la imagen binarizada que le has pasado por parametro, o sea, “threshold”.

Si lo que quieres es sacar la cantidad de pixeles (tamaño del área) que tiene la mancha puedes hacer lo siguiente:

for c in contornos:
	t = 0
	area = cv2.contourArea(c)
	if area > t:
		t = area

De esta forma sacamos el tamaño de la mas grande. que es teóricamente nuestra mancha, pero OJO:

1º Ten cuidado con el filtro que aplicas en el threshold ya que puede hacer que binarices demasiado o demasiado poco!
2º El ala tiene “pinchos” muy negros por lo que cuando binarices la mancha y los pinchos se te unirán en un solo contorno, para “arreglar” yo te aconsejo que erosiones la imagen 4 o 5 veces, y luego la dilates la misma cantidad de veces.

Aquí esta la documentación de estos dos métodos muy bien explicada:

http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.html

Los métodos que te comento son los siguientes:

erosion = cv2.erode(img,kernel,iterations = 4)
dilation = cv2.dilate(img,kernel,iterations = 4)

Espero que te sirva!


#4

Estoy usando Python 3.6.4 y opencv 3.4.0.

Muchas gracias por darle un intento!


#5

Hola! Muchas gracias por la ayuda. Un par de cuestiones:

En realidad en mi código todavía se encuentran contornos más grandes, por eso la he seleccionado a mano. Es verdad que tengo que encontrar una manera de automatizar que elija la mancha y no otro.

En mi código consigo que los ‘pinchos’ no se me unan al contorno al ‘emborronar’ la imagen (blurred), pero lo tendré en cuenta para otros especímenes, sobre todo porque tu opción es bastante más elegante.

¿Alguna idea sobre por qué al ejecutar cv2.imshow(‘Spot area’, im) me aparecen dos contornos?