我有一个口罩,里面可能有洞。我想从蒙版的外部(而不是孔)水平方向侵 eclipse 一定数量的像素。
诀窍是,如果我向内侵 eclipse 5px,并且在某个点距边缘 3px 处有一个洞,我想侵 eclipse 这 3px,然后侵 eclipse 洞后剩余的 2px。所以我总是每边侵 eclipse 5px,基本上跳过任何洞。
例如使用这个掩码:
这些灰色区域将被侵 eclipse :
我可以通过循环每一行来了解如何做到这一点,例如:
erode_px = 5
for y, row in enumerate(mask):
idxs = np.nonzero(row)[0]
if idxs.size:
if idxs.size < erode_px * 2:
mask[y] = 0
else:
mask[y, :idxs[erode_px]] = 0
mask[y, idxs[-erode_px]:] = 0
但是我正在处理非常大的掩模,这需要高效。有没有一种方法可以在不循环Python中的每一行的情况下实现这一点?最好只使用 OpenCV/numpy。
最佳答案
您可以使用累积总和来完成您想要的事情:
- 计算沿水平线的累积和。
- 所需距离
n
处的阈值累积和。 - 与输入进行逻辑与。
这将取消每行上前 n
组像素的设置。要从右边缘应用运算,请翻转矩阵,应用上面的运算,然后翻转结果。
以下代码演示了该操作:
import numpy as np
import matplotlib.pyplot as plt
def erode_left(mask, n):
return np.logical_and(np.cumsum(mask, axis=1) > n, mask)
def erode_both(mask, n):
mask = erode_left(mask, n)
mask = np.fliplr(erode_left(np.fliplr(mask), n))
return mask
mask = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,1,1,1,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0],
[0,1,1,1,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0],
[0,1,1,1,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0],
[0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]], dtype=bool)
f, axarr = plt.subplots(2,2)
axarr[0,0].imshow(mask)
axarr[0,0].title.set_text('Input')
axarr[0,1].imshow(erode_left(mask, 5))
axarr[0,1].title.set_text('Eroded left side')
axarr[1,0].imshow(erode_both(mask,5))
axarr[1,0].title.set_text('Eroded both sides')
axarr[1,1].imshow(erode_both(mask,5) + 2*mask)
axarr[1,1].title.set_text('Overlay')
plt.show()
关于python - 在 OpenCV 中从带有孔的掩模侧面腐 eclipse x 像素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68241209/