从RGB不同的颜色转换为YCbCr与OpenCV的和Matlab

问题描述 投票:2回答:2

我试图用OpenCV的复制JPEG算法后,我成功地在MATLAB中实现它。我注意到,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通道我获得相同的值(对于第一8×8块)都为Matlab和OpenCV的,而对于Y,Cb和Cr我得到不同的值。例如,对于明度分量:

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
2个回答
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 OCVimplementation)在另一方面,这是使用以下关系执行:

enter image description here

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

如果我们使用MATLAB中的相同方程,我们得到非常接近OCV的(也许是我使用不同的源图像)的结果。例如,对于Y

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

给出了这样的第一8×8:

   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中的任何其他变种。


2
投票

原来都是“正确的”。而采用的OpenCV的整个范围用于Y,MATLAB无二[16,235]。推理可以在此另一个question/answer可以看出。

正如你可以在MATLAB docs阅读:

图像在YCbCr颜色空间,退回作为m乘n-3阵列。

  • 如果输入是双或单,则Y为在范围[255分之16,255分之235]和Cb和Cr是在范围[255分之16,二百五十五分之二百四十○]。
  • 如果输入是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+ \增量
  • CB =(B - Y)⋅0.564+ \增量

[...]

Y,Cr和Cb覆盖整个值的范围。

© www.soinside.com 2019 - 2024. All rights reserved.