如何将NV21格式CameraImage转换为Flutter Image格式?
解决NV21格式CameraImage转Flutter Image的旋转问题
问题分析
你的转换代码出现旋转问题,核心原因有两点:
- 创建输出Image时宽高参数顺序错误(原代码用了
img.Image(height, width),正确应为img.Image(width, height)) - 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
相关产品推荐
相关产品推荐

