ImageReaderクラスを触ってみた
今日はまとめる余裕がないのでこっちにおくんじゃ。
- ImageReaderはAPI19で追加された、他のSurface(入力元=カメラなど)から画像を読み取る & 読み取ったコールバックで加工して他の部分へ流す(たとえばBitmapにしてImageViewに渡す)という使い方ができるSurface
- ImageはImageReaderがonImageAvailableコールバックが呼び出された時に持ってる、画像のバイト列などが扱えるオブジェクト
- MaxImagesを見ていると、何枚分かデータが貯められるそうだが、よくわからず
- 生のbyte列を扱えるが、Bitmapと違いUIへ渡せない
- 今回は http://woshidan.hatenablog.com/entry/2017/09/06/083000 をもとにして https://developer.android.com/things/training/doorbell/camera-input.html を参考にプレビューを見ながらシャッターを押したらさっき撮った画像が小窓に表示される、みたいなのを書いた
- ImageはImageReaderがonImageAvailableコールバックが呼び出された時に持ってる、画像のバイト列などが扱えるオブジェクト
- 追加でCamera2 APIについて気づいたこと
- mCameraDevice.createCaptureSession にはそのセッションで出力を送りうるすべてのSurfaceを配列で渡す
- このタイプのリクエストの結果はこのデバイスに… というのは、
CaptureRequest.Builder.addTarget
で設定 - すべてのSurfaceで画面サイズが適切に設定されていないとセッションが開始されないっぽい
- 新しく追加した
ImageReader
のSurface
の設定がおかしかった時のエラーが以下Surface with size (w=180, h=180) and format 0x21 is not valid, size not in valid set: [5248x3936, 5248x2952, 3840x2160, 3264x2448, 2048x1536, 1920x1080, 1280x720, 640x480, 480x320, 320x240]
CameraDevice-JV-0: Stream configuration failed
- 新しく追加した
- 追加でもんにゃりしていること
- Preview画面の向きについて(一番下を見ればわかるが、ずれた)
- CameraDevice解放のタイミングについて
- CameraCaptureSession closeのタイミングについて
こちらはコード全体のgist ImageReader初見メモ · GitHub
メモがてらのコメント付きコード断片。
// ImageReaderインスタンスの初期化 // MAX_IMAGES個だけ同時にImageオブジェクトが取得できる mImageReader = ImageReader.newInstance(IMAGE_WIDTH, IMAGE_HEIGHT, ImageFormat.JPEG, MAX_IMAGES); // imageAvailableListener -> 画像準備できた時反応するくん // backgroundHandler -> Listenerが実行された時に呼び出されるHandler // (に対応したLooperって形で処理を実行するバックグラウンドスレッドの指定) mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);
private ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { // Surfaceから画像が利用できるようになった時に呼び出される @Override public void onImageAvailable(ImageReader reader) { // Imageは各種コーデック(圧縮方法みたいなもの)で圧縮したりする、画像のByteBufferを扱うためのオブジェクト Image image = reader.acquireLatestImage(); // 何枚か画像を扱うことができて(?)、それぞれはPlanesに入っている // この辺のコードは https://developer.android.com/things/training/doorbell/camera-input.html のサンプルより ByteBuffer imageBuf = image.getPlanes()[0].getBuffer(); final byte[] imageBytes = new byte[imageBuf.remaining()]; imageBuf.get(imageBytes); image.close(); final Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length); MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { ImageView imageView = (ImageView) findViewById(R.id.picture); imageView.setImageBitmap(bitmap); } }); } };
private void copyPreview() { // ImageViewへ静止画を送るためのCaptureRequestを作る // 静止画を送ってもらうためのリクエストのビルダーですよ CaptureRequest.Builder copyPreviewRequestBuilder = null; try { copyPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); } catch (CameraAccessException e) { e.printStackTrace(); } // 送り先はImageReaderにしてね copyPreviewRequestBuilder.addTarget(mImageReader.getSurface()); CaptureRequest copyPreviewRequest = copyPreviewRequestBuilder.build(); // (プレビュー時にセッションは開いたままで、)追加で静止画送ってくれリクエストを送る try { mCaptureSession.capture(copyPreviewRequest, null, null); } catch (CameraAccessException e) { e.printStackTrace(); } }
画面は以下のような感じ。
参考
- Add Camera Support | Android Things
- ImageReader | Android Developers
- Image | Android Developers
- https://developer.android.com/about/versions/android-4.4.html
- ImageReaderの概要としてはここの
Surface Image Reader
の項目がわかりやすいです
- ImageReaderの概要としてはここの