André Marques
André Marques

Reputation: 178

Can't convert Bitmap to IplImage

I'm trying to make an image cropping tool.

I am following this https://www.codeproject.com/Articles/703519/Cropping-Particular-Region-In-Image-Using-Csharp

But since it's a bit old and the plugin/DLL's it uses have changed I have been trying to adapt his code from OpenCvSharp 2.0 to OpenCvSharp 2.4

When I'm converting the bitmaps to IplImages and using Cv.Mul() it gives me this error:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt

I have never used OpenCvSharp other ways of creating the IplImage even reading the IplImage from a written image.

Code:

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

-----------------------------EDIT-----------------------------------------

I tried to follow what Markus posted, and I got it to work without any errors in the code.

Although the image cropped is a bit strange here are the methods I use, plus the RefreshImageViewer that is how I put the bitmap in the image control.

I have been trying to see if I missed something for hours, but I think not.

Output example: Imgur image link

Code:

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

Upvotes: 2

Views: 594

Answers (1)

Markus
Markus

Reputation: 66

“IplImage” ist the old image container from OpenCv 1. As Andreas already mentioned, today you should use “Mat” instead. Have also a look here : Difference between cvMat, Mat and IpImage

Unfortunately, your code sample is not complete, hence I corrected the two methods from the original project ( https://www.codeproject.com/Articles/703519/Cropping-Particular-Region-In-Image-Using-Csharp).

The following methods are tested and work as intended in the original project in combination with the latest OpenCVSharp version (v4.x) . It should be very simple now to convert the changes to your code.

    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

    }

Upvotes: 2

Related Questions