2

I succesfully implemented a Delaunay triangulation of a contour in OpenCV 2.3.1.

With cvPointPolygonTest I can get all the triangles in the convex hull, then I tried to perform another cvPointPolygonTest on triangles centroid to know if they are in the main contour or not, so I can have the constrained triangulation of the contour.

But, it doesn't work well, as some triangles are (eg. with a walking man who has his two legs distant) 'over' a hole.

Does anyone know a way to perform a constrained triangulation. I thought about convexityDefects, but can't manage to understand how to begin with this.

Thanks in advance !

Ben


In fact, it is not a Convex Hull defects problem, but a triangulation one. This image will show you the trouble :

Particularly in the bottom of the triangulated hull, you can see that the triangulation is in AND out of the contour, because OpenCV is triangulating the convex hull. I would like to find a way to triangulate the contour itself.

I found some ideas about adding Steiner Points in the contour itself, but can't find where to begin with OpenCV.

My idea was to :

  • test if the triangle is in AND out of the contour ;
  • if true : get the intersection point ;
  • and add it to the cvSubdiv2D.

Am I right with this ?

Thanks for your patience and your answers !

Community
  • 1
  • 1
Benoît Lahoz
  • 1,270
  • 1
  • 18
  • 43
  • Do you mean that your contour has some holes inside it and some of the triangles have the centroids in them? – Adrian Nov 23 '11 at 06:53
  • Thanks for your comment. Yes, I mean exactly that. cvSubdiv2D performs the Delaunay triangulation of the convex hull of the contour, not the contour itself. So (in the case of a man walking) I have one point on an edge of the left leg, and another point of the same triangle on an edge of the right leg.In this case it's ok: the centroid is out of the man contour, but when a triangle is over the contour **and** the hole, it only erase the triangle or take it entirely, depending of the centroid position. – Benoît Lahoz Nov 23 '11 at 12:53

2 Answers2

2

Finally I implemented the poly2tri library in my program.

Here is the result (OpenCV to get the contours, then poly2tri to perform triangulation) :

// -------------------- 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];                       

where contour32 is your OpenCV contour found with cvFindContours, then converted to float32.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Benoît Lahoz
  • 1,270
  • 1
  • 18
  • 43
  • This is really interesting! Can you may give me a hint how to implement cvFindContours the right way? I'm trying to work with it on the iPhone … – dom Dec 14 '11 at 09:57
  • You'll have to perform a threshold (and, if you want, a canny edge, but this is really bad for performance) on your gray image, then create a CvSeq for the contour. After that you can perform your cvFindContours and iterate the contours to obtain its coordinates or to directly draw it. – Benoît Lahoz Dec 14 '11 at 19:44
  • Thanks a lot! Got it working, but it's a mess because I first need proper background substraction I guess. Do you have any recommendations? – dom Dec 15 '11 at 15:43
  • I don't know on what platform you're working, but background substraction on OpenCV is very heavy for performances. You might want to do a simple BG with a shader, then take your texture and convert it in a IplImage. – Benoît Lahoz Dec 15 '11 at 16:22
1

You will have to use:

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

This will return a sequence(CvSeq) of CvConvexityDefect and not CvPoint or anything else like the CvSeq that you are probably used to.

You can go trough the defects in a loop, like this:

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

A defect has the following structure:

    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;

So after getting each defect you can build a CvSeq of points from them and use cvPointPolygonTest on the centroids of the triangles to see if they are inside of them. If they are inside the defects, then it means that they are outside the main contour.

Hope this is what you need and that it helps.

Adrian
  • 2,028
  • 2
  • 17
  • 28
  • Hi, Thanks you for your message. Won't your solution return approximately the same thing that is returning the cvPointPolygonTest I'm performing in the **contour itself** ? The problem is that I have sometime triangles which are **inside the convex hull** but **over a hole** so the centroid might be in the contour or in the defect. I try your proposal ! Thanks again ! – Benoît Lahoz Nov 24 '11 at 11:36
  • I was thinking of adding Steiner Points to perform the constrained triangulation ([Steiner points](http://en.wikipedia.org/wiki/Steiner_points)) , but don't know where to begin... :-/ – Benoît Lahoz Nov 24 '11 at 11:43
  • Here's an image : [on Google Doc](https://docs.google.com/open?id=0B4I3rXGO003hMGVjOGUzNjQtZmViMS00MmJmLTlmNTAtYjIwNjBlMTY3NmU5) – Benoît Lahoz Nov 24 '11 at 11:58
  • What I explained covers this case. The space between the legs will be a defect found by cvConvexityDefects, and if any triangle has the centroid in that defect, than you know you have to delete it because it is not inside the contour. – Adrian Nov 24 '11 at 12:10
  • Thanks a lot ! I'll try this right now ! But I'm afraid it will erase some particular triangles like the one which is over the deisred contour AND the hole. I'll tell you ! – Benoît Lahoz Nov 24 '11 at 12:30
  • I'm thinking about refining the contour to take in consideration the inner contour of the hole, by adding points. What do you think ? – Benoît Lahoz Nov 24 '11 at 12:37
  • I'm sorry but in fact it doesn't work : I'll have to refine the contours to find this constrained triangulation. There's something to do with convexityDefects, but not with centroids, as my triangulation doesn't take in consideration Delaunay edges crossing contours, but only the convex hull triangulation. – Benoît Lahoz Nov 27 '11 at 19:38