YUV420P旋转

YUV420与YUV420P

YUV 和我们熟知的 RGB 类似,是一种颜色编码格式。它主要用于电视系统和模拟视频邻域(如 Camera 系统)。

YUV 包含三个分量,其中 Y 表示明亮度(Luminance 或 Luma),也就是灰度值。而 U 和 V 则表示色度(Chrominance 或 Chroma),作用是描述图像色彩及饱和度,用于指定像素的颜色。没有 UV 分量信息,一样可以显示完整的图像,只不过是黑白的灰度图像。YUV 格式的好处是很好地解决了彩色电视机与黑白电视机的兼容问题。而且 YUV 不像 RGB 那样要求三个独立的视频信号同时传输,所以用 YUV 方式传送占用极少的频宽。

YUV 格式包含两大类,分别为 planar 和 packed:
1)对于 planar 格式,先连续存储所有像素点的 Y 分量,紧接着存储所有像素点的 U 分量,最后是所有像素点的 V 分量;
2)对于 packed 格式,和 planar 格式一样,也是先连续存储所有像素点的 Y 分量,紧接着存储所有像素点的 UV 分量。不同的是,UV 分量是交替存放的。

在 YUV420 中,一个像素点对应一个 Y 分量,一个 2x2 的小方块对应一个 U 和 V,上面两种格式的 Y 值在排列是完全相同的(只有 Y 的图像就是灰度图像)。

420p 它是先存放完 U 分量,再存放 V 放量,也就是说他们的 UV 分量是连续的。

假设原始图像的宽度和高度分别使用 w 和 h 表示,旋转前的图像尺寸是 wh,旋转后的图像尺寸是 hw,旋转前后图像大小保持不变。对于 YUV420p 数据格式,其数据在内存中安排如下:
图像占用的内存空间大小: w * h * 3 / 2;
1)Y 分量占用的内存大小为 w * h,从内存起始位置开始存放;
2)Y 分量中每个 2x2 的小方块对应一个 U 和 V;
3)U 分量大小为 (w/2)(h/2),存放的位置从图像的 w * h 偏移位置开始;
4)V 分量大小为 (w/2)
(h/2),存放的位置从图像的 w * h + (w * h)/4 偏移位置开始。

YUV420p 格式

这些数据在内存中是线性存储的。当使用图片浏览器显示的是时候需要指定它们的尺寸(宽度和高度),否则不能正确显示。例如,40x30 和 20x60 这两张图像的像素点的个数相同,但如果把 40x30 的图像按照 20x60 的图像来显示,就会出现显示异常。
在这里插入图片描述

YUV420p 旋转 90 度

把 YUV420p 的图像顺时针旋转 90 度后,Y 分量在内存中存放如下图所示,随后是连续的 U 分量 和 V 分量。
在这里插入图片描述
旋转步骤如下,把图像看作是一个类似 image[w][h] 的二维数组。
1)先处理 Y 分量,原始图像的第一个像素位置为 (h-1)*w,旋转后的目标位置为 (0, 0);第二个像素位置为 (h-2)*w,旋转后的目标位置为 (0, 1),以此类推;
2)接下来处理 U 分量,U 和 V 分量的大小都为 (w/2)*(h/2)。原图的第一个像素位置为 (w*h)+(((h/2)-1)*(w/2)),旋转后的目标位置为(w*h)+(0, 0);第二个像素位置为 (w*h)+(((h/2)-2)*(w/2)),旋转后的目标位置为 (w*h)+(0, 1),以此类推;
3)最后处理 V 分量。原图的第一个像素位置为 (w*h)+(w*h/4)+(((h/2)-1)*(w/2)),旋转后的目标位置为 (w*h)+(w*h/4)+(0, 0);第二个像素位置为 (w*h)+(w*h/4)+(((h/2)-2)*(w/2)),旋转后的目标位置为 (w*h)+(w*h/4)+(0, 1),以此类推。

void YUV420p_Rotate_90(BYTE* &des, BYTE* &src, int width, int height)
{
    
    
    int n = 0;
    int wh = width * height;
    //y
    for (int j = 0; j < width; j++)
    {
    
    
        for(int i = height - 1; i >= 0; i--)
        {
    
    
            des[n++] = src[width * i + j];
        }
    }
    //u
    for (int i = 0; i < width / 2; i++)
    {
    
    
        for (int j = 1; j <= height / 2; j++)
        {
    
    
            des[n++] = src[wh + ((height/2 - j) * (width / 2) + i)];
        }
    }
    //v
    for(int i = 0; i < width / 2; i++)
    {
    
    
        for(int j = 1; j <= height / 2; j++)
        {
    
    
            des[n++] = src[wh + wh / 4 + ((height / 2 - j) * (width / 2) + i)];
        }
    }
}

YUV420p 旋转 180 度

void YUV420p_Rotate_180(BYTE* &des, BYTE* &src, int width, int height)
{
    
    
    int n = 0;
    int hw = width / 2;
    int hh = height / 2;
    //copy y
    for(int j = height - 1; j >= 0; j--)
    {
    
    
        for(int i = width; i > 0; i--)
        {
    
    
            des[n++] = src[width*j + i];
        }
    }

    //copy u
    BYTE *ptemp = src + width * height;
    for(int j = hh - 1;j >= 0; j--)
    {
    
    
        for(int i = hw; i > 0; i--)
        {
    
    
            des[n++] = ptemp[hw * j + i];
        }
    }

    //copy v
    ptemp += width * height / 4;
    for(int j = hh - 1;j >= 0; j--)
    {
    
    
        for(int i = hw; i > 0; i--)
        {
    
    
            des[n++] = ptemp[hw * j + i];
        }
    }
}

YUV420p 旋转 270 度

void YUV420p_Rotate_270(BYTE* &des, BYTE* &src, int width, int height)
{
    
    
    int n = 0;
    int hw = width / 2;
    int hh = height / 2;
    //copy y
    for(int j = width; j > 0; j--)
    {
    
    
        for(int i = 0; i < height;i++)
        {
    
    
            des[n++] = src[width*i + j];
        }
    }

    //copy u
    BYTE *ptemp = src + width * height;
    for(int j = hw; j > 0;j--)
    {
    
    
        for(int i = 0; i < hh;i++)
        {
    
    
            des[n++] = ptemp[hw * i + j];
        }
    }

    //copy v
    ptemp += width * height / 4;
    for(int j = hw; j > 0;j--)
    {
    
    
        for(int i = 0; i < hh;i++)
        {
    
    
            des[n++] = ptemp[hw * i + j];
        }
    }
}

YUV420p 水平镜像

void YUV420p_Flip_Horizontal(BYTE* &des, BYTE* &src, int width, int height)  
{
    
      
    int n = 0;  
    int hw = width / 2;  
    int hh = height / 2;  
    //copy y  
    for(int j = 0; j < height; j++)  
    {
    
      
        for(int i = width - 1;i >= 0;i--)  
        {
    
      
            des[n++] = src[width * j + i];  
        }  
    }  
  
    //copy u  
    BYTE *ptemp = src + width * height;  
    for(int j = 0; j < hh; j++)  
    {
    
      
        for(int i = hw - 1;i >= 0;i--)  
        {
    
      
            des[n++] = ptemp[hw * j + i];  
        }  
    }  
      
    //copy v  
    ptemp += width * height / 4;  
    for(int j = 0; j < hh; j++)  
    {
    
      
        for(int i = hw - 1;i >= 0;i--)  
        {
    
      
            des[n++] = ptemp[hw * j + i];  
        }  
    }  
}  

YUV420p 垂直镜像

void YUV420p_Flip_Vertical(BYTE* &des, BYTE* &src, int width, int height)  
{
    
      
    int n = 0;  
    int hw = width / 2;  
    int hh = height / 2;  
    //copy y  
    for(int j = 0; j < width;j++)  
    {
    
      
        for(int i = height - 1; i >= 0;i--)  
        {
    
      
            des[n++] = src[width * i + j];  
        }  
    }  
  
    //copy u  
    BYTE *ptemp = src + width * height;  
    for(int j = 0; j < hw; j++)  
    {
    
      
        for(int i = hh - 1; i >= 0;i--)  
        {
    
      
            des[n++] = ptemp[ hw * i + j];  
        }  
    }  
  
    //copy v  
    ptemp += width * height / 4;  
    for(int j = 0; j < hw; j++)  
    {
    
      
        for(int i = hh - 1; i >= 0; i--)  
        {
    
      
            des[n++] = ptemp[ hw * i + j];  
        }  
    }  
}  

原始图片

在这里插入图片描述

旋转后的图片

在这里插入图片描述

打印yuv420p

uint8_t* pData = new uint8_t [width*height*3/2];
YUV420p_Rotate_90(pData, *_decodeO.ppData, width, height);

FILE *file4 = fopen("/mnt/WebShare/Media/DST/yuvv4.yuv", "wb");
fwrite(pData, _decodeO.nWidth*_decodeO.nHeight*3/2, 1, file4);
fclose(file4);

delete [] pData;
pData = nullptr;

猜你喜欢

转载自blog.csdn.net/qq_36314864/article/details/120312544
今日推荐