【音视频数据数据处理 2】【YUV篇】将YUV420P_I420数据旋转90°-180°-270°-镜像旋转
【音视频数据数据处理 2】【YUV篇】将YUV420P_I420数据旋转90°
- 一、理论分析(以yuv420p_i420格式为例)
- 二、顺时针旋转90° 代码实现
- 三、顺时针旋转180° 代码实现
- 四、旋转90°-180°-270°-镜像旋转,完整代码实现
- 五、运行结果
本文接着前文:
《【音视频数据数据处理 1】【YUV篇】分离YUV420P像素数据中的Y、U、V分量》
一、理论分析(以yuv420p_i420格式为例)
如下,以2x4的源图为例:
而,经过顺时针旋转90度后
取数据时,相当于下面黑色方向的箭头。
本文链接:《【音视频数据数据处理 2】【YUV篇】将YUV420P_I420数据旋转90°-180°-270°-镜像旋转》
二、顺时针旋转90° 代码实现
核心代码如下:
// 顺时针旋转90度
// 格式为:YY YY YY YY ... UU...VV
void Rotate_90_YUV420_I420(char *path, int width, int height)
{int i, j; FILE *file = fopen(path, "rb+"); //只读打开源文件FILE *file_r = fopen("yuv420p_i420_90.y", "wb+"); //可读可写创建 Y分量文件 // 申请 width * hight * 3 / 2 的内存unsigned char *p, *pic = (unsigned char *)malloc(sizeof(char) * width * height * 3 / 2);unsigned char *d, *pic_d = (unsigned char *)malloc(sizeof(char) * width * height * 3 / 2);size_t num=0;num = fread(pic, 1, width*height*3/2, file); // 读取源图片的所有内容,每个数据块为1字节 printf("读取 %d 个字节的数据\n", num); //旋转 Y分量 p = pic;d = pic_d;for(i = 0; i<width; i++)for(j = 0; j<height; j++)*d++ = *(p + i + (height-j)*width); //p[i][height-j];printf("旋转Y分分量完毕 num=%d \n", d-pic_d); // 旋转 U分量p += width * height; for(i = 0; i<width/2; i+=1)for(j = 0; j<height/2; j++){*d++ = *(p + i + (height/2 -j) * width/2); //p[i][height/2-j];}printf("旋转U分分量完毕 num=%d \n", d-pic_d);// 旋转 V分量p += width * height / 4; for(i = 0; i<width/2; i+=1)for(j = 0; j<height/2; j++){*d++ = *(p + i + (height/2 -j) * width/2); //p[i][height/2-j];}printf("旋转V分分量完毕 num=%d \n", d-pic_d);// 写入旋转后的图 num = fwrite(pic_d, 1, width * height *3 / 2, file_r); // 保存Y分量,pic[0, width*height] ,每个数据块写1字节 printf("写入 %d 个字节的数据\n", num); free(pic);free(pic_d);fclose(file);fclose(file_r);
}
运行结果如下
三、顺时针旋转180° 代码实现
// 顺时针旋转180度
// 格式为:YY YY YY YY ... UU...VV
void Rotate_180_YUV420_I420(char *path, int width, int height)
{int i, j; FILE *file = fopen(path, "rb+"); //只读打开源文件FILE *file_r = fopen("yuv420p_i420_180.y", "wb+"); //可读可写创建 Y分量文件 // 申请 width * hight * 3 / 2 的内存unsigned char *p, *pic = (unsigned char *)malloc(sizeof(char) * width * height * 3 / 2);unsigned char *d, *pic_d = (unsigned char *)malloc(sizeof(char) * width * height * 3 / 2);size_t num=0;num = fread(pic, 1, width*height*3/2, file); // 读取源图片的所有内容,每个数据块为1字节 printf("读取 %d 个字节的数据\n", num); //旋转 Y分量 p = pic;d = pic_d;for(i = 0; i<height; i++)for(j = 0; j<width; j++)*d++ = *(p + width-j + (height-i)*width); //p[heidht-i][widht-j];printf("旋转Y分分量完毕 num=%d \n", d-pic_d); // 旋转 U分量p += width * height; for(i = 0; i<height/2; i++)for(j = 0; j<width/2; j++)*d++ = *(p + width/2-j + (height/2-i)*width/2); //p[heidht-i][widht-j];printf("旋转U分分量完毕 num=%d \n", d-pic_d);// 旋转 V分量// 旋转 U分量p += width * height / 4; for(i = 0; i<height/2; i++)for(j = 0; j<width/2; j++)*d++ = *(p + width/2-j + (height/2-i)*width/2); //p[heidht-i][widht-j];printf("旋转V分分量完毕 num=%d \n", d-pic_d);// 写入旋转后的图 num = fwrite(pic_d, 1, width * height *3 / 2, file_r); // 保存Y分量,pic[0, width*height] ,每个数据块写1字节 printf("写入 %d 个字节的数据\n", num); free(pic);free(pic_d);fclose(file);fclose(file_r);
}
四、旋转90°-180°-270°-镜像旋转,完整代码实现
#include <stdio.h>
#include <stdlib.h>// 顺时针旋转 n*90 度
// 格式为:YY YY YY YY ... UU...VV
// path:源图地址 width,height 源图宽高
// rota: 希望旋转的度数
void Rotate_YUV420_I420(char *path, int width, int height, int rota)
{int i, j, num; // 找开源文件 FILE *file_d, *file = fopen(path, "rb+"); //只读打开源文件// 申请 width * hight * 3 / 2 的内存unsigned char *p, *pic = (unsigned char *)malloc(sizeof(char) * width * height * 3 / 2);unsigned char *d, *pic_d = (unsigned char *)malloc(sizeof(char) * width * height * 3 / 2);num = fread(pic, 1, width*height*3/2, file); // 读取源图片的所有内容,每个数据块为1字节 printf("读取 %d 个字节的数据\n", num); // 根据旋转度数,计算switch( rota ){// 镜像旋转0度case 1: // 创建旋转后的文件名 file_d = fopen("yuv420p_i420_0_mirror.yuv", "wb+"); //可读可写创建 Y分量文件 //旋转 Y分量 p = pic;d = pic_d;for(i = 0; i<height; i++)for(j = 0; j<width; j++)*d++ = *(p + width-j + (i)*width); //p[height-j][i]printf("旋转Y分分量完毕 num=%d \n", d-pic_d); // 旋转 U,分量p += width * height; for(i = 0; i<height/2; i++)for(j = 0; j<width/2; j++)*d++ = *(p + width/2-j + (i)*width/2); //p[height-j][i]printf("旋转U分分量完毕 num=%d \n", d-pic_d);// 旋转 V分量p += width * height / 4; for(i = 0; i<height/2; i++)for(j = 0; j<width/2; j++)*d++ = *(p + width/2-j + (i)*width/2); //p[height-j][i]printf("旋转V分分量完毕 num=%d \n", d-pic_d);break; // 90度case 2: // 创建旋转后的文件名 file_d = fopen("yuv420p_i420_90.yuv", "wb+"); //可读可写创建 Y分量文件 //旋转 Y分量 p = pic;d = pic_d;for(i = 0; i<width; i++)for(j = 0; j<height; j++)*d++ = *(p + i + (height-j)*width); //p[height-j][i]printf("旋转Y分分量完毕 num=%d \n", d-pic_d); // 旋转 U,分量p += width * height; for(i = 0; i<width/2; i++)for(j = 0; j<height/2; j++)*d++ = *(p + i + (height/2-j)*width/2); //p[height-j][i]printf("旋转U分分量完毕 num=%d \n", d-pic_d);// 旋转 V分量p += width * height / 4; for(i = 0; i<width/2; i++)for(j = 0; j<height/2; j++)*d++ = *(p + i + (height/2-j)*width/2); //p[height-j][i]printf("旋转V分分量完毕 num=%d \n", d-pic_d);break; // 镜像90度case 3: // 创建旋转后的文件名 file_d = fopen("yuv420p_i420_90_mirror.yuv", "wb+"); //可读可写创建 Y分量文件 //旋转 Y分量 p = pic;d = pic_d;for(i = 0; i<width; i++)for(j = 0; j<height; j++)*d++ = *(p + width-i + (height-j)*width); //p[height-j][i]printf("旋转Y分分量完毕 num=%d \n", d-pic_d); // 旋转 U,分量p += width * height; for(i = 0; i<width/2; i++)for(j = 0; j<height/2; j++)*d++ = *(p + width-i + (height/2-j)*width/2); //p[height-j][i]printf("旋转U分分量完毕 num=%d \n", d-pic_d);// 旋转 V分量p += width * height / 4; for(i = 0; i<width/2; i++)for(j = 0; j<height/2; j++)*d++ = *(p + width-i + (height/2-j)*width/2); //p[height-j][i]printf("旋转V分分量完毕 num=%d \n", d-pic_d);break; // 180度 case 4: // 创建旋转后的文件名 file_d = fopen("yuv420p_i420_180.yuv", "wb+"); //可读可写创建 Y分量文件 //旋转 Y分量 p = pic;d = pic_d;for(i = 0; i<height; i++)for(j = 0; j<width; j++)*d++ = *(p + j + (height-i)*width); //p[height-i][j]printf("旋转Y分分量完毕 num=%d \n", d-pic_d); // 旋转 U,分量p += width * height; for(i = 0; i<height/2; i++)for(j = 0; j<width/2; j++)*d++ = *(p + j + (height/2-i)*width/2); //p[height/2-i][j]printf("旋转U分分量完毕 num=%d \n", d-pic_d);// 旋转 V分量p += width * height / 4; for(i = 0; i<height/2; i++)for(j = 0; j<width/2; j++)*d++ = *(p + j + (height/2-i)*width/2); //p[height/2-i][j]printf("旋转V分分量完毕 num=%d \n", d-pic_d);break; // 旋转270度 case 5: // 创建旋转后的文件名 file_d = fopen("yuv420p_i420_270.yuv", "wb+"); //可读可写创建 Y分量文件 //旋转 Y分量 p = pic;d = pic_d;for(i = 0; i<width; i++)for(j = 0; j<height; j++)*d++ = *(p + width-i + (j)*width); //p[height-j][i]printf("旋转Y分分量完毕 num=%d \n", d-pic_d); // 旋转 U,分量p += width * height; for(i = 0; i<width/2; i++)for(j = 0; j<height/2; j++)*d++ = *(p + width/2-i + (j)*width/2); //p[height-j][i]printf("旋转U分分量完毕 num=%d \n", d-pic_d);// 旋转 V分量p += width * height / 4; for(i = 0; i<width/2; i++)for(j = 0; j<height/2; j++)*d++ = *(p + width/2-i + (j)*width/2); //p[height-j][i]printf("旋转V分分量完毕 num=%d \n", d-pic_d);break; default:if(rota != 0)printf("不支持旋转%d度,当前不旋转\n", rota); // 创建旋转后的文件名 file_d = fopen("yuv420p_i420_0.yuv", "wb+"); //可读可写创建 Y分量文件 // 写入旋转后的图 num = fwrite(pic, 1, width * height *3 / 2, file_d); // 保存Y分量,pic[0, width*height] ,每个数据块写1字节 printf("写入 %d 个字节的数据\n", num); free(pic);free(pic_d);fclose(file);fclose(file_d);return;} // 写入旋转后的图 num = fwrite(pic_d, 1, width * height *3 / 2, file_d); // 保存Y分量,pic[0, width*height] ,每个数据块写1字节 printf("写入 %d 个字节的数据\n", num); free(pic);free(pic_d);fclose(file);fclose(file_d);
}int main(void)
{char path[]="yuv420p_i420.yuv";//Split_YUV420_I420(path, 720, 480);Rotate_YUV420_I420(path,720, 480, 0); // 旋转 0°Rotate_YUV420_I420(path,720, 480, 1); // 镜像旋转 0°Rotate_YUV420_I420(path,720, 480, 2); // 旋转90°Rotate_YUV420_I420(path,720, 480, 3); // 镜像旋转90°Rotate_YUV420_I420(path,720, 480, 4); // 旋转180°Rotate_YUV420_I420(path,720, 480, 5); // 旋转270°return 0;
}
五、运行结果
图片太多,我就放一起显示了:
《视音频数据处理入门:RGB、YUV像素数据处理》
《图文详解YUV420数据格式》
《YUV420图像旋转90算法的优化》
【音视频数据数据处理 2】【YUV篇】将YUV420P_I420数据旋转90°-180°-270°-镜像旋转相关推荐
- iOS音视频的那些事儿(一):数据的采集和编码
1.AVFoundation简介 AVFoundation是苹果在iOS和OS X系统中用于处理基于时间的媒体数据的Objective-C框架. 供使用者来开发媒体类型的应用程序. 如果只是进行简单的 ...
- Android IOS WebRTC 音视频开发总结(六二)-- 大数据解密国外实时通讯行业开发现状...
Android IOS WebRTC 音视频开发总结(六二)-- 大数据解密国外实时通讯行业开发现状 本文主要介绍国外实时通讯行业现状,文章最早发表在我们的微信公众号上,详见这里,欢迎关注微信公众号b ...
- linux摄像头 sdl,Linux音视频(SDL与YUV)
SDL是一个比较底层的音视频处理库,很多UI系统的内核都用到它,我们还可以用它来处理摄像头中YUV数据. 拓展: SDL(Simple DirectMedia Layer)是一个跨平台的底层开发库,提 ...
- 音视频大合集最终篇;学废了
前言 加企鹅群:1079654574 解锁 <音视频八大板块资料> 音视频大合集,从初中高到面试应有尽有;让学习更贴近未来实战.已形成PDF版 八个模块内容如下: 1.音视频基础 2.FF ...
- 音视频 测试分享-基础工具篇
在视频直播 方向的测试经验 想借个机会一起分享下,一起提高大家的测试技术 1.测试工具 ffmpeg-强大工具支撑 验证flv ,mp4 等多媒体信息的工具:ffmporb srs-bench:音视频 ...
- 音视频编码实战-------pcm+yuv数据转成MP4
文章目录 1.编码流程图 2.相关模块及函数 2.1 编码器相关API 2.2 复用器相关API 2.3 重采样相关API 注意点 简单的编码流程相关代码 1.编码流程图 2.相关模块及函数 2.1 ...
- android视频剪辑处理第三方,Android 中通过 FFmpeg 命令对音视频编辑处理
以下文章来源于DevYk ,作者DevYK 音视频编辑器 前言 有时候我们想对音视频进行加工处理,比如视频编辑.添加字幕.裁剪等功能处理,虽然 Github 上开源了一些比较不错的项目,但是如果我们想 ...
- Android 中通过 FFmpeg 命令对音视频编辑处理(已开源)
视音频编辑器 前言 有时候我们想对音视频进行加工处理,比如视频编辑.添加字幕.裁剪等功能处理,虽然 Github 上开源了一些比较不错的项目,但是如果我们想在此项目上进行二次开发,比如我想拿到该项目的 ...
- 音视频数据处理入门:原始视频格式YUV,NV12,NV21,YV12,YU12(I420)
我们知道,在Camera中设置Preview的回调函数onPreviewFrame时谷歌推荐我们使用NV21,YV12两种格式,因为这两种格式几乎在所有的设备里都通用.然而,视频的格式远远不止这俩种, ...
- webRTC(四):Webrtc音视频数据采集录制采集屏面数据
WebRTC音视频数据采集 var constraints={video: true,audio: true,}navigator.mediaDevices.getUserMedia(constrai ...
最新文章
- pods install 无法安装库
- Java中的main()方法详解
- 蚂蚁金服张洁:基于深度学习的支付宝人脸识别技术解秘-1
- Android自定义Dialog及与Activity的交互
- docker查看容器并运行
- 基于Python的电子教室软件中远程关机功能的原理与实现
- vs code c语言json文件配置,解析VScode在Windows环境下c_cpp_properties.json文件配置问题(推荐)...
- nodejs首个框架开发(先只发个连接,有空再写)
- Wunderlist – 免费同步 Todo List
- 免费批量化音频切割软件 AutoVoiceCut
- 原神角色展示(HTML+CSS)
- 手把手教你怎么从微软官方下载 Windos10 正版镜像
- 【JS】446- 你不知道的 map
- c++的构造函数赋值函数重载运算符等
- 海康威视网络摄像头购买指南(焦距像素等参数)
- v-show和v-if有什么区别?使用场景分别是什么?
- 小傻蛋的妹妹跟着小甲鱼学习Python的第七节007
- 怪物农场2修改日志3 - 年轮
- html5几张图片怎么并排一行_html5 图片与文字中间对齐处于同一行、或者图片与按钮处于同一行...
- RT-Thread_rt_kprintf()打印浮点数(解决方法2:添加rt_vsnprintf_full)