【问题标题】:Counting homogeneous objects along the contour沿轮廓计算同质对象
【发布时间】:2020-02-03 11:37:09
【问题描述】:

我正在尝试通过使用 OpenCV 找到它们的轮廓来获取框架上的对象数量。

That's a frame 应用 Canny 过滤器后:

然后我调用 findContours() 方法并留下适合大小的方法。 当我将它们叠加在一个框架上时,我得到了 the following picture.

可以看出,我们只有完整的轮廓对象。

所以问题是: 我们如何人为地使对象的边界成为整体?

我尝试使用扩张和腐蚀 (result of that),但之后对象的边界被粘在一起,我们再也找不到它们的轮廓了。

【问题讨论】:

    标签: image opencv image-processing computer-vision


    【解决方案1】:

    由于轮廓连接在一起,findContours 会将连接的轮廓检测为单个轮廓,而不是单个分离的圆。当您连接了轮廓时,一种可能的方法是使用分水岭来标记和检测每个轮廓。结果如下:

    输入图像

    输出

    代码

    import cv2
    import numpy as np
    from skimage.feature import peak_local_max
    from skimage.morphology import watershed
    from scipy import ndimage
    
    # Load in image, convert to gray scale, and Otsu's threshold
    image = cv2.imread('1.png')
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
    
    # Compute Euclidean distance from every binary pixel
    # to the nearest zero pixel then find peaks
    distance_map = ndimage.distance_transform_edt(thresh)
    local_max = peak_local_max(distance_map, indices=False, min_distance=20, labels=thresh)
    
    # Perform connected component analysis then apply Watershed
    markers = ndimage.label(local_max, structure=np.ones((3, 3)))[0]
    labels = watershed(-distance_map, markers, mask=thresh)
    
    # Iterate through unique labels
    for label in np.unique(labels):
        if label == 0:
            continue
    
        # Create a mask
        mask = np.zeros(gray.shape, dtype="uint8")
        mask[labels == label] = 255
    
        # Find contours and determine contour area
        cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        cnts = cnts[0] if len(cnts) == 2 else cnts[1]
        c = max(cnts, key=cv2.contourArea)
        color = list(np.random.random(size=3) * 256) 
        cv2.drawContours(image, [c], -1, color, 4)
    
    cv2.imshow('image', image)
    cv2.waitKey()
    

    这里有一些其他参考资料:

    1. Image segmentation with Watershed Algorithm

    2. Watershed Algorithm: Marker-based Segmentation

    3. How to define the markers for Watershed

    4. Find contours after watershed

    【讨论】:

    • 不错的参考!您可以在结果图像上方分享输入图像吗?我认为它可以让人们更容易欣赏你的算法。
    【解决方案2】:

    您的对象似乎有一个模式,这些对象有时会重叠。 我建议您将图像与对象模式进行卷积,然后处理输出的分数图像。

    更详细:

    为简单起见,假设您的初始图像只有一个通道。您要查找的对象如下所示:。这是我们的模式。说它的大小是 [W_p,H_p]

    第一步:构建新图像 - scores - 其中scores中的每个像素S = 该像素是图案中心的概率。

    做到这一点的一种方法是:对于原始图像中的每个像素 P,“剪切” P 周围的 [W_p,H_p] 补丁(例如 img(Rect(P-W_p/2,P-H_p/2,W_p ,H_p))),然后从pattern中减去patch以找到它们之间的“距离”(例如opencv中的cv::sum(cv::absdiff(patch, pattern))函数),并将这个和保存到S。

    另一种方法是:S = P.clone();模式 = 模式 / cv::sum(模式); 然后将 cv::filter2D 用于带模式的 S...

    现在您有了分数图像,您应该过滤误报: 1. 获得前 2% 的分数(一种方法是使用 cv::calcHist) 2. 对于在 [W_p,H_p] 内具有更高分数的邻居的每个像素 - 将此像素设为零!

    现在您应该保留只有图案中心才有价值的零图像。万岁!

    如果您事先不知道一个对象的外观,您可以使用轮廓找到一个对象,然后使用其轮廓的凸包(+边界框)将其“剪切”,并将其用作卷积内核用于查找其余部分。

    【讨论】:

    • 您说“将图像与对象模式进行卷积,然后处理输出的分数图像”。也许您可以为此指出必要的方法?
    • 我已经根据一般准则编辑了我的答案。现在好点了吗?
    猜你喜欢
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2019-05-22
    • 2013-04-26
    • 1970-01-01
    • 2020-07-17
    • 1970-01-01
    • 2021-08-01
    相关资源
    最近更新 更多