简体   繁体   English

如何使用python计算图像中的对象?

[英]How to count objects in image using python?

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, but the center color of those drops seems too similar to the background.我试图将此图像转换为黑白,但这些水滴的中心颜色似乎与背景过于相似。 So I only got something like the second picture.所以我只得到了第二张照片。 Is there any way to solve this problem or any better ideas?有什么办法可以解决这个问题或有更好的想法吗? Thanks a lot.非常感谢。

源图像

转换后的图像

You can fill the holes of your binary image using scipy.ndimage.binary_fill_holes .您可以使用scipy.ndimage.binary_fill_holes填充二进制图像的孔。 I also recommend using an automatic thresholding method such as Otsu's (avaible in scikit-image ).我还建议使用自动阈值方法,例如 Otsu 的(在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对于滴数,您可以使用scikit-image另一个功能

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

And for the coverage对于覆盖范围

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

I used the following code to detect the number of contours in the image using OpenCV and python.我使用以下代码使用 OpenCV 和 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之后,“轮廓”的大小会给你计数

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)

Solution解决方案

image = cv2.imread('image path.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# (thresh, blackAndWhiteImage) = cv2.threshold(gray, 127, 255, 
cv2.THRESH_BINARY)
plt.imshow(gray, cmap='gray')
blur = cv2.GaussianBlur(gray, (11, 11), 0)
plt.imshow(blur, cmap='gray')
canny = cv2.Canny(blur, 30, 40, 3)
plt.imshow(canny, cmap='gray')
dilated = cv2.dilate(canny, (1, 1), iterations=0) 
plt.imshow(dilated, cmap='gray')
(cnt, hierarchy) = cv2.findContours(
dilated.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
cv2.drawContours(rgb, cnt, -1, (0, 255, 0), 2)
plt.imshow(rgb)
print("No of circles: ", len(cnt))

灰度图

边缘检测 绘制轮廓

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM