Я пытаюсь найти контуры на изображениях в оттенках серого. Мой код основан на постоянных гомологиях и здесь не имеет значения. Но контуры, которые я собираю, идут с некоторыми хвостами.
Итак, мне нужно постобработать эти контуры, удалив хвосты. Я придумал способ сделать это: залить заливку снаружи контура, а затем удалить пиксели контура, которые не являются границей исходного 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 отслеживает хвосты и дает мне больший контур, чем мне нужно. Должно быть легкое задание, но чего мне не хватает?