You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Mobile Vision CameraSource调用takePicture返回低分辨率图的问题及修复

Alright, let's break down why you're seeing low-res images from CameraSource.takePicture() on some devices, and how to fix it.

Why This Happens

The core issue comes down to how Google's Mobile Vision CameraSource is designed, plus device-specific camera HAL (Hardware Abstraction Layer) behavior:

  • Default priority is preview, not photography: Mobile Vision is built for real-time detection tasks (like face or barcode scanning), so CameraSource prioritizes low-latency, small-resolution preview streams by default. When you call takePicture(), it reuses the same resolution parameters as the active preview—hence the 320x240 output.
  • Device compatibility inconsistencies: Different manufacturers implement camera HALs differently. Some devices (like your Samsung tablet) might automatically switch to a higher resolution for still captures, while others (like the Lenovo Tab 3) stick to the preview resolution because of how their HAL handles CameraSource requests.
Fixes & Workarounds

Here are actionable solutions to get higher-res photos with CameraSource:

1. Customize CameraSource to Force Photo Resolution

The stock CameraSource doesn't expose an API to set photo resolution, so you'll need to extend or modify it to override camera parameters before taking a picture.

Step-by-Step Implementation:

First, create a custom subclass of CameraSource that lets you set a target photo size:

public class CustomCameraSource extends CameraSource {
    private Size mTargetPictureSize;

    public CustomCameraSource(Context context, Detector<?> detector) {
        super(context, detector);
    }

    public void setTargetPictureSize(Size pictureSize) {
        mTargetPictureSize = pictureSize;
    }

    @Override
    public void takePicture(Surface shutter, PictureCallback callback) throws IOException {
        synchronized (getCameraLock()) {
            if (getCamera() == null) return;

            Camera.Parameters params = getCamera().getParameters();
            // Save original preview size to restore later
            Size originalPreviewSize = new Size(params.getPreviewSize().width, params.getPreviewSize().height);

            // Set the desired photo resolution if specified
            if (mTargetPictureSize != null) {
                params.setPictureSize(mTargetPictureSize.getWidth(), mTargetPictureSize.getHeight());
                getCamera().setParameters(params);
            }

            // Trigger the photo capture
            super.takePicture(shutter, callback);

            // Restore preview resolution to avoid breaking real-time detection
            params.setPreviewSize(originalPreviewSize.getWidth(), originalPreviewSize.getHeight());
            getCamera().setParameters(params);
        }
    }

    // Helper to access private fields via reflection
    private Object getCameraLock() {
        try {
            Field lockField = CameraSource.class.getDeclaredField("mCameraLock");
            lockField.setAccessible(true);
            return lockField.get(this);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            return new Object();
        }
    }

    private Camera getCamera() {
        try {
            Field cameraField = CameraSource.class.getDeclaredField("mCamera");
            cameraField.setAccessible(true);
            return (Camera) cameraField.get(this);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            return null;
        }
    }
}

Next, find a supported high-res photo size for your device and apply it:

// Get supported photo sizes from the camera
Camera tempCamera = Camera.open();
Camera.Parameters tempParams = tempCamera.getParameters();
List<Camera.Size> supportedPictureSizes = tempParams.getSupportedPictureSizes();
tempCamera.release();

// Pick a target size (e.g., 1280x720 or the largest available)
Camera.Size targetSize = null;
for (Camera.Size size : supportedPictureSizes) {
    // Adjust this to match your desired resolution
    if (size.width == 1280 && size.height == 720) {
        targetSize = size;
        break;
    }
}
// Fallback to largest size if target isn't found
if (targetSize == null) {
    targetSize = supportedPictureSizes.get(0);
}

// Initialize your custom CameraSource
CustomCameraSource cameraSource = new CustomCameraSource(this, yourDetector);
cameraSource.setTargetPictureSize(new Size(targetSize.width, targetSize.height));
// Optional: Set a matching preview size to avoid resolution mismatches
cameraSource.setRequestedPreviewSize(1280, 720);

2. Switch to Camera2 API (For Android 5.0+)

If your app targets Android 5.0 (API 21) or higher, consider using the Camera2 API instead of the old Camera API that CameraSource relies on. Camera2 gives you full control over capture resolutions, so you can explicitly request high-res stills without workarounds.

You'll need to integrate Mobile Vision's Detector with Camera2's capture pipeline—this requires more code, but it's a more robust long-term solution for modern devices.

3. Preview Frame Workaround (Quick Fix)

If you don't want to modify CameraSource, you can try increasing the preview resolution and capturing frames from the preview stream instead of using takePicture():

// Set a higher preview resolution first
cameraSource.setRequestedPreviewSize(1280, 720);

// Capture frames from the preview stream
cameraSource.setPreviewCallback(new Camera.PreviewCallback() {
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        // Convert preview frame to Bitmap (handle rotation/format as needed)
        Camera.Parameters params = camera.getParameters();
        Camera.Size previewSize = params.getPreviewSize();
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inMutable = true;
        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
        
        // Rotate bitmap to match device orientation
        bitmap = rotateBitmap(bitmap, params.getRotation());
        
        // Use or save the bitmap here
        Glide.with(getApplicationContext()).load(bitmap).into(capturedImg);
    }
});

Note: This can impact real-time detection performance since higher-res previews use more CPU/GPU resources.

Key Notes
  • Always verify that the resolution you're requesting is supported by the camera (use getSupportedPictureSizes() or getSupportedPreviewSizes()).
  • Image rotation varies by device—make sure to adjust the bitmap orientation based on the camera's rotation parameters.

内容的提问来源于stack exchange,提问作者V.Bhat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:54:42