首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

图片格式之YUV420 转RGB格式(含代码)

  • 23-09-22 20:41
  • 3835
  • 9400
blog.csdn.net

在数字图像处理种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
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代码如下:

  1. void ConvertYUV420SPToRGB(unsigned char *Src, unsigned char *Dest, int ImageWidth, int ImageHeight)
  2. {
  3. int total = ImageWidth * ImageHeight;
  4. unsigned char *ybase = Src;
  5. unsigned char *ubase = &Src[total];
  6. unsigned int index = 0;
  7. for (int y = 0; y < ImageHeight ; y++) {
  8. for (int x = 0; x < ImageWidth; x++) {
  9. //YYYYYYYYVUVU
  10. u_char Y = ybase[x + y * ImageWidth];
  11. u_char U = ubase[y / 2 * ImageWidth + (x / 2) * 2 + 1];
  12. u_char V = ubase[y / 2 * ImageWidth + (x / 2) * 2];
  13. Dest[index++] = Y + 1.402* (V - 128); //R
  14. Dest[index++] = Y - 0.34413 * (U - 128) - 0.71414 * (V - 128); //G
  15. Dest[index++] = Y + 1.772 * (U - 128); //B
  16. }
  17. }
  18. }

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

方法二:

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

实现代码如下:

 

  1. 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 };
  2. 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 };
  3. 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 };
  4. 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 };
  5. void ConvertYUV420SPToBGR(unsigned char* src,unsigned char* Dst,int ImageWidth,int ImageHeight)
  6. {
  7. if (ImageWidth < 1 || ImageHeight < 1 || src == NULL || Dst == NULL)
  8. return ;
  9. const long len = ImageWidth * ImageHeight;
  10. unsigned char* yData = src;
  11. unsigned char* vData = &yData[len];
  12. unsigned char* uData = &vData[len >> 2];
  13. int bgr[3];
  14. int yIdx,uIdx,vIdx,idx;
  15. int rdif,invgdif,bdif;
  16. for (int i = 0;i < ImageHeight;i++){
  17. for (int j = 0;j < ImageWidth;j++){
  18. yIdx = i * ImageWidth + j;
  19. vIdx = (i/2) * (ImageWidth/2) + (j/2);
  20. uIdx = vIdx;
  21. rdif = Table_fv1[vData[vIdx]];
  22. invgdif = Table_fu1[uData[uIdx]] + Table_fv2[vData[vIdx]];
  23. bdif = Table_fu2[uData[uIdx]];
  24. bgr[0] = yData[yIdx] + bdif;
  25. bgr[1] = yData[yIdx] - invgdif;
  26. bgr[2] = yData[yIdx] + rdif;
  27. for (int k = 0;k < 3;k++){
  28. idx = (i * ImageWidth + j) * 3 + k;
  29. if(bgr[k] >= 0 && bgr[k] <= 255)
  30. Dst[idx] = bgr[k];
  31. else
  32. Dst[idx] = (bgr[k] < 0)?0:255;
  33. }
  34. }
  35. }
  36. }

实际转换效果如下: 

上述效果较好。

方法三:

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

http://iyenn.com/rec/327362.html

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

  1. void ConvertYUV420SPToRGB(unsigned char *Src, unsigned char *Dest, int ImageWidth, int ImageHeight)
  2. {
  3. int total = ImageWidth * ImageHeight;
  4. unsigned char *ybase = Src;
  5. unsigned char *ubase = &Src[total];
  6. unsigned int index = 0;
  7. for (int y = 0; y < ImageHeight; y++) {
  8. for (int x = 0; x < ImageWidth; x++) {
  9. //YYYYYYYYVUVU
  10. u_char Y = ybase[x + y * ImageWidth];
  11. u_char U = ubase[y / 2 * ImageWidth + (x / 2) * 2 + 1];
  12. u_char V = ubase[y / 2 * ImageWidth + (x / 2) * 2];
  13. Dest[index++] = cv::saturate_cast(Y + 1.402* (V - 128)); //R
  14. Dest[index++] = cv::saturate_cast(Y - 0.34413 * (U - 128) - 0.71414 * (V - 128)); //G
  15. Dest[index++] = cv::saturate_cast(Y + 1.772 * (U - 128)); //B
  16. }
  17. }
  18. }

 

文章知识点与官方知识档案匹配,可进一步学习相关知识
OpenCV技能树首页概览20473 人正在系统学习中
注:本文转载自blog.csdn.net的Huo的藏经阁的文章"https://blog.csdn.net/weixin_42730667/article/details/97233856"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top