Не удается преобразовать растровое изображение в IplImage - PullRequest
1 голос
/ 31 января 2020

Я пытаюсь сделать инструмент обрезки изображения.

Я слежу за этим https://www.codeproject.com/Articles/703519/Cropping-Particular-Region-In-Image-Using-Csharp

Но так как он устарел и используемые им плагины / DLL изменились, я пытался адаптировать его код из OpenCvSharp 2.0 в OpenCvSharp 2.4

Когда я конвертирую растровые изображения в IplImages и использую Cv.Mul (), это дает мне такую ​​ошибку:

Попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена

Я никогда не использовал 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();
    }

----------------------------- РЕДАКТИРОВАТЬ -------------- ---------------------------

Я пытался следить за тем, что выложил Маркус, и я получил его на работу без ошибок в коде.

Хотя обрезанное изображение немного странно, вот методы, которые я использую, а также 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;
    }

1 Ответ

1 голос
/ 06 февраля 2020

«IplImage» - это старый контейнер изображений из OpenCv 1. Как уже упоминал Андреас, сегодня вы должны использовать «Мат» вместо этого. Также посмотрите здесь: Разница между cvMat, Mat и 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

    }
...