Преобразование изображений YUV420 во флаттер

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

Преобразование изображений YUV420 во флаттер

Я проверил, что изображения с камеры, возвращенные для обоих телефонов, используют 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 — это фиксированное определение.

1
0
105
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел проблему. Виновной была эта строка

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;

решил проблему!

Возможно, вы могли бы получить img.Image, используя стандартный виджет и flutter_image_converter. Я автор. И если тема актуальна, добавляю YUV420 конверсию в пакет.

Andrii Syrokomskyi 11.04.2024 18:28

@AndriiSyrokomskyi Спасибо за информацию! Обязательно попробую ваш виджет! Это утомительно самому кодировать все эти преобразования. Спасибо за ваш вклад в pub.dev!

finisinfinitatis 12.04.2024 12:41

Другие вопросы по теме

Как исправить ошибку «Не удалось загрузить FirebaseOptions из ресурса. Убедитесь, что вы правильно определили файл Values.xml.'
После удаления использовался контроллер редактирования текста. порхать
Переполнение текста в локализации Flutter с помощью пакета easy_localization
Flutter — перетаскивание перетаскиваемого объекта из ящика в тело
Как использовать значение кривой флаттера от высокого до низкого
Обновление определенного поля в столбце JSONB в Supabase во Flutter
Flutter: Как нам установить «позицию», а не просто установить выравнивание виджета, который отображается в функции диалога?
При использовании пакета go_router во Flutter можно ли использовать параметр «extra» для передачи некоторых данных и работает ли он с глубокими ссылками?
Как показать ресурсы плагина в родительском проекте Flutter
Flutter: как сделать объект доступным для других виджетов без передачи