c# - 无法将位图转换为 IplImage

标签 c# opencv pointers iplimage

我正在尝试制作一个图像裁剪工具。

我正在关注这个https://www.codeproject.com/Articles/703519/Cropping-Particular-Region-In-Image-Using-Csharp

但是由于它有点旧并且它使用的插件/DLL 已经改变,我一直在尝试将他的代码从 OpenCvSharp 2.0 调整为 OpenCvSharp 2.4

当我将位图转换为 IplImages 并使用 Cv.Mul() 时,出现以下错误:

尝试读取或写入 protected 内存。这通常表明其他内存已损坏

我从未使用过 OpenCvSharp 其他方式来创建 IplImage,甚至从写入的图像中读取 IplImage。

代码:

    public static IplImage BitmapToIplImage(Bitmap bitmap)
    {
        IplImage tmp, tmp2;

        System.Drawing.Rectangle bRect = new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), new System.Drawing.Size((int)bitmap.Width, (int)bitmap.Height));
        BitmapData bmData = bitmap.LockBits(bRect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
        tmp = Cv.CreateImage(Cv.Size(bitmap.Width, bitmap.Height), BitDepth.U8, 3);
        tmp2 = Cv.CreateImage(Cv.Size(bitmap.Width, bitmap.Height), BitDepth.U8, 1);

        byte[] data = new byte[Math.Abs(bmData.Stride * bmData.Height)];

        tmp.SetData(bmData.Scan0, data.Length);

        bitmap.UnlockBits(bmData);
        // Cv.CvtColor(tmp, tmp2, ColorConversion.RgbToGray);
        return tmp;
    }

    private void CropImage()
    {
        IplImage ipl = Cv.CreateImage(new CvSize(curBmp.Width, curBmp.Height), BitDepth.U8, 3);

        Graphics ga = Graphics.FromImage(curBmp);

        ga.FillRectangle(new SolidBrush(System.Drawing.Color.Black), new System.Drawing.Rectangle(0, 0, curBmp.Width, curBmp.Height));

        SolidBrush brush = new SolidBrush(System.Drawing.Color.FromArgb(1, 1, 1));

        curGraphics.FillClosedCurve(brush, imagePoints.ToArray());

        Cv.Mul(BitmapToIplImage(curOgBmp), BitmapToIplImage(curBmp), ipl, 1);

        ComputeCrop();

        Stream s = null;

        ipl.ToStream(s, ".png", null);

        curBmp = new Bitmap(s);

        RefreshImageViewer();
    }

----------------------------------------编辑----------------- ------------------------

我尝试按照 Markus 发布的内容进行操作,并且代码正常运行,没有出现任何错误。

虽然裁剪的图像有点奇怪,但这里是我使用的方法,加上 RefreshImageViewer,这就是我将位图放入图像控件中的方法。

几个小时以来我一直在尝试查看是否错过了某些内容,但我认为没有。

输出示例:Imgur image link

代码:

    public void RefreshImageViewer()
    {
        bmpSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                           curBmp.GetHbitmap(),
                           IntPtr.Zero,
                           System.Windows.Int32Rect.Empty,
                           BitmapSizeOptions.FromWidthAndHeight(curBmp.Width, curBmp.Height));
        imageViewer.Source = bmpSource;

        curGraphics = Graphics.FromImage(curBmp);
    }
    private void CropImage()
    {

        Graphics Ga = Graphics.FromImage(curBmp);
        //the black image
        Ga.FillRectangle(new SolidBrush(System.Drawing.Color.Black), new System.Drawing.Rectangle(0, 0, curBmp.Width, curBmp.Height));
        //draw from the last point to first point  
        Ga.DrawLine(new System.Drawing.Pen(System.Drawing.Color.Red, 3), imagePoints[imagePoints.Count - 1], imagePoints[0]);

        //all of the rgb values are being set 1 inside the polygon 
        SolidBrush Brush = new SolidBrush(System.Drawing.Color.FromArgb(1, 1, 1));
        //we have to prepare one mask of Multiplying operation for cropping region
        curGraphics.FillPolygon(Brush, imagePoints.ToArray());

        Mat accc = (BitmapToMat(curOgBmp).Mul(BitmapToMat(curBmp))).ToMat();

        System.Drawing.Rectangle r = ComputeCrop();
        curBmp = accc.ToBitmap().Clone(r, curOgBmp.PixelFormat);

        RefreshImageViewer();
    }

    private System.Drawing.Rectangle ComputeCrop()
    {
        int smallestX = curBmp.Width, biggestX = 0, biggestY = 0, smallestY = curBmp.Height;
        for (int i = 0; i < imagePoints.Count; i++)
        {
            biggestX = Math.Max(biggestX, imagePoints[i].X);
            smallestX = Math.Min(smallestX, imagePoints[i].X);

            biggestY = Math.Max(biggestY, imagePoints[i].Y);
            smallestY = Math.Min(smallestY, imagePoints[i].Y);
        }

        System.Drawing.Rectangle rectCrop = new System.Drawing.Rectangle(smallestX, smallestY, biggestX - smallestX, biggestY - smallestY);

        return rectCrop;
    }

    public static Mat BitmapToMat(Bitmap bitmap)
    {
        Mat tmp, tmp2;

        System.Drawing.Rectangle bRect = new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), new System.Drawing.Size((int)bitmap.Width, (int)bitmap.Height));
        BitmapData bmData = bitmap.LockBits(bRect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
        tmp2 = new Mat(new OpenCvSharp.Size(bitmap.Width, bitmap.Height), MatType.CV_8U);

        tmp = new Mat(bitmap.Height, bitmap.Width, MatType.CV_8UC3, bmData.Scan0);

        bitmap.UnlockBits(bmData);
        return tmp;
    }

最佳答案

“IplImage”是 OpenCv 1 中的旧图像容器。正如 Andreas 已经提到的,今天您应该使用“Mat”。也看看这里:Difference between cvMat, Mat and IpImage

不幸的是,您的代码示例不完整,因此我更正了原始项目( https://www.codeproject.com/Articles/703519/Cropping-Particular-Region-In-Image-Using-Csharp )中的两个方法。

以下方法经过测试,并在原始项目中结合最新的 OpenCVSharp 版本 (v4.x) 正常工作。现在将更改转换为代码应该非常简单。

    public static Mat BitmapToIplImage(Bitmap bitmap)
    {
        Mat tmp, tmp2;

        Rectangle bRect = new Rectangle(new System.Drawing.Point(0, 0), new System.Drawing.Size((int)bitmap.Width, (int)bitmap.Height));
        BitmapData bmData = bitmap.LockBits(bRect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
        tmp2 = new Mat(new Size(bitmap.Width, bitmap.Height), MatType.CV_8U);

        tmp = new Mat(bitmap.Height, bitmap.Width, MatType.CV_8UC3, bmData.Scan0);

        bitmap.UnlockBits(bmData);
        return tmp;         
    }

    private void crop()
    {
        timer1.Stop();

        Graphics Ga = Graphics.FromImage(bmp);
        //the black image
        Ga.FillRectangle(new SolidBrush(Color.Black), new Rectangle(0, 0, bmp.Width, bmp.Height));
        //draw from the last point to first point  
        Ga.DrawLine(new Pen(Color.Red, 3), polygonPoints[polygonPoints.Count - 1], polygonPoints[0]);

        //all of the rgb values are being set 1 inside the polygon 
        SolidBrush Brush = new SolidBrush(Color.FromArgb(1, 1, 1));
      //we have to prepare one mask of Multiplying operation for cropping region
        G.FillClosedCurve(Brush, polygonPoints.ToArray());
        var accc= (BitmapToIplImage(Source).Mul(BitmapToIplImage(bmp))).ToMat();

        computecrop();
        croplast = accc.ToBitmap().Clone(rectcrop, Source.PixelFormat);//just show cropped region part of image
        pictureBox2.Image = croplast; // crop region of image

    }

关于c# - 无法将位图转换为 IplImage,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60009471/

相关文章:

python - 如果使用python在捕获区域中存在某些颜色,如何返回 bool 值

python - 给定两个大小相等的二进制矩阵,计算模式相似度分数

c++ - 用不同的方法填充指针

c# - 如何获取实现 IMyInterface 的引用中的所有类型

c# - 了解 MVVM : simple non-working code

c# - 远程机器上的 iisreset (C#)

c - 数组a和&a的起始地址

javascript - 引用 View 文件夹中的 JavaScript 文件 - MVC 5

opencv - 使用OpenCV和Alexa进行面部识别

c++ - 更新指针?