【图像处理】-小议YUV色彩空间-YUV和RGB格式的来由,相互关系以及转换方式,并对编程实现的YUV转为RGB程序进行介绍

本文主要是介绍【图像处理】-小议YUV色彩空间-YUV和RGB格式的来由,相互关系以及转换方式,并对编程实现的YUV转为RGB程序进行介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

小议YUV色彩空间
摘要:
在视频图像处理等相关相关领域,YUV是一个经常出现的格式。本文主要以图解的资料形式详细描述YUV和RGB格式的来由,相互关系以及转换方式,并对编程实现的YUV转为RGB程序进行介绍。
1 引言
自然界的颜色千变万化,为了给颜色一个量化的衡量标准,就需要建立色彩空间模型来描述各种各样的颜色,由于人对色彩的感知是一个复杂的生理和心理联合作用的过程,所以在不同的应用领域中为了更好更准确的满足各自的需求,就出现了各种各样的色彩空间模型来量化的描述颜色。我们比较常接触到的就包括 RGB / CMYK / YCbCr/ YUV / HSI等等。
即使只是RGB、 YUV这两大类色彩空间,所涉及到的知识也是十分丰富复杂的,自知具备的相关专业知识有限,所以本文主要针对自己所了解的相关知识以及项目开发中遇到的相关问题对YUV色彩空间相关进行讨论。

2 理论分析
2.1 RGB、YUV色彩空间模型介绍
RGB与YUV有着千丝万缕的联系与区别,其中RGB是按三基色加光系统的原理来描述颜色,而YUV则是按照亮度、色差的原理来描述颜色。
2.1.1 RGB 颜色空间
RGB 颜色空间是我们最常见的颜色空间,是一种简单鲁棒性较好的定义颜色的空间。RGB 颜色空间由红、绿、蓝三个基本颜色通道组成,由这些颜色通道组合代表一种颜色。RGB 颜色模型可以通过一个立方体颜色模型,如图 1 表示,其三个轴分别代表红、绿、蓝 3 个颜色分量。对于一张 24 位真彩色的图片,R、G、B 三个通道各自具有 8 位宽,像素的取值范围为0-255,红色为(255,0,0),绿色为(0,255,0),蓝色为(0,0,255)。
在这里插入图片描述

图 1 RGB颜色模型
2.1.2 YUV颜色空间
在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD(点耦合器件)摄像机,它把摄得的彩色图像信号,经分色、分别放大校正得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号R-Y、B-Y,最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这就是我们常用的YUV色彩空间。

2.1.2.1 RGB 颜色空间过渡到YUV色彩空间
对于视频捕获和编解码等应用来讲,RGB这样的表示方式数据量太大了。需要想办法在不太影响感觉的情况下,对原始数据的表示方法进行更改,减少数据量。
在RGB色彩空间中,三个颜色的重要程度相同,所以需要使用相同的分辨率进行存储, 3个颜色通道需要按照相同的分辨率进行存储,数据量还是很大的。所以,利用人眼睛对亮度比对颜色更加敏感,将图像的亮度信息和颜色信息分离,并使用不同的分辨率进行存储,这样可以在对主观感觉影响很小的前提下,更加有效的存储图像数据。
YCbCr色彩空间和它的变形(也就是YUV)是最常用的有效的表示彩色图像的方法。Y是图像的亮度(luminance/luma)分量,使用以下公式计算,为R,G,B分量的加权平均值:
Y = kr R + kgG + kbB,其中k是权重因数。
上面的公式计算出了亮度信息,还有颜色信息,使用色差(color difference/chrominance或chroma)来表示,其中每个色差分量为R,G,B值和亮度Y的差值:
  Cb = B -Y Cr = R -Y Cg = G- Y
其中,Cb+Cr+Cg是一个常数(其实是一个关于Y的表达式),所以,只需要其中两个数值结合Y值就能够计算出原来的RGB值。所以,我们仅保存亮度和蓝色、红色的色差值,这就是(Y,Cb,Cr)。
相比RGB色彩空间,YCbCr色彩空间有一个显著的优点。Y的存储可以采用和原来画面一样的分辨率,但是Cb,Cr的存储可以使用更低的分辨率。这样可以占用更少的数据量,并且在图像质量上没有明显的下降。所以,将色彩信息以低于量度信息的分辨率来保存是一个简单有效的图像压缩方法。
注释:YCbCr进行不同的取样就是所谓的YUV了。

2.1.2.2 YUV与RGB相互转换
YUV 空间和RGB空间存在如下转换关系:
在这里插入图片描述

注释:
1、从公式中,我们关键要理解的一点是,UV / CbCr信号实际上就是蓝色差信号和红色差信号,进而言之,实际上一定程度上间接的代表了蓝色和红色的强度,理解这一点对于我们理解各种颜色变换处理的过程会有很大的帮助。
2、我们在数字电子多媒体领域所谈到的YUV格式,实际上准确的说,是以YcrCb色彩空间模型为基础的具有多种存储格式的一类颜色模型的家族(包括YUV444 / YUV422 / YUV420 / YUV420P等等)。并不是传统意义上用于PAL制模拟电视的YUV模型。这些YUV模型的区别主要在于UV数据的采样方式和存储方式

2.2 RGB、YUV色彩空间模型内存分布
在RGB24格式中,对于宽度为w,高度为h的画面,需要wh3个字节来存储其每个像素的rgb信息,画面的像素数据是连续排列的。按照r(0,0),g(0,0),b(0,0);r(0,1),g(0,1),b(0,1);…;r(w-1,0),g(w-1,0),b(w-1,0);…;r(w-1,h-1),g(w-1,h-1),b(w-1,h-1)这样的顺序存放起来。
在YUV格式中,以YUV420格式为例。宽度为w高度为h的画面,其亮度Y数据需要wh个字节来表示(每个像素点一个亮度)。而Cb和Cr数据则是画面中4个像素共享一个Cb,Cr值。这样Cb用wh/4个字节,Cr用wh/4个字节。
YUV文件中,把多个帧的画面连续存放。就是YUV YUV YUV……这样的不断连续的形式,而其中每个YUV,就是一幅画面。
在这单个YUV中,前w
h个字节是Y数据,接着的wh/4个字节是Cb数据,再接着的wh/4个字节为Cr数据。

2.3 RGB、YUV色彩空间模型数据表达方式
以320240的一帧图像为例RGB24的排列方式如下图所示:
每个像素点有三个字节组成分别表示R,G,B分量上的颜色值。在数据中的表示方式为一个像素 一个像素表示。字节流可以表述如下:
BGRBGRBGRBGRBGR……
|---------------320
2403-------|
每一个字母表示一个字节,也就是该颜色分量的数值,相邻的三个BGR字节表示一个像素点。在我们做计算时,通常一次取三个字节,也就是一个像素点。
相应的YV12的排列方式如下图所示:
每个像素点都有一个Y分量,每隔一列就有一个U或者V分量,U和V交替出现。YV12的字节流表示方式和RGB24有很大区别,YV12并不是按照像素依次排列的,而是先放置Y空间,然后放置整个V空间,最后放置U空间,那么字节流如下所示:
YYYYYYY……VVVV……UUUU……
|-----320
240----|-320240/4-|-320240/4-|
在320240个字节的Y后,紧跟着320240/4个V和320240/4个U。
YV12和RGB24同样都有320
240个像素点,但是在数据结构和字节流上有着很大区别。单纯从数据大小来看,RGB24的数据大小为3202403Bytes,而YV12为3202401.5Bytes,可见YV12的数据量为RGB24的一半。

2.4 YCbCr色彩空间模型取样格式
对YCbCr色彩空间,进行不同格式的取样就得到不同的YUV格式了,如下图3所示。
在这里插入图片描述

2.5 RGB、YUV色彩空间模型转换示例
核心编程示例
//RGB转YUV
bool RGB2YUV(byte* RgbBuf,int nWidth,int nHeight,byte* yuvBuf,unsigned long len)
{
int i, j;
byte
bufY, *bufU, *bufV, *bufRGB,bufYuv;
memset(yuvBuf,0,(unsigned int )len);//len表示yuvBuf长度(WH3/2)
bufY = yuvBuf;//Y首址
bufV = yuvBuf + nWidth * nHeight;//V首址
bufU = bufV + (nWidth * nHeight
1/4);//U首址
*len = 0;
byte y, u, v, r, g, b,testu,testv;
unsigned int ylen = nWidth * nHeight; //Y长度
unsigned int ulen = (nWidth * nHeight)/4;//U长度
unsigned int vlen = (nWidth * nHeight)/4; //V长度

for (j = 0; j < nHeight;j++)
{bufRGB = RgbBuf + nWidth * (nHeight - 1 - j) * 3 ;for (i = 0;i < nWidth;i++){int pos = nWidth * i + j;r = *(bufRGB++);g = *(bufRGB++);b = *(bufRGB++);y = (byte)( ( 66 * r + 129 * g +  25 * b + 128) >> 8) + 16  ;          u = (byte)( ( -38 * r -  74 * g + 112 * b + 128) >> 8) + 128 ;          v = (byte)( ( 112 * r -  94 * g -  18 * b + 128) >> 8) + 128 ;*(bufY++) = max( 0, min(y, 255 ));if (j%2==0&&i%2 ==0){	//存u分量if (u>255){u=255;}if (u<0){u = 0;}*(bufU++) =u;}else{//存v分量if (i%2==0){ if (v>255){v = 255;}if (v<0){v = 0;}

*(bufV++) =v;
}
}
}
}
*len = nWidth * nHeight+(nWidth * nHeight)/2;
return true;
}

//YUV4转RGB
static void YUV420p_to_RGB24(unsigned char *yuv420[3], unsigned char *rgb24, int width, int height)
{
int R,G,B,Y,U,V,x,y;
int nWidth = width>>1; //色度信号宽度
for (y=0;y<height;y++)
{
for (x=0;x<width;x++)
{
Y = (yuv420[0] + ywidth + x);
U = (yuv420[1] + ((y>>1)nWidth) + (x>>1));
V = (yuv420[2] + ((y>>1)nWidth) + (x>>1));
R = Y + 1.402
(V-128);
G = Y - 0.34414
(U-128) - 0.71414
(V-128);
B = Y + 1.772
(U-128);
//防止越界
if (R>255)R=255;if (R<0)R=0;
if (G>255)G=255;if (G<0)G=0;
if (B>255)B=255;if (B<0)B=0;
*(rgb24 + ((height-y-1)*width + x)*3) = B;
*(rgb24 + ((height-y-1)*width + x)*3 + 1) = G;
*(rgb24 + ((height-y-1)*width + x)*3 + 2) = R;
}
}
}

2.4 RGB、YUV色彩空间模型转换示例实验结果
为了验证转换的效果,从RGB色彩空间转换到YUV420色彩空间再转换到RGB色彩空间,结果如下图4所示。

在这里插入图片描述

                      图4 RGB与YUV转换结果图

从上图看出,转换的效果还是可以的,部分地方出现色彩失真,算法还需优化。
3 结语
在视频监控领域,YUV是一个经常出现的格式。本文主要以图解的资料形式详细描述YUV和RGB格式的来由,相互关系以及转换方式,并对编程实现的YUV转为RGB程序进行介绍。

这篇关于【图像处理】-小议YUV色彩空间-YUV和RGB格式的来由,相互关系以及转换方式,并对编程实现的YUV转为RGB程序进行介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/888184

相关文章

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Debezium 与 Apache Kafka 的集成方式步骤详解

《Debezium与ApacheKafka的集成方式步骤详解》本文详细介绍了如何将Debezium与ApacheKafka集成,包括集成概述、步骤、注意事项等,通过KafkaConnect,D... 目录一、集成概述二、集成步骤1. 准备 Kafka 环境2. 配置 Kafka Connect3. 安装 D

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque