2015-07-01 21 views
1

Я пытаюсь сравнить скриншоты и писать только различия.C# найти различия между изображениями

Это мой код

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; 

    } 

И мой призыв:

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

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

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

им получать Bitmap region is already locked.Ошибки в этой строке

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

это мой скриншот код, простой .net способ захвата экрана:

это действительно странно, потому что я даже не использовали LockBits в методе screenshot поэтому я понятия не имею, почему он бросает эту ошибку ...

+1

Одна проблема (хотя, возможно, не самая главная проблема) является то, что вы назвали 'UnlockBits' для всех перед тем, как попытаться получить доступ к их данным через объекты «BitmapData». Вы должны делать все ваши чтения/записи из/в объекты «BitmapData» перед * вызовом 'UnlockBits', что по существу делает недействительными объекты« BitmapData ». – adv12

+0

@ adv12 все спасибо, но это не проблема, которую я отредактировал и разблокировал в конце, но все же ту же ошибку –

ответ

1

Если точечный рисунок «снизу вверх», в отличие от «сверху вниз», свойство Stride будет отрицательным.

Смотрите здесь: https://msdn.microsoft.com/en-us/library/system.drawing.imaging.bitmapdata.stride%28v=vs.110%29.aspx

Из этой статьи:
«походка ширина одной строки пикселей (линия сканирования), округленные до границы четырех байт Если шаг находится. положительный, битмап сверху вниз. Если шаг отрицательный, растровое изображение снизу вверх. "

Использование

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

Если вы используете снизу вверх растровое изображение вам нужно будет использовать другой механизм для копирования растрового изображения в буфер. Есть несколько различных предложений о том, как справиться с этим в этом вопросе, увидеть первые три ответа:

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



Из последнего редактирования на ваш вопрос, ваша проблема в том, что теперь вы используете один и тот же Bitmap экземпляр для обоих скриншотов. Переместить «выстрел» заявление внутри метода скриншот() так другой экземпляр используется для каждого экрана:

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

теперь im получает еще одну ошибку в этой строке 'Marshal.Copy (bmpData0.Scan0, data0, 0, len);' 'Попытка чтение или запись защищенной памяти. Это часто свидетельствует о том, что другая память повреждена. '@ User469104 –

+0

Вы переместили UnlockBits до конца в соответствии с комментарием adv12? – user469104

+0

да смотри также в вопросе, я отредактировал эти строки –