2016-07-22 3 views
0

Я пытаюсь преобразовать простой вариант YCbCr в RGB и обратно. Формула, которую я использую на this page (RGB для полнодиапазонного YCbCr и наоборот).Полный диапазон YCbCr до RGB и обратно в OpenCV не обратимый

inline cv::Mat rgb_to_ycrcb(cv::Mat input) { 
    cv::Mat output(input.size(), input.type(), cv::Scalar(0, 0, 0)); 
    float rgb_to_ycrcb_data[] = { 
       0.2990, 0.5870, 0.114, 
       -0.169, -0.331, 0.500, 
       0.5000, -0.419, -0.081 
      }; 
    cv::Mat rgb_to_ycrcb = cv::Mat(3, 3, CV_32FC1, rgb_to_ycrcb_data); 

    for (int r = 0; r < input.rows; r++) { 
     for (int c = 0; c < input.cols; c++) { 
      cv::Vec3f rgb_value; 
      cv::Mat input_rgb = cv::Mat(input.ptr<cv::Vec3b>(r)[c], false); 
      input_rgb.convertTo(rgb_value, CV_32F); 
      cv::Vec3f offset(0., 128., 128.); 

      cv::Mat converted = cv::Mat(offset, false) + 
           rgb_to_ycrcb * cv::Mat(rgb_value, false); 
      cv::Vec3b final_vec; 
      converted.convertTo(final_vec, 
           CV_8U); 
      output.ptr<cv::Vec3b>(r)[c] = converted; 
     } 
    } 
    return output; 
} 

inline cv::Mat ycrcb_to_rgb(cv::Mat input) { 
    cv::Mat output(input.size(), input.type(), cv::Scalar(0, 0, 0)); 
    float ycrcb_to_rgb_data[] = { 
       1.000, 0.0000, 1.4000, 
       1.000, -0.343, -0.711, 
       1.000, 1.7650, 0.000 
      }; 
    cv::Mat ycrcb_to_rgb = cv::Mat(3, 3, CV_32FC1, ycrcb_to_rgb_data); 
    for (int r = 0; r < input.rows; r++) { 
     for (int c = 0; c < input.cols; c++) { 
      cv::Vec3f ycrcb_value; 
      cv::Mat(input.ptr<cv::Vec3b>(r)[c], false). 
      convertTo(ycrcb_value, CV_32F); 
      ycrcb_value[1] -= 128; 
      ycrcb_value[2] -= 128; 
      cv::Mat converted = ycrcb_to_rgb * cv::Mat(ycrcb_value, false); 
      cv::Vec3b final_vec; 
      converted.convertTo(final_vec, 
           CV_8U); 
      output.ptr<cv::Vec3b>(r)[c] = converted; 
     } 
    } 
    return output; 
} 

Когда я преобразовать изображение в цветном формате YCrCb, состоящей из кортежа (28, 113, 14) к RGB, я получаю (0, 114, 2). Преобразование этого значения RGB обратно в YCrCb дает (67, 91, 80).

Формула для полного диапазона YCrCb указывает, что домен всех компонентов YCrCb равен [0, 255], а соответствующий кодоменин RGB-компонентов также равен [0, 255]. Я неправильно использовал эту формулу? Если нет, то почему это не обратимо? И если это не обратимо, есть ли еще одна YUV-подобная формула?

+0

Есть некоторые значения YCbCr, которые не представлены в RGB, поэтому они не полностью обратимы. Однако я не знаю, если конкретное значение, о котором вы упомянули, является одним из них. –

ответ

0

Ваш кортеж YCbCr превышает допустимый диапазон RGB.
Формула преобразования (BT.601) стандарт следующим образом:

R '= 1,164 * (Y' - 16) + 1,596 * (Cr '- 128)

G' = 1.164 * (Y '- 16) - 0,813 * (Кр' - 128) - 0,392 * (Cb '- 128)

В' = 1,164 * (Y '- 16) + 2,017 * (Cb' - 128)

См. https://software.intel.com/en-us/node/503907

Это не точная формула, которую вы использовали в своем коде, но принцип тот же.

Поместите значения кортеж YCbCr в формуле преобразования:

R' = 1.164*(Y' - 16) + 1.596*(Cr' - 128) = -167.9760 
G' = 1.164*(Y' - 16) - 0.813*(Cr' - 128) - 0.392*(Cb' - 128) = 112.5300 
B' = 1.164*(Y' - 16) + 2.017*(Cb' - 128) = -16.2870 

Как вы можете увидеть R и В превышает диапазон [0, 255].
В моем примере значения R и B зажаты до нуля.
В вашем преобразовании только R был зажат до нуля.
Когда значения зажаты, результат не обратим.

Попробуйте проиллюстрировать диаграмму (не уверен, что она правильная).
Как вы можете видеть, значения YCbCr превышают диапазон sRGB.
enter image description here