1

在我使用 camera2api 构建相机应用程序的过程中,我在尝试保存原始图像时遇到了一个小问题。

我将捕获结果分配给以下代码中的成员。

@Override

public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                        super.onCaptureCompleted(session, request, result);


                        mCaptureResult = result;
                        Toast.makeText(getApplicationContext(),
                                "Image Captured",Toast.LENGTH_SHORT).show();

                    }
                };

当我在这个位置调试它时,成员被分配而不是 null。DngCreator但是,当它在类中引发空错误时ImageSaver

我的听众:

private ImageReader mImageReader;
private ImageReader.OnImageAvailableListener mOnImageAvailableListener =
        new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader imageReader) {
                mBackgroundHandler.post(new ImageSaver(imageReader.acquireNextImage(),mUiHandler,
                        mCaptureResult, mCameraCharacteristics));
            }
        };

private ImageReader mRawImageReader;
private ImageReader.OnImageAvailableListener mOnRawImageAvailableListener =
        new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader imageReader) {
                mBackgroundHandler.post(new ImageSaver(imageReader.acquireNextImage(),mUiHandler,
                        mCaptureResult, mCameraCharacteristics));
            }
        };

我的图像保护程序类:

    private ImageSaver(Image image, Handler handler, CaptureResult captureResult,
                       CameraCharacteristics cameraCharacteristics) {
        mImage = image;
        mHandler =handler;
        mCaptureResult = captureResult;
        mCameraCharacteristics = cameraCharacteristics;
    }



    @Override
    public void run() {
        int format = mImage.getFormat();
        switch(format){
            case ImageFormat.JPEG:
                ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer();
                byte[] bytes = new byte[byteBuffer.remaining()];
                byteBuffer.get(bytes);

                FileOutputStream fileOutputStream = null;
                try {
                    fileOutputStream = new FileOutputStream(mImageFile);
                    fileOutputStream.write(bytes);
                }
                catch (IOException e){
                    e.printStackTrace();
                }
                finally {
                    mImage.close();
                    if(fileOutputStream != null){
                        try{
                            fileOutputStream.close();
                        }
                        catch (IOException e){
                            e.printStackTrace();
                        }
                    }
                    //Message message = mHandler.obtainMessage();
                    //message.sendToTarget();
                }
                break;
            case ImageFormat.RAW_SENSOR:
                DngCreator dngCreator = new DngCreator(mCameraCharacteristics,mCaptureResult);
                FileOutputStream rawFileOutputStream = null;
                try {
                    rawFileOutputStream = new FileOutputStream(mRawImageFile);
                    dngCreator.writeImage(rawFileOutputStream, mImage);
                }
                catch (IOException e){
                    e.printStackTrace();
                }
                finally{
                    mImage.close();
                    if(rawFileOutputStream != null){
                        try {
                            rawFileOutputStream.close();
                        }
                        catch (IOException e){
                            e.printStackTrace();
                        }
                    }
                }
                break;
        }


    }
}

现在,当我尝试初始化 DngCreator 并且堆栈跟踪如下时,它给了我一个错误。

FATAL EXCEPTION: Camera2 Background Thread Process: com.something.something, PID: 5162 java.lang.IllegalArgumentException: Null argument to DngCreator constructor at android.hardware.camera2.DngCreator.<init>(DngCreator.java:89) at com.something.something.ControlCameraActivity$ImageSaver.run(ControlCameraActivity.java:328) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:148) at android.os.HandlerThread.run(HandlerThread.java:61)

有人可以帮我解决这个问题吗?如果您需要我提供更多信息,请立即告诉我。谢谢

4

2 回答 2

2

不能保证 onCaptureCompleted() 在 OnImageAvailable() 之前发生。事实上,由于 RAW 图像缓冲区通常在图像处理预览和结果元数据完成之前就已准备好,因此 onCaptureCompleted() 很可能会在 onImageAvailable() 之后发生。

如果 onImageAvailable 首先发生,则您还没有捕获结果。

相反,您应该等待图像和捕获结果都完成,然后创建 ImageSaver。作为一种选择,让两个回调将它们各自的输出(捕获结果和图像)保存在某个共享位置,然后检查两者是否非空 - 如果是,则调用 ImageSaver。然后不管哪个先运行,第二个运行的都会启动 ImageSaver。

于 2016-08-31T02:04:55.473 回答
1

首先,当您调用imageReader.acquireNextImage()将其设置在 Image 对象中并在使用后执行 Image.close 时。ImageReader 对垃圾收集器来说真的很危险,而且如果 ImageReader maxImages 中的数字很低,你会很快填充它,因为你没有关闭图像。

其次,关于您的参考资料,您的 SavingImage 方法在哪里?image 不是可解析的对象,因此,如果您将其发送到服务或其他类,则可能会遇到问题。

最后,正如@Eddy 所说,有时在您的 OnImageAvailable 之前不会调用 onCaptureComplete。因此,您对此有 2 个解决方案:

只需在您的应用程序中添加一个避免 FC 的检查:

if (mImage != null && mCameraCharacteristics != null && mDngResult != null) { 
//process your dng
}

或者,您可以创建一个侦听器。因此,当您收到您的. 时onImageAvailable(),您可以将请愿书放入自定义列表或 Hastable 中。

在那里,检查列表是否有任何captureResult可用,如果你有一个 CaptureResult,就拿它并处理你的 DNG,如果没有实例化一个监听器,它将在你的onCaptureComplete. 在那里,您只需要检查侦听器是否为空,如果不是,则在您的结果可用时调用“处理”图像。

public class MyResultList {

    private DngListener mDngListener;
    private Hashtable<String, CaptureResult> mDngCaptureResults;

    public int getSize() {
        return mDngCaptureResults.size();
    }

    public Object getResult() {
        if (mDngCaptureResults.size() == 0){
            mDngListener = new DngListener() {
                @Override
                public void onResultAvailable() {
                    //Now result is not null, so you can get the available item
                    YourSavingImage(mDngCaptureResults.get(0));
                }
            }
            return null;
        } else {
            return mDngCaptureResults.get(0);
        }
    }

    public void add(CaptureResult result, String index){
        mDngCaptureResults.put(index,result);
    }
}

我刚刚提出了这个想法,根据您的目标对其进行修改。这很简单,如果您有很多依赖项,它可能效果不佳。

于 2016-09-09T11:12:01.983 回答