【OpenCV】探索YUV颜色空间:YUV420sp转为RGB
最编程
2024-08-15 16:14:03
...
对于 YUV 所表示的图像,Y 和 UV 分量是分离的。如果只有 Y 分量而没有 UV 分离,那么图像表示的就是黑白图像。彩色电视机采用的就是 YUV 图像,解决与和黑白电视机的兼容问题,使黑白电视机也能接受彩色电视信号。
人眼对色度的敏感程度低于对亮度的敏感程度。主要原因是视网膜杆细胞多于视网膜锥细胞,其中视网膜杆细胞的作用就是识别亮度,视网膜锥细胞的作用就是识别色度。所以,眼睛对于亮度的分辨要比对颜色的分辨精细一些。
利用这个原理,可以把色度信息减少一点,人眼也无法查觉这一点。
所以,并不是每个像素点都需要包含了 Y、U、V 三个分量,根据不同的采样格式,可以每个 Y 分量都对应自己的 UV 分量,也可以几个 Y 分量共用 UV 分量。相比 RGB,能够节约不少存储空间。
YUV 4:4:4采样方式与 RGB 图像大小是一样的。
YUV 4:2:2相比 RGB, 节省了三分之一的存储空间。
YUV 4:2:0相比 RGB, 节省了一半的存储空间。
设实际宽高为w*h
的图像,如果是RGB
格式,那么他的数据量为w*h*3
;
如果是yuv420
格式,那么他的数据量为w*h*1.5
因为yuv4:4:4
的数据量等于RGB数据量,而yuv4:4:4
是yuv4:2:0
数据量的2倍,所以yuv4:2:0
的数据量为w*h*3/2
。
从yuv420sp
转化得到RGB
的步骤:
- 1.当我们拿到一帧图像的yuv原始数据后,首先需要明确拿到的是以下哪种yuv数据:
yuv4:4:4
、yuv4:2:2
、yuv4:2:0
。并且,我们都会知道给对应图像的宽和高,因为这都是驱动配置给出的。如果你是从yuv元素数据中截取出来的某roi区域的yuv数据,那么你也应该知道该roi的宽和高。注意,此时的宽和高是指图像的宽和高,不是指代图像数据码流排列的行数和列数。 - 2.把原始yuv数据通过构造
cv::Mat
格式封装起来,此时的cv::Mat
的宽(.cols
)和高(.rows
)就需要变化了,因为yuv格式和RGB格式的数据量是不一样的,yuv格式如果不是yuv4:4:4
(yuv数据量为w*(h*3)
)的话,那么yuv格式的数据量是一定比RGB少的。所以,此时如果是yuv420
格式,就根据yuv420
格式的特点,把cv::Mat
的宽高设置为w*(h*1.5)
,且必须为单通道,注意这里宽度不变,是在高度上延伸。yuyv原始数据变成cv::Mat
格式后,你如果直接imshow
显示的话,图像会变高。转化成RGB格式后才会恢复为正常宽和高。 - 3.然后再通过
cv::cvtColor(yuyv_img, rgb_img, cv::COLOR_YUV420sp2RGB);
转化得到RGB图像。
注意构造yuyv的cv::Mat
时通道类型是CV_8UC1
,而构造RGB的cv::Mat
时通道类型是CV_8UC3
.
cv::Mat yuyv_img =
cv::Mat(box.height * 3 / 2, box.width, CV_8UC1,
const_cast<unsigned char *>(yuv_raw.data()));
if (!yuyv_img.data) {
std::cout << "empty yuyv_img"<< std::endl;
}
cv::Mat rgb_img = cv::Mat(box.height, box.width, CV_8UC3);
cv::cvtColor(yuyv_img, rgb_img, cv::COLOR_YUV420sp2RGB);
可参考下面两篇文章来理解YUV:
一文理解 YUV
YUV色彩格式总结