【问题标题】:C++-ObjC OpenCV Constrained DelaunayC++-ObjC OpenCV 约束 Delaunay
【发布时间】:2012-01-04 09:23:53
【问题描述】:

我在 OpenCV 2.3.1 中成功实现了轮廓的 Delaunay 三角剖分。

使用 cvPointPolygonTest 我可以获得凸包中的所有三角形,然后我尝试在三角形质心上执行另一个 cvPointPolygonTest 以了解它们是否在主轮廓中,所以我可以轮廓的约束三角剖分。

但是,它不能很好地工作,因为有些三角形是(例如,一个走路的人,他的两条腿分开)“越过”一个洞

有谁知道执行约束三角测量的方法。我想到了convexityDefects,但无法理解如何从这个开始。

提前致谢!


实际上,这不是凸壳缺陷问题,而是三角剖分问题。这张图片会告诉你麻烦:

特别是在三角包的底部,您可以看到三角剖分在轮廓内和外,因为 OpenCV 正在对凸包进行三角剖分。我想找到一种方法来对轮廓本身进行三角测量。

我发现了一些关于在轮廓本身中添加施泰纳点的想法,但找不到从哪里开始使用 OpenCV。

我的想法是:

  • 测试三角形是否在轮廓内和外;
  • 如果为真:获取交点;
  • 并将其添加到 cvSubdiv2D。

我说得对吗?

感谢您的耐心和回答!

【问题讨论】:

  • 你的意思是你的轮廓里面有一些洞,一些三角形里面有质心?
  • 感谢您的评论。是的,我就是这个意思。 cvSubdiv2D 对轮廓的凸包执行 Delaunay 三角剖分,而不是轮廓本身。所以(在一个人走路的情况下)我在左腿的边缘有一个点,在右腿的边缘有同一个三角形的另一个点。在这种情况下没关系:质心不在男人身上轮廓,但是当三角形在轮廓 孔上方时,它只会擦除三角形或完全占据它,具体取决于质心位置。

标签: opencv triangulation delaunay convex-hull


【解决方案1】:

最后我在我的程序中实现了 poly2tri 库。

这是结果(OpenCV 获取轮廓,然后 poly2tri 执行三角剖分):

// -------------------- poly2tri --------------------


NSMutableArray* temp = [[NSMutableArray alloc] init];

vector<p2t::Triangle*> triangles;
vector< vector<p2t::Point*> > polylines;
vector<p2t::Point*> polyline;

for(int i = 0; i < contour32->total; i++ ) {
    CvPoint2D32f* pt32 = CV_GET_SEQ_ELEM(CvPoint2D32f, contour32, i);
    polyline.push_back(new p2t::Point((double)pt32->x, (double)pt32->y));
}

polylines.push_back(polyline);


p2t::CDT* cdt = new p2t::CDT(polyline);



// TODO -> holes with CV_RETR_TREE

// Triangulation !
cdt->Triangulate();

// On exporte nos triangles
triangles = cdt->GetTriangles();

for (int i = 0; i < triangles.size(); i++) {

    p2t::Triangle& t = *triangles[i];
    p2t::Point& a = *t.GetPoint(0);
    p2t::Point& b = *t.GetPoint(1);
    p2t::Point& c = *t.GetPoint(2);

    double x1 = (width / rWidth * (double)a.x) - (width / 2.f);
    double y1 = (height / rHeight * (double)a.y) - (height / 2.f);                   
    double x2 = (width / rWidth * (double)b.x) - (width / 2.f);
    double y2 = (height / rHeight * (double)b.y) - (height / 2.f);
    double x3 = (width / rWidth * (double)c.x) - (width / 2.f);
    double y3 = (height / rHeight * (double)c.y) - (height / 2.f);

    [temp addObject:[[NSArray arrayWithObjects:
                      [NSArray arrayWithObjects:
                       [NSNumber numberWithDouble:x1],
                       [NSNumber numberWithDouble:y1],
                       [NSNumber numberWithDouble:0.],
                       nil], 
                      [NSArray arrayWithObjects:
                       [NSNumber numberWithDouble:x2],
                       [NSNumber numberWithDouble:y2],
                       [NSNumber numberWithDouble:0.],
                       nil], 
                      [NSArray arrayWithObjects:
                       [NSNumber numberWithDouble:x3],
                       [NSNumber numberWithDouble:y3],
                       [NSNumber numberWithDouble:0.],
                       nil], 
                      nil] autorelease]];

}

[outDelaunay addObject:temp];                       

contour32 是使用 cvFindContours 找到的 OpenCV 轮廓,然后转换为 float32。

【讨论】:

  • 这真的很有趣!你能给我一个提示如何正确地实现 cvFindContours 吗?我正在尝试在 iPhone 上使用它……
  • 你必须在你的灰度图像上执行一个阈值(如果你想要,一个精明的边缘,但这对性能来说真的很糟糕),然后为轮廓创建一个 CvSeq。之后,您可以执行 cvFindContours 并迭代轮廓以获得其坐标或直接绘制它。
  • 非常感谢!得到它的工作,但它是一团糟,因为我想我首先需要适当的背景减法。你有什么建议吗?
  • 我不知道你在什么平台上工作,但是 OpenCV 的背景减法对于性能来说非常重要。您可能想用着色器做一个简单的 BG,然后获取您的纹理并将其转换为 IplImage。
【解决方案2】:

你必须使用:

    CvSeq* cvConvexityDefects(
const CvArr* contour,
const CvArr* convexhull,
CvMemStorage* storage = NULL
);

这将返回CvConvexityDefect 的序列(CvSeq),而不是 CvPoint 或您可能习惯的任何其他类似 CvSeq 的东西。

你可以像这样循环处理缺陷:

CvSeq* defects =  cvConvexityDefects(.....);
for (i = 0; i < defects->total; i++)
{
CvConvexityDefect* def = (CvConvexityDefect*)cvGetSeqElem(defects, i);
//do something with them
}

缺陷具有以下结构:

    typedef struct CvConvexityDefect {
// point of the contour where the defect begins
CvPoint* start;
// point of the contour where the defect ends
CvPoint* end;
// point within the defect farthest from the convex hull
CvPoint* depth_point;
// distance between the farthest point and the convex hull
float depth;
} CvConvexityDefect;

因此,在获得每个缺陷后,您可以从它们构建一个点的 CvSeq,并在三角形的质心上使用 cvPointPolygonTest 以查看它们是否在它们内部。 如果它们在缺陷内部,则意味着它们在主要轮廓之外。

希望这是您需要的并且对您有所帮助。

【讨论】:

  • 您好,感谢您的留言。您的解决方案不会返回与返回我在 contour 本身 中执行的 cvPointPolygonTest 大致相同的东西吗?问题是我有时会有在凸包内在孔上的三角形,所以质心可能在轮廓或缺陷中。我试试你的提议!再次感谢!
  • 我正在考虑添加施泰纳点来执行约束三角剖分 (Steiner points),但不知道从哪里开始... :-/
  • 这是一张图片:on Google Doc
  • 我解释的内容涵盖了这个案例。两腿之间的空间将是 cvConvexityDefects 发现的缺陷,如果任何三角形的质心在该缺陷中,那么您必须将其删除,因为它不在轮廓内。
  • 非常感谢!我现在就试试这个!但我担心它会擦除一些特定的三角形,比如在预期轮廓和孔上方的三角形。我告诉你!
猜你喜欢
  • 2013-05-12
  • 1970-01-01
  • 2012-04-06
  • 2014-05-16
  • 2014-02-06
  • 1970-01-01
  • 2013-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多