2011-11-22 16 views
3

我試圖訪問Android中圖像的原始像素數據。
代碼看起來是這樣的:Android圖像表示

Bitmap bitmap = BitmapFactory.decodeFile("image.png"); 
    // assert valid input 
    if ((bitmap.getConfig() == null) || bitmap.getConfig() == Config.ARGB_8888) 
     throw new Exception("bad config"); 

    ByteBuffer buffer = ByteBuffer.allocate(4 * bitmap.getWidth() * bitmap.getHeight()); 
    bitmap.copyPixelsToBuffer(buffer);   
    return buffer.array(); 

如何線性1D buffer.array()像素存儲?

  1. 第一個元素是左上角像素還是左下角像素(或其他)?
  2. 行專業(行後)或列專業(列後專欄)?
  3. 渠道訂單ARGB或BGRA?
  4. 單獨的每個通道的行專業或列專業?
  5. 別的東西

回答

5

,以獲得與每個像素bytesPerPixel字節偏移buffer.array()對於給定像素xy大小width X height的圖像中,使用以下公式:

offsetForPixel = (y * width + x) * bytesPerPixel 

在換句話說,數組中的第一個元素是左上角的像素,以下元素是主要行。像素的所有數據都存儲在相鄰的字節中,並且不會根據通道進行分散。這是上面1,2和4的答案。現在讓我們來討論3,這是事情變得複雜的地方。

您使用Bitmap.copyPixelsToBuffer()獲得的是Android低級繪圖庫skia使用的原始位圖數據表示。這有三個顯著後果:

  • 通道順序取決於字節序
  • 通道預乘阿爾法
  • 通道如何裝入包含數據類型是可配置的

最後如果您想檢查單個像素,那麼使用​​會很尷尬,因爲您根本無法知道skia是如何配置爲打包通道的。作爲一個實驗,試試這個代碼:

int inputPixel = 0x336699cc; 
int[] pixels = new int[] { inputPixel }; 
Bitmap bm = Bitmap.createBitmap(pixels, 1, 1, Config.ARGB_8888); 
ByteBuffer bb = ByteBuffer.allocate(4); 
bm.copyPixelsToBuffer(bb); 
Log.i("TAG", "inputPixel = 0x" + Integer.toHexString(inputPixel)); 
for (int i = 0; i < 4; i++) { 
    String byteString = "0x" + Integer.toHexString(bb.array()[i] & 0xff); 
    Log.i("TAG", "outputPixel byte " + i + " = " + byteString); 
} 

當我運行的是,我得到這樣的輸出:

I/TAG (1995): inputPixel = 0x336699cc 
I/TAG (1995): outputPixel byte 0 = 0x14 
I/TAG (1995): outputPixel byte 1 = 0x1f 
I/TAG (1995): outputPixel byte 2 = 0x29 
I/TAG (1995): outputPixel byte 3 = 0x33 

我們可以看到,我們正在處理的大端,將內存中表示爲預先倍增,並且這些通道已經從ARGB重新排列到RGBA(在skia源代碼中的動機與OpenGL在內存中的表示相同)。

如果你想讀取像素數據,我建議你使用Bitmap.getPixels()來代替。涉及到一些複製,但至少API指定了返回數據的格式。