一、YUV422SP的存储方式
YUV422SP属于平面格式(Planar),它的 YUYV 格式在内存中的存储方式为:YUYV YUYV YUYV …,Y为亮度信息,UV为色度信息,YUV422 是每两个像素点共用一对UV分量,每个像素点的Y分量是独立的,UV分量是共享的,所以一幅 YUV422 图像的总的字节数为:
totalBytes = Width * Height + Width * Height / 2 + Width * Height / 2 = Width * Height * 2
二、YUV422SP的旋转
YUV422SP是两个Y值共享一组UV,那么旋转后,还得是两个Y值共享一组UV。因此在进行旋转操作是必须满足 YUYV 的结构不变,即4个字节为一组;保证Y分量在相应的位置上,否则会产生颜色不对、锯齿等
三、旋转代码
下述程序是直接粗暴旋转90°,如果是420,可以这样操作,但是这是422,因此旋转得到的yuv图像和原图比较是错误的
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define rotateFile "rotate.yuv"
#define sourceFile "out.yuv"
int main()
{
FILE *file = NULL;
FILE *yuv = NULL;
int imgWidth = 1920;
int imgHeight = 1080;
int i = 0, j = 0;
char filename[64] = {
0};
snprintf(filename, sizeof(filename), rotateFile);
//输出旋转图像
file = fopen(filename, "w");
if (NULL == file)
{
printf("open file(%s) failed!\n", rotateFile);
return 0;
}
//待旋转图像
yuv = fopen(sourceFile, "r");
if (NULL == yuv)
{
printf("open file(%s) failed!\n", sourceFile);
return 0;
}
char *srcimg, *dstimg;
//开辟内存
dstimg = (char *)malloc(imgWidth * imgHeight * 2); //yuv422
if(NULL == dstimg)
{
printf("malloc memory for %s faild!\n", dstimg);
return 0;
}
srcimg = (char *)malloc(imgWidth * imgHeight * 2); //yuv422
if(NULL == srcimg)
{
printf("malloc memory for %s faild!\n", srcimg);
return 0;
}
//读取待旋转图像yuv422数据
if((imgWidth * imgHeight *2) != fread(srcimg, 1, imgWidth * imgHeight * 2, yuv))
{
printf("Read image1 faild!\n");
return -1;
}
//旋转90度
printf("rotate yuv........\n");
for (i = 0; i < imgWidth; i++)
{
for (j = imgHeight - 1; j >= 0; j--)
{
dstimg[i] = srcimg[j * imgWidth + i];
i++;
}
}
//写入文件
for (i = 0; i < imgWidth; i++)
{
fwrite(dstimg, 1, imgWidth*2, file);
dstimg += imgWidth*2;
}
return 0;
}
四、优化点一
如三所示,旋转后使得以前垂直相邻的Y像素点变成了水平相邻,而水平相邻的Y像素点需要共享UV数据,但是旋转前这两个像素点没有任何关系,也就是根本没有这个UV值数据,所以这种粗暴的旋转是错误的。
可以把YUV422的旋转,当做YUV420一样进行旋转,即4个Y值,共享一组UV,这样旋转后,会损失一般的色度值,但是画面不会出错。
四、优化点二
可以先将422转换为420,然后再去旋转90°,这样就不存在422旋转后像素之间没有关系的问题了。
相关文章在本专栏后面几篇文章