ここで提案されているように、camera2 apiを使用してカメラプレビュー画像データ処理を実装しようとしています: Android LおよびCamera2API を使用したカメラプレビュー画像データ処理。
OnImageAvailableListenerを使用してコールバックを正常に受信しましたが、将来の処理のために、YUV_420_888Android.media.Imageからビットマップを取得する必要があります。私は同様の質問を検索しましたが、どれも役に立ちませんでした。
Android.media.Image(YUV_420_888)をビットマップに変換する方法を教えてください。プレビューフレームを聞くためのより良い方法があるかもしれません。
これについていくつかのコードを書きます。これはYUVデータのプレビューであり、JPEGデータに変更します。これを使用して、ビットマップ、byte []などとして保存できます(クラス「Allocation」を確認できます)。
そしてSDKドキュメントには次のように書かれています。
"Android.renderscriptで効率的なYUV処理を行うには、サポートされているYUVタイプ、IO_INPUTフラグ、およびgetOutputSizes(Allocation.class)によって返されるサイズの1つを使用してRenderScript割り当てを作成し、getSurface( )。」
ここにコードがあります。お役に立てば幸いです: https://github.com/pinguo-yuyidong/Camera2/blob/master/camera2/src/main/rs/yuv2rgb.rs
より簡単な解決策については、ここで私の実装を参照してください:
YUV 420_888からビットマップへの変換(フルコード)
この関数は、media.imageを入力として受け取り、y平面、u平面、およびv平面に基づいて3つのRenderScript割り当てを作成します。このウィキペディアの図に示されているように、YUV_420_888ロジックに従います。
ただし、ここでは、Y、U、およびVチャネル用に3つの個別のイメージプレーンがあるため、これらを3バイト[]、つまりU8割り当てと見なします。 y割り当てのサイズ幅*高さバイト、u割り当てとv割り当てのサイズ幅*高さ/ 4バイトは、各uバイトが4ピクセル(各vバイトと同じ)をカバーするという事実を反映しています。
これは、組み込みのRenderscript組み込み関数 ScriptIntrinsicYuvToRGB
を使用して実行できます。 Camera2 api Imageformat.yuv_420_888から取得したコードは、回転した画像 になります。
@Override public void onImageAvailable(ImageReader reader) { // Get the YUV data final Image image = reader.acquireLatestImage(); final ByteBuffer yuvBytes = this.imageToByteBuffer(image); // Convert YUV to RGB final RenderScript rs = RenderScript.create(this.mContext); final Bitmap bitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888); final Allocation allocationRgb = Allocation.createFromBitmap(rs, bitmap); final Allocation allocationYuv = Allocation.createSized(rs, Element.U8(rs), yuvBytes.array().length); allocationYuv.copyFrom(yuvBytes.array()); ScriptIntrinsicYuvToRGB scriptYuvToRgb = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs)); scriptYuvToRgb.setInput(allocationYuv); scriptYuvToRgb.forEach(allocationRgb); allocationRgb.copyTo(bitmap); // Release bitmap.recycle(); allocationYuv.destroy(); allocationRgb.destroy(); rs.destroy(); image.close(); } private ByteBuffer imageToByteBuffer(final Image image) { final Rect crop = image.getCropRect(); final int width = crop.width(); final int height = crop.height(); final Image.Plane[] planes = image.getPlanes(); final byte[] rowData = new byte[planes[0].getRowStride()]; final int bufferSize = width * height * ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8; final ByteBuffer output = ByteBuffer.allocateDirect(bufferSize); int channelOffset = 0; int outputStride = 0; for (int planeIndex = 0; planeIndex < 3; planeIndex++) { if (planeIndex == 0) { channelOffset = 0; outputStride = 1; } else if (planeIndex == 1) { channelOffset = width * height + 1; outputStride = 2; } else if (planeIndex == 2) { channelOffset = width * height; outputStride = 2; } final ByteBuffer buffer = planes[planeIndex].getBuffer(); final int rowStride = planes[planeIndex].getRowStride(); final int pixelStride = planes[planeIndex].getPixelStride(); final int shift = (planeIndex == 0) ? 0 : 1; final int widthShifted = width >> shift; final int heightShifted = height >> shift; buffer.position(rowStride * (crop.top >> shift) + pixelStride * (crop.left >> shift)); for (int row = 0; row < heightShifted; row++) { final int length; if (pixelStride == 1 && outputStride == 1) { length = widthShifted; buffer.get(output.array(), channelOffset, length); channelOffset += length; } else { length = (widthShifted - 1) * pixelStride + 1; buffer.get(rowData, 0, length); for (int col = 0; col < widthShifted; col++) { output.array()[channelOffset] = rowData[col * pixelStride]; channelOffset += outputStride; } } if (row < heightShifted - 1) { buffer.position(buffer.position() + rowStride - length); } } } return output; }