我想使用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)我的程序出了什么问题?
谢谢。
发布于 2011-07-04 18:22:06
我已经调查了几个小时类似的问题,我想我已经找到了可能是你的问题所在。我猜您的位图可能以略有不同的格式存储。位图可以向前或向后存储。向后存储时,Stride将为负值。但是,Scan0将始终指向扫描的第一行,即第一个像素不是数组中的第一个字节。
因此,在向后扫描位图中,Scan0 +Abs(步长)-1是数组中的最后一个字节。Scan0 + Stride将始终是第二行的开始,因此如果stride为负,它将向后工作,而正将向前工作。
如果以负步长执行Marshal.Copy(bm2Ptr,rgbValues2,0,rgbValues2.Length),这将复制进入访问冲突区域之前的最后一条扫描线。下面的代码将把任何位图转换成向后扫描的字节just because that's what I was working with。我猜你现在已经修复/解决了你的问题,但希望这能帮助其他人。
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;
}发布于 2011-01-27 22:02:14
我测试了代码,对我来说它是有效的。
首先,我使用了一些随机的图片,然后是一张更大的全白图片,和你的图片大小一样。也许你可以提供更多关于这两张图片的信息:它们是否具有相同的大小或像素格式?
我看到的唯一可能的错误是在复制之后没有调用UnlockBits。
This article很好地解释了LockBit函数。
发布于 2011-01-27 22:11:36
它是为我而运行的。我试图使图像文件无效,但这抛出了一个不同的异常。它确实需要清理一下。
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);
}
}https://stackoverflow.com/questions/4816956
复制相似问题