2011-01-27 66 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; 
    }