【问题标题】:Different color conversion from RGB to YCbCr with OpenCV and Matlab使用 OpenCV 和 Matlab 从 RGB 到 YCbCr 的不同颜色转换
【发布时间】:2019-07-04 01:27:37
【问题描述】:

在 MATLAB 中成功实现 jpeg 算法后,我正在尝试使用 openCV 复制 jpeg 算法。我注意到 MATLAB 和 OpenCV 对从 RGB 到 YCbCr 的颜色空间转换给出了不同的结果。

看OpenCV的文档,好像唯一用到的函数就是cv::cvtColor,但是打印Y、Cb和Cr的第一个8x8子矩阵,它们不一样。

这是我的 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 通道,我为 Matlab 和 OpenCV 获得相同的值(对于第一个 8x8 块),而对于 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

什么是正确的转换?为什么结果不同?

【问题讨论】:

    标签: c++ matlab opencv rgb color-conversion


    【解决方案1】:

    事实证明两者都是“正确的”。 OpenCV 采用整个 Y 范围,而 MATLAB 采用 [16, 235]。推理可以看这个另一个question/answer

    正如您在 MATLAB 中所读到的那样docs

    YCbCr 颜色空间中的图像,以 m×n×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 中docs:

    • Y = 0.299R + 0.587G + 0.114B
    • Cr = (R - Y)⋅0.713 + \delta
    • Cb = (B - Y)⋅0.564 + \delta

    [...]

    Y、Cr、Cb 覆盖整个取值范围

    【讨论】:

      【解决方案2】:

      通过查看 MATLAB 的 rgb2ycbcr 的源代码,转换是根据“Poynton 的“数字视频简介”(第 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] 范围内,CbCr[16 240] 范围内。

      In OCV (implementation) 另一方面,这是使用以下关系执行的:

      注意它是如何说“Y、Cr 和 Cb 覆盖整个值范围”。

      如果我们在 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
      

      根据wikipedia article on YCbCr,OCV 似乎实现了“JPEG Conversion”变体,而 MATLAB 实现了用于“标准清晰度电视”的 ITU-R BT.601 变体。

      总结:我会说这两个定义都是正确的,但如果您特别关心 JPEG 的正确实现,我会说 OCV 的方式更好。无论如何,在 MATLAB 中实现任何其他变体都非常容易。

      【讨论】:

      • 这是一个很好的警告,YCbCr 没有一个单一的定义。但也没有单一的 RGB 定义,也没有 HSV,也没有大多数其他色彩空间。除非您明确说明您遵循的标准。
      猜你喜欢
      • 1970-01-01
      • 2015-05-08
      • 2012-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-15
      • 2016-06-06
      • 1970-01-01
      相关资源
      最近更新 更多