¿Cómo contar objetos en imagen usando python?

Estoy tratando de contar el número de gotas en esta imagen y el porcentaje de cobertura del área cubierta por esas gotas. Intenté convertir esta imagen en blanco y negro, pero el color central de esas gotas parece demasiado similar al fondo. Así que solo tengo algo como la segunda foto. ¿Hay alguna manera de resolver este problema o alguna idea mejor? Muchas gracias.

imagen de origen

imagen convertida

Utilicé el siguiente código para detectar el número de contornos en la imagen usando openCV y python.

img = cv2.imread('ba3g0.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret,thresh = cv2.threshold(gray,127,255,1) contours,h = cv2.findContours(thresh,1,2) for cnt in contours: cv2.drawContours(img,[cnt],0,(0,0,255),1) 

Resultado Para que Furthur elimine los contornos dentro de otro contorno, debe recorrer toda la lista y comparar y eliminar los contornos internos. Después de eso, el tamaño de los “contornos” le dará la cuenta

Puede rellenar los agujeros de su imagen binaria utilizando scipy.ndimage.binary_fill_holes . También recomiendo usar un método de umbral automático como el de Otsu (disponible en scikit-image ). introduzca la descripción de la imagen aquí

 from skimage import io, filters from scipy import ndimage import matplotlib.pyplot as plt im = io.imread('ba3g0.jpg', as_grey=True) val = filters.threshold_otsu(im) drops = ndimage.binary_fill_holes(im < val) plt.imshow(drops, cmap='gray') plt.show() 

Para el número de gotas puede usar otra función de scikit-image

 from skimage import measure labels = measure.label(drops) print(labels.max()) 

Y para la cobertura.

 print('coverage is %f' %(drops.mean())) 

La idea es aislar el fondo desde el interior de las gotas que se parecen al fondo. Por lo tanto, encontré que los componentes conectados para el fondo y las gotas interiores tomaron el componente más grande conectado y cambié su valor para que sea como el valor de primer plano, lo que me dejó con una imagen que él coloca como un valor diferente al del fondo. Que utilicé esta imagen para completar la imagen del umbral original. Al final, utilizando la imagen rellena, calculé los valores relevantes.

 import cv2 import numpy as np from matplotlib import pyplot as plt # Read image I = cv2.imread('drops.jpg',0); # Threshold IThresh = (I>=118).astype(np.uint8)*255 # Remove from the image the biggest conneced componnet # Find the area of each connected component connectedComponentProps = cv2.connectedComponentsWithStats(IThresh, 8, cv2.CV_32S) IThreshOnlyInsideDrops = np.zeros_like(connectedComponentProps[1]) IThreshOnlyInsideDrops = connectedComponentProps[1] stat = connectedComponentProps[2] maxArea = 0 for label in range(connectedComponentProps[0]): cc = stat[label,:] if cc[cv2.CC_STAT_AREA] > maxArea: maxArea = cc[cv2.CC_STAT_AREA] maxIndex = label # Convert the background value to the foreground value for label in range(connectedComponentProps[0]): cc = stat[label,:] if cc[cv2.CC_STAT_AREA] == maxArea: IThreshOnlyInsideDrops[IThreshOnlyInsideDrops==label] = 0 else: IThreshOnlyInsideDrops[IThreshOnlyInsideDrops == label] = 255 # Fill in all the IThreshOnlyInsideDrops as 0 in original IThresh IThreshFill = IThresh IThreshFill[IThreshOnlyInsideDrops==255] = 0 IThreshFill = np.logical_not(IThreshFill/255).astype(np.uint8)*255 plt.imshow(IThreshFill) # Get numberof drops and cover precntage connectedComponentPropsFinal = cv2.connectedComponentsWithStats(IThreshFill, 8, cv2.CV_32S) NumberOfDrops = connectedComponentPropsFinal[0] CoverPresntage = float(np.count_nonzero(IThreshFill==0)/float(IThreshFill.size)) # Print print "Number of drops = " + str(NumberOfDrops) print "Cover precntage = " + str(CoverPresntage)