2012-12-24 17 views
1

我寫了一個這個函數的版本,它將灰度位圖作爲蒙板和源位圖,並輸出一個位圖,其中應用了蒙板SetPixelGetPixel,但速度很慢,所以改爲我試圖寫一個使用BitmapData和指針算術,但我得到一個訪問衝突,我不知道爲什麼。在圖像蒙板中使用BitmapData訪問衝突

當寫入結果位圖中的像素時,我得到一個AccessViolationException - 我認爲這是由不正確的索引造成的,但我看不到我出錯的地方。

public static Bitmap ApplyAlphaMask2(Bitmap source, Bitmap mask) 
{ 
    if (source.Size != mask.Size) 
    { 
     throw new NotImplementedException("Applying a mask of a different size to the source image is not yet implemented"); 
    } 
    Bitmap result = new Bitmap(source.Width, source.Height); 
    unsafe 
    { 
     BitmapData source_data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 
     BitmapData mask_data = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 
     BitmapData result_data = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 
     for(int column = 0; column < source.Height; column++) 
     { 
      Int32* source_column_ptr = (Int32*)source_data.Scan0 + (column * Math.Abs(source_data.Stride)); 
      Int32* mask_column_ptr = (Int32*)mask_data.Scan0 + (column * Math.Abs(mask_data.Stride)); 
      Int32* result_column_ptr = (Int32*)result_data.Scan0 + (column * Math.Abs(mask_data.Stride)); 
      for (int row = 0; row < source.Width; row++) 
      { 
       Color source_color = Color.FromArgb(source_column_ptr[row]); 
       Color mask_color = Color.FromArgb(mask_column_ptr[row]); 
       Int32* result_pixel_ptr = &result_column_ptr[row]; 
       Color result_color = Color.FromArgb((int)(255.0f * mask_color.GetBrightness()), source_color); 
       *result_pixel_ptr = result_color.ToArgb(); //Access violation! 
      } 
     } 
     source.UnlockBits(source_data); 
     mask.UnlockBits(mask_data); 
     result.UnlockBits(result_data); 
    } 
    return result; 
} 

任何幫助,將不勝感激。

編輯:這並不總是發生在同一列,但該行始終顯示爲0

回答

1

您正在使用mask_data.Stride兩次(複製粘貼錯誤)。

你爲什麼在步伐上使用Math.Abs?大步是否定的?這可能意味着圖像是從下到上編碼的,而採用abs值會破壞這些信息。


編輯:問題就在這裏:

(Int32*)source_data.Scan0 + (column * Math.Abs(source_data.Stride)) 

您添加(column * Math.Abs(source_data.Stride))int*這意味着你得到4倍的偏移量,你需要的。您可能打算:

(Int32*)((byte*)source_data.Scan0 + (column * Math.Abs(source_data.Stride))) 
+0

僅使用Math.Abs​​是因爲示例顯示它在此msdn頁面上使用:http://msdn.microsoft.com/zh-cn/library/system。 drawing.imaging.bitmapdata.aspx另外,從'mask_data.Stride'改爲'result_data.Stride'沒有幫助:/ – Ell

+0

步幅是否定的?請檢查所有3個步驟。嘗試沒有吸收。該示例僅使用Abs分配空間,而不是「導航」現有緩衝區。 – usr

+0

@所有文檔都包含以下語句:「跨度是單行像素(掃描線)的寬度,四捨五入爲四字節邊界。如果跨度爲正,則位圖爲自上而下。如果步幅是負值,則位圖是自下而上的。「所以這似乎是錯誤 - 位圖是自下而上的。 – usr

1

順便說一句,你的變量名是錯誤的...需要交換他們!
請嘗試下列修改。 未經測試!

public static Bitmap ApplyAlphaMask2(Bitmap source, Bitmap mask) 
    { 
     int x, y; 
     Color mask_color; 

     if (source.Size != mask.Size) 
     { 
      throw new NotImplementedException("Applying a mask of a different size to the source image is not yet implemented"); 
     } 
     Bitmap result = new Bitmap(source.Width, source.Height, PixelFormat.Format32bppArgb); 
     BitmapData source_data = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 
     BitmapData mask_data = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 
     BitmapData result_data = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); 
     unsafe 
     { 
      Int32* source_line_ptr = (Int32*)source_data.Scan0; 
      Int32* mask_line_ptr = (Int32*)mask_data.Scan0; 
      Int32* result_line_ptr = (Int32*)result_data.Scan0; 
      for (y = 0; y < source.Height; y++) 
      { 
       for (x = 0; x < source.Width; x++) 
       { 
        mask_color = Color.FromArgb(mask_line_ptr[x]); 
        result_line_ptr[x] = ((int)(mask_color.GetBrightness() * 255.0f) << 24) | (source_line_ptr[x] & 0xFFFFFF); 
       } 
       source_line_ptr += source_data.Stride; 
       mask_line_ptr += mask_data.Stride; 
       result_line_ptr += result_data.Stride; 
      } 
      source.UnlockBits(source_data); 
      mask.UnlockBits(mask_data); 
      result.UnlockBits(result_data); 
     } 
     return result; 
    } 

我不知道你會得到預期的結果無論如何,因爲GDI +與灰度圖像的問題(如果我沒記錯的話,如果你申請LockBits它返回一個灰度圖像圖像16灰度,而不是256)。
另一件事是如果你想優化你的代碼,你不應該在循環內聲明局部變量。
最後,我認爲返回的值Color.GetBrightness不準確(不確定這一點)。

+0

只有命名不正確。實際的代碼在這個問題上是正確的。 – usr

+0

@usr我在談論什麼_columns_和_rows_是混淆。沒有什麼關於這是一個編程錯誤,只是一種誤解(所以'..._ column_ptr'名字也是錯誤的)。 – Jigsore

+0

設置結果指針時,仍會導致訪問衝突:/ – Ell