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

如何将NV21格式CameraImage转换为Flutter Image格式?

解决NV21格式CameraImage转Flutter Image的旋转问题

问题分析

你的转换代码出现旋转问题,核心原因有两点:

  1. 创建输出Image时宽高参数顺序错误(原代码用了img.Image(height, width),正确应为img.Image(width, height))
  2. Android相机预览帧的原生方向与Flutter Image的显示坐标系不匹配,竖屏场景下通常需要旋转90度修正

修正后的NV21转换代码

import 'package:image/image.dart' as img;
import 'package:camera/camera.dart';

static img.Image _convertNV21(CameraImage image) {
  final width = image.width.toInt();
  final height = image.height.toInt();
  final yuvBytes = image.planes[0].bytes;
  final frameSize = width * height;

  // 修正:创建宽高参数正确的Image对象
  final outImg = img.Image(width, height);

  for (int j = 0, yp = 0; j < height; j++) {
    int uvp = frameSize + (j >> 1) * width;
    int u = 0, v = 0;
    for (int i = 0; i < width; i++, yp++) {
      int y = (0xff & yuvBytes[yp]) - 16;
      y = y < 0 ? 0 : y;

      if ((i & 1) == 0) {
        v = (0xff & yuvBytes[uvp++]) - 128;
        u = (0xff & yuvBytes[uvp++]) - 128;
      }

      // YUV转RGB标准计算逻辑
      int y1192 = 1192 * y;
      int r = y1192 + 1634 * v;
      int g = y1192 - 833 * v - 400 * u;
      int b = y1192 + 2066 * u;

      // 限制RGB值在有效范围内,避免颜色失真
      r = r.clamp(0, 262143);
      g = g.clamp(0, 262143);
      b = b.clamp(0, 262143);

      // 转换为8位RGB值
      int r8 = (r >> 8) & 0xFF;
      int g8 = (g >> 8) & 0xFF;
      int b8 = (b >> 8) & 0xFF;

      // 设置像素点
      outImg.setPixelRgba(i, j, r8, g8, b8);
    }
  }

  // 修正:竖屏场景下顺时针旋转90度匹配显示方向
  return img.copyRotate(outImg, 90);
}

额外适配建议

  • 前置摄像头场景:转换后需添加镜像翻转,可调用img.flipHorizontal(outImg)实现
  • 动态方向适配:通过MediaQuery.of(context).orientation获取设备当前方向,横屏时可跳过旋转步骤
  • 性能优化:YUV转RGB计算耗时较高,可使用Isolate进行异步处理,避免阻塞UI线程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 22:35:44