Различное преобразование цветов из RGB в YCbCr с OpenCV и Matlab - PullRequest
0 голосов
/ 10 февраля 2019

Я пытаюсь повторить алгоритм jpeg с openCV, после того, как я успешно реализовал его в MATLAB.Я заметил, что MATLAB и OpenCV дают разные результаты для преобразования цветового пространства из RGB в YCbCr.

Глядя на документацию OpenCV, кажется, что единственная используемая функция - это cv :: cvtColor, но при печати первой подматрицы 8x8 Y, Cb и Cr они не совпадают.

Вот мой код как для MATLAB, так и для C ++ (с OpenCV 4.0.1).

Matlab:

% Read rgb image
imgrgb = imread('lena512color.bmp');

% Convert to ycbcr
imgycbcr = rgb2ycbcr(imgrgb);

% Extract the 3 components
luma = imgycbcr (:,:,1);
cb = imgycbcr (:,:,2);
cr = imgycbcr (:,:,3);

C ++:

// Load img
cv::Mat bgrImg = imread( "lena512color.bmp", cv::IMREAD_COLOR );
assert( bgrImg.data && "No image data");

// Declare an empty Mat for dst image
cv::Mat ycrcbImg;

// Convert to ycrcb
cv::cvtColor(bgrImg, ycrcbImg, cv::COLOR_BGR2YCrCb);

// Split bgr into 3 channels
cv::Mat bgrChan[3];
cv::split(bgrImg, bgrChan);

// Split ycrcb into 3 channels
cv::Mat ycrcbChan[3];
cv::split(ycrcbImg, ycrcbChan);

// Print first block for each channel
PRINT_MAT(ycrcbChan[0](cv::Rect(0, 0, 8, 8)), "LUMA (first 8x8 block)")
PRINT_MAT(ycrcbChan[1](cv::Rect(0, 0, 8, 8)), "Cr (first 8x8 block)")
PRINT_MAT(ycrcbChan[2](cv::Rect(0, 0, 8, 8)), "Cb (first 8x8 block)")

PRINT_MAT(bgrChan[0](cv::Rect(0, 0, 8, 8)), "Blue (first 8x8 block)")
PRINT_MAT(bgrChan[1](cv::Rect(0, 0, 8, 8)), "Green (first 8x8 block)")
PRINT_MAT(bgrChan[2](cv::Rect(0, 0, 8, 8)), "Red (first 8x8 block)")

, где PRINT_MATэто следующий макрос:

#define PRINT_MAT(mat, msg) std::cout<< std::endl <<msg <<":" <<std::endl <<mat <<std::endl;

Распечатывая каналы RGB, я получаю одинаковые значения (для первого блока 8x8) как для Matlab, так и для OpenCV, в то время как для Y, Cb и Cr я получаю разные значения.Например, для компонента Luma:

Matlab:

155 155 155 154 155 150 156 154
155 155 155 154 155 150 156 154
155 155 155 154 155 150 156 154
155 155 155 154 155 150 156 154
155 155 155 154 155 150 156 154
157 157 151 149 154 153 152 153
154 154 156 152 154 155 153 150
152 152 149 150 152 152 150 151

OpenCV:

162 162 162 161 162 157 163 161
162 162 162 161 162 157 163 161
162 162 162 161 162 157 163 161
162 162 162 161 162 157 163 161
162 162 162 161 162 157 163 161
164 164 158 155 161 159 159 160
160 160 163 158 160 162 159 156
159 159 155 157 158 159 156 157

Что такое правильное преобразование?А почему результаты разные?

Ответы [ 2 ]

0 голосов
/ 10 февраля 2019

Посмотрев на исходный код MATLAB rgb2ycbcr, преобразование выполняется в соответствии с уравнением, взятым из "" Пойнтона "Введение в цифровое видео" (стр. 176, уравнения 9.6)":

origT = [ ...
     65.481 128.553  24.966;...
    -37.797 -74.203 112    ;...
    112     -93.786 -18.214];
origOffset = [16; 128; 128];
ycbcr = origT * rgb + origOffset;

И также упоминается, что:

Если входное значение равно uint8, тогда YCBCR равно uint8, где Y находится в диапазоне [16 235],Cb и Cr находятся в диапазоне [16 240].

В OCV ( реализация ) нас другой стороны, это выполняется с использованием следующих соотношений:

enter image description here

Обратите внимание, как написано " Y, Cr и Cb cover весь диапазон значений .".

Если мы будем использовать те же уравнения в MATLAB, мы получим результат намного ближе к OCV (возможно, я использую другое исходное изображение).Например, для Y:

OCV_Y = 0.299*imgrgb(:,:,1) + 0.587*imgrgb(:,:,2) + 0.114*imgrgb(:,:,3);

Дает это первое 8x8:

   162   162   162   162   163   157   163   161
   162   162   162   162   163   157   163   161
   162   162   162   162   163   157   163   161
   162   162   162   162   163   157   163   161
   162   162   162   162   163   157   163   161
   164   164   158   155   162   159   159   160
   161   161   163   158   160   161   158   155
   159   159   156   156   159   158   157   157

Согласно статье Википедии о YCbCr , похоже, что OCV реализуетвариант " JPEG Conversion ", тогда как MATLAB реализует вариант ITU-R BT.601 для "телевидения стандартной четкости".

В заключение: я бы сказал, что оба определения правильный , но если вы заботитесь конкретно о правильной реализации для JPEG, я бы сказал, что путь OCV лучше .В любом случае, в MATLAB очень просто реализовать любой другой вариант.

0 голосов
/ 10 февраля 2019

Оказывается, оба "правильные".В то время как OpenCV принимает целый диапазон значений Y, MATLAB использует [16, 235].Обоснование можно увидеть в этом другом вопрос / ответ .

Как вы можете прочитать в MATLAB документы :

Изображение в YCbCrцветовое пространство, возвращаемое как массив m-by-n-by-3.

  • Если входной сигнал является двойным или единичным, то Y находится в диапазоне [16/255, 235/255] иCb и Cr находятся в диапазоне [16/255, 240/255].
  • Если ввод uint8, то Y находится в диапазоне [16, 235], а Cb и Cr находятся вдиапазон [16, 240] .
  • Если входное значение равно uint16, то Y находится в диапазоне [4112, 60395], а Cb и Cr находятся в диапазоне [4112, 61680].

В OpenCV документы :

  • Y = 0,299R + 0,587G + 0,114B
  • Cr = (R - Y) 0,713 + \ delta
  • Cb = (B - Y) = 0,564 + \ delta

[...]

Y, Cr и Cb охватывают весь диапазон значений .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...