简体   繁体   English

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

[英]Android Camera 2: ImageReader's Images Have no Stride Values

I've been trying to route the images from the camera to an ImageReader so that I can manipulate the images directly using the Camera2 API. 我一直试图将图像从相机路由到ImageReader,以便可以使用Camera2 API直接操作图像。 When I have the capture session stream to a SurfaceView, the stream works just fine. 当我将捕获会话流传输到SurfaceView时,该流工作正常。 When I then set the capture session stream to my ImageReader, I notice that the images are somehow invalid. 然后,当我将捕获会话流设置为ImageReader时,我注意到图像在某种程度上是无效的。

In my ImageReader's OnImageAvailable callback function, I pull the next available Image and try to read it. 在ImageReader的OnImageAvailable回调函数中,我提取下一个可用的Image并尝试读取它。 This is where I have the problem. 这就是我的问题所在。 The Image isn't null and the planes are there, but the planes' buffers are null at first. Image不为null,并且飞机在那里,但是飞机的缓冲区最初为null。 When I try to grab the buffers, they are suddenly not null, but trying to read from them crashes the app without a stack trace. 当我尝试获取缓冲区时,它们突然不为null,但是尝试从中读取将导致应用程序崩溃而没有堆栈跟踪。 Further, the pixel and row strides in the planes are set to 0. The width and height of the image are properly set, though. 此外,将平面中的像素和行跨距设置为0。但是,图像的宽度和高度也已正确设置。

Therefore, I think that I'm not setting my ImageReader up correctly. 因此,我认为我没有正确设置ImageReader。 The question is then what am I not doing correctly? 问题是我在做什么不正确?

Code: 码:

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;
    }
}

RAW_SENSOR is a special beast of formats. RAW_SENSOR是格式的特殊野兽。

General raw camera sensor image format, usually representing a single-channel Bayer-mosaic image. 一般原始相机传感器的图像格式,通常代​​表单通道拜耳马赛克图像。 Each pixel color sample is stored with 16 bits of precision. 每个像素颜色样本以16位精度存储。

The layout of the color mosaic, the maximum and minimum encoding values of the raw pixel data, the color space of the image, and all other needed information to interpret a raw sensor image must be queried from the android.hardware.camera2.CameraDevice which produced the image. 必须从android.hardware.camera2.CameraDevice中查询颜色镶嵌的布局,原始像素数据的最大和最小编码值,图像的颜色空间以及用于解释原始传感器图像的所有其他所需信息。产生了图像。

You should not attempt to use its stride info directly, as if it were a YUV frame. 您不应尝试直接使用其步幅信息,就好像它是YUV框架一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM