2011-01-27 68 views
3

的时候,我想更多的比较类似的图像使用LockBits方法更快如下AccessViolation使用LockBits

using System; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Runtime.InteropServices; 

public class CompareImages { 

public static void Main (String[] args) { 

Bitmap bm1 = new Bitmap ("PB270029.JPG"); 
Console.WriteLine (bm1.PixelFormat.ToString()); 

int width = bm1.Width; 
int height = bm1.Height; 
Console.WriteLine ("width = " + width + " height = " + height); 

Rectangle rect1 = new Rectangle (0, 0, width, height); 
BitmapData bm1Data = bm1.LockBits (rect1, ImageLockMode.ReadOnly, bm1.PixelFormat); 

Console.WriteLine ("stride = " + bm1Data.Stride); 

IntPtr bm1Ptr = bm1Data.Scan0; 

int bytes = Math.Abs(bm1Data.Stride) * height; 
Console.WriteLine ("bytes = " + bytes); 

byte[] rgbValues1 = new byte [ bytes ]; 
Marshal.Copy (bm1Ptr, rgbValues1, 0, bytes); 

Console.WriteLine ("After 1st Marshal.Copy ..."); 

Bitmap bm2 = new Bitmap ("PA050164.JPG"); 
Rectangle rect2 = new Rectangle (0, 0, bm2.Width, bm2.Height); 
BitmapData bm2Data = bm2.LockBits (rect2, ImageLockMode.ReadOnly, bm2.PixelFormat); 

IntPtr bm2Ptr = bm2Data.Scan0; 
byte[] rgbValues2 = new byte [ Math.Abs(bm2Data.Stride) * bm2.Height ]; 
Marshal.Copy (bm2Ptr, rgbValues2, 0, rgbValues2.Length); 

} 

} 

但第二Marshal.Copy期间发生AccessViolationException:

C:\CompareImages>csc CompareImages.cs 
Microsoft (R) Visual C# 2010 Compiler version 4.0.30319.1 
Copyright (C) Microsoft Corporation. All rights reserved. 


C:\CompareImages>CompareImages.exe 
Format24bppRgb 
width = 3648 height = 2736 
stride = 10944 
bytes = 29942784 
After 1st Marshal.Copy ... 

Unhandled Exception: System.AccessViolationException: Attempted to read or write 
protected memory. This is often an indication that other memory is corrupt. 
    at System.Runtime.InteropServices.Marshal.CopyToManaged(IntPtr source, Object 
destination, Int32 startIndex, Int32 length) 
    at CompareImages.Main(String[] args) 

是什么我的程序错了吗?

谢谢。

+0

你可以尝试用`bm1.UnlockBits(bmpData)``第一次复制后解锁吗? – CharlesB 2011-01-27 13:45:46

+0

是的,我试过了,但结果是一样的。此外,我不明白如何可以与处理第二个位图链接。 – Yury 2011-01-27 13:59:41

+0

你可以尝试从新的数组分配中删除Math.Abs​​吗?我非常确定步幅总是正数,如果我是你,我会避免将int转换为double并返回。 – Biggles 2011-01-27 14:04:05

回答

0

我测试的代码,对我来说它的工作原理...

首先,我用我的一些随机的图片,然后一个更大的完整的白画面与画面尺寸。也许你可以提供一些关于这两张照片的更多信息,它们是否具有相同的尺寸或像素格式?

我看到的唯一可能的错误是您在Copy之后不调用UnlockBits。

site解释LockBit功能相当不错。

0

它为我运行。我试图使图像文件无效,但引发了一个不同的异常。它确实需要一些清理。

using (Bitmap bm1 = new Bitmap("PB270029.JPG")) 
{ 
    Console.WriteLine(bm1.PixelFormat.ToString()); 

    int width = bm1.Width; 
    int height = bm1.Height; 
    Console.WriteLine("width = " + width + " height = " + height); 

    Rectangle rect1 = new Rectangle(0, 0, width, height); 
    BitmapData bm1Data = bm1.LockBits(rect1, ImageLockMode.ReadOnly, bm1.PixelFormat); 
    try 
    { 
     Console.WriteLine("stride = " + bm1Data.Stride); 

     IntPtr bm1Ptr = bm1Data.Scan0; 

     int bytes = Math.Abs(bm1Data.Stride) * height; 
     Console.WriteLine("bytes = " + bytes); 

     byte[] rgbValues1 = new byte[bytes]; 
     Marshal.Copy(bm1Ptr, rgbValues1, 0, bytes); 

     Console.WriteLine("After 1st Marshal.Copy ..."); 
    } 
    finally 
    { 
     bm1.UnlockBits(bm1Data); 
    } 
} 

using (Bitmap bm2 = new Bitmap("PA050164.JPG")) 
{ 
    Rectangle rect2 = new Rectangle(0, 0, bm2.Width, bm2.Height); 
    BitmapData bm2Data = bm2.LockBits(rect2, ImageLockMode.ReadOnly, bm2.PixelFormat); 
    try 
    { 
     IntPtr bm2Ptr = bm2Data.Scan0; 
     byte[] rgbValues2 = new byte[Math.Abs(bm2Data.Stride) * bm2.Height]; 
     Marshal.Copy(bm2Ptr, rgbValues2, 0, rgbValues2.Length); 
    } 
    finally 
    { 
     bm2.UnlockBits(bm2Data); 
    } 
} 
8

我一直在寻找类似的问题几个小时了,我想我已经找到了什么可能是你的问题。我猜你的位图可能会以不同的格式存储。位图可以向前或向后存储。向后存储时,步幅将为负值。但是,Scan0将始终指向扫描的第一行,即第一个像素NOT数组中的第一个字节。

因此,在向后扫描的位图,SCAN0 + ABS(步幅) - 1是阵列中的最后一个字节。 Scan0 + Stride始终是第二行的开始,所以如果步幅是负值,它会反向工作,积极的将会继续。

如果您使用负跨度执行Marshal.Copy(bm2Ptr,rgbValues2,0,rgbValues2.Length),则会在进入访问冲突区域之前复制最后一条扫描线。下面的代码会将任何位图转换为反向扫描字节[](仅仅因为这正是我正在使用的)。我猜你现在已经修复/解决了你的问题,但希望这可以帮助其他人。

private byte[] BitmapToByteArray2(Bitmap bmp) 
    { 
     // Lock the bitmap's bits. 
     Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); 
     System.Drawing.Imaging.BitmapData bmpData = 
      bmp.LockBits(rect, ImageLockMode.ReadOnly, 
      bmp.PixelFormat); 

     int absStride = Math.Abs(bmpData.Stride); 
     int bytes = absStride * bmp.Height; 

     // Declare an array to hold the bytes of the bitmap. 
     byte[] rgbValues = new byte[bytes]; 

     for (int i = 0; i < bmp.Height; i++) 
     { 
      IntPtr pointer = new IntPtr(bmpData.Scan0.ToInt32() + (bmpData.Stride * i)); 
      System.Runtime.InteropServices.Marshal.Copy(pointer, rgbValues, absStride * (bmp.Height - i - 1), absStride); 
     } 

     // Unlock the bits. 
     bmp.UnlockBits(bmpData); 

     return rgbValues; 
    }