Я написал функцию flutter для обработки изображения предварительного просмотра камеры телефона в RGB. Это работает для большинства устройств, которые я тестировал до сих пор. Но для одного устройства (Nokia X10) полученное изображение выглядит странно, и я не знаю, что делаю не так. Вот так выглядят обработанные изображения с камеры. Правильный код взят с моего телефона Samsung, а неправильный был получен с помощью кода на телефоне Nokia.

Я проверил, что изображения с камеры, возвращенные для обоих телефонов, используют YUV420_888.
Это мой код преобразования yuv:
static img.Image convertYUV420toImageColor(CameraImage image) {
try {
final int width = image.width;
final int height = image.height;
final int uvRowStride = image.planes[1].bytesPerRow;
final int? uvPixelStride = image.planes[1].bytesPerPixel;
myLogger.d(image.planes[0].bytesPerRow); // nokia: 512, samsung: 320
myLogger.d(image.planes[0].bytesPerPixel); // 1 for both phones
myLogger.d(image.planes[1].bytesPerRow); // nokia: 512, samsung: 320
myLogger.d(image.planes[1].bytesPerPixel); // 2 for both phones
myLogger.d(image.planes[2].bytesPerRow); // nokia: 512, samsung: 320
myLogger.d(image.planes[2].bytesPerPixel); // 2 for both phones
// imgLib -> Image package from https://pub.dartlang.org/packages/image
var img2 = img.Image(width:width, height:height); // Create Image buffer
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
final int uvIndex =
uvPixelStride! * (x / 2).floor() + uvRowStride * (y / 2).floor();
final int index = y * width + x;
final yp = image.planes[0].bytes[index];
final up = image.planes[1].bytes[uvIndex];
final vp = image.planes[2].bytes[uvIndex];
// Calculate pixel color
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); //Image.memory(png);
} catch (e) {
Log.logger.d("ERROR: " + e.toString());
}
throw Exception("error during YUV420 conversion");
}
У меня сложилось впечатление, что любое преобразование YUV420_888 будет работать с моим кодом, но мои тесты показывают, что это не так. Я не могу найти разницу в формате изображения, указанном между двумя устройствами.
Что я здесь делаю не так? Я даже не уверен, какой параметр может быть причиной неправильного преобразования. Я думал, что YUV420_888 — это фиксированное определение.
Я нашел проблему. Виновной была эта строка
final int index = y * width + x;
где я ошибочно предположил, что width всегда равно image.planes[0].bytesPerRow
но значения, указанные в моем вопросе, уже указывают на то, что они могут быть разными (512 против 320).
Дополнительная длина — это отступ, который необходимо правильно настроить при преобразовании изображения. Если этого не сделать, полосы появятся, поскольку при обработке используются неправильные значения y.
Просто исправив расчет на
final int bytesPerRowY = image.planes[0].bytesPerRow;
final int index = y * bytesPerRowY + x;
решил проблему!
@AndriiSyrokomskyi Спасибо за информацию! Обязательно попробую ваш виджет! Это утомительно самому кодировать все эти преобразования. Спасибо за ваш вклад в pub.dev!
Возможно, вы могли бы получить
img.Image, используя стандартный виджет и flutter_image_converter. Я автор. И если тема актуальна, добавляюYUV420конверсию в пакет.