YUV图像格式转换方法实践
一 I420转NV12
1.I420格式
(1)I420是每四个Y共用一组UV,如果一帧I420图像宽带是width,高度是height,1个像素占1个字节,那么共有width✖height个Y,U和V都是width✖height / 4个,因此一帧I420图像占用字节数是width✖height✖3/2。
(2)I420是先存完所有Y后,在接着存完U,最后存V。
2.NV12格式
(1)NV12是每四个Y共用一组UV,如果一帧NV12图像宽带是width,高度是height,1个像素占1个字节,那么共有width✖height个Y,U和V都是width✖height / 4个,因此一帧I420图像占用字节数是width✖height✖3/2。
(2)NV12是先存完所有Y后,随后U、V交替存储。
3.转换方法
(1)将一帧I420图像中所有Y拷贝到NV12数据区,将一帧I420图像中所有U和V交替拷贝到NV12数据区。
(2)代码:
bool convert_i420_nv12(const char *i420_file_path, size_t width, size_t height, const char *nv12_file_path) {if (!i420_file_path || !nv12_file_path) {return false;}FILE *fp = fopen(i420_file_path, "rb");if (!fp) {return false;}fseek(fp, 0, SEEK_END);size_t file_size = ftell(fp);fseek(fp, 0, SEEK_SET);size_t y_size = width * height;size_t uv_size = y_size / 4;if (file_size != (y_size + uv_size * 2)) {fclose(fp);return false;}char *i420_content = (char *)malloc(sizeof(char) * file_size);if (!i420_content) {fclose(fp);return false;}if (file_size != fread(i420_content, 1, file_size, fp)) {free(i420_content);fclose(fp);return false;}fclose(fp);// convert i420 to nv12char *nv12_content = (char *)malloc(sizeof(char) * file_size);if (!nv12_content) {free(i420_content);return false;}// copy y channelmemcpy(nv12_content, i420_content, y_size);// copy uv channelchar *i420_u_base = i420_content + y_size;char *i420_v_base = i420_u_base + uv_size;char *nv12_uv_base = nv12_content + y_size;int i = 0, j = 0;for (;i < uv_size;i++) {nv12_uv_base[j] = i420_u_base[i];nv12_uv_base[j + 1] = i420_v_base[i];j += 2;}free(i420_content);fp = fopen(nv12_file_path, "wb");if (!fp) {free(nv12_content);return false;}if (file_size != fwrite(nv12_content, 1, file_size, fp)) {free(nv12_content);fclose(fp);return false;}free(nv12_content);fclose(fp);return true;
}
二 I420转NV21
1.NV21格式
NV21内存布局基本与NV12类似,只是将NV12中U和V次序互换,如下所示:
2.转换代码
bool convert_i420_nv21(const char *i420_file_path, size_t width, size_t height, const char *nv21_file_path) {if (!i420_file_path || !nv21_file_path) {return false;}FILE *fp = fopen(i420_file_path, "rb");if (!fp) {return false;}fseek(fp, 0, SEEK_END);size_t file_size = ftell(fp);fseek(fp, 0, SEEK_SET);size_t y_size = width * height;size_t uv_size = y_size / 4;if (file_size != (y_size + uv_size * 2)) {fclose(fp);return false;}char *i420_content = (char *)malloc(sizeof(char) * file_size);if (!i420_content) {fclose(fp);return false;}if (file_size != fread(i420_content, 1, file_size, fp)) {free(i420_content);fclose(fp);return false;}fclose(fp);// convert i420 to nv21char *nv21_content = (char *)malloc(sizeof(char) * file_size);if (!nv21_content) {free(i420_content);return false;}// copy y channelmemcpy(nv21_content, i420_content, y_size);// copy uv channelchar *i420_u_base = i420_content + y_size;char *i420_v_base = i420_u_base + uv_size;char *nv21_uv_base = nv21_content + y_size;int i = 0, j = 0;for (;i < uv_size;i++) {nv21_uv_base[j] = i420_v_base[i];nv21_uv_base[j + 1] = i420_u_base[i];j += 2;}free(i420_content);fp = fopen(nv21_file_path, "wb");if (!fp) {free(nv21_content);return false;}if (file_size != fwrite(nv21_content, 1, file_size, fp)) {free(nv21_content);fclose(fp);return false;}free(nv21_content);fclose(fp);return true;
}
三 UYVY转NV12
1.UYVY格式
(1)UYVY是每两个Y共用一组UV,如果一帧UYVY图像宽带是width,高度是height,1个像素占1个字节,那么共有width✖height个Y,U和V都是width✖height / 2个,因此一帧I420图像占用字节数是width✖height✖2。
(2)UYVY是每4个像素中,2个Y共用一组UV,一行像素数是width * 2,如下所示:
2.转换方法
(1)将一帧UYVY图像中所有Y存入NV12图像的缓存区,隔行存入相应的U和V,如下所示:
(2)转换代码:
bool convert_uyvy_nv12(const char *uyvy_file_path, size_t width, size_t height, const char *nv12_file_path) {if (!uyvy_file_path || !nv12_file_path) {return false;}FILE *fp = fopen(uyvy_file_path, "rb");if (!fp) {return false;}fseek(fp, 0, SEEK_END);size_t file_size = ftell(fp);fseek(fp, 0, SEEK_SET);size_t frame_size = width * height * 2;if (file_size != frame_size) {fclose(fp);return false;}char *uyvy_content = (char *)malloc(sizeof(char) * file_size);if (!uyvy_content) {fclose(fp);return false;}if (file_size != fread(uyvy_content, 1, file_size, fp)) {free(uyvy_content);fclose(fp);return false;}fclose(fp);// convert uyvy to nv12frame_size = width * height * 3 / 2;char *nv12_content = (char *)malloc(sizeof(char) * frame_size);if (!nv12_content) {free(uyvy_content);return false;}size_t y_size = width * height;size_t pixels_in_a_row = width * 2;char *nv12_y_ptr = nv12_content;char *nv12_uv_ptr = nv12_content + y_size;int lines = 0;for (int i = 0;i < file_size;i += 4) {// copy y channel*nv12_y_ptr++ = uyvy_content[i + 1];*nv12_y_ptr++ = uyvy_content[i + 3];if (0 == i % pixels_in_a_row) {++lines;}if (lines % 2) { // extract the UV value of odd rows// copy uv channel*nv12_uv_ptr++ = uyvy_content[i];*nv12_uv_ptr++ = uyvy_content[i + 2];}}free(uyvy_content);fp = fopen(nv12_file_path, "wb");if (!fp) {free(nv12_content);return false;}if (frame_size != fwrite(nv12_content, 1, frame_size, fp)) {free(nv12_content);fclose(fp);return false;}free(nv12_content);fclose(fp);return true;
}
四 UYVY转NV21
方法与转NV12类似,代码如下:
bool convert_uyvy_nv21(const char *uyvy_file_path, size_t width, size_t height, const char *nv21_file_path) {if (!uyvy_file_path || !nv21_file_path) {return false;}FILE *fp = fopen(uyvy_file_path, "rb");if (!fp) {return false;}fseek(fp, 0, SEEK_END);size_t file_size = ftell(fp);fseek(fp, 0, SEEK_SET);size_t frame_size = width * height * 2;if (file_size != frame_size) {fclose(fp);return false;}char *uyvy_content = (char *)malloc(sizeof(char) * file_size);if (!uyvy_content) {fclose(fp);return false;}if (file_size != fread(uyvy_content, 1, file_size, fp)) {free(uyvy_content);fclose(fp);return false;}fclose(fp);// convert uyvy to nv12frame_size = width * height * 3 / 2;char *nv21_content = (char *)malloc(sizeof(char) * frame_size);if (!nv21_content) {free(uyvy_content);return false;}size_t y_size = width * height;size_t pixels_in_a_row = width * 2;char *nv21_y_ptr = nv21_content;char *nv21_uv_ptr = nv21_content + y_size;int lines = 0;for (int i = 0;i < file_size;i += 4) {// copy y channel*nv21_y_ptr++ = uyvy_content[i + 1];*nv21_y_ptr++ = uyvy_content[i + 3];if (0 == i % pixels_in_a_row) {++lines;}if (lines % 2) { // extract the UV value of odd rows// copy uv channel*nv21_uv_ptr++ = uyvy_content[i + 2];*nv21_uv_ptr++ = uyvy_content[i];}}free(uyvy_content);fp = fopen(nv21_file_path, "wb");if (!fp) {free(nv21_content);return false;}if (frame_size != fwrite(nv21_content, 1, frame_size, fp)) {free(nv21_content);fclose(fp);return false;}free(nv21_content);fclose(fp);return true;
}
五 编译及测试
1.编译:使用g++编译
2.github:GitHub - wangzhicheng2013/common_utility
YUV图像格式转换方法实践相关推荐
- 海康彩色工业相机图像格式转换方法(Bayer转RGB)
海康彩色工业相机图像格式转换方法 1.彩色相机是如何变成彩色的-Bayer的由来 2.工业相机支持的图像格式 3.图像格式转化 4.一些其他的问题 1.彩色相机是如何变成彩色的-Bayer的由来 提到 ...
- YUV图像格式进行的ALPHA BLEND操作
YUV图像格式进行的ALPHA BLEND操作 RGB的alpha blend操作采用如下的公式: 假设 r0 g0 b0 为原始图像的 三个色彩分量, r1 g1 b1 为alpha blend过程 ...
- c语言bmp图像YUV转化成RGB,RGB与YUV图像格式的相互转换
RGB与YUV图像格式的相互转换 (参考上的<RGB与YUV图像视频格式的相互转换>文章,做了些修改) RGB介绍:在记录计算机图像时,最常见的是采用RGB(红.绿,蓝)颜色分量来保存颜色 ...
- RAW、RGB、YUV 图像格式区别
前言 颜色是人的视觉系统对光谱中可见区域的感知效果,它仅存在于人的眼睛和大脑中.为了准确地描述颜色,必须引入色彩空间的概念.正如几何上用坐标空间来描述坐标集合,色彩空间用数学方式来描述颜色集合. 1 ...
- RAW、RGB 、YUV三种图像格式理解
文章目录 1. 背景 2. 相关概念 2.1 颜色与色彩空间 2.2 RAW图像 2.3 RGB图像 2.4 YUV图像 3. 分类简图 RAW.RGB .YUV三种图像格式理解 1. 背景 在工作中 ...
- AOE工程实践-银行卡OCR里的图像处理
AOE工程实践-银行卡OCR里的图像处理 作者:杨科 近期我们开发了一个银行卡 OCR 项目.需求是用手机对着银行卡拍摄以后,通过推理,可以识别出卡片上的卡号. 工程开发过程中,我们发现手机拍摄以后的 ...
- OpenCV YUV 与 RGB的互转(草稿)
YUV 转 RGB cv::Mat yuvImg; /*//下面两行是我自己代码里用来构成YUV图像的数据,可以忽略 yuvImg.create(pInput->height*3/2, pInp ...
- 图像处理 花屏_滴滴开源的 AoE:工程实践中的图像处理
近期,滴滴开源了AOE项目,很多人还是一脸懵逼,不太清楚AOE 到底是干什么的,所以今天我们再来听听官方工程师是怎么介绍的吧,不信你还是听不懂:近期我们开发了一个银行卡 OCR 项目.需求是用手机对着 ...
- Android OpenGL ES 学习(十一) –渲染YUV视频以及视频抖音特效
OpenGL 学习教程 Android OpenGL ES 学习(一) – 基本概念 Android OpenGL ES 学习(二) – 图形渲染管线和GLSL Android OpenGL ES 学 ...
最新文章
- IDEA打包出现Unable to find main class
- 李飞飞下半年或将从 Google离职?李飞飞回应
- 资源盗链困扰站长 安全狗内置盗链保护功能
- 推荐阅读《赢在下班后》
- iOS linker command failed with exit code 1 (use -v to see invocation)多种解决方案汇总
- Error creating bean with name ‘fastJsonpResponseBodyAdvice‘ defined in URL xxx
- Windows 7 正在走 XP 系统的老路
- shell 备份并删除几日内的历史文件
- 精确到门牌号的地图_IP地址精准查询工具:能精确到门牌号
- python爬取豆瓣top250电影名称_Python--爬取豆瓣TOP250电影信息
- 深度学习硬件购买指南
- Golang导出并下载excel封装
- 机器学习代码整理pLSA、BoW、DBN、DNN
- 南京大学2021计算机考研复试线是多少,2021南京大学
- 操作系统——(11)多媒体操作系统
- 如何将优酷KUX格式转换为MP4格式?
- 网页自动刷新的三种方法
- Golang-报错-go get github/xxx
- DP线和HDMI线相比哪个比较好用?
- 使用MPS模型——应对当下全球疫情经济危机互联网寒冬
热门文章
- 单片机自制时钟(年月日星期时分秒显示、按键校准)
- linux u8 u16 u32 u64,C 语言printf打印各种数据类型的方法(u8/s8/u16/s16.../u64/doub
- 提示Microsoft office word 遇到问题需要关闭。还问是否发送错误报告。
- 初识OpenVINO
- 如何以信创软硬件来实现隐私计算的大规模产业化,听听冲量怎么说
- 渝粤题库 陕西师范大学《西方文论》作业
- python爬取百度地图数据_百度地图POI数据爬取
- Lei ❤函数的初识
- Mac磁盘分析工具ncdu使用
- 带双参数的双极S型函数