Flutter中YUV420转RGB适配问题:诺基亚X10转换异常排查
问题根源分析
你的代码核心问题是忽略了YUV420_888格式中平面数据的行对齐填充:
- YUV420_888的每个平面(Y、U、V)的
bytesPerRow不一定等于图像实际宽度,很多设备(比如诺基亚X10)会为内存对齐要求,让bytesPerRow取4的倍数或更大的对齐值。你之前直接用y * width + x计算Y平面索引,会误取每行末尾的填充无效数据,最终导致颜色错乱。 - 从日志能看出,诺基亚X10的Y平面
bytesPerRow=512,但图像实际宽度远小于这个值(三星设备对应宽度为320),每行存在大量填充字节,你的代码把这些无效数据当成了有效Y分量,才出现异常图像。
修正后的转换代码
static img.Image convertYUV420toImageColor(CameraImage image) { try { final int width = image.width; final int height = image.height; // 提取三个平面的关键参数 final yPlane = image.planes[0]; final uPlane = image.planes[1]; final vPlane = image.planes[2]; final int yRowStride = yPlane.bytesPerRow; final int yPixelStride = yPlane.bytesPerPixel!; final int uvRowStride = uPlane.bytesPerRow; final int uvPixelStride = uPlane.bytesPerPixel!; // 创建图像缓冲区 var img2 = img.Image(width: width, height: height); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // 计算Y分量的正确索引:行步长*行数 + 像素步长*列数 final int yIndex = y * yRowStride + x * yPixelStride; // 计算UV分量索引(UV为半分辨率,坐标取整) final int uvY = y ~/ 2; final int uvX = x ~/ 2; final int uvIndex = uvY * uvRowStride + uvX * uvPixelStride; final yp = yPlane.bytes[yIndex]; final up = uPlane.bytes[uvIndex]; final vp = vPlane.bytes[uvIndex]; // YUV转RGB计算逻辑保持不变 int r = (yp + vp * 1436 / 1024 - 179).round().clamp(0, 255); int g = (yp - up * 46549 / 131072 + 44 - vp * 93604 / 131072 + 91) .round() .clamp(0, 255); int b = (yp + up * 1814 / 1024 - 227).round().clamp(0, 255); img2.setPixelRgba(x, y, r, g, b, 255); } } return img.copyRotate(img2, angle: 90); } catch (e) { Log.logger.d("ERROR: " + e.toString()); } throw Exception("error during YUV420 conversion"); }
关键改动说明
- Y平面索引修正:将原有的
y * width + x替换为y * yRowStride + x * yPixelStride,严格遵循每个平面的行步长和像素步长计算索引,彻底避开填充的无效数据。 - UV索引优化:用Dart整数除法
~/替代浮点除法后取整,运算效率更高且索引计算更准确。 - 参数解耦:单独提取每个平面的参数,代码结构更清晰,也便于后续适配不同的YUV子格式。
额外注意事项
- YUV420_888的U、V平面存在多种排列方式(交错或独立平面),你的代码中UV像素步长为2,对应NV21/NV12交错格式,当前索引计算完全适配该场景。
- 不同设备的相机预览分辨率、内存对齐规则差异很大,永远不要假设
bytesPerRow等于图像宽度,必须依赖每个平面提供的bytesPerRow和bytesPerPixel来计算索引。
内容的提问来源于stack exchange,提问作者finisinfinitatis
相关产品推荐
相关产品推荐

