图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别android平台下基于Camera详解NV21(YUV420P)、NV12(YUV420SP)和RGBA、RGB、BGRA、BGR概述NV21参考:https://blog.csdn.net/leixiaohua1020/article/details/50534150https://blog.csdn.net/junzia/article/details/76315120https…

大家好,又见面了,我是你们的朋友全栈君。

音视频实践学习

概述

YUV模型是根据一个亮度(Y分量)和两个色度(UV分量)来定义颜色空间,常见的YUV格式有YUY2、YUYV、YVYU、UYVY、AYUV、Y41P、Y411、Y211、IF09、IYUV、YV12、YVU9、YUV411、YUV420等,其中比较常见的YUV420分为两种:YUV420P和YUV420SP

我们在android平台下使用相机默认图像格式是NV21属于YUV420SP格式

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

YUV采样

YUV 4:4:4采样,每一个Y对应一组UV分量,一个YUV占8+8+8 = 24bits 3个字节。
YUV 4:2:2采样,每两个Y共用一组UV分量,一个YUV占8+4+4 = 16bits 2个字节。
YUV 4:2:0采样,每四个Y共用一组UV分量,一个YUV占8+2+2 = 12bits 1.5个字节。

我们最常见的YUV420P和YUV420SP都是基于4:2:0采样的,所以如果图片的宽为width,高为heigth,在内存中占的空间为width * height * 3 / 2,其中前width * height的空间存放Y分量,接着width * height / 4存放U分量,最后width * height / 4存放V分量

YUV420P(YU12和YV12)格式

YUV420P又叫plane平面模式Y , U , V分别在不同平面,也就是有三个平面,它是YUV标准格式4:2:0,主要分为:YU12和YV12

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

  • YU12格式

android平台下也叫作I420格式,首先是所有Y值,然后是所有U值,最后是所有V值

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

YU12:亮度(行×列) + U(行×列/4) + V(行×列/4)

  • YV12格式

YV12格式YU12基本相同,首先是所有Y值,然后是所有V值,最后是所有U值。只要注意从适当的位置提取U和V值YU12和YV12都可以使用相同的算法进行处理。

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

YV12:亮度Y(行×列) + V(行×列/4) + U(行×列/4)

YU12: YYYYYYYY UUVV    =>    YUV420P
YV12: YYYYYYYY VVUU    =>    YUV420P

YUV模型是根据一个亮度(Y分量)和两个色度(UV分量)来定义颜色空间,常见的YUV格式有YUY2、YUYV、YVYU、UYVY、AYUV、Y41P、Y411、Y211、IF09、IYUV、YV12、YVU9、YUV411、YUV420等,其中比较常见的YUV420分为两种:YUV420P和YUV420SP。

我们在android平台下使用相机默认图像格式是NV21属于YUV420SP格式## YUV420SP(NV21和NV12)格式

YUV420SP格式的图像阵列,首先是所有Y值,然后是UV或者VU交替存储,NV12和NV21属于YUV420SP格式,是一种two-plane模式,即Y和UV分为两个plane,但是UV(CbCr)为交错存储,而不是分为三个平面。

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

  • NV21格式

android手机从摄像头采集的预览数据一般都是NV21,存储顺序是先存Y,再VU交替存储,NV21存储顺序是先存Y值,再VU交替存储:YYYYVUVUVU,以 4 X 4 图片为例子,占用内存为 4 X 4 X 3 / 2 = 24 个字节

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

  • NV12格式

NV12与NV21类似,也属于YUV420SP格式,NV12存储顺序是先存Y值,再UV交替存储:YYYYUVUVUV,以 4 X 4 图片为例子,占用内存为 4 X 4 X 3 / 2 = 24 个字节

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

注意:在DVD中,色度信号被存储成Cb和Cr(C代表颜色,b代表蓝色,r代表红色)

NV12: YYYYYYYY UVUV    =>YUV420SP
NV21: YYYYYYYY VUVU    =>YUV420SP

YUV和RGB转换

Y      =  (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
Cr = V =  (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128

B = 1.164(Y - 16) + 2.018(U - 128)
G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
R = 1.164(Y - 16) + 1.596(V - 128)

分离YUV420P

下面基于实例来理解Y,U,V分量的作用

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

先使用ffmpeg将指定的图片转为yuv420p格式

ffmpeg -i input.jpg -s 510x510 -pix_fmt yuv420p input.yuv
  • 分离YUV分量

笔者使用的Clion直接运行下面这段代码,分离出所需的文件

void split_yuv420(char *inputPath, int width, int height) { 
   

    FILE *fp_yuv = fopen(inputPath, "rb+");

    FILE *fp_y = fopen("output_420_y.y", "wb+");
    FILE *fp_u = fopen("output_420_u.y", "wb+");
    FILE *fp_v = fopen("output_420_v.y", "wb+");

    unsigned char *data = (unsigned char *) malloc(width * height * 3 / 2);

    fread(data, 1, width * height * 3 / 2, fp_yuv);
    //Y
    fwrite(data, 1, width * height, fp_y);
    //U
    fwrite(data + width * height, 1, width * height / 4, fp_u);
    //V
    fwrite(data + width * height * 5 / 4, 1, width * height / 4, fp_v);

    //释放资源
    free(data);

    fclose(fp_yuv);
    fclose(fp_y);
    fclose(fp_u);
    fclose(fp_v);
}

笔者使用的是ubuntu系统,因此运行yuvplayer.exe文件,需要提前安装好winesudo apt install wine,运行yuvplayer之后,需要先设置像素格式为Y,否则你看到的图像可能会有问题

先看output_420_y.y文件:(分辨率设置为510×510)

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

output_420_u.y显示如下:(分辨率设置为255×255)

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

output_420_v.y显示如下:(分辨率设置为255×255)

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

  • 生成灰度图

上面的例子实际上已经生成了一个灰度图了,但是只保留了Y分量,你如果直接用ffplay工具查看会有问题,下面的函数将会生成一个标准的YUV文件并且保留Y分量,你可能会有疑问,为什么U分量和V分量要写入0x80,其实你可以参考上面的YUV转RGB的公式,YUV数据是无法直接显示的,最终需要转成RGB显示,因此我这里是只需要保留Y分量,忽略UV分量的影响,因此根据上面的公式,我在U和V分量中都写入128就是十六进制的0x80

  • 保留Y分量(生成灰度图)
void yuv420p_y(char *inputPath, char *outputPath, int width, int height) { 
   

    FILE *inFile = fopen(inputPath, "rb+");
    FILE *outFile = fopen(outputPath, "wb+");

    unsigned char *data = (unsigned char *) malloc(width * height * 3 / 2);

    fread(data, 1, width * height * 3 / 2, inFile);

    //Y分量
    fwrite(data, 1, width * height, outFile);

    unsigned char *buffer = (unsigned char *) malloc(width * height / 4);
    memset(buffer, 0x80, width * height / 4);
    //U分量
    fwrite(buffer, 1, width * height / 4, outFile);
    //V分量
    fwrite(buffer, 1, width * height / 4, outFile);

    free(buffer);
    free(data);
    fclose(inFile);
    fclose(outFile);
}
int main() { 
   

    yuv420p_y("/home/byhook/media/input.yuv", "/home/byhook/media/output.yuv", 510, 510);

    return 0;
}

使用ffplay来播放yuv格式的文件:

ffplay -f rawvideo -video_size 510x510 output.yuv

要注意这里的分辨率不能错

图解YU12、I420、YV12、NV12、NV21、YUV420P、YUV420SP、YUV422P、YUV444P的区别

分离YUV422P

YUV422P基于YUV 4:2:2采样,每两个Y共用一组UV分量,一个YUV占8+4+4 = 16bits 2个字节。分离代码如下:

void split_yuv422(char *inputPath, int width, int height) { 
   

    FILE *fp_yuv = fopen(inputPath, "rb+");

    FILE *fp_y = fopen("output_422_y.y", "wb+");
    FILE *fp_u = fopen("output_422_u.y", "wb+");
    FILE *fp_v = fopen("output_422_v.y", "wb+");

    unsigned char *data = (unsigned char *) malloc(width * height * 2);

    fread(data, 1, width * height * 2, fp_yuv);
    //Y
    fwrite(data, 1, width * height, fp_y);
    //U
    fwrite(data + width * height, 1, width * height / 2, fp_u);
    //V
    fwrite(data + width * height * 3 / 2, 1, width * height / 2, fp_v);

    //释放资源
    free(data);

    fclose(fp_yuv);
    fclose(fp_y);
    fclose(fp_u);
    fclose(fp_v);
}

分离YUV444P

YUV444P基于YUV 4:4:4采样,每一个Y对应一组UV分量,一个YUV占8+8+8 = 24bits 3个字节。分离代码如下:

void split_yuv444(char *inputPath, int width, int height) { 
   

    FILE *fp_yuv = fopen(inputPath, "rb+");

    FILE *fp_y = fopen("output_444_y.y", "wb+");
    FILE *fp_u = fopen("output_444_u.y", "wb+");
    FILE *fp_v = fopen("output_444_v.y", "wb+");

    unsigned char *data = (unsigned char *) malloc(width * height * 3);

    fread(data, 1, width * height * 3, fp_yuv);
    //Y
    fwrite(data, 1, width * height, fp_y);
    //U
    fwrite(data + width * height, 1, width * height, fp_u);
    //V
    fwrite(data + width * height * 2, 1, width * height, fp_v);

    //释放资源
    free(data);

    fclose(fp_yuv);
    fclose(fp_y);
    fclose(fp_u);
    fclose(fp_v);
}

参考:
https://blog.csdn.net/leixiaohua1020/article/details/50534150
https://en.wikipedia.org/wiki/YUV

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/160223.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • murmurhash算法_MurmurHash与随机数

    murmurhash算法_MurmurHash与随机数unsignedintmurMurHash(constvoid*key,intlen){constunsignedintm=0x5bd1e995;constintr=24;constintseed=97;unsignedinth=seed^len;//Mix4bytesatatimeintothehashconstunsigne…

    2022年10月18日
    4
  • Pycharm如何上传、更新本地代码到github[通俗易懂]

    Pycharm如何上传、更新本地代码到github[通俗易懂]原文:https://blog.csdn.net/zhaiyujia15195383763/article/details/87773771文章目录一、Pycharm上传本地代码到github1、点击左上角的File,选择Settings,然后选择VersionControl,点击出现的GitHub,点击“Addacco…

    2022年8月29日
    7
  • github开源可视化_可视化拖拽项目管理 github

    github开源可视化_可视化拖拽项目管理 githubGIT下载:国内太慢甚至下载不了的解决方法。在淘宝的镜像网站上下载: https://npm.taobao.org/mirrors/git-for-windows/gitconfig

    2022年8月2日
    9
  • 中国地图china.js[通俗易懂]

    中国地图china.js[通俗易懂]中国地图china.js一、简介中国地图china是基于echarts.js和china.js绘制图像。官方已不支持china.js下载china.js:https://static.delebug.com/echarts/china.js二、配置项//china.js的配置项与echarts基本图形配置项相通//关于echarts基本图形配置参考:https://echarts.apache.org/v4/zh/option.html//其中china地图主要配置不同处在seri

    2022年7月20日
    25
  • 十大经典武侠小说[通俗易懂]

    孤枕侧畔,一灯如豆,看尽万千红尘旧事刀枪入梦,剑气漫天,重温多少江湖恩仇    一说起武侠小说,每个像我这么大的男性或是比我小一些的男性都会眉飞色舞的侃上半天,仿佛每个人都是此中高手,但是武侠小说浩如烟海,能称得上作家的也多如牛毛,故高手或是低手之分并不在于看得多少,而在于精的程度。我之所以谈起这些来就不由得总是有些洋洋自得,便是因为我觉得自己看武侠小说既精又多,称得上此中高手,所

    2022年4月17日
    126
  • jsonobject详解_object转json字符串

    jsonobject详解_object转json字符串JSON(JavaScriptObjectNotation的首字母缩写)是一种轻量级数据交换格式,最常用于客户端-服务器通信。它既易于读/写,又与语言无关。JSON值可以是另一个JSON对象,数组,数字,字符串,布尔值(true/false)或null。也是后端开发中经常要接触的一个一个类,将要数据封装成json然后传递给前端。只要我们导入如下maven依赖即可使用由阿里巴巴发布的…

    2022年9月22日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号