【问题标题】:Filling gaps between borders/contours in images填充图像中边框/轮廓之间的间隙
【发布时间】:2019-02-01 12:45:04
【问题描述】:

我有两张图片,我想将它们组合在一起,并在组合后填充/移除边框之间的间隙。左边的图像是边缘,而右边的图像是蒙版。 (忽略右图的小补丁,能去掉就好了)

组合后的预期结果是

但这是目前取得的成果

我尝试了与 scikit-image apis 不同的策略,其中包括:

ndi.binary_openingndi.binary_closingmorphology.{erosion, dilation, opening, closing} 但它们似乎都不起作用。

【问题讨论】:

  • 总是在一边吗?你可以cv2.floodFill() 左边的第一个面具。
  • 正确的mask图像如何影响你想要的最终结果?看来您只想填写左侧 edge 图像的左侧,而不管 mask 图像的比赛。
  • @HeinWessels,不,填充不一定从所有图像的左侧开始。有时边缘是水平的,请参阅其他examples(左侧的组合边缘和蒙版,右侧的目标)。所以填充的方向将基于大多数黑色像素所在的位置。
  • @AlexanderReynolds,我尝试了 cv2.floodFill 但它填充了整个像素,只留下了edges
  • 是否保证“边缘图像”中的边缘是连续的(没有间隙/中断)并且它总是接触/加入2中图片的外边缘不同的地方?

标签: opencv image-processing scikit-image smoothing flood-fill


【解决方案1】:

我认为这可能是战略的基础......

第 1 步:

“边缘图像”开始。随机选择任何白色像素。使用该像素作为种子或起点填充黑色。这应该填充边缘的一侧。记住种子,并获得新的质心(可能还有区域),填充为黑色区域。反转填充的图像,得到图像另一部分的质心。

您现在知道边缘两侧的质心 - 如下图红色标记:

第 2 步:

现在移动到蒙版图像。也许使用膨胀/腐蚀来填补任何小洞。然后在图像上运行“标记”以获取连续黑色斑点及其质心和区域的列表。按区域选择最大的 blob。

您现在应该拥有最大斑点的质心,如下面的绿色标记:

第 3 步:

现在选择两个红色点中离绿色点较近的一个,并使用相应的种子进行填充。


在步骤 1 中重复随机选择白色种子点可能会更好,直到获得不同的质心,而不是进行反演。那是因为如果你只是反转并获得质心,你不知道一个好的种子像素。不能确定质心是否是好种子。

【讨论】:

  • 你提到你不能确定它是一个好种子。你为什么这么说?质心应该在填充空间的中间,这对我来说听起来是一个很好的起点? :) @马克
  • @HeinWessels 如果您查看第三个示例(cmets 中的链接),您会看到它有很多白色“洞”,并且质心可能会落入其中一个,然后当您进行洪水时填补,你只会填补这个洞 - 我想。我可能错了!我曾经使用质心和讨厌的大写 C 被输入,当然白色背景上的大黑色 C 的质心是白色 - 不是黑色!
  • 确实如此。但这些漏洞存在于mask 图像上,而edge 图像仅包含一条线。如果你FloodFilledge 图像,则没有可掉入的孔,FloodFill 应该可以顺利运行。显示的示例将edgemask 图像组合在一起。 @马克
【解决方案2】:

好像你需要找到mask函数的质心(CoM)来确定填充哪一边,然后使用floodFilledge来自 CoM 的图像作为播种点。

你可以试试这样的:

# Calculate the Center of Mass
com = np.zeros(2)
sum = np.zeros(2)
for x in range(0, nu_of_rows):
    for y in range(0, num_of_cols):
        com += image[x][y] * np.array([x,y])
        sum += image[x][y]
com /= sum

# FloodFill a new image
h, w = mask_img.shape[:2]
new_image = mask_img.copy()
temp = np.zeros((h+2,w+2),np.uint8) # Needs to be 2 pixels wider/higher
cv2.FloodFill(new_image, temp, coi, 255, flags=cv2.FLOODFILL_MASK_ONLY)

如果您的 edgemask 图像中的线条具有值 255 和背景 0,这将起作用。如果不是这种情况,请首先使用以下命令反转您的两个图像:

inverted_img = cv2.bitwise_not(img)

注意:我没有用你的图片测试这个,而是用我的一张。所以你可能不得不在这里和那里改变一些东西。这是我的粗略示例:

【讨论】: