How to count objects in image using python?

后端 未结 3 2091
無奈伤痛
無奈伤痛 2020-12-06 03:12

I am trying to count the number of drops in this image and the coverage percentage of the area covered by those drops. I tried to convert this image into black and white, bu

相关标签:
3条回答
  • 2020-12-06 03:33

    You can fill the holes of your binary image using scipy.ndimage.binary_fill_holes. I also recommend using an automatic thresholding method such as Otsu's (avaible in scikit-image).

    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()
    

    For the number of drops you can use another function of scikit-image

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

    And for the coverage

    print('coverage is %f' %(drops.mean()))
    
    0 讨论(0)
  • 2020-12-06 03:38

    I used the following code to detect the number of contours in the image using OpenCV and python.

    import cv2
    import numpy as np
    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)
    

    For further removing the contours inside another contour, you need to iterate over the entire list and compare and remove the internal contours. After that, the size of "contours" will give you the count

    0 讨论(0)
  • 2020-12-06 03:40

    The idea is to isolate the background form the inside of the drops that look like the background. Therefore i found the connected components for the background and the inside drops took the largest connected component and change its value to be like the foreground value which left me with an image which he inside drops as a different value than the background. Than i used this image to fill in the original threshold image. In the end using the filled image i calculated the relevant values

    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)
    
    0 讨论(0)
提交回复
热议问题