Android Camera 2:ImageReader的图像没有步幅值

时间:2018-07-08 09:11:30

标签: android android-camera2 image-reader

我一直试图将图像从相机路由到ImageReader,以便可以使用Camera2 API直接操作图像。当我将捕获会话流传输到SurfaceView时,该流工作正常。然后,当我将捕获会话流设置为ImageReader时,我注意到图像在某种程度上是无效的。

在ImageReader的OnImageAvailable回调函数中,我提取下一个可用的Image并尝试读取它。这就是我的问题所在。 Image不为null,并且飞机在那里,但是飞机的缓冲区最初为null。当我尝试获取缓冲区时,它们突然不为null,但是尝试从中读取将导致应用程序崩溃而没有堆栈跟踪。此外,将平面中的像素和行跨距设置为0。不过,图像的宽度和高度也已正确设置。

因此,我认为我没有正确设置ImageReader。问题是我在做什么不正确?

代码:

public class CompatibleCamera {
    private static final int CAMERA2_API_LEVEL = 23;
    public static final int FORMAT_RAW = ImageFormat.RAW_SENSOR;
    public static final int FORMAT_JPEG = ImageFormat.JPEG;
    private static final int MAX_IMAGES = 2;
    // Interface for the user to use. User supplies the function to manipulate the image
    public interface ImageTransform
    {
        void doTransform(Image image);
    }

    //***********Camera 2 API Members***********

    // The camera2 API CameraManager. Used to access the camera device
    private CameraManager mCamera2Manager;
    // The information used by the device to reference the camera. Not a camera object itself
    private CameraDevice mCamera2Device;
    private String mCamera2DeviceID = "";
    // The class that allows us to get the camera's image

    private ImageReader mImageReader;
    // This listener is where we have the programmer deal with the image. Just edit the interface
    private ImageReader.OnImageAvailableListener mListener;
    // This is the thread for the handler. It keeps it off the UI thread so we don't block the GUI

    private HandlerThread mCameraCaptureHandlerThread;
    // This runs in the background and handles the camera feed, activating the OnImageAvailableListener
    private Handler mCameraCaptureHandler;

    private HandlerThread mImageAvailableHandlerThread;
    // This runs in the background and handles the camera feed, activating the OnImageAvailableListener
    private Handler mImageAvailableHandler;

    // This object is the camera feed, essentially. We store it so we can properly close it later
    private CameraCaptureSession cameraCaptureSession;

    // DEBUG
    private boolean TEST_SURFACE_VIEW = false;
    private Surface dbSurface;

    // Mutex lock. Locks and unlocks when the ImageReader is pulling and processing an image
    private Semaphore imageReaderLock = new Semaphore(1);

    //***********Common Members***********

    // The context of the activity holding this object
    private Context mContext;

    // Our ImageTransform implementation to alter the image as it comes in
    private ImageTransform mTransform;

    private int iImageFormat= FORMAT_RAW;

    //==========Methods==========

    public CompatibleCamera(Context context, ImageTransform transform, int imageFormat)
    {
        mContext = context;
        mTransform = transform;

        mListener = new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader imageReader) {
                try {
                    imageReaderLock.acquire();
                    Image image = imageReader.acquireNextImage();

                    //<--------------Problem With Image is Here-------------->
                    mTransform.doTransform(image);
                    image.close();
                    imageReaderLock.release();
                }
                catch(InterruptedException ex)
                {
                    ex.printStackTrace();
                }
            }
        };
    }

    private boolean camera2GetManager()
    {
        //----First, get the CameraManager and a Camera Device----
        mCamera2Manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
        if (mCamera2Manager == null) {
            System.out.println("    DEBUG: Manager is null");
            return false;
        }
        else {
            System.out.println("    DEBUG: Camera Manager obtained");

            try {
                String[] cameraIDs = mCamera2Manager.getCameraIdList();

                for (String cameraID : cameraIDs) {
                    CameraCharacteristics cameraCharacteristics = mCamera2Manager.getCameraCharacteristics(cameraID);
                    if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) ==
                            CameraCharacteristics.LENS_FACING_BACK) {
                        mCamera2DeviceID = cameraID;
                        break;
                    }
                }
                if (mCamera2DeviceID.equals("")) {
                    System.out.println("No back camera, exiting");
                    return false;
                }
                System.out.println("    DEBUG: Camera Device obtained");

                // Open the Camera Device
            } catch (Exception ex) {
                ex.printStackTrace();
                return false;
            }
            return camera2OpenCamera();
        }
    }

    private boolean camera2SetupImageReader()
    {
        // Get the largest image size available

        CameraCharacteristics cameraCharacteristics;
        try {
            cameraCharacteristics= mCamera2Manager.getCameraCharacteristics(mCamera2DeviceID);
        } catch(Exception e) {
            e.printStackTrace();
            return false;
        }

        StreamConfigurationMap map = cameraCharacteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        Size largestSize = Collections.max(
                Arrays.asList(map.getOutputSizes(iImageFormat)),
                new CompareSizesByArea());


        // Set up the handler
        mCameraCaptureHandlerThread = new HandlerThread("cameraCaptureHandlerThread");
        mCameraCaptureHandlerThread.start();
        mCameraCaptureHandler = new Handler(mCameraCaptureHandlerThread.getLooper());


        mImageAvailableHandlerThread = new HandlerThread("imageReaderHandlerThread");
        mImageAvailableHandlerThread.start();
        mImageAvailableHandler = new Handler(mImageAvailableHandlerThread.getLooper());

        mImageReader = ImageReader.newInstance( largestSize.getWidth(),
                largestSize.getHeight(),
                iImageFormat,
                MAX_IMAGES);
        mImageReader.setOnImageAvailableListener(mListener, mImageAvailableHandler);

        // This callback is used to asynchronously set up the capture session on our end
        final CameraCaptureSession.StateCallback captureStateCallback = new CameraCaptureSession.StateCallback() {
            // When configured, set the target surface
            @Override
            public void onConfigured(@NonNull CameraCaptureSession session) {
                try
                {
                    CaptureRequest.Builder requestBuilder = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
                    if (TEST_SURFACE_VIEW)
                        requestBuilder.addTarget(dbSurface);
                    else
                        requestBuilder.addTarget(mImageReader.getSurface());
                    //set to null - image data will be produced but will not receive metadata
                    session.setRepeatingRequest(requestBuilder.build(), null, mCameraCaptureHandler);
                    cameraCaptureSession = session;
                }
                catch (Exception ex)
                {
                    ex.printStackTrace();
                }
            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                System.out.println("Failed to configure the capture session :(");
            }
        };

        ArrayList<Surface> surfaces = new ArrayList<>();
        if (TEST_SURFACE_VIEW)
            surfaces.add(dbSurface);
        else
            surfaces.add(mImageReader.getSurface());

        try
        {
            mCamera2Device.createCaptureSession(surfaces, captureStateCallback, mCameraCaptureHandler);
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
        return true;
    }
}

1 个答案:

答案 0 :(得分:1)

RAW_SENSOR是格式的特殊野兽。

  

一般原始相机传感器图像格式,通常代​​表单通道拜耳马赛克图像。每个像素颜色样本的存储精度为16位。

     

必须从android.hardware.camera2.CameraDevice中查询颜色镶嵌的布局,原始像素数据的最大和最小编码值,图像的颜色空间以及所有其他用于解释原始传感器图像的信息。产生图像。

您不应尝试直接使用其步幅信息,就好像它是YUV框架一样。