удаление лишних хвостов от контуров - PullRequest
0 голосов
/ 24 января 2020

Я пытаюсь найти контуры на изображениях в оттенках серого. Мой код основан на постоянных гомологиях и здесь не имеет значения. Но контуры, которые я собираю, идут с некоторыми хвостами.

enter image description here

Итак, мне нужно постобработать эти контуры, удалив хвосты. Я придумал способ сделать это: залить заливку снаружи контура, а затем удалить пиксели контура, которые не являются границей исходного l oop Я пытаюсь захватить.

#####################################
# 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 misdr aws контуры и cv2.convexHull отслеживает хвосты и дает мне больший контур, чем мне нужно. Должно быть легкое задание, но чего мне не хватает?

...