【音视频数据数据处理 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算法的优化》