Преобразование изображения Android Camera2 YUV_420_888 в растровое изображение RGBA дает зеленоватое изображение

На моем устройстве Samsung Galaxy A54 5G с Android 14 я пробую API камеры2 и делаю снимки в формате YUV 420. Устройство поддерживает только JPEG и YUV 420. Я пробовал множество методов преобразования растрового изображения YUV 420 в RGBA и его отображения/сохранения, но независимо от того, какой метод, все они работают более или менее и возвращают правильное, но зеленоватое изображение. Среди прочего я попробовал следующие методы:

  • Встроенный метод RenderScript ScriptIntrinsicYuvToRGB
  • Android RenderScript Intrinscs Relpacement Toolkit, который имеет метод преобразования yuvToRgbBitmap
  • Метод Github #1
  • Метод образцов Camera2 #1
  • Метод Android420ToABGR библиотеки libyuv

Как упоминалось ранее, все вышеперечисленные методы возвращают зеленоватое (или желтоватое) изображение, где зеленоватый оттенок виден в основном на белых/серых областях, как в примере ниже, взятом с моим приложением для разработки:

В качестве правильного результата преобразования я ожидал бы что-то очень похожее на приведенный ниже справочный снимок экрана:

Обновление №1: Попробовал некоторые доступные коды и примеры на устройстве Huawei, цвета правильные! Например, самый простой способ использования ScriptIntrinsicYuvToRGB дает правильные цвета на устройстве Huawei, но возвращает зеленоватое изображение на Samsung. Видимо, это странное поведение Samsung.

Обновление №2: Демонстрация HDRViewFinder, доступная в образцах камер Google, дает правильный цвет, но, к сожалению, эту часть рендеринга я не могу использовать на платформе Xamarin.Android. Можно ли как-то переписать код hdrmerge на собственный код Android?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
220
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Это все еще не 100% удовлетворительное решение, но, по крайней мере, оно дает гораздо лучшие цвета после преобразования YUV -> RGB. Плюс он медленный для изображений с очень высоким разрешением. Код ниже представляет собой комбинацию this ответа и this ядра рендерскрипта:

case ImageFormatType.Yuv420888:
    var planes = img.GetPlanes();
    var yPlane = planes[0];
    var uPlane = planes[1];
    var vPlane = planes[2];

    var rgbBytes = new int[img.Height * img.Width];
    var idx = 0;

    var yBuffer = yPlane.Buffer;
    var yPixelStride = yPlane.PixelStride;
    var yRowStride = yPlane.RowStride;

    var uBuffer = uPlane.Buffer;
    var uPixelStride = uPlane.PixelStride;
    var uRowStride = uPlane.RowStride;

    var vBuffer = vPlane.Buffer;
    var vPixelStride = vPlane.PixelStride;
    var vRowStride = vPlane.RowStride;

    for (var row = 0; row < img.Height; row++) {
        for (var col = 0; col < img.Width; col++) {
            var Y = (byte)yBuffer.Get(col * yPixelStride + row * yRowStride);
            var U = (byte)uBuffer.Get(col / 2 * uPixelStride + row / 2 * uRowStride);
            var V = (byte)vBuffer.Get(col / 2 * vPixelStride + row / 2 * vRowStride);

            // Convert YUV to RGB, JFIF transform with fixed-point math.
            // Formulas can be found here: https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion
            // R = Y + 1.402 * (V - 128)
            // G = Y - 0.34414 * (U - 128) - 0.71414 * (V - 128)
            // B = Y + 1.772 * (U - 128)
            var R = Y + 1436 / 1024 * (V - 128);
            var G = Y - 46549 / 131072 * (U - 128) - 93604 / 131072 * (V - 128);
            var B = Y + 1814 / 1024 * (U - 128);

            R = MathUtils.Clamp(R, 0, 255);
            G = MathUtils.Clamp(G, 0, 255);
            B = MathUtils.Clamp(B, 0, 255);

            rgbBytes[idx++] = BitConverter.ToInt32(new byte[] { (byte)B, (byte)G, (byte)R, 0xFF }, 0);
        }
    }

    FinalBitmap = Bitmap.CreateBitmap(rgbBytes, img.Width, img.Height, Bitmap.Config.Argb8888);
    img.Close();
    break;
Ответ принят как подходящий

Мне потребовались годы, чтобы понять, но проблема наконец решена!

В настройках запроса на захват камеры перед захватом мне пришлось изменить настройки баланса белого с «Авто» на «Флуоресцентный», и зеленый оттенок окончательного изображения исчез!

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