【发布时间】:2011-09-18 13:56:19
【问题描述】:
当前情况:我正在尝试从图像中提取片段。多亏了 openCV 的 findContours() 方法,我现在有了每个轮廓的 8 个连接点的列表。但是,这些列表不能直接使用,因为它们包含很多重复项。
问题:给定一个包含重复的 8 个连接点的列表,从中提取线段。
可能的解决方案:
- 一开始我使用openCV的
approxPolyDP()方法。然而,结果很糟糕......这是缩放的轮廓:
这是approxPolyDP()的结果:(9段!有些重叠)
但我想要的更像是:
这很糟糕,因为approxPolyDP() 可以将“看起来像几个段”的东西转换为“几个段”。但是,我所拥有的是一个点列表,这些点往往会对其自身进行多次迭代。
例如,如果我的观点是:
0 1 2 3 4 5 6 7 8
9
然后,点列表将是0 1 2 3 4 5 6 7 8 7 6 5 4 3 2 1 9... 如果点数变大(>100),那么很遗憾,approxPolyDP() 提取的段不是重复的(即:它们相互重叠,但是不是严格相等的,所以我不能只说“删除重复项”,而不是像素)
- 也许,我有一个解决方案,但它很长(虽然很有趣)。首先,对于所有 8 连通列表,我创建一个稀疏矩阵(为了提高效率),如果像素属于列表,则将矩阵值设置为 1。然后,我创建了一个 graph,其中节点对应于像素,边缘位于相邻像素之间。这也意味着我在像素之间添加所有缺失的边缘(复杂性很小,可能是因为稀疏矩阵)。然后我删除所有可能的“正方形”(4 个相邻节点),这是可能的,因为我已经在处理非常细的轮廓。然后我可以启动一个最小生成树算法。最后,我可以用 openCV 的
approxPolyDP()近似树的每个分支
总结一下:我有一个乏味的方法,我还没有实现它,因为它似乎很容易出错。但是,我问你们,Stack Overflow 的人:还有其他现有的方法,可能有很好的实现吗?
编辑:澄清一下,一旦我有一棵树,我可以提取“分支”(分支从链接到 3 个或更多其他节点的叶子或节点开始)然后,openCV 的approxPolyDP() 中的算法是Ramer–Douglas–Peucker algorithm,这是它所做的维基百科图片:
有了这张图,很容易理解为什么当点可能相互重复时它会失败
另一个编辑:在我的方法中,有一些有趣的地方需要注意。当您考虑位于网格中的点(如像素)时,一般来说,最小生成树算法没有用处,因为有许多可能的最小树
X-X-X-X
|
X-X-X-X
与
有着根本的不同X-X-X-X
| | | |
X X X X
但两者都是最小生成树
但是,在我的例子中,我的节点很少形成集群,因为它们应该是轮廓,并且已经有一个细化算法预先在 findContours() 中运行。
对 Tomalak 评论的回答:
如果 DP 算法返回 4 段(从点 2 到中心的段有两次)我会很高兴!当然,通过良好的参数,我可以达到“偶然”拥有相同片段的状态,并且可以删除重复片段。但是,很明显,该算法不是为它设计的。
这是一个包含太多片段的真实示例:
【问题讨论】:
-
are unfortunately not duplicates (i.e : they overlap each other, but are not stricly equal, so I can't just say "remove duplicates", as opposed to pixels for example)我不明白这个。为什么不呢? -
我的回答是用另一张精美的画图编辑我的帖子 =)
-
我正在查看您为响应 Tomalak 添加的图片,并且我有一个疑问:DP 算法的结果实际上是一个有效的解决方案,如果您接受观察点可以为远非“真实”!段作为图像的中心点。您对算法必须遵守的点线距离是否有特定阈值?
-
不,我没有特定的阈值,但问题是我正在处理具有数千个轮廓的数千个图像。如果我为阈值设置一个特定的值,那么对于大多数轮廓,我将有一个可怕的重叠段混乱。我了解 DP 算法返回的是“有效”。但只要看看我帖子第一张照片中的蓝色部分。您可以看到有很多段,其中只需要两个或三个。由于列表的 8 连接性质,它们重叠。
标签: c++ image-processing graph opencv boost-graph