Преобразование YUV420 в RGB - PullRequest
2 голосов
/ 03 июля 2011

Я преобразовал матрицу RGB в матрицу YUV по следующей формуле:

Y  =      (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
Cr = V =  (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128

Затем я выполнил подвыборку цветности 4: 2: 0 на матрице. Я думаю, что я сделал это правильно, я взял 2x2 подматрицы из матрицы YUV, упорядочил значения от наименьшего к наибольшему и взял среднее значение между двумя значениями в середине.

Затем я использовал эту формулу из Википедии, чтобы получить доступ к плоскостям Y, U и V:

size.total = size.width * size.height;
y = yuv[position.y * size.width + position.x];
u = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total];
v = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total + (size.total / 4)];

Я использую OpenCV, поэтому я попытался интерпретировать это как можно лучше:

y = src.data[(i*channels)+(j*step)];
u = src.data[(j%4)*step + ((i%2)*channels+1) + max];
v = src.data[(j%4)*step + ((i%2)*channels+2) + max + (max%4)];

src - матрица субдискретизации YUV. Правильно ли я истолковал эту формулу?

Вот как я преобразовал цвета обратно в RGB:

bgr.data[(i*channels)+(j*step)] = (1.164 * (y - 16)) + (2.018 * (u - 128)); // B
bgr.data[(i*channels+1)+(j*step)] = (1.164 * (y - 16)) - (0.813 * (v - 128)) - (0.391 * (u - 128)); // G
bgr.data[(i*channels+2)+(j*step)] = (1.164 * (y - 16)) + (1.596 * (v - 128));   // R

Проблема в том, что мое изображение не возвращается к исходным цветам.

Вот изображения для справки: http://i.stack.imgur.com/vQkpT.jpg (субдискретизация) http://i.stack.imgur.com/Oucc5.jpg (вывод)

Я вижу, что сейчас мне нужно конвертировать из YUV444 в RGB, но я не совсем понимаю, что делает функция клипа в примере, который я нашел в Wiki.

C = Y' − 16
D = U − 128
E = V − 128

R = clip(( 298 * C           + 409 * E + 128) >> 8)
G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
B = clip(( 298 * C + 516 * D           + 128) >> 8)

Означает ли >>, что я должен сдвигать биты?

Буду признателен за любую помощь / комментарии! Спасибо

Обновление

Попытался выполнить преобразование YUV444, но оно просто заставило мое изображение появиться в оттенках зеленого.

        y = src.data[(i*channels)+(j*step)];
        u = src.data[(j%4)*step + ((i%2)*channels+1) + max];
        v = src.data[(j%4)*step + ((i%2)*channels+2) + max + (max%4)];

        c = y - 16;
        d = u - 128;
        e = v - 128;

        bgr.data[(i*channels+2)+(j*step)] = clip((298*c + 409*e + 128)/256);
        bgr.data[(i*channels+1)+(j*step)] = clip((298*c - 100*d - 208*e + 128)/256);
        bgr.data[(i*channels)+(j*step)] = clip((298*c + 516*d + 128)/256);

И моя функция клипа: int clip (двойное значение) { возврат (значение> 255)? 255: (значение <0)? 0: значение; } </p>

Ответы [ 3 ]

2 голосов
/ 14 июля 2011

У меня была такая же проблема при декодировании кадров WebM в RGB.Я наконец нашел решение после нескольких часов поиска.

Возьмите функцию SCALEYUV отсюда: http://www.telegraphics.com.au/svn/webpformat/trunk/webpformat.h

Затем, чтобы декодировать данные RGB из YUV, смотрите этот файл: http://www.telegraphics.com.au/svn/webpformat/trunk/decode.c

Поиск "py = img-> planes [0];", есть два алгоритма для преобразования данных.Я попробовал только простой (после «// затем вернемся к более дешевому методу.»).

Комментарии в коде также относятся к этой странице: http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC30

Прекрасно работает для меня.

1 голос
/ 03 июля 2011

Вы не получите обратно совершенно то же самое изображение, так как UV сжимает изображение.
Вы не скажете, является ли результат полностью неправильным (то есть ошибкой) или просто не идеальным

R = clip(( 298 * C           + 409 * E + 128) >> 8)
G = clip(( 298 * C - 100 * D - 208 * E + 128) >> 8)
B = clip(( 298 * C + 516 * D           + 128) >> 8)

>> 8 - битовый сдвиг, эквивалентный делению на 256. Это просто для того, чтобы вы могли делать все арифметические в целочисленных единицах, а не с плавающей запятой для скорости

0 голосов
/ 05 сентября 2015

Экспериментировал с формулами, присутствующими в вики, и обнаружил, что смешанная формула:

byte c = (byte) (y - 16);
byte d = (byte) (u - 128);
byte e = (byte) (v - 128);

byte r = (byte) (c + (1.370705 * (e))); 
byte g = (byte) (c - (0.698001 * (d)) - (0.337633 * (e)));
byte b = (byte) (c + (1.732446 * (d)));

создает "лучшие" ошибки для моих изображений, просто делает некоторые черные точки чистыми зелеными (т.е. rgb = 0x00FF00), что лучшедля обнаружения и исправления ...

wiki source: https://en.wikipedia.org/wiki/YUV#Y.27UV420p_.28and_Y.27V12_or_YV12.29_to_RGB888_conversion

...