Access Violation Exception mystery

前端 未结 2 1518
梦毁少年i
梦毁少年i 2020-12-29 23:33

I\'ve been working with EMGU+OpenCV for quite some time and ran into this AccessViolationException mystery.

First thing first, the code:



        
2条回答
  •  余生分开走
    2020-12-29 23:47

    Your example doesn't keep a reference to the result image from Image.SmoothBilatral. The input images are rooted in a static array so are fine.

    An Emgu.CV Image's data array is pinned to a GCHandle inside the actual image, this is no different from the fact that image contains the array and doesn't prevent collection while the GCHandle's pointer is in use by unmanaged code (in the abscence of a managed root to the image).

    Because the Image.SmoothBilatral method doesn't do anything with its temporary result image other than pass its pointer and return it, I think it gets optimised away to the extent that the result image can be collected while the smooth is processing.

    Because there's no finalizer for this class, opencv will not get called upon to release it's unmanaged image header (which has a pointer to the managed image data) so opencv still thinks it has a usable image structure.

    You can fix it by taking a reference to the result of SmoothBilatral and doing something with it (like disposing it).

    This extension method would also work (i.e. allow it to be called successfuly for benchmarking without the result being used):

    public static class BilateralExtensionFix
    {
        public static Emgu.CV.Image SmoothBilateral(this Emgu.CV.Image image, int p1, int p2 , int p3)
        {
            var result = image.CopyBlank();
            var handle = GCHandle.Alloc(result);
            Emgu.CV.CvInvoke.cvSmooth(image.Ptr, result.Ptr, Emgu.CV.CvEnum.SMOOTH_TYPE.CV_BILATERAL, p1, p1, p2, p3);
            handle.Free();
            return result;
        }
    }
    

    I think what EmguCV should be doing is only pinning pointers to pass to opencv while making an interop call.

    p.s The OpenCv bilateral filter crashes (producing a very similar error to your problem) on any kind of float image passed with zero variation (min() = max()) across all channels. I think because of how it builds it's binned exp() lookup table.

    This can be reproduced with:

        // create new blank image
        var zeroesF1 = new Emgu.CV.Image(75, 75);
        // uncomment next line for failure
        zeroesF1.Data[0, 0, 0] += 1.2037063600E-035f;
        zeroesF1.SmoothBilatral(15, 50, 50);
    

    This was confusing me as I was actually sometimes getting this error due to a bug in my test code...

提交回复
热议问题