Camera preview image data processing with Android L and Camera2 API

匿名 (未验证) 提交于 2019-12-03 02:50:02

问题:

I'm working on an android app that is processing the input image from the camera and displays it to the user. This is fairly simple, I register a PreviewCallback on the camera object with the setPreviewCallbackWithBuffer. This is easy and works smoothly with the old camera API

public void onPreviewFrame(byte[] data, Camera cam) {     // custom image data processing } 

I'm trying to port my app to take advantage of the new Camera2 API and I'm not sure how exactly shall I do that. I followed the Camera2Video in L Preview samples that allows to record a video. However, there is no direct image data transfer in the sample, so I don't understand where exactly shall I get the image pixel data and how to process it.

Could anybody help me or suggest the way how one can get the the functionality of PreviewCallback in android L, or how it's possible to process preview data from the camera before displaying it to the screen? (there is no preview callback on the camera object)

Thank you!

回答1:

Since the Camera2 API is very different from the current Camera API, it might help to go through the documentation.

A good starting point is camera2basic example. It demonstrates how to use Camera2 API and configure ImageReader to get JPEG images and register ImageReader.OnImageAvailableListener to receive those images

To receive preview frames, you need to add your ImageReader's surface to setRepeatingRequest's CaptureRequest.Builder.

Also, you should set ImageReader's format to YUV_420_888, which will give you 30fps at 8MP (The documentation guarantees 30fps at 8MP for Nexus 5).



回答2:

Combining a few answers into a more digestible one because @VP's answer, while technically clear, is difficult to understand if it's your first time moving from Camera to Camera2:

Using https://github.com/googlesamples/android-Camera2Basic as a starting point, modify the following:

In createCameraPreviewSession() init a new Surface from mImageReader

Surface mImageSurface = mImageReader.getSurface(); 

Add that new surface as a output target of your CaptureRequest.Builder variable. Using the Camera2Basic sample, the variable will be mPreviewRequestBuilder

mPreviewRequestBuilder.addTarget(mImageSurface); 

Here's the snippet with the new lines (see my @AngeloS comments):

private void createCameraPreviewSession() {      try {          SurfaceTexture texture = mTextureView.getSurfaceTexture();         assert texture != null;          // We configure the size of default buffer to be the size of camera preview we want.         texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());          // This is the output Surface we need to start preview.         Surface surface = new Surface(texture);          //@AngeloS - Our new output surface for preview frame data         Surface mImageSurface = mImageReader.getSurface();          // We set up a CaptureRequest.Builder with the output Surface.         mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);          //@AngeloS - Add the new target to our CaptureRequest.Builder         mPreviewRequestBuilder.addTarget(mImageSurface);          mPreviewRequestBuilder.addTarget(surface);          ... 

Next, in setUpCameraOutputs(), change the format from ImageFormat.JPEG to ImageFormat.YUV_420_888 when you init your ImageReader. (PS, I also recommend dropping your preview size for smoother operation - one nice feature of Camera2)

mImageReader = ImageReader.newInstance(largest.getWidth() / 16, largest.getHeight() / 16, ImageFormat.YUV_420_888, 2); 

Finally, in your onImageAvailable() method of ImageReader.OnImageAvailableListener, be sure to use @Kamala's suggestion because the preview will stop after a few frames if you don't close it

    @Override     public void onImageAvailable(ImageReader reader) {          Log.d(TAG, "I'm an image frame!");          Image image =  reader.acquireNextImage();          ...          if (image != null)             image.close();     } 


回答3:

In the ImageReader.OnImageAvailableListener class, close the image after reading as shown below (this will release the buffer for next capture). You will have to handle exception on close

      Image image =  imageReader.acquireNextImage();       ByteBuffer buffer = image.getPlanes()[0].getBuffer();       byte[] bytes = new byte[buffer.remaining()];       buffer.get(bytes);       image.close(); 


回答4:

I needed the same thing, so I used their example and added a call to a new function when the camera is in preview state.

private CameraCaptureSession.CaptureCallback mCaptureCallback             = new CameraCaptureSession.CaptureCallback()     private void process(CaptureResult result) {         switch (mState) {             case STATE_PREVIEW: {                     if (buttonPressed){                         savePreviewShot();                     }                 break;             } 

The savePreviewShot() is simply a recycled version of the original captureStillPicture() adapted to use the preview template.

   private void savePreviewShot(){         try {             final Activity activity = getActivity();             if (null == activity || null == mCameraDevice) {                 return;             }             // This is the CaptureRequest.Builder that we use to take a picture.             final CaptureRequest.Builder captureBuilder =                     mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);             captureBuilder.addTarget(mImageReader.getSurface());              // Orientation             int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();             captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));              CameraCaptureSession.CaptureCallback CaptureCallback                     = new CameraCaptureSession.CaptureCallback() {                  @Override                 public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,                                                TotalCaptureResult result) {                     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss:SSS");                     Date resultdate = new Date(System.currentTimeMillis());                     String mFileName = sdf.format(resultdate);                     mFile = new File(getActivity().getExternalFilesDir(null), "pic "+mFileName+" preview.jpg");                      Log.i("Saved file", ""+mFile.toString());                     unlockFocus();                 }             };              mCaptureSession.stopRepeating();             mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);         } catch (Exception e) {             e.printStackTrace();         }     }; 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!