3

I'm using OpenCVSharp to run some calibration tests but i can't seem to get FindCirclesGrid to work, i'm getting a really unexpected AccessViolationException when calling FindCirclesGrid.

I'm not sure what i could be doing wrong as the first two line are pretty much exactly as in samples,centers is not initialized as it is an output parameter and everything that is passed down to OpenCV seems to be initialized in OpenCVSharp's wrapper function.

void test()
{
    Mat im = Cv2.ImRead(@"path_to_my_file.jpg");
    Size patternsize = new Size(11, 4);
    Point2f[] centers;
    var f = Cv2.FindCirclesGrid(im, patternsize, out centers, FindCirclesGridFlag.AsymmetricGrid);
}

I'm using the latest OpenCVSharp straight from nuget

Edit1 : i forgot to mention this in the question but i have already tried adding the foillowing after FindCirclesGrid to ensure objects weren't wrongly collected before they should, this changed nothing. Also the bug happens just the same in debug and release.

 Console.Writeline(im.ToString());
 Console.Writeline(patternsize.ToString());
 Console.Writeline(centers.ToString());
 Console.Writeline(f.ToString());
Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
Ronan Thibaudau
  • 3,413
  • 3
  • 29
  • 78

4 Answers4

1

This was a bug in OpenCvSharp, I submitted a fix which was included in NuGet release 2.4.10.20150604.

There are two interop calls exported by the C++ wrapper dll OpenCvSharpExtern that OpenCvSharp uses internally: calib3d_findCirclesGrid_InputArray and calib3d_findCirclesGrid_vector.

Their signatures differ only by the use of C++ types cv::_OutputArray and std::vector<cv::Point2f> for the centers parameter, but in the C# extern definitions these are both defined as IntPtr, making the methods interchangable at compile time in C#.

The affect git version (latest commit e14c711958) has both C# overloads of FindCirclesGrid mapped to the same interop call calib3d_findCirclesGrid_InputArray, hence the overload using Point2f[] doesn't work, as the C++ code doesn't get the parameter it expects.

E.g. using a simulation of the calibration image here as the input image:

// Fails with NuGet package OpenCvSharp-AnyCPU 2.4.10.20150320. 
using (var imageStream = new MemoryStream())
{
    using (var circleBoard = new System.Drawing.Bitmap(650, 850))
    using (var g = System.Drawing.Graphics.FromImage(circleBoard))
    {
        g.Clear(System.Drawing.Color.White);
        for (int y = 0; y <= 10; y += 1)
            for (int x = 0; x <= 3; x += 1)
            {
                var dx = 10 + x * 150;
                var dy = 10 + y * 75;
                g.FillEllipse(System.Drawing.Brushes.Black, dx + ((y + 1) % 2) * 75, dy, 50, 50);
            }
        circleBoard.Save(imageStream, System.Drawing.Imaging.ImageFormat.Png);
    }

    Mat im = Cv2.ImDecode(imageStream.GetBuffer(), OpenCvSharp.LoadMode.GrayScale);
    Size patternsize = new Size(4, 11);

    var centers = new List<Point2f>();
    if (Cv2.FindCirclesGrid(im, patternsize, OutputArray<Point2f>.Create(centers), FindCirclesGridFlag.AsymmetricGrid | FindCirclesGridFlag.Clustering))
    {
        // Ok, finds 44 circles
        Console.WriteLine(centers.Count());
    }
    Point2f[] centers2 = null;
    if (Cv2.FindCirclesGrid(im, patternsize, out centers2, FindCirclesGridFlag.AsymmetricGrid | FindCirclesGridFlag.Clustering))
    {
        // Crashes with AccessViolationException
        Console.WriteLine(centers2.Count());
    }
}
Peter Wishart
  • 11,600
  • 1
  • 26
  • 45
  • You're right this sounds like a bug and the other overload doesn't throw (it doesn't work and returns false for me however, if you kept it any chance you could zip your sample project including the png file so that i can compare and find where my issue is? I copy / pasted your code and converted the pdf to jpeg and findcircles returns false) – Ronan Thibaudau May 05 '15 at 18:28
  • Thanks for the updated sample, i can reproduce this as working now. If you can do the github bug that would be great as i'm clueless about git & co, i don't even have an account there. – Ronan Thibaudau May 06 '15 at 02:42
0

The garbage collection maybe executed while the circle grid is being found. If you run your application in release mode without debugging, then JIT compiler will perform optimizations and the object can be subject to garbage collection before the operation over the unmanaged resource is finished. Most likely it will result in the application crash.

The issue can be easily fixed: it’s just necessary to keep reference to the current image, pattern size, etc. till the method completes its work, or try to use GC.KeepAlive method:

void test()
{
    Mat im = Cv2.ImRead(@"path_to_my_file.jpg");
    Size patternsize = new Size(11, 4);
    Point2f[] centers;
    var f = Cv2.FindCirclesGrid(im, patternsize, out centers, FindCirclesGridFlag.AsymmetricGrid);
    GC.KeepAlive(this);
}
Kornel
  • 5,264
  • 2
  • 21
  • 28
  • I should have added this to my question but i had already discarded that in my tests by tossing in a console.Writeline(obj.ToString) for each object defined (im patternsize and centers) to make sure there was no GC issue around those. So this can't be the issue. Also the issue happens all the same in debug and release – Ronan Thibaudau May 05 '15 at 16:38
0

Instead of writing this line

var f = Cv2.FindCirclesGrid(im, patternsize, out centers, FindCirclesGridFlag.AsymmetricGrid);

Try This:

var f = Cv2.FindCirclesGrid(im, patternsize, out centers, CALIB_CB_ASYMMETRIC_GRID);

As, FindCirclesGrid() function takes fourth argument as a constant depending upon your pattern of circles.

It can be one of the following:

CALIB_CB_SYMMETRIC_GRID uses symmetric pattern of circles. CALIB_CB_ASYMMETRIC_GRID uses asymmetric pattern of circles. CALIB_CB_CLUSTERING uses a special algorithm for grid detection. It is more robust to perspective distortions but much more sensitive to background clutter.

You can use Fifth argument of type Ptr(FeatureDetector) for finding blobs like dark circles on light background.

Or ELSE you can try converting "FindCirclesGridFlag.AsymmetricGrid" to integer. e.g. (int)FindCirclesGridFlag.AsymmetricGrid Hope I have understood your question.

0

I reported a bug at github. It seems to be fixed by now, but I can't test it atm.

https://github.com/shimat/opencvsharp/issues/106