在数字图像处理种YUV格式也是我们经常遇到,与RGB一样也是一种编码格式,开始主要用于电视系统以及模拟视频领域。YUV,分为三个分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。如果没用UV信息,只有Y信息,也可以进行成像不过只是黑白的,这样就能很好解决彩色电视与黑白电视的兼容问题,与RGB相比,YUV占用带宽较少,目前摄像头输出格式普遍采用YUV格式。

YUV格式

目前主流的YUV格式有三种:YUV4:4:4, YUV 4:2:2,以及YUV4:2:0,其相应的格式如下:

1:YUV 4:4:4采样,每一个Y对应一组UV分量。

2:YUV 4:2:2采样,每两个Y共用一组UV分量。

3:YUV 4:2:0采样,每四个Y共用UV分量。

其分布格式如下:

限于篇幅原因,先介绍YUV420格式,其他格式下节再介绍。

YUV类型

首先介绍下基础知识,YUV格式为两大类:plannar 和 packed.

1:plannar 的YUV格式,是先连续存储所有像素的Y,然后紧接着存储所有像素点的U,最后是所有像素点的V(即YYYYUUUUVVVV)或者还有其他方式先Y再V再U(即YYYYYYYVVVVVVUUUUUU)

2: packed格式,每个像素点的YUV连续交替存储(如YUVYUV, YYUVYYUV等)。

YUV420存储格式

YUV420格式由上述描述可知4个Y对应一个UV分量,基本是采样plannar格式存储(笔者学识较短,Packed的YUV420格式不知道有没有,还未见过)。Plannar格式先排所有Y分量然后按照UV排版格式,主要分为如下集中:

YV12,YU12格式(YUV420P)

YV12和YU12格式属于YUV420格式,其中Cr和Cb分别代表U,V分量 ,其存储格式是先排Y分量再分别排UV分量。

UV先后顺序不一样。YV12格式为YYYYYVVVVVVUUUUU, YU12为YYYYUUUUUUUVVVVVVV,可以用如下所图表示:

YV12

YU12

NV12、NV21(YUV420SP)

NV12和NV21是YUV420的另外两种格式,先排所有Y,然后UV交替排布。NV21格式为YYYYYYVUVUVU,

NV12为YYYYYYUVUVUV,通常 NV21和NV12也被称为YUV420SP。

NV21

NV12

YUV420转RGB实现方法

方法一:

YUV420 转RGB有很多方法,网上大部分的方法按照以下公式来进行转换(实际效果参数可调):

R = Y + 1.402* (V - 128); //R
             G = Y - 0.34413 * (U - 128) - 0.71414 * (V - 128); //G
            B = Y + 1.772 * (U - 128); //B

以YUV420SP为例,转换成RGB代码如下:

void ConvertYUV420SPToRGB(unsigned char *Src, unsigned char *Dest, int ImageWidth, int ImageHeight)
{int total = ImageWidth * ImageHeight;unsigned char *ybase = Src;unsigned char *ubase = &Src[total];unsigned int index = 0;for (int y = 0; y < ImageHeight ; y++) {for (int x = 0; x < ImageWidth; x++) {//YYYYYYYYVUVUu_char Y = ybase[x + y * ImageWidth];u_char U = ubase[y / 2 * ImageWidth + (x / 2) * 2 + 1];u_char V = ubase[y / 2 * ImageWidth + (x / 2) * 2];Dest[index++] = Y + 1.402* (V - 128); //RDest[index++] = Y - 0.34413 * (U - 128) - 0.71414 * (V - 128); //GDest[index++] = Y + 1.772 * (U - 128); //B}}
}

实际转换效果如下图,太亮或者边界会出现失真,效果不理想,原因是G分量有可能出现负值,并没有考虑到边界问题,这是网上方法普遍存在问题。

方法二:

为了解决上述边界会造成失真问题,建议采用方法二改为查表方式,可以防止出现边界失真问题,参考了国外一大神的方法,链接如下:http://wss.co.uk/pinknoise/yuv2rgb/

实现代码如下:

static int Table_fv1[256] = { -180, -179, -177, -176, -174, -173, -172, -170, -169, -167, -166, -165, -163, -162, -160, -159, -158, -156, -155, -153, -152, -151, -149, -148, -146, -145, -144, -142, -141, -139, -138, -137,  -135, -134, -132, -131, -130, -128, -127, -125, -124, -123, -121, -120, -118, -117, -115, -114, -113, -111, -110, -108, -107, -106, -104, -103, -101, -100, -99, -97, -96, -94, -93, -92, -90,  -89, -87, -86, -85, -83, -82, -80, -79, -78, -76, -75, -73, -72, -71, -69, -68, -66, -65, -64,-62, -61, -59, -58, -57, -55, -54, -52, -51, -50, -48, -47, -45, -44, -43, -41, -40, -38, -37,  -36, -34, -33, -31, -30, -29, -27, -26, -24, -23, -22, -20, -19, -17, -16, -15, -13, -12, -10, -9, -8, -6, -5, -3, -2, 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 14, 15, 16, 18, 19, 21, 22, 23, 25, 26, 28, 29, 30, 32, 33, 35, 36, 37, 39, 40, 42, 43, 44, 46, 47, 49, 50, 51, 53, 54, 56, 57, 58, 60, 61, 63, 64, 65, 67, 68, 70, 71, 72, 74, 75, 77, 78, 79, 81, 82, 84, 85, 86, 88, 89, 91, 92, 93, 95, 96, 98, 99, 100, 102, 103, 105, 106, 107, 109, 110, 112, 113, 114, 116, 117, 119, 120, 122, 123, 124, 126, 127, 129, 130, 131, 133, 134, 136, 137, 138, 140, 141, 143, 144, 145, 147, 148,  150, 151, 152, 154, 155, 157, 158, 159, 161, 162, 164, 165, 166, 168, 169, 171, 172, 173, 175, 176, 178 };
static int Table_fv2[256] = { -92, -91, -91, -90, -89, -88, -88, -87, -86, -86, -85, -84, -83, -83, -82, -81, -81, -80, -79, -78, -78, -77, -76, -76, -75, -74, -73, -73, -72, -71, -71, -70, -69, -68, -68, -67, -66, -66, -65, -64, -63, -63, -62, -61, -61, -60, -59, -58, -58, -57, -56, -56, -55, -54, -53, -53, -52, -51, -51, -50, -49, -48, -48, -47, -46, -46, -45, -44, -43, -43, -42, -41, -41, -40, -39, -38, -38, -37, -36, -36, -35, -34, -33, -33, -32, -31, -31, -30, -29, -28, -28, -27, -26, -26, -25, -24, -23, -23, -22, -21, -21, -20, -19, -18, -18, -17, -16, -16, -15, -14, -13, -13, -12, -11, -11, -10, -9, -8, -8, -7, -6, -6, -5, -4, -3, -3, -2, -1, 0, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 8, 9, 10, 10, 11, 12, 12, 13, 14, 15, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23, 24, 25, 25, 26, 27, 27, 28, 29, 30, 30, 31, 32, 32, 33, 34, 35, 35, 36, 37, 37, 38, 39, 40, 40, 41, 42, 42, 43, 44, 45, 45, 46, 47, 47, 48, 49, 50, 50, 51, 52, 52, 53, 54, 55, 55, 56, 57, 57, 58, 59, 60, 60, 61, 62, 62, 63, 64, 65, 65, 66, 67, 67, 68, 69, 70, 70, 71, 72, 72, 73, 74, 75, 75, 76, 77, 77, 78, 79, 80, 80, 81, 82, 82, 83, 84, 85, 85, 86, 87, 87, 88, 89, 90, 90 };
static int Table_fu1[256] = { -44, -44, -44, -43, -43, -43, -42, -42, -42, -41, -41, -41, -40, -40, -40, -39, -39, -39, -38, -38, -38, -37, -37, -37, -36, -36, -36, -35, -35, -35, -34, -34, -33, -33, -33, -32, -32, -32, -31, -31, -31, -30, -30, -30, -29, -29, -29, -28, -28, -28, -27, -27, -27, -26, -26, -26, -25, -25, -25, -24, -24, -24, -23, -23, -22, -22, -22, -21, -21, -21, -20, -20, -20, -19, -19, -19, -18, -18, -18, -17, -17, -17, -16, -16, -16, -15, -15, -15, -14, -14, -14, -13, -13, -13, -12, -12, -11, -11, -11, -10, -10, -10, -9, -9, -9, -8, -8, -8, -7, -7, -7, -6, -6, -6, -5, -5, -5, -4, -4, -4, -3, -3, -3, -2, -2, -2, -1, -1, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, 28, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35, 36, 36, 36, 37, 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42, 43, 43 };
static int Table_fu2[256] = { -227, -226, -224, -222, -220, -219, -217, -215, -213, -212, -210, -208, -206, -204, -203, -201, -199, -197, -196, -194, -192, -190, -188, -187, -185, -183, -181, -180, -178, -176, -174, -173, -171, -169, -167, -165, -164, -162, -160, -158, -157, -155, -153, -151, -149, -148, -146, -144, -142, -141, -139, -137, -135, -134, -132, -130, -128, -126, -125, -123, -121, -119, -118, -116, -114, -112, -110, -109, -107, -105, -103, -102, -100, -98, -96, -94, -93, -91, -89, -87, -86, -84, -82, -80, -79, -77, -75, -73, -71, -70, -68, -66, -64, -63, -61, -59, -57, -55, -54, -52, -50, -48, -47, -45, -43, -41, -40, -38, -36, -34, -32, -31, -29, -27, -25, -24, -22, -20, -18, -16, -15, -13, -11, -9, -8, -6, -4, -2, 0, 1, 3, 5, 7, 8, 10, 12, 14, 15, 17, 19, 21, 23, 24, 26, 28, 30, 31, 33, 35, 37, 39, 40, 42, 44, 46, 47, 49, 51, 53, 54, 56, 58, 60, 62, 63, 65, 67, 69, 70, 72, 74, 76, 78, 79, 81, 83, 85, 86, 88, 90, 92, 93, 95, 97, 99, 101, 102, 104, 106, 108, 109, 111, 113, 115, 117, 118, 120, 122, 124, 125, 127, 129, 131, 133, 134, 136, 138, 140, 141, 143, 145, 147, 148, 150, 152, 154, 156, 157, 159, 161, 163, 164, 166, 168, 170, 172, 173, 175, 177, 179, 180, 182, 184, 186, 187, 189, 191, 193, 195, 196, 198, 200, 202, 203, 205, 207, 209, 211, 212, 214, 216, 218, 219, 221, 223, 225 };void ConvertYUV420SPToBGR(unsigned char* src,unsigned char* Dst,int ImageWidth,int ImageHeight)
{if (ImageWidth < 1 || ImageHeight < 1 || src == NULL || Dst == NULL)return ;const long len = ImageWidth * ImageHeight;unsigned char* yData = src;unsigned char* vData = &yData[len];unsigned char* uData = &vData[len >> 2];int bgr[3];int yIdx,uIdx,vIdx,idx;int rdif,invgdif,bdif;for (int i = 0;i < ImageHeight;i++){for (int j = 0;j < ImageWidth;j++){yIdx = i * ImageWidth + j;vIdx = (i/2) * (ImageWidth/2) + (j/2);uIdx = vIdx;rdif = Table_fv1[vData[vIdx]];invgdif = Table_fu1[uData[uIdx]] + Table_fv2[vData[vIdx]];bdif = Table_fu2[uData[uIdx]];bgr[0] = yData[yIdx] + bdif;    bgr[1] = yData[yIdx] - invgdif;bgr[2] = yData[yIdx] + rdif;for (int k = 0;k < 3;k++){idx = (i * ImageWidth + j) * 3 + k;if(bgr[k] >= 0 && bgr[k] <= 255)Dst[idx] = bgr[k];elseDst[idx] = (bgr[k] < 0)?0:255;}}}
}

实际转换效果如下:

上述效果较好。

方法三:

近期在看opencv,发现了可以使用cv::saturate_cast<>()防止数据溢出,关于cv::saturate_cast<>()的介绍有兴趣的读者可以了解下:

https://blog.csdn.net/weixin_42730667/article/details/104255670

这种方法应该也可以,由于距离方法一和二过去很久,实验环境已经拆除,数据没有保存,无法拿到当初的数据,并没有亲自做实验,应该也是可以解决,更新此方法的代码防止时间长遗忘掉,做备份后面有时间再做实验

void ConvertYUV420SPToRGB(unsigned char *Src, unsigned char *Dest, int ImageWidth, int ImageHeight)
{int total = ImageWidth * ImageHeight;unsigned char *ybase = Src;unsigned char *ubase = &Src[total];unsigned int index = 0;for (int y = 0; y < ImageHeight; y++) {for (int x = 0; x < ImageWidth; x++) {//YYYYYYYYVUVUu_char Y = ybase[x + y * ImageWidth];u_char U = ubase[y / 2 * ImageWidth + (x / 2) * 2 + 1];u_char V = ubase[y / 2 * ImageWidth + (x / 2) * 2];Dest[index++] = cv::saturate_cast<uchar>(Y + 1.402* (V - 128)); //RDest[index++] = cv::saturate_cast<uchar>(Y - 0.34413 * (U - 128) - 0.71414 * (V - 128)); //GDest[index++] = cv::saturate_cast<uchar>(Y + 1.772 * (U - 128)); //B}}
}

图片格式之YUV420 转RGB格式(含代码)相关推荐

  1. 为什么opencv使用BGR 格式,而不是RGB格式?

    https://www.learnopencv.com/why-does-opencv-use-bgr-color-format/ 原因其实很简单啊,这个解释非常的风趣,"古罗马的马屁股&q ...

  2. 使用C++实现YUV格式图像与RGB格式图像之间相互转换

    使用C++实现YUV格式图像与RGB格式图像之间相互转换 一.RGB与YUV转换公式 1.RGB转YUV 1)RGB转换亮度与色差信号公试: 2)归一化为YUV的转化公试为: 2.YUV转RGB 二. ...

  3. 图片YUV格式与RGB格式的转换

    YUV格式与RGB格式的转换 YUV格式介绍 YUV420.YUV422.YUV444 (1) YUV4:2:0 (2) YUV4:2:2 (3) YUV4:4:4 内存排列方式 YUV与RGB转换 ...

  4. YUY2(YUV) 与 RGB 格式图片的相互转换 以及 基于YUY2(YUV)的blending

    这是一个项目里使用的,API里从pool里取出的格式都是YUY2,但是图像处理的API库中要求都是jepg格式. YUY2经常用于电视制式以及许多摄像头的输出格式.而我们在处理时经常需要将其转化为RG ...

  5. YUY2(YUV) 与 RGB 格式图片的相互转换

    [版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/jtujtujtu/article/d ...

  6. 批量更改图片格式(png改为rgb)

    一.使用labelme进行关键点标注,打开一些图片出现闪退,并报如下错误: KeyError: 'RGBA' OSError: cannot write mode RGBA as JPEG (keyp ...

  7. YUV / RGB 格式及快速转换

    YUV是指亮度参量和色度参量分开表示的像素格式,而这样分开的好处就是不但可以避免相互干扰,还可以降低色度的采样率而不会对图像质量影响太大. YUV是一个比较笼统地说法,针对它的具体排列方式,可以分为很 ...

  8. YUV / RGB 格式及快速转换算法

    1 前言 自然界的颜色千变万化,为了给颜色一个量化的衡量标准,就需要建立色彩空间模型来描述各种各样的颜色,由于人对色彩的感知是一个复杂的生理和心理联合作用 的过程,所以在不同的应用领域中为了更好更准确 ...

  9. mysql padding_解决RGB模式下图片的padding(补边框)问题(含代码实现)

    首先,说到图片的padding问题,我们知道对于灰度图(channel=1)的图片我们可以之间将其转化为numpy.array,然后利用np.pad(image,((up,down),(left,ri ...

最新文章

  1. CICC《城市大脑建设规范》标准建设启动会在京召开
  2. select,epoll,poll比较(网络资源总结)
  3. mysql数据库熟悉表空间数据文件_Oracle表空间和数据文件
  4. rxjava 并行_使用RxJava和Completable并行执行阻塞任务
  5. Apache Camel教程– EIP,路由,组件,测试和其他概念的简介
  6. python中dtypes_Dataframe创建及index,columns,values,dtypes等属性介绍
  7. WPF 自定义命令 以及 命令的启用与禁用
  8. 小程序·云服务的系统架构和运维实现
  9. 文字垂直居中(HTML、CSS)
  10. 13 MySQL--存储过程
  11. AI顶会论文“趋势”:对新方法的过度关注,与现实问题的脱节
  12. 图的最短路径-----------Dijkstra算法详解(TjuOj2870_The Kth City)
  13. 经典案例悬臂梁受力有限元理论与程序设计_《数值计算与程序设计》系列课程之三
  14. python代码判断身份证号是男是女
  15. 使用pthread后,界面假死现象问题
  16. 《走遍美国》MP3 共78集下载地址
  17. UC/OSII一些小知识
  18. Python制作PPT
  19. 京东android面试题2019,2019京东的面试题(牛客)
  20. [Texture]详解Texture2D

热门文章

  1. Mysql查询优化——中间表方法优化count()统计大数据量总数问题
  2. JEEWX微信开发更便捷,Ngrok 内网穿透利器应用
  3. quartz 表达式解析 详解
  4. matlab预测ARMA-GARCH 条件均值和方差模型
  5. #淘宝#复制分享宝贝内容,打开淘宝APP,自己主动弹出宝贝提示信息
  6. 使用 Core Graphics 绘制基本形状
  7. Android -- 自定义ScrollView实现放大回弹效果
  8. 基于Spring MVC的ECharts动态数据实时展示
  9. DDD:四色原型、DDD、DCI之间的关系
  10. mysql 四叉树的应用_游戏算法(2):查找优化之四叉树的应用