简体   繁体   中英

C# find differences between images

I'm trying to compare screenshots and write only the differences.

This is my code

public Bitmap Difference(Bitmap bmp0, Bitmap bmp1)
{
        Bitmap bmp2;
        int Bpp = bmp0.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4;

        bmp2 = new Bitmap(bmp0.Width, bmp0.Height, bmp0.PixelFormat);

        var bmpData0 = bmp0.LockBits(
                        new Rectangle(0, 0, bmp0.Width, bmp0.Height),
                        ImageLockMode.ReadOnly, bmp0.PixelFormat);
        var bmpData1 = bmp1.LockBits(
                        new Rectangle(0, 0, bmp1.Width, bmp1.Height),
                        ImageLockMode.ReadOnly, bmp1.PixelFormat);
        var bmpData2 = bmp2.LockBits(
                        new Rectangle(0, 0, bmp2.Width, bmp2.Height),
                        ImageLockMode.ReadWrite, bmp2.PixelFormat);

       // MessageBox.Show(bmpData0.Stride.ToString());
       int len = bmpData0.Height * bmpData0.Stride;

       //   MessageBox.Show(bmpData0.Stride.ToString());
       bool changed = false;

       byte[] data0 = new byte[len];
       byte[] data1 = new byte[len];
       byte[] data2 = new byte[len];

       Marshal.Copy(bmpData0.Scan0, data0, 0, len);
       Marshal.Copy(bmpData1.Scan0, data1, 0, len);
       Marshal.Copy(bmpData2.Scan0, data2, 0, len);

       for (int i = 0; i < len; i += Bpp)
       {
            changed = ((data0[i] != data1[i])
                          || (data0[i + 1] != data1[i + 1])
                          || (data0[i + 2] != data1[i + 2]));

            // this.Invoke(new Action(() => this.Text = changed.ToString()));

            data2[i] = changed ? data1[i] : (byte)2;   // special markers
            data2[i + 1] = changed ? data1[i + 1] : (byte)3;   // special markers
            data2[i + 2] = changed ? data1[i + 2] : (byte)7;   // special markers

            if (Bpp == 4) 
               data2[i + 3] = changed ? (byte)255 : (byte)42;  // special markers
    }

    //  this.Invoke(new Action(() => this.Text = changed.ToString()));
    Marshal.Copy(data2, 0, bmpData2.Scan0, len);
    bmp0.UnlockBits(bmpData0);
    bmp1.UnlockBits(bmpData1);
    bmp2.UnlockBits(bmpData2);

    return bmp2;
}


    Bitmap shot = new Bitmap(SystemInformation.VirtualScreen.Width,
                    SystemInformation.VirtualScreen.Height,
                    PixelFormat.Format24bppRgb);

    public Bitmap screenshot()
    {


        Graphics screenGraph = Graphics.FromImage(shot);
        screenGraph.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                                   Screen.PrimaryScreen.Bounds.Y,
                                   0,
                                   0,
                                   SystemInformation.VirtualScreen.Size,
                                   CopyPixelOperation.SourceCopy);

        return shot;

    }

And my call:

private void Form1_Load(object sender, EventArgs e)
{
        Bitmap prev = screenshot();

        Thread.Sleep(1000);
        Bitmap  curr = screenshot();

        pictureBox1.Image=Difference(prev,curr);
}

im getting an Bitmap region is already locked. Error in this line

   var bmpData1 = bmp1.LockBits(
                        new Rectangle(0, 0, bmp1.Width, bmp1.Height),
                        ImageLockMode.ReadOnly, bmp1.PixelFormat);

this is my screenshot code, a simple .net screen capture method:

it's realy weird because i dont even used LockBits in the screenshot method so i have no idea why it's throwing this error...

If your bitmap is 'bottom up' as opposed to 'top down', the Stride property will be a negative value.

See here: https://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.stride%28v=vs.110%29.aspx

From this article:
"The stride is the width of a single row of pixels (a scan line), rounded up to a four-byte boundary. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up."

Use

int len = bmpData0.Height * Math.Abs(bmpData0.Stride);

If you are using a bottom-up bitmap you will need to use a different mechanism for copying the bitmap to your buffer. There are some different suggestions for how to handle this in this question, see the first three answers:

How can I copy the pixel data from a Bitmap with negative stride?



From the latest edit to your question, your problem is now that you are using the same Bitmap instance for both your screenshots. Move the 'shot' declaration inside the screenshot() method so a different instance is used for each screenshot:

public Bitmap screenshot()
{

     Bitmap shot = new Bitmap(SystemInformation.VirtualScreen.Width,
                SystemInformation.VirtualScreen.Height,
                PixelFormat.Format24bppRgb);
    Graphics screenGraph = Graphics.FromImage(shot);
    screenGraph.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
                               Screen.PrimaryScreen.Bounds.Y,
                               0,
                               0,
                               SystemInformation.VirtualScreen.Size,
                               CopyPixelOperation.SourceCopy);

    return shot;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM