【问题标题】:Extracting objects after watershed segmentation分水岭分割后提取对象
【发布时间】:2020-06-14 05:12:21
【问题描述】:

我需要分割下图中的种子并裁剪它们。

https://i.stack.imgur.com/ndOkX.jpg

它们可能非常接近,有时会重叠,所以我选择使用分水岭算法来完成这项任务。

在绘制返回的标记的轮廓之后,我的结果如下图所示,正如您所见,我在定义用于应用它的良好标记时遇到了问题。个别种子被勾勒出来,但有许多我不想要的内部线条。

https://i.stack.imgur.com/BtOfj.jpg

我将如何删除它们或定义更好的标记?

我正在运行的代码:

from skimage.feature import peak_local_max
from skimage.segmentation import watershed
import matplotlib.pyplot as plt
from scipy import ndimage
import cv2 as cv
import imutils
import numpy as np

img = cv.imread("image.jpg");
blur = cv.GaussianBlur(img,(7,7),0)


#color space change
mSource_Hsv = cv.cvtColor(blur,cv.COLOR_BGR2HSV);
mMask = cv.inRange(mSource_Hsv,np.array([0,0,0]),np.array([80,255,255]));
output = cv.bitwise_and(img, img, mask=mMask)

#grayscale
img_grey = cv.cvtColor(output, cv.COLOR_BGR2GRAY)

#thresholding
ret,th1 = cv.threshold(img_grey,0,255,cv.THRESH_BINARY + cv.THRESH_OTSU)

#dist transform
D = ndimage.distance_transform_edt(th1)

#markers
localMax = peak_local_max(D, indices=False, min_distance=20, labels=th1)
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]

#apply watershed
labels = watershed(-D, markers, mask=th1)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))

# loop over the unique labels

for label in np.unique(labels):
    if label == 0:
        continue

    # draw label on the mask
    mask = np.zeros(img_grey.shape, dtype="uint8")
    mask[labels == label] = 255

    # detect contours in the mask and grab the largest one
    cnts = cv.findContours(mask.copy(), cv.RETR_EXTERNAL,
        cv.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    c = max(cnts, key=cv.contourArea)

    cv.drawContours(img, cnts, -1, (0, 255, 0), 2)


cv.imshow("segmented",img)
cv.waitKey(0)

【问题讨论】:

    标签: python opencv computer-vision image-segmentation watershed


    【解决方案1】:

    您可以合并每两个应用以下条件的轮廓:

    • 合并轮廓的凸包面积接近两个轮廓的面积之和。

    以下解决方案使用一种“蛮力”方法,尝试将每个轮廓与所有其他轮廓合并(不是很有效)。

    这是一个工作代码示例(请阅读 cmets):

    from skimage.feature import peak_local_max
    from skimage.segmentation import watershed
    import matplotlib.pyplot as plt
    from scipy import ndimage
    import cv2 as cv
    import imutils
    import numpy as np
    
    img = cv.imread("image.jpg");
    blur = cv.GaussianBlur(img,(7,7),0)
    
    
    #color space change
    mSource_Hsv = cv.cvtColor(blur,cv.COLOR_BGR2HSV);
    mMask = cv.inRange(mSource_Hsv,np.array([0,0,0]),np.array([80,255,255]));
    output = cv.bitwise_and(img, img, mask=mMask)
    
    #grayscale
    img_grey = cv.cvtColor(output, cv.COLOR_BGR2GRAY)
    
    #thresholding
    ret,th1 = cv.threshold(img_grey,0,255,cv.THRESH_BINARY + cv.THRESH_OTSU)
    
    #dist transform
    D = ndimage.distance_transform_edt(th1)
    
    #markers
    localMax = peak_local_max(D, indices=False, min_distance=20, labels=th1)
    markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
    
    #apply watershed
    labels = watershed(-D, markers, mask=th1)
    print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))
    
    
    contours = []
    
    # loop over the unique labels, and append contours to all_cnts
    for label in np.unique(labels):
        if label == 0:
            continue
    
        # draw label on the mask
        mask = np.zeros(img_grey.shape, dtype="uint8")
        mask[labels == label] = 255
    
        # detect contours in the mask and grab the largest one
        cnts = cv.findContours(mask.copy(), cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
        cnts = imutils.grab_contours(cnts)
        c = max(cnts, key=cv.contourArea)
    
        ## Ignore small contours
        #if c.shape[0] < 20:
        #    continue
    
        # Get convex hull of contour - it' going to help when merging contours
        hull = cv.convexHull(c)
    
        #cv.drawContours(img, c, -1, (0, 255, 0), 2)
        cv.drawContours(img, [hull], -1, (0, 255, 0), 2, 1)
    
        # Append hull to contours list
        contours.append(hull)
    
    
    # Merge the contours that does not increase the convex hull by much.
    # Note: The solution is kind of "brute force" solution, and can be better.
    ################################################################################
    for i in range(len(contours)):
        c = contours[i]
    
        area = cv.contourArea(c)
    
        # Iterate all contours from i+1 to end of list
        for j in range(i+1, len(contours)):
            c2 = contours[j]
    
            area2 = cv.contourArea(c2)
    
            area_sum = area + area2
    
            # Merge contours together
            tmp = np.vstack((c, c2))
            merged_c = cv.convexHull(tmp)
    
            merged_area = cv.contourArea(merged_c)
    
            # Replace contours c and c2 by the convex hull of merged c and c2, if total area is increased by no more then 10%
            if merged_area < area_sum*1.1:
                # Replace contour with merged one.
                contours[i] = merged_c
                contours[j] = merged_c
                c = merged_c
                area = merged_area
    ################################################################################
    
    
    # Draw new contours in red color
    for c in contours:
        #Ignore small contours
        if cv.contourArea(c) > 100:
            cv.drawContours(img, [c], -1, (0, 0, 255), 2, 1)
    
    
    cv.imshow("segmented",img)
    cv.waitKey(0)
    cv.destroyAllWindows()
    

    结果:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-11
      • 2019-04-22
      • 1970-01-01
      • 2015-02-24
      • 2013-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多