【问题标题】:OpenCVSharp AccessViolationException in FindCirclesGridFindCirclesGrid 中的 OpenCVSharp AccessViolationException
【发布时间】:2015-05-02 16:12:34
【问题描述】:

我正在使用 OpenCVSharp 运行一些校准测试,但我似乎无法让 FindCirclesGrid 工作,我在调用 FindCirclesGrid 时遇到了一个非常意外的 AccessViolationException。

我不确定我做错了什么,因为前两行与示例中的几乎完全相同,centers 未初始化,因为它是一个输出参数,并且传递给 OpenCV 的所有内容似乎都已初始化OpenCVSharp 的包装函数。

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);
}

我正在使用直接来自 nuget 的最新 OpenCVSharp

Edit1:我忘了在问题中提到这一点,但我已经尝试在 FindCirclesGrid 之后添加箔纸,以确保在它们应该之前不会错误地收集对象,这没有改变。此外,在调试和发布时,该错误也会发生。

 Console.Writeline(im.ToString());
 Console.Writeline(patternsize.ToString());
 Console.Writeline(centers.ToString());
 Console.Writeline(f.ToString());

【问题讨论】:

  • 因为 NativeMethods.calib3d_findCirclesGrid_InputArray(...) 被称为可能具有非托管代码属性的东西?

标签: c# opencv access-violation opencvsharp


【解决方案1】:

这个was a bug in OpenCvSharp,我提交了一个修复,它包含在 NuGet 版本 2.4.10.20150604 中。

OpenCvSharp 在内部使用的 C++ 包装器 dll OpenCvSharpExtern 导出了两个互操作调用:calib3d_findCirclesGrid_InputArraycalib3d_findCirclesGrid_vector

它们的签名不同之处仅在于 centers 参数使用 C++ 类型 cv::_OutputArraystd::vector<cv::Point2f>,但在 C# 外部定义中,它们都定义为 IntPtr,使得方法在编译时可互换C#。

影响 git 版本(最新提交 e14c711958)有两个 C# 重载 FindCirclesGrid 映射到相同的互操作调用 calib3d_findCirclesGrid_InputArray,因此使用 Point2f[] 的重载不起作用,因为 C++ 代码没有得到它期望的参数。

例如使用模拟校准图像here作为输入图像:

// 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());
    }
}

【讨论】:

  • 你是对的,这听起来像一个错误,并且其他重载不会抛出(它不起作用并且对我返回 false,但是,如果你保留它任何机会,你可以压缩你的示例项目包括 png 文件,以便我可以比较并找到我的问题所在?我复制/粘贴了您的代码并将 pdf 转换为 jpeg 并且 findcircles 返回 false)
  • 感谢更新的示例,我可以将其复制为现在工作。如果你能做一个很棒的 github bug,因为我对 git & co 一无所知,我什至没有帐户。
【解决方案2】:

我在 github 上报告了一个错误。现在好像已经修复了,但是我无法在 atm 测试它。

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

【讨论】:

  • 该错误已关闭,它与我修复的错误重复(请参阅我的答案中的链接)。
【解决方案3】:

在找到圆形网格时可能会执行垃圾收集。如果您在没有调试的情况下以发布模式运行您的应用程序,那么 JIT 编译器将执行优化,并且在对非托管资源的操作完成之前,对象可能会受到垃圾回收。很可能会导致应用程序崩溃。

这个问题很容易解决:只需要保持对当前图像、图案大小等的引用,直到方法完成它的工作,或者尝试使用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);
}

【讨论】:

  • 我应该把这个添加到我的问题中,但我已经在我的测试中丢弃了它,方法是为每个定义的对象(im 模式大小和中心)扔一个 console.Writeline(obj.ToString) 以确保这些没有GC问题。所以这不可能是问题。此外,问题在调试和发布中也同样发生
【解决方案4】:

而不是写这行

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

试试这个:

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

作为,FindCirclesGrid() 函数将第四个参数作为常数,具体取决于您的圆圈图案。

可以是以下之一:

CALIB_CB_SYMMETRIC_GRID 使用对称的圆形图案。 CALIB_CB_ASYMMETRIC_GRID 使用不对称的圆形图案。 CALIB_CB_CLUSTERING 使用特殊算法进行网格检测。它对透视失真更稳健,但对背景杂波更敏感。

您可以使用 Ptr(FeatureDetector) 类型的第五个参数来查找浅色背景上的黑眼圈等斑点。

或者其他你可以尝试转换 “FindCirclesGridFlag.AsymmetricGrid”为整数。 例如(int)FindCirclesGridFlag.AsymmetricGrid 希望我能理解你的问题。

【讨论】:

    猜你喜欢
    • 2017-02-03
    • 1970-01-01
    • 2021-10-07
    • 1970-01-01
    • 1970-01-01
    • 2016-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多