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

如何在ARCore应用中获取与屏幕比例一致的未增强相机图像?

解决ARCore获取与屏幕比例一致的YUV图像问题

方法1:配置ARCore使用16:9的相机分辨率

acquireCameraImage返回的是相机原生传感器帧,默认多为4:3比例。你可以通过指定相机配置,让ARCore直接输出16:9的YUV帧:

  • 先获取当前Session支持的所有相机配置:
    List<CameraConfig> supportedConfigs = session.getSupportedCameraConfigs(CameraConfigFilter.create(session));
    
  • 从列表中筛选16:9比例的配置,优先选分辨率最接近屏幕的选项:
    CameraConfig targetConfig = null;
    final float targetAspectRatio = 16f/9f;
    DisplayMetrics metrics = getResources().getDisplayMetrics();
    
    for (CameraConfig config : supportedConfigs) {
        Size size = config.getImageSize();
        float aspectRatio = (float) size.getWidth() / size.getHeight();
        // 匹配16:9比例(允许微小误差)
        if (Math.abs(aspectRatio - targetAspectRatio) < 0.01f) {
            // 优先选择分辨率更高的配置
            if (targetConfig == null || 
                size.getWidth() * size.getHeight() > targetConfig.getImageSize().getWidth() * targetConfig.getImageSize().getHeight()) {
                targetConfig = config;
            }
        }
    }
    
  • 找到符合条件的配置后,设置给Session:
    if (targetConfig != null) {
        session.setCameraConfiguration(targetConfig);
    }
    

之后调用acquireCameraImage就能拿到16:9比例的YUV帧,再缩放至屏幕分辨率即可用于非实时处理。

方法2:裁剪4:3的YUV图像为16:9比例

如果设备不支持16:9的相机配置,可对获取到的4:3 YUV帧进行裁剪:

  1. 计算裁剪区域:以640x480的4:3图像为例,16:9的目标高度为 640 * 9 / 16 = 360,上下各裁剪 (480-360)/2 = 60 像素;
  2. 针对YUV_420_888的三个平面分别裁剪:Y平面是全分辨率,直接裁剪对应区域;U、V平面是半分辨率,裁剪区域的坐标和尺寸需同步除以2;
  3. 将裁剪后的YUV数据转换为Bitmap或保存为图像文件,再缩放至屏幕分辨率。

示例裁剪代码:

CameraImage image = frame.acquireCameraImage();
try {
    Image.Plane yPlane = image.getPlanes()[0];
    Image.Plane uPlane = image.getPlanes()[1];
    Image.Plane vPlane = image.getPlanes()[2];

    int originalWidth = image.getWidth();
    int originalHeight = image.getHeight();
    int targetHeight = originalWidth * 9 / 16;
    int cropTop = (originalHeight - targetHeight) / 2;

    // 处理Y平面
    ByteBuffer yBuffer = yPlane.getBuffer();
    yBuffer.position(cropTop * yPlane.getRowStride());
    byte[] yData = new byte[originalWidth * targetHeight];
    for (int y = 0; y < targetHeight; y++) {
        yBuffer.get(yData, y * originalWidth, originalWidth);
        yBuffer.position(yBuffer.position() + (yPlane.getRowStride() - originalWidth));
    }

    // 处理U平面(半分辨率)
    int uCropTop = cropTop / 2;
    int uTargetHeight = targetHeight / 2;
    ByteBuffer uBuffer = uPlane.getBuffer();
    uBuffer.position(uCropTop * uPlane.getRowStride());
    byte[] uData = new byte[(originalWidth / 2) * uTargetHeight];
    for (int y = 0; y < uTargetHeight; y++) {
        uBuffer.get(uData, y * (originalWidth / 2), originalWidth / 2);
        uBuffer.position(uBuffer.position() + (uPlane.getRowStride() - (originalWidth / 2)));
    }

    // 处理V平面(同U平面逻辑)
    ByteBuffer vBuffer = vPlane.getBuffer();
    vBuffer.position(uCropTop * vPlane.getRowStride());
    byte[] vData = new byte[(originalWidth / 2) * uTargetHeight];
    for (int y = 0; y < uTargetHeight; y++) {
        vBuffer.get(vData, y * (originalWidth / 2), originalWidth / 2);
        vBuffer.position(vBuffer.position() + (vPlane.getRowStride() - (originalWidth / 2)));
    }

    // 后续将yData、uData、vData转换为所需格式
} finally {
    image.close();
}

注意事项

  • 优先用方法1,直接获取对应比例的帧无需额外裁剪,效率更高;
  • 非实时场景下,裁剪和缩放的性能开销可忽略;
  • 转换YUV到RGB时,需注意色彩空间匹配,避免偏色。

内容的提问来源于stack exchange,提问作者Csaba Toth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 09:15:34