Search code examples
pythonc#opencvemgucv

How to convert contour hierarchy from python openCV to emgu cv to find enclosing contours


I have a circle detection written in python which I now need to convert into emgu cv to enable bundling into an Xamarin IOS App.

For that I save images of the detection process at various parts to compare it to the new .net implementation. While some parts are straight forward others seems to be more tricky. I am currently stuck on the hierarchy for detected shapes and already checked for examples as well as this answer which I then picked as a first solution.

This is the python line I try to convert:

# finding all contours in the image which are enclosed within other contours (child contours)
( cnts, cnts_hs ) = cv2.findContours(img.copy(), cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) 
cnts = [cnt for i,cnt in enumerate(cnts) if cnts_hs[0,i,3] != -1]

Currently I tried it using the mentioned answer which results in the following implementation:

// finding all contours in the image which are enclosed within other contours (child contours)
// NOTE: 
// 'hier' is of type 'Mat'
// 'cnts' 'cntsContourOut' are both of type 'VectorOfVectorOfPoint'
CvInvoke.FindContours(img.Clone(), cnts, hier, RetrType.Ccomp, ChainApproxMethod.ChainApproxSimple);
int count = cnts.Size;
for (int i = 0; i < count; i++)
{
    using (VectorOfPoint cntr = cnts[i]) {
        // check if the contour is enclosed in another contour
        if (hier.GetDataPointer(i).ToInt32() != -1)
        {
            cntsContourOut.Push(cntr);
        }
    }
}

But the result is quite different... while the python lines results in 49 contours after filtering for a given sample-image the .net lines result in the original 91 contours (none is filtered out). I guess I have some misunderstanding what the python line does, which I still have when it comes to the 0 or 3 in cnts_hs[0,i,3]. That's why I just left them out in the .net implementation.

Edit 1:

I guess I should have mentioned that I tried the following param variants for hier.GetDataPointer():

hier.GetDataPointer(0,i,3)
// result in an array size exceeded exception

hier.GetDataPointer(i,3) // or even 4 instead of 3
// result in the same 91 contours

Solution

  • After some more digging in I've found the solution:

    var data = hier.GetData();
    for (int i = 0; i < count; i++)
    {
        using (VectorOfPoint cntr = cnts[i]) {
            var d = (int)data.GetValue(new int[3] { 0, i, 3 });
            if(d != -1)
                cntsContourOut.Push(cntr);
        }
    }