如何使用python计算图像中的对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38619382/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to count objects in image using python?
提问by JIAHAO HUANG
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.
我正在尝试计算此图像中的水滴数量以及这些水滴所覆盖区域的覆盖百分比。我试图将此图像转换为黑白,但这些水滴的中心颜色似乎与背景太相似。所以我只得到了类似于第二张图的东西。有什么办法可以解决这个问题或者有什么更好的想法吗?非常感谢。
回答by Emmanuelle Gouillart
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
).
您可以使用scipy.ndimage.binary_fill_holes
. 我还建议使用自动阈值方法,例如 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()))
回答by Saurav
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
回答by Amitay Nachmani
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)