1. 程式人生 > >Android camera2 回撥imagereader 從Image拿到YUV資料轉化成RGB,生成bitmap並儲存

Android camera2 回撥imagereader 從Image拿到YUV資料轉化成RGB,生成bitmap並儲存

ImageUtil.java
import android.graphics.ImageFormat;
import android.media.Image;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Log;

import java.nio.ByteBuffer;

public class ImageUtil {
        public static final int YUV420P = 0;
        public static
final int YUV420SP = 1; public static final int NV21 = 2; private static final String TAG = "ImageUtil"; /*** * 此方法內註釋以640*480為例 * 未考慮CropRect的 */ @RequiresApi(api = Build.VERSION_CODES.KITKAT) public static byte[] getBytesFromImageAsType(Image image, int
type) { try { //獲取源資料,如果是YUV格式的資料planes.length = 3 //plane[i]裡面的實際資料可能存在byte[].length <= capacity (緩衝區總大小) final Image.Plane[] planes = image.getPlanes(); //資料有效寬度,一般的,圖片width <= rowStride,這也是導致byte[].length <= capacity的原因
// 所以我們只取width部分 int width = image.getWidth(); int height = image.getHeight(); //此處用來裝填最終的YUV資料,需要1.5倍的圖片大小,因為Y U V 比例為 4:1:1 byte[] yuvBytes = new byte[width * height * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8]; //目標陣列的裝填到的位置 int dstIndex = 0; //臨時儲存uv資料的 byte uBytes[] = new byte[width * height / 4]; byte vBytes[] = new byte[width * height / 4]; int uIndex = 0; int vIndex = 0; int pixelsStride, rowStride; for (int i = 0; i < planes.length; i++) { pixelsStride = planes[i].getPixelStride(); rowStride = planes[i].getRowStride(); ByteBuffer buffer = planes[i].getBuffer(); //如果pixelsStride==2,一般的Y的buffer長度=640*480,UV的長度=640*480/2-1 //源資料的索引,y的資料是byte中連續的,u的資料是v向左移以為生成的,兩者都是偶數位為有效資料 byte[] bytes = new byte[buffer.capacity()]; buffer.get(bytes); int srcIndex = 0; if (i == 0) { //直接取出來所有Y的有效區域,也可以儲存成一個臨時的bytes,到下一步再copy for (int j = 0; j < height; j++) { System.arraycopy(bytes, srcIndex, yuvBytes, dstIndex, width); srcIndex += rowStride; dstIndex += width; } } else if (i == 1) { //根據pixelsStride取相應的資料 for (int j = 0; j < height / 2; j++) { for (int k = 0; k < width / 2; k++) { uBytes[uIndex++] = bytes[srcIndex]; srcIndex += pixelsStride; } if (pixelsStride == 2) { srcIndex += rowStride - width; } else if (pixelsStride == 1) { srcIndex += rowStride - width / 2; } } } else if (i == 2) { //根據pixelsStride取相應的資料 for (int j = 0; j < height / 2; j++) { for (int k = 0; k < width / 2; k++) { vBytes[vIndex++] = bytes[srcIndex]; srcIndex += pixelsStride; } if (pixelsStride == 2) { srcIndex += rowStride - width; } else if (pixelsStride == 1) { srcIndex += rowStride - width / 2; } } } } // image.close(); //根據要求的結果型別進行填充 switch (type) { case YUV420P: System.arraycopy(uBytes, 0, yuvBytes, dstIndex, uBytes.length); System.arraycopy(vBytes, 0, yuvBytes, dstIndex + uBytes.length, vBytes.length); break; case YUV420SP: for (int i = 0; i < vBytes.length; i++) { yuvBytes[dstIndex++] = uBytes[i]; yuvBytes[dstIndex++] = vBytes[i]; } break; case NV21: for (int i = 0; i < vBytes.length; i++) { yuvBytes[dstIndex++] = vBytes[i]; yuvBytes[dstIndex++] = uBytes[i]; } break; } return yuvBytes; } catch (final Exception e) { if (image != null) { image.close(); } Log.i(TAG, e.toString()); } return null; } /*** * YUV420 轉化成 RGB */ public static int[] decodeYUV420SP(byte[] yuv420sp, int width, int height) { final int frameSize = width * height; int rgb[] = new int[frameSize]; for (int j = 0, yp = 0; j < height; j++) { int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; for (int i = 0; i < width; i++, yp++) { int y = (0xff & ((int) yuv420sp[yp])) - 16; if (y < 0) y = 0; if ((i & 1) == 0) { v = (0xff & yuv420sp[uvp++]) - 128; u = (0xff & yuv420sp[uvp++]) - 128; } int y1192 = 1192 * y; int r = (y1192 + 1634 * v); int g = (y1192 - 833 * v - 400 * u); int b = (y1192 + 2066 * u); if (r < 0) r = 0; else if (r > 262143) r = 262143; if (g < 0) g = 0; else if (g > 262143) g = 262143; if (b < 0) b = 0; else if (b > 262143) b = 262143; rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff); } } return rgb; } }

回撥OnImageReader

    private ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader reader) {
            Image image = reader.acquireLatestImage();

            int imageWidth = image.getWidth();
            int imageHeight = image.getHeight();

            byte[] data68 = ImageUtil.getBytesFromImageAsType(image,2);

            if(time==5) {
               int rgb[] = ImageUtil.decodeYUV420SP(data68, imageWidth, imageHeight);
                Bitmap bitmap2 = Bitmap.createBitmap(rgb, 0, imageWidth,
                        imageWidth, imageHeight,
                        android.graphics.Bitmap.Config.ARGB_8888);
                try {
                    File newFile = new File(Environment.getExternalStorageDirectory(), "345.png");
                    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile));
                    bitmap2.compress(Bitmap.CompressFormat.PNG, 100, bos);
                    bos.flush();
                    bos.close();
                    bitmap2.recycle();
                } catch (Exception e) {

                }
            }

//            Message msg = Message.obtain();
//            msg.obj = bitmap2;
//            msg.what = 003;
//            runHandler.sendMessage(msg);

            image.close();
        }
    };