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

iOS平台YUV420格式图像转RGB的Flutter实现问题求助

Flutter iOS平台YUV420(NV12)转RGB图像解决方案

针对iOS平台CameraImage的2平面NV12格式(Y平面 + UV交错平面),以下是正确的转换实现,解决图像偏绿的问题:

完整转换代码

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

img.Image convertYUV420ToImage(CameraImage cameraImage) {
  final width = cameraImage.width;
  final height = cameraImage.height;

  // Y平面数据
  final yPlane = cameraImage.planes[0];
  final yRowStride = yPlane.bytesPerRow;
  final yBytes = yPlane.bytes;

  // UV平面数据(NV12格式:U、V交错存储)
  final uvPlane = cameraImage.planes[1];
  final uvRowStride = uvPlane.bytesPerRow;
  final uvPixelStride = uvPlane.bytesPerPixel!; // iOS下该值为2
  final uvBytes = uvPlane.bytes;

  final image = img.Image(width: width, height: height);

  for (int h = 0; h < height; h++) {
    for (int w = 0; w < width; w++) {
      // 计算Y像素索引
      final yIndex = h * yRowStride + w;
      final y = yBytes[yIndex];

      // 计算UV像素对应的索引(每个UV对应2x2的Y像素)
      final uvH = h ~/ 2;
      final uvW = w ~/ 2;
      final uvIndex = uvH * uvRowStride + uvW * uvPixelStride;

      // 提取U和V值:NV12格式中U在前,V在后,各占1字节
      final u = uvBytes[uvIndex];
      final v = uvBytes[uvIndex + 1];

      // 将YUV转换为RGB并设置像素
      image.data!.setPixel(w, h, yuvToRgb(y, u, v));
    }
  }

  return image;
}

// 标准YUV420(BT.601)转RGB公式,处理U/V的偏移
int yuvToRgb(int y, int u, int v) {
  // 将无符号字节转换为有符号值(U/V范围:-128 ~ 127)
  final yInt = y & 0xFF;
  final uInt = (u & 0xFF) - 128;
  final vInt = (v & 0xFF) - 128;

  // 计算RGB分量
  int r = (yInt + 1.370705 * vInt).round();
  int g = (yInt - 0.698001 * vInt - 0.337633 * uInt).round();
  int b = (yInt + 1.732446 * uInt).round();

  // 确保分量在0-255范围内
  r = r.clamp(0, 255);
  g = g.clamp(0, 255);
  b = b.clamp(0, 255);

  // 组装为ARGB格式(alpha设为255)
  return (0xFF << 24) | (r << 16) | (g << 8) | b;
}

关键修正点

  1. UV数据提取方式
    iOS的CameraImage采用NV12格式,UV平面是U和V交错存储,每个UV对占2字节(U在前,V在后),而非单个字节存储UV的高低位。之前的代码错误地从单个字节拆分U/V,导致色彩完全偏移。

  2. YUV转RGB的偏移处理
    原始的U/V字节是无符号的(0-255),但标准YUV420中U/V的实际范围是-128到127,必须先减去128转换为有符号值,否则计算出的RGB分量会偏差,导致图像偏绿。

  3. 索引计算优化
    按行优先遍历,先处理高度再处理宽度,逻辑更清晰;同时确保UV索引对应正确的2x2 Y像素块。

平台兼容建议

可以通过判断cameraImage.planes.length来区分Android(3平面,YUV420_888)和iOS(2平面,NV12),实现跨平台统一转换:

img.Image convertCameraImageToImage(CameraImage cameraImage) {
  if (cameraImage.planes.length == 3) {
    // Android平台的3平面转换逻辑(使用你原有的Android代码)
    return convertYUV420Android(cameraImage);
  } else if (cameraImage.planes.length == 2) {
    // iOS平台的NV12转换逻辑
    return convertYUV420ToImage(cameraImage);
  } else {
    throw Exception("不支持的图像格式");
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 21:34:57