OpenCVSharp AccessViolationException in FindCirclesGrid
I'm using OpenCVSharp to run some calibration tests, but I can't get FindCirclesGrid to work, I get an unexpected AccessViolationException when I call FindCirclesGrid.
I'm not sure if I could be wrong as the first two lines are exactly the same as in the samples, the centers are not initialized as it is an output parameter, and everything passed to OpenCV seems to be initialized in the OpenCVSharp 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 am using the latest OpenCVSharp straight from nuget
Edit1: I forgot to mention this in the question, but I already tried adding foillowing after FindCirclesGrid to ensure that the objects weren't collected incorrectly before they did, it didn't change anything. Also the error is debugged and debugged.
Console.Writeline(im.ToString());
Console.Writeline(patternsize.ToString());
Console.Writeline(centers.ToString());
Console.Writeline(f.ToString());
source to share
This was a bug in OpenCvSharp , I posted a fix that was included in the NuGet 2.4.10.20150604 release.
There are two calls to interop, exported by OpenCvSharpExtern
the C ++ wrapper dll that OpenCvSharp uses internally: calib3d_findCirclesGrid_InputArray
and calib3d_findCirclesGrid_vector
.
Their signatures differ only in the use of C ++ types cv::_OutputArray
and std::vector<cv::Point2f>
for the parameter centers
, but in the extern C # definitions they are both defined as IntPtr
, making the methods interchangeable at compile time in C #.
The git affect (latest commit e14c711958) has both C # overloads FindCirclesGrid
mapped to the same interop call calib3d_findCirclesGrid_InputArray
, so the using overload Point2f[]
does not work, since C ++ code does not work, t get the expected parameter.
eg. using a calibration image here as 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());
}
}
source to share
Garbage collection can be performed as long as the circle mesh is found. If you run the application in free mode without debugging, the JIT compiler will perform optimization and the object may be garbage collected before the operation completes on the unmanaged resource. This will most likely cause the application to crash.
The problem can be easily fixed: you just need to keep the link to the current image, the size of the picture, etc. until the method exits, or try using GC.KeepAlive
:
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);
}
source to share
Instead of writing this line
var f = Cv2.FindCirclesGrid(im, patternsize, out centers, FindCirclesGridFlag.AsymmetricGrid);
Try the following:
var f = Cv2.FindCirclesGrid(im, patternsize, out centers, CALIB_CB_ASYMMETRIC_GRID);
As, the FindCirclesGrid () function takes a fourth argument as a constant, depending on your circle pattern.
It can be one of the following:
CALIB_CB_SYMMETRIC_GRID uses a symmetrical circle structure. CALIB_CB_ASYMMETRIC_GRID uses an asymmetric circle pattern. CALIB_CB_CLUSTERING uses a special mesh detection algorithm. It is more resistant to perspective distortion, but much more sensitive to background noise.
You can use the fifth argument of type Ptr (FeatureDetector) to find blobs, such as dark circles on a light background.
Or ELSE you can try to convert "FindCirclesGridFlag.AsymmetricGrid" - integer. eg (int)FindCirclesGridFlag.AsymmetricGrid
Hope I understood your question.
source to share