通过FindContours方法找到的轮廓层次结构进行导航?

5
这对于直接使用OpenCV的C++开发人员来说应该很简单。然而,我使用的是Emgu(.NET的OpenCV包装器),在最新版本中,我们有一个返回void的方法CvInvoke.FindContours,输出结果通过参数引用传递,并且是类型为VectorOfVectorOfPoint的变量。
下面是一个简单的调用示例:
//outputResult is a VectorOfVectorOfPoint
CvInvoke.FindContours(inputImage, outputResult, null, RetrType.Tree, 
                      ChainApproxMethod.ChainApproxSimple);

对于RetrType.List模式,我们可以将结果转换为一些数组的数组,并轻松地遍历所有轮廓。然而,在这里,我想通过树形结构浏览所有轮廓。我猜我们必须使用指针(通过输出结果的Ptr属性访问)来进行本机(不安全的)C++代码处理。但我想知道是否有更.NET友好的解决方案。即使使用指针是唯一的解决方案,我仍然不知道如何深入探索那个Ptr以遍历轮廓树。
Emgu安装附带的示例代码中有一个使用CvInvoke.FindContourTree的片段(并返回int[,])。

1
层次结构不是输出到你设置为null的第三个参数中吗?无论你使用RetrType.List还是Tree,都可以以完全相同的方式枚举轮廓,以获取层次信息,创建一个类型为Mat的新变量,并将其作为第三个参数传递(现在为null)。 - Evk
@Evk 是的,我没有意识到我应该在第三个位置传递什么,即使我知道那是什么类型,我也不会知道它是什么类型。现在你让我知道我应该传递一个 Mat。但是我刚刚试图找到更多关于这种类型的信息,似乎没有任何易于识别的成员来帮助浏览树形结构。如果可能的话,请在你的回答中给我一些示例代码。非常感谢。谢谢! - Hopeless
1个回答

7
为了获得轮廓的层次结构,您必须首先将Mat对象传递给该函数:
Mat hierarchy = new Mat() ;
CvInvoke.FindContours(inputImage, outputResult, hierarchy, RetrType.Tree, 
                  ChainApproxMethod.ChainApproxSimple);

然后您可以按照以下方式使用`hierarchy`对象(有关Python OpenCV的更多详细信息,请参见此处):
`hierarchy`将是一个大小为1 x `outputResult`大小 x 4的`Mat`对象。所以对于索引为`i`的轮廓:
- `hierarchy[0,i,0]` 是相同层次结构中下一个轮廓的索引(具有相同父级),如果不存在则为-1。 - `hierarchy[0,i,1]` 是相同层次结构中上一个轮廓的索引,如果不存在则为-1。 - `hierarchy[0,i,2]` 是轮廓`i`的子代索引,如果不存在则为-1。 - `hierarchy[0,i,3]` 是轮廓`i`的父级索引,如果不存在则为-1。
这就是如何使用层次结构对象的方法。
通过使用它们的索引,可以通过`outputResult`对象访问轮廓本身。

你确定 Mat 有接受3个参数的索引器吗?我尝试声明一个简单的 Mat 变量并编写类似于 m[0,0,0] 的代码,但会导致一些设计时错误,当然它甚至无法编译。你提出的可能在Python中有效,但这里我是在问C#。谢谢! - Hopeless
你试过 m.Data[0,0,0] 吗?虽然我不能用C#测试,但是一些网络回答似乎表明这是可能的。 - Sunreef
m.Data 是一个可能具有不同维度(秩)的 Array,因此它可能具有 3 的秩,但是我们需要使用 GetValue 方法来代替(Array 也没有接受 3 个参数的索引器)。然而,我已经尝试了我的代码,发现 m.Data 实际上是 null,这是不可能实现树形结构的,这意味着 m.Data 不是提取树形数据的地方。这个 Map 对我来说本身就很复杂,它是一种通用类,所以很难知道如何在这种特定情况下使用它。 - Hopeless
@Hopeless 如果您想解决这个问题,可以使用hierarchy.CopyTo方法将数据复制到数组中,具体请参考此讨论。但是,您需要调整索引以访问正确的元素。您可以尝试复制数据以查看是否有效。 - Sunreef

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接