Android图像表示

时间:2011-11-22 11:16:52

标签: android image pixels

我正在尝试访问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. 其他东西

1 个答案:

答案 0 :(得分:5)

要获得buffer.array()的特定像素x的偏移,y,尺寸为width x heightbytesPerPixel的图片中为offsetForPixel = (y * width + x) * bytesPerPixel 每个像素的字节数,使用以下公式:

Bitmap.copyPixelsToBuffer()

换句话说,数组中的第一个元素是左上角像素,以下元素是行主要元素。像素的所有数据都存储在相邻的字节中,并且不会基于通道展开。这是上面1,2和4的答案。现在让我们讨论3,这就是事情变得复杂的地方。

您使用Bitmap.copyPixelsToBuffer()获得的是Android的低级绘图库skia使用的原始位图数据表示。这有三个重要的后果:

  • 频道顺序取决于字节顺序
  • 频道与alpha
  • 预乘
  • 如何将通道打包到包含数据类型中

如果你想检查单个像素,最后一点会让你很难使用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); } ,因为你根本无法知道如何配置skia来打包频道。作为实验,请尝试以下代码:

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

当我运行时,我得到了这个输出:

{{1}}

我们可以看到我们正在处理大端,内存表示是预乘的,并且频道已经从ARGB重新排列到RGBA(在skia源代码中的动机是相同的-memory表示为OpenGL)。

如果您想要读取像素数据,建议您改用Bitmap.getPixels()。涉及一些复制,但至少API指定了如何格式化返回的数据。