我正在使用 google_mlkit_face_detection 来检测人脸,但我找不到将 nv21 帧转换为 flutter 图像格式的好方法(package:image/src/image.dart )
问题仅在Android上,因为人脸检测包要求在Android上的CameraController中使用nv21格式,并且我需要返回用人脸检测包检测到的人脸的帧(CameraImage对象),但我找不到任意位置从 nv21 到 Flutter 格式的转换函数。
我找到了YUV420的:
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
import 'package:image/image.dart' as img;
static img.Image _convertYUV420(CameraImage input) {
var imge = img.Image(input.width, input.height); // Create Image buffer
Plane plane = input.planes[0];
const int shift = (0xFF << 24);
// Fill image buffer with plane[0] from YUV420_888
for (int x = 0; x < input.width; x++) {
for (int planeOffset = 0;
planeOffset < input.height * input.width;
planeOffset += input.width) {
final pixelColor = plane.bytes[planeOffset + x];
// color: 0x FF FF FF FF
// A B G R
// Calculate pixel color
var newVal =
shift | (pixelColor << 16) | (pixelColor << 8) | pixelColor;
imge.data[planeOffset + x] = newVal;
}
}
return imge;
}
和bgra8888:
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
import 'package:image/image.dart' as img;
static img.Image _convertBGRA8888(CameraImage image) {
return img.Image.fromBytes(
(image.planes[0].bytesPerRow / 4).round(),
image.height,
image.planes[0].bytes,
format: img.Format.argb,
);
}
但不适用于 nv21,
最后我找到了执行转换的代码,但是照片顺时针旋转了90度(或逆时针旋转270度),但我不知道如何纠正它
static img.Image _convertNV21(CameraImage image) {
final width = image.width.toInt();
final height = image.height.toInt();
Uint8List yuv420sp = image.planes[0].bytes;
final outImg = img.Image(height, width);
final int frameSize = width * height;
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & yuv420sp[yp]) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0)
r = 0;
else if (r > 262143) r = 262143;
if (g < 0)
g = 0;
else if (g > 262143) g = 262143;
if (b < 0)
b = 0;
else if (b > 262143) b = 262143;
// I don't know how these r, g, b values are defined, I'm just copying what you had bellow and
// getting their 8-bit values.
outImg.setPixelRgba(i, j, ((r << 6) & 0xff0000) >> 16,
((g >> 2) & 0xff00) >> 8, (b >> 10) & 0xff);
}
}
return outImg;
}
有人有什么建议吗?
按照代码片段将 nv21 转换为图像
imglib.Image _convertNV21(CameraImage image) {
final width = image.width.toInt();
final height = image.height.toInt();
Uint8List yuv420sp = image.planes[0].bytes;
// Initial conversion from NV21 to RGB
final outImg = imglib.Image(height, width); // Note the swapped dimensions
final int frameSize = width * height;
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & yuv420sp[yp]) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) {
r = 0;
} else if (r > 262143) r = 262143;
if (g < 0) {
g = 0;
} else if (g > 262143) g = 262143;
if (b < 0) {
b = 0;
} else if (b > 262143) b = 262143;
outImg.setPixelRgba(j, width - i - 1, ((r << 6) & 0xff0000) >> 16,
((g >> 2) & 0xff00) >> 8, (b >> 10) & 0xff);
}
}
return outImg;
// Rotate the image by 90 degrees (or 270 degrees if needed)
// return imglib.copyRotate(outImg, -90); // Use -90 for a 270 degrees rotation
}