opencv - 从轮廓中去除多余的尾巴
问题描述
我试图在灰度图像中找到轮廓。我的代码基于持久同源性,在这里无关紧要。但是我正在拾取的轮廓带有一些尾巴。
所以,我需要通过去除尾部对这些轮廓进行后处理。我想出了一种方法来做到这一点,方法是填充轮廓外部,然后删除不是我要捕获的原始循环边界的轮廓像素。
#####################################
# 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 跟踪尾部并给我一个比我需要的更大的轮廓。应该是一件容易的事,但我错过了什么?
解决方案
推荐阅读
- javascript - 如何验证用户登录的 Web 应用程序(php)?
- lua - premake5 如何生成相对于用户调用 premake 的项目,而不是相对于 premake5.lua 文件?
- go - golang type []dao.Record 没有字段或方法 Id
- r - 如何构建一个变量来汇总多变量
- python - 如何在本地系统上设置 rasa 多语言机器人
- c++ - Boost ASIO - 无法从正文中读取数据包标头
- python - 使用 BeautifulSoup 抓取多个 URL
- html - 如何在忽略父级设置的高度的情况下停止 flexbox 容器中的图像?
- c++ - ESP32 build in Arduino IDE: undefined reference to `CLASS::function' 错误
- reactjs - ReactJs onClick 手机