flutter相机流ImageStream取图片偏蓝色绿红篮紫各种随机偏色BGRA8888,YUV420

siman 2 小时前 2 0
最近又在写我的im社交了,活体检测api太贵自己写了一个本地版,我主要是活体检测和人脸是比对不是同一个人.使用CameraImage 无感拿图片
在对比时有有时正常有时错误输出图片一看  图片颜色各种偏色  再此做个笔记后面还会用到 有需要的拿去


  1. import 'package:camera/camera.dart';
  2. import 'package:flutter/foundation.dart';
  3. import 'package:image/image.dart' as imglib;

  4. class FaceImageUtils {
  5.   static Uint8List? convertCameraImage(CameraImage cameraImage) {
  6.     if (cameraImage.format.group == ImageFormatGroup.yuv420) {
  7.       final yuvImage = convertYUV420ToImage(cameraImage);
  8.       return Uint8List.fromList(imglib.encodeJpg(yuvImage));
  9.     } else if (cameraImage.format.group == ImageFormatGroup.bgra8888) {
  10.       final bgraImage = convertBGRA8888ToImage(cameraImage);
  11.       return Uint8List.fromList(imglib.encodeJpg(bgraImage));
  12.     }
  13.     return null;
  14.   }

  15.   /// iOS BGRA8888 修复,彻底解决随机偏色
  16.   static imglib.Image convertBGRA8888ToImage(CameraImage cameraImage) {
  17.     final width = cameraImage.width;
  18.     final height = cameraImage.height;
  19.     final plane = cameraImage.planes[0];
  20.     final bytes = plane.bytes;
  21.     final bytesPerRow = plane.bytesPerRow;

  22.     // 手动创建空图,避免fromBytes的坑
  23.     final image = imglib.Image(width: width, height: height);

  24.     // 逐行、逐像素解析,严格按照相机流的 bytesPerRow 来读取,不会错位
  25.     for (int y = 0; y < height; y++) {
  26.       // 计算当前行的起始位置,严格按 bytesPerRow 偏移
  27.       final rowStart = y * bytesPerRow;

  28.       for (int x = 0; x < width; x++) {
  29.         // BGRA8888 每个像素占4字节,计算当前像素在该行的位置
  30.         final pixelOffset = x * 4;
  31.         final index = rowStart + pixelOffset;

  32.         // 防止越界
  33.         if (index + 3 >= bytes.length) continue;

  34.         // BGRA 格式顺序:B、G、R、A
  35.         final int b = bytes[index];
  36.         final int g = bytes[index + 1];
  37.         final int r = bytes[index + 2];

  38.         // 直接写入RGB,不依赖任何自动转换
  39.         image.setPixelRgb(x, y, r, g, b);
  40.       }
  41.     }

  42.     // 移除所有硬编码旋转,iOS相机流不需要这个,否则会导致画面错位
  43.     return image;
  44.   }

  45.   /// 原YUV逻辑保持不变(如果你Android也有问题,我可以再优化)
  46.   static imglib.Image convertYUV420ToImage(CameraImage cameraImage) {
  47.     final imageWidth = cameraImage.width;
  48.     final imageHeight = cameraImage.height;

  49.     final yBuffer = cameraImage.planes[0].bytes;
  50.     final uBuffer = cameraImage.planes[1].bytes;
  51.     final vBuffer = cameraImage.planes[2].bytes;

  52.     final int yRowStride = cameraImage.planes[0].bytesPerRow;
  53.     final int yPixelStride = cameraImage.planes[0].bytesPerPixel!;

  54.     final int uvRowStride = cameraImage.planes[1].bytesPerRow;
  55.     final int uvPixelStride = cameraImage.planes[1].bytesPerPixel!;

  56.     final image = imglib.Image(width: imageWidth, height: imageHeight);

  57.     for (int h = 0; h < imageHeight; h++) {
  58.       int uvh = (h / 2).floor();

  59.       for (int w = 0; w < imageWidth; w++) {
  60.         int uvw = (w / 2).floor();

  61.         final yIndex = (h * yRowStride) + (w * yPixelStride);
  62.         final int y = yBuffer[yIndex];

  63.         final int uvIndex = (uvh * uvRowStride) + (uvw * uvPixelStride);

  64.         final int u = uBuffer[uvIndex];
  65.         final int v = vBuffer[uvIndex];

  66.         int r = (y + v * 1436 / 1024 - 179).round();
  67.         int g = (y - u * 46549 / 131072 + 44 - v * 93604 / 131072 + 91).round();
  68.         int b = (y + u * 1814 / 1024 - 227).round();

  69.         r = r.clamp(0, 255);
  70.         g = g.clamp(0, 255);
  71.         b = b.clamp(0, 255);

  72.         image.setPixelRgb(w, h, r, g, b);
  73.       }
  74.     }

  75.     // 如果你Android也有随机偏色,把下面这行也注释掉
  76.     return imglib.copyRotate(image, angle: 270);
  77.   }
  78. }
复制代码



评论
登录 后才能评论

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2026-4-24 20:11, Processed in 0.311900 second(s), 30 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表