卧式纯绿 2024-05-06 18:21 采纳率: 62.1%
浏览 14
已结题

安卓开发摄像头预览后获取实时数据出错

安卓开发摄像头预览后获取实时帧数据出错
摄像头预览功能已经完成且成功开启,在获取帧图像时出现错误,这里设置了一个点击按钮,点击后获取帧图像并展示在imagevie上,但是实操下来点击按钮直接退出

img


这是点击按钮后的事件函数
设置imagReader函数

img


detect函数

img


最后是yuv格式数据转换为bitmap类型

img

  • 写回答

5条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-05-06 18:21
    关注

    引自免费微信小程序:皆我百晓生

    根据您提供的代码片段,我发现了一些可能的问题所在,并为您提供相应的修复建议。

    首先,让我们查看convertImageToBitmap()方法中的错误。当从YUV格式转换为Bitmap时,我们应确保正确处理YUV数据。以下是修复过的convertImageToBitmap()方法:

    private Bitmap convertImageToBitmap(Image image) {
        if (image == null) {
            return null;
        }
        Image.Plane[] planes = image.getPlanes();
        ByteBuffer byteBuffer = planes[0].getBuffer();
        int ySize = byteBuffer.remaining();
    
        // NV21 format requires a buffer for U and V data, which is half the size of Y data.
        int uvSize = ySize / 2;
        byte[] nv21Bytes = new byte[ySize + uvSize];
    
        // Copy Y plane to the beginning of the NV21 buffer.
        byteBuffer.get(nv21Bytes, 0, ySize);
    
        // Prepare UV planes.
        byteBuffer.position(ySize);
        byte[] uData = Arrays.copyOfRange(nv21Bytes, ySize, ySize + uvSize / 2);
        byte[] vData = Arrays.copyOfRange(nv21Bytes, ySize + uvSize / 2, ySize + uvSize);
        byte[] uvData = new byte[uData.length + vData.length];
        System.arraycopy(uData, 0, uvData, 0, uData.length);
        System.arraycopy(vData, 0, uvData, uData.length, vData.length);
    
        // Combine Y and UV planes into one buffer.
        byte[] combinedData = new byte[ySize + uvSize];
        System.arraycopy(nv21Bytes, 0, combinedData, 0, ySize);
        System.arraycopy(uvData, 0, combinedData, ySize, uvData.length);
    
        YuvImage yuvImage = new YuvImage(combinedData, ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        yuvImage.compressToJpeg(new Rect(0, 0, image.getWidth(), image.getHeight()), 100, baos);
        byte[] jpegByteArray = baos.toByteArray();
        Bitmap bitmap = BitmapFactory.decodeByteArray(jpegByteArray, 0, jpegByteArray.length);
    
        return bitmap;
    }
    

    接下来,检查您的setupImageReader()方法,确保maxImages参数设置正确。将maxImages:2改为maxImages:1,因为我们需要立即处理最新的一张图片,而不是等待多张图片累积在一起。

    private void setupImageReader() {
        capturesize = chooseOptimalSize(cameraManager.getAvailablePreviewSizes());
        imageReader = ImageReader.newInstance(capturesize.getWidth(), capturesize.getHeight(), ImageFormat.JPEG, 1); // Change maxImages from 2 to 1
        imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                backgroundHandler.post(new ImageDetection(reader.acquireLatestImage()));
            }, backgroundHandler);
    }
    

    然后,检查一下您的capture()方法,确保在捕获回调中没有忘记调用startRepeating()来重新启动捕获会话。这样可以防止在捕获单张照片后停止捕获会话,导致无法继续接收新的图像。

    private void capture(View view) {
        try {
            CaptureRequest.Builder cameraBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            cameraBuilder.addTarget(imageReader.getSurface());
    
            int rotation =getWindowManager().getDefaultDisplay().getRotation();
            CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull Totalt result) {
                    Toast.makeText(getApplicationContext(), "已获取帧图像", Toast.LENGTH_LONG).show();
                    // unlockFocus();
                    super.onCaptureCompleted(session, request, result);
                }
            };
    
            cameraBuilder.set(CaptureRequest.JPEG_ORIENTATION, (Integer) ORIENTATION.get(rotation));
            
            cameraCaptureSessions.stopRepeating(); // 停止当前重复的捕获
            cameraCaptureSessions.capture(cameraBuilder.build(), captureCallback, backgroundHandler);
    
            // 在捕获完成后重启捕获会话
            startRepeatingCapture();
        } catch (CameraAccessException e){
            throw new RuntimeException(e);
        }
    }
    
    private void startRepeatingCapture() {
        // 如果捕获会话尚未准备就绪,则等待其准备完成
        if (!cameraCaptureSessions.isConfigured()) {
            Log.w("CameraApp", "Capture sessions not configured yet");
            return;
        }
    
        try {
            cameraCaptureSessions.setRepeatingRequest(cameraBuilder.build(), captureCallback, backgroundHandler);
        } catch (CameraAccessException e) {
            throw new RuntimeException(e);
        }
    }
    

    最后,确保您已经在初始化相机设备和捕获会话的地方添加了必要的代码。如果您还没有这样做,请参考以下代码:

    private CameraDevice cameraDevice;
    private CameraCaptureSession cameraCaptureSessions;
    
    // 初始化相机设备和捕获会话
    private void openCamera() {
        // ... 其他代码 ...
    
        cameraManager.openCamera(deviceId, stateCallback, backgroundHandler);
    }
    
    private CameraCaptureSession.StateCallback stateCallback = new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
            cameraCaptureSessions = session;
            startRepeatingCapture();
        }
    
        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
            // Handle configuration failure
        }
    };
    
    // ... 其他代码 ...
    

    按照这些更改,应该能解决您在获取实时帧数据时遇到的问题。记得在应用中实施上述修改,并确保其他相关部分(例如初始化相机、设置预览等)也正确配置。如果还有任何问题,请随时告诉我。

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 8月9日
  • 创建了问题 5月6日