首页 > 解决方案 > 从轮廓中去除多余的尾巴

问题描述

我试图在灰度图像中找到轮廓。我的代码基于持久同源性,在这里无关紧要。但是我正在拾取的轮廓带有一些尾巴。

在此处输入图像描述

所以,我需要通过去除尾部对这些轮廓进行后处理。我想出了一种方法来做到这一点,方法是填充轮廓外部,然后删除不是我要捕获的原始循环边界的轮廓像素。

#####################################
# Post-process the cycles(Get rid of the tails)
#####################################

def fill_mask(self,data, start_coords, fill_value):
    """
    Flood fill algorithm 
    Parameters
    ----------
    data : (M, N) ndarray of uint8 type
        Image with flood to be filled. Modified inplace.
    start_coords : tuple
        Length-2 tuple of ints defining (row, col) start coordinates.
    fill_value : int
        Value the flooded area will take after the fill.

    Returns
    -------
    None, ``data`` is modified inplace.
    """
    xsize, ysize = data.shape
    orig_value = data[start_coords[0], start_coords[1]]
    stack = set(((start_coords[0], start_coords[1]),))
    if fill_value == orig_value:
        raise ValueError("Filling region with same value "
                 "already present is unsupported. "
                 "Did you already fill this region?")

    while stack:
        x, y = stack.pop()

        if data[x, y] == orig_value:
            data[x, y] = fill_value
            if x > 0:
                stack.add((x - 1, y))
            if x < (xsize - 1):
                stack.add((x + 1, y))
            if y > 0:
                stack.add((x, y - 1))
            if y < (ysize - 1):
                stack.add((x, y + 1))

def remove_non_boundary(self,good_cycles):
    #Helper function to remove tails from the contours
    #if plot=True, it allows to see individual cycles as a matrix
    #we use fill_mask to floodfill everywhere on the mask except the hole bounded by the loop.
    #we start floodfilling from (0,0), so we need to use 2 pixels bigger image along left-right and up-down just in case there is a 
    #cycle whose coordinates go through (0,0)
    #"input:cycles with tails to be removed"
    #"Returns:coordinates of the clean cycles and the correponding matrix representation 1-pixel bigger than the original image"
    #"from all four directions"
    good_cycles_cleaned=[]
    masks=[]
    for k in range(len(good_cycles)):
        mask=self.overlay(good_cycles[[k]])
        self.fill_mask(mask[:,:,0],(0,0),0.5)
        for i in self.cycle2pixel(good_cycles[k]):
            if mask[i[0]+2,i[1]+1,0]==0:pass#break
            elif mask[i[0]+1,i[1]+2,0]==0:pass#break
            elif mask[i[0],i[1]+1,0]==0:pass#break
            elif mask[i[0]+1,i[1],0]==0:pass#break
            else: mask[i[0]+1,i[1]+1,0]=0.5
        if mask[:,:,0].all()==0.5: good_cycles_cleaned.append(good_cycles[k]);mask=self.overlay(good_cycles[[k]]);masks.append(mask)
        else: self.fill_mask(mask[:,:,0],(0,0),0); cycle=np.transpose(np.nonzero(mask[:,:,0])) ;  good_cycles_cleaned.append(cycle) ; masks.append(mask)
    pixels = np.vstack([cycle for cycle in good_cycles_cleaned])
    mask_good_clean = np.zeros((self.image.shape[0]+2, self.image.shape[1]+2, 4))
    mask_good_clean[pixels[:,0]+1, pixels[:,1]+1,0] = 1
    mask_good_clean[pixels[:,0]+1, pixels[:,1]+1,3] = 1
    return good_cycles_cleaned,mask_good_clean,masks

但是,这种方法需要很长时间,我需要一种更快的方法。我尝试在 opencv 中使用几乎所有东西,但没有什么能完全满足我的需求。cv2.approxPolyDP 画错轮廓,而 cv2.convexHull 跟踪尾部并给我一个比我需要的更大的轮廓。应该是一件容易的事,但我错过了什么?

标签: opencvcontourflood-fill

解决方案


推荐阅读