2011-10-08 105 views
2

什麼是從位圖獲取像素列的最快方法? 我不考慮兩個循環,因爲它可能需要很長時間。任何想法我都會很感激。謝謝!什麼是獲取像素的位圖列的最佳和快速的方法?

+0

你只想得到一個像素陣列在圖中單個列? –

+0

@ChrisTaylor無論如何,但它必須是與像素的像素列,像上面:)哇,如此之快 – deadfish

回答

3

我會建議您的位圖轉換成使用下面的代碼的字節數組:

Bitmpa myImage=new Bitmap("myImage.bmp");  

BitmapData bmpData1=myImage.LockBits(new Rectangle(0,0,myImage.Width,myImage.Height), 
       System.Drawing.Imaging.ImageLockMode.ReadWrite, myImage.PixelFormat); 
byte[] myImageData = new byte[bmpData1.Stride * bmpData1.Height]; 
System.Runtime.InteropServices.Marshal.Copy(bmpData1.Scan0,myImageData,0 
         ,myImageData.Length); 
myImgage.UnlockBits(bmpData1); 

然後就很容易獲取你想要的列的像素。只需循環遍歷矢量myImageData,其步長等於每行像素數*每像素的字節數。

只要注意每個像素的字節數就可以用來表示位圖。 這取決於PixelFormat

+0

當我列出所有像素的值是否可以改變它們並保存到新的位圖?我研究了你的代碼,我明白marshal.copy將值保存到字節數組中,對嗎? – deadfish

+0

我發現它是可能的,只是改變字節數組中的元素,然後再次使用marschall副本。檢查[庫ms](http://msdn.microsoft.com/en-us/library/ms146625.aspx) – deadfish

+0

小提示:在第一行,「Bitmpa」應該是「位圖」 – Nic

2

假設你只需要一個列,以下例程應該可以幫到你。

首先這裏是標準的解決方案採用可驗證的C#代碼

static Color[] GetPixelColumn(Bitmap bmp, int x) 
{ 
    Color[] pixelColumn = new Color[bmp.Height]; 
    for (int i = 0; i < bmp.Height; ++i) 
    { 
    pixelColumn[i] = bmp.GetPixel(x, i); 
    } 
    return pixelColumn; 
} 

這裏是一個更快的替代方案,但是這需要您啓用的C#編譯器

static Color[] GetPixelColumnFast(Bitmap bmp, int x) 
{ 
    Color[] pixelColumn = new Color[bmp.Height]; 
    BitmapData pixelData = bmp.LockBits(
    new Rectangle(0, 0, bmp.Width, bmp.Height), 
    ImageLockMode.ReadOnly, 
    PixelFormat.Format32bppArgb); 
    unsafe 
    { 
    int* pData = (int*)pixelData.Scan0.ToPointer(); 
    pData += x; 
    for (int i = 0; i < bmp.Height; ++i) 
    { 
     pixelColumn[i] = Color.FromArgb(*pData); 
     pData += bmp.Width; 
    } 
    } 
    bmp.UnlockBits(pixelData); 

    return pixelColumn; 
} 

這兩個函數將返回unsafe支持一個Color數組,其中包含位圖中特定列的像素的顏色。

1

將其轉換爲字節數組

private static byte[, ,] BitmapToBytes(Bitmap bitmap) 
    { 
     BitmapData bitmapData = 
      bitmap.LockBits(new Rectangle(new Point(), bitmap.Size), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 
     byte[] bitmapBytes; 
     var stride = bitmapData.Stride; 
     try 
     { 
      int byteCount = bitmapData.Stride * bitmap.Height; 
      bitmapBytes = new byte[byteCount]; 
      Marshal.Copy(bitmapData.Scan0, bitmapBytes, 0, byteCount); 
     } 
     finally 
     { 
      bitmap.UnlockBits(bitmapData);     
     } 
     byte[, ,] result = new byte[3, bitmap.Width, bitmap.Height]; 
     for (int k = 0; k < 3; k++) 
     { 
      for (int i = 0; i < bitmap.Width; i++) 
      { 
       for (int j = 0; j < bitmap.Height; j++) 
       { 
        result[k, i, j] = bitmapBytes[j * stride + i * 3 + k]; 
       } 
      } 
     } 
     return result; 
    } 
+0

爲什麼我必須使用跨度?如果我想在圖像上製作兩個循環,其長度不會是100 .. – deadfish

+0

當我得到BitmapData時,我使用了PixelFormat.Format24bppRgb集,因此每個像素使用24位(每個像素使用8位,綠色和藍色組件),但是行的大小可能不是像素大小的精確倍數,因爲爲了提高效率,系統將其打包在從四字節邊界開始的行中,並且步幅是單行像素,四捨五入到四個字節的邊界 – MishaU

+0

我在我的代碼中發現錯誤:(我必須使用bitmapData.Stride而不是bitmap.Width * 3當我得到像素:result [k,i,j] = bitmapBytes [j * bitmapData.Stride + i * 3 + k]; – MishaU

相關問題