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

Google Mobile Vision CameraSource部分设备返回旋转图像的适配问题

解决Google Mobile Vision CameraSource拍照Bitmap旋转不一致的问题

我之前也踩过Android多设备相机拍照旋转的坑,不同厂商对相机传感器的方向处理差异确实让人头疼,原生的parameters.setRotation()在部分设备上并不会自动修正拍摄图片的方向,导致解码后的Bitmap和屏幕显示方向不匹配。下面是我整理的可行解决方案:

第一步:修改CameraSource.java保存旋转角度

首先我们需要把setRotation()方法中计算好的angle值留存下来,这个值是根据设备屏幕方向和摄像头朝向算出的正确旋转角度。修改CameraSource的代码如下:

// 在CameraSource类中添加成员变量
private int mCameraRotationAngle;

private void setRotation(Camera camera, Camera.Parameters parameters, int cameraId) {
    WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
    int degrees = 0;
    int rotation = windowManager.getDefaultDisplay().getRotation();
    switch (rotation) {
        case Surface.ROTATION_0: degrees = 0; break;
        case Surface.ROTATION_90: degrees = 90; break;
        case Surface.ROTATION_180: degrees = 180; break;
        case Surface.ROTATION_270: degrees = 270; break;
        default: Log.e(TAG, "Bad rotation value: " + rotation);
    }
    CameraInfo cameraInfo = new CameraInfo();
    Camera.getCameraInfo(cameraId, cameraInfo);
    int angle;
    int displayAngle;
    if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
        angle = (cameraInfo.orientation + degrees) % 360;
        displayAngle = (360 - angle) % 360; // compensate for it being mirrored
    } else { // back-facing
        angle = (cameraInfo.orientation - degrees + 360) % 360;
        displayAngle = angle;
    }
    // This corresponds to the rotation constants in {@link Frame}.
    mRotation = angle / 90;
    camera.setDisplayOrientation(displayAngle);
    parameters.setRotation(angle);
    // 保存计算好的旋转角度
    mCameraRotationAngle = angle;
}

// 添加公共方法供外部获取旋转角度
public int getCameraRotationAngle() {
    return mCameraRotationAngle;
}

第二步:在onPictureTaken中手动旋转Bitmap

现在我们可以在拍照回调里,用保存的旋转角度来修正Bitmap方向,同时处理前置摄像头的镜像问题:

@Override
public void onPictureTaken(byte[] bytes) {
    try {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 2;
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, currentCameraId == 0 ? options : null);
        
        // 获取CameraSource中计算好的旋转角度
        int rotationAngle = cameraSource.getCameraRotationAngle();
        
        if (bitmap != null) {
            Matrix matrix = new Matrix();
            if (currentCameraId == 0) {
                // 前置摄像头:先水平镜像翻转,再旋转对应角度
                matrix.postScale(-1, 1);
                matrix.postRotate(rotationAngle);
            } else {
                // 后置摄像头:直接旋转对应角度
                matrix.postRotate(rotationAngle);
            }
            
            // 创建旋转后的Bitmap,注意回收原Bitmap避免内存泄漏
            Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            bitmap.recycle();
            bitmap = rotatedBitmap;
            
            // 这里就可以使用与屏幕显示方向一致的bitmap了
        }
    } catch (Exception ex) {
        ex.printStackTrace();
        Log.e("PictureTaken", ex.toString());
    }
}

方案原理

原生的parameters.setRotation(angle)只是告知相机传感器要记录图片的旋转信息,但部分设备的相机驱动并没有正确应用这个信息,导致解码后的Bitmap还是原始传感器方向。我们手动使用CameraSource中已经计算好的angle值来旋转Bitmap,这个值是严格根据屏幕方向和摄像头朝向推导出来的,能保证和当前屏幕显示方向一致。

如果个别设备仍有异常,可以考虑添加设备型号的特殊判断,但优先使用这种通用的角度计算方式,避免硬编码设备列表带来的维护麻烦。

内容的提问来源于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 04:55:40