数据压缩实验报告一

RGB24和YUV420

RGB24简介

RGB24使用24位来表示一个像素,RGB分量都用8位表示,取值范围为0-255。注意在内存中RGB各分量的排列顺序为:BGR BGR BGR…。通常可以使用RGBTRIPLE数据结构来操作一个像素,它的定义为:

typedef struct tagRGBTRIPLE {
BYTE rgbtBlue; // 蓝色分量
BYTE rgbtGreen; // 绿色分量
BYTE rgbtRed; // 红色分量
} RGBTRIPLE;

YUV420简介

1.YUV定义:
“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。YUV 的优点之一是,色度频道的采样率可比 Y 频道低,同时不会明显降低视觉质量。
2.YUV 4:2:0采样
色度格式4:2:0 表示 2:1 的水平下采样,2:1 的垂直下采样。4:2:0 采样有两种常见的变化形式。其中一种形式用于 MPEG-2 视频,另一种形式用于 MPEG-1 以及 ITU-T recommendations H.261 和 H.263。图 1 显示了 MPEG-1 方案中使用的采样网格,图 2 显示了 MPEG-2 方案中使用的采样网格。
图1
图2
3.YUV格式通常有两大类:
打包(packed)格式:将YUV分量存放在同一个数组中,通常是几个相邻的像素组 成一个宏像素(macro-pixel);
平面(planar)格式:使用三个数组分开存放YUV三个分量,就像是一个三维平面一样。
而YUV420 是一种planar数据存储, 以720×488大小图象YUV420 planar为例,其存储格式是: 共大小为(720×480×3>>1)字节,分为三个部分: Y分量720×480)个字节,U(Cb)分量(720×480>>2)个字节,V(Cr)分量(720×480>>2)个字节 。三个部分内部均是行优先存储,三个部分之间是Y,U,V 顺序存储。

实验原理

1.YUV420数据的存储格式(见上)
2.RGB转YUV公式
YUV(256 级别) 可以从8位 RGB 直接计算:
Y = 0.299 R + 0.587 G + 0.114 B
U = - 0.1687 R - 0.3313 G + 0.5 B + 128
V = 0.5 R - 0.4187 G - 0.0813 B + 128
反过来,RGB 也可以直接从YUV (256级别) 计算:
R = Y + 1.402 (Cr-128)
G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
B = Y + 1.772 (Cb-128)
在代码中各个公式多+0.5是为了四舍五入的操作

RGB转换成YUV代码实现



#include <stdio.h>

#include<stdlib.h>

#include<malloc.h>

#include<math.h>

constexpr auto width = 256;

constexpr auto height = 256;

 
#define MY(a,b,c) (( a*  0.2989 + b*  0.5866  + c* 0.1145) + 0.5)

#define MU(a,b,c) (( a*(-0.1688) +b*(-0.3312) + c*  0.5000 + 128 + 0.5))

#define MV(a,b,c) (( a*  0.5000 + b*(-0.4184) + c*(-0.0816) + 128 + 0.5))

#define DY(a,b,c) (MY(a,b,c) > 255 ? 255: (MY(a,b,c) < 0 ? 0 : MY(a,b,c)))

#define DU(a,b,c) (MU(a,b,c) > 255 ? 255: (MU(a,b,c) < 0 ? 0 : MU(a,b,c)))

#define DV(a,b,c) (MV(a,b,c) > 255 ? 255: (MV(a,b,c) < 0 ? 0 : MV(a,b,c)))


int main(int argc, char* argv[])

{

   
FILE* rgbFile = NULL;

FILE* yuvFile = NULL;

  
//打开rgb图像

   
errno_t err;

   
err = fopen_s(&rgbFile, argv[1], "rb");

   
if (err == 0)

    {

       printf("打开rgb文件成功!\n");

    }

   
else printf("打开rgb文件失败!\n");

 

   
err = fopen_s(&yuvFile, "down2.yuv", "wb");

   
if (err == 0)

    {

       printf("打开yuv文件成功!\n");

    }

   
else printf("打开yuv文件失败!\n");

 

   
//分配动态内存

   
unsigned char* RGB = NULL;

unsigned char* yBuff = NULL;

unsigned char* uBuff = NULL;

unsigned char* vBuff= NULL;

unsigned int imgSize = width * height;

   
RGB = (unsigned char*)malloc(sizeof(unsigned char) * imgSize * 3);

   
yBuff = (unsigned char*)malloc(sizeof(unsigned char) * imgSize);

   
uBuff = (unsigned char*)malloc(sizeof(unsigned char) * imgSize / 4);

   
vBuff = (unsigned char*)malloc(sizeof(unsigned char) * imgSize / 4);

 

   
fread(RGB, sizeof(unsigned char), 3 * width * height, rgbFile);

   

   
for (int i = 0; i < width * height; i++)

    {

       yBuff[i] = (unsigned char)(DY(RGB[3 * i + 2], RGB[3 * i + 1], RGB[3 *i]));

    }

   
int k = 0;

   
for (int i = 0; i < height; i++)

    {

           for (int j = 0; j < width; j++)

           {

                if (i % 2 == 0 && j % 2== 0)

                {

                    uBuff[k] = (unsigned char)(DU(RGB[3 * (width * i + j) + 2], RGB[3 * (width * i + j) + 1], RGB[3 *(width * i + j)]));

                    vBuff[k] = (unsigned char)(DV(RGB[3 * (width * i + j) + 2], RGB[3 * (width * i + j) + 1], RGB[3 *(width * i + j)]));

                    k++;

                }

           }

    }

    

   
fwrite(yBuff, sizeof(unsigned char),imgSize, yuvFile);

   
fwrite(uBuff, sizeof(unsigned char), imgSize / 4, yuvFile);

   
fwrite(vBuff, sizeof(unsigned char), imgSize / 4, yuvFile);

   
if(RGB!=NULL)  

       
free(RGB);

   
if (yBuff != NULL)

       
free(yBuff);

   
if (uBuff != NULL)

       
free(uBuff);

   
if (vBuff != NULL)

       
free(vBuff);

  

   
if (rgbFile != NULL)

       
fclose(rgbFile);

   
if (yuvFile != NULL)

       
fclose(yuvFile);

return 0;

}

YUV转换成RGB代码实现



#include <iostream>

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>

#include <math.h>

constexpr auto width = 256;

constexpr auto height = 256;

 

#define MB(a,b,c) (( a + 1.722*(b-128) + 0.5))

#define MG(a,b,c) (( a  - 0.34413*(b-128) - 0.71414*(c-128)+0.5))

#define MR(a,b,c) (( a + 1.4075*(c-128)+0.5))

 

#define DB(a,b,c) (MB(a,b,c) > 255 ? 255: (MB(a,b,c) < 0 ? 0 : MB(a,b,c)))

#define DG(a,b,c) (MG(a,b,c) > 255 ? 255: (MG(a,b,c) < 0 ? 0 : MG(a,b,c)))

#define DR(a,b,c) (MR(a,b,c) > 255 ? 255: (MR(a,b,c) < 0 ? 0 : MR(a,b,c)))



int main(int argc, char* argv[])

{

   
FILE* yuvFile;

   
FILE* rgbFile;

   
unsigned char* YUV;

   
unsigned char* RGB;

//open the file
  
errno_t err;

   
err = fopen_s(&yuvFile, argv[1], "rb");

   
if (err == 0)

    {

       printf("打开yuv文件成功!\n");

    }

   
else printf("打开yuv文件失败!\n");

   
err = fopen_s(&rgbFile, "down.rgb", "wb");

   
if (err == 0)

    {

       printf("打开rgb文件成功!\n");

    }

   
else printf("打开rgb文件失败!\n");

 

   
//allocate

   
YUV = (unsigned char*)malloc(sizeof(unsigned char) * width * height * 3 / 2);

   
RGB = (unsigned char*)malloc(sizeof(unsigned char) * width * height * 3);


//read the yuvfile

   
fread(YUV, sizeof(unsigned char), width * height * 3 / 2, yuvFile);


//yuv2rgb

   
int Y, U, V;

   
int i, j;

   
int cwidth = width >> 1;

   
for (i = 0; i < height; ++i)

    {

       for (j = 0; j < width; ++j)

       {

           Y = *(YUV + i * width + j);

           U = *(YUV + width * height + (i >> 1)* cwidth + (j >> 1));

           V = *(YUV + width * height * 5 / 4 + (i >> 1)* cwidth + (j >> 1));

           *(RGB + (i * width + j) * 3) = (unsigned char)(DB(Y, U, 0));      //B = Y +1.779*(U-128)        

           *(RGB + (i * width + j) * 3 + 1) = (unsigned char)(DG(Y, U, V));  //G = Y-0.3455*(U-128)-0.7169*(V-128)        

           *(RGB + (i * width + j) * 3 + 2) = (unsigned char)(DR(Y, 0, V));  //R = Y+1.4075*(V-128)    

       } 

    }

   
// write the rgbfile

   
fwrite(RGB, sizeof(unsigned char), width * height * 3 ,rgbFile);


if (YUV != NULL)

       
free(YUV);

   
if (RGB != NULL)

       
free(RGB);

   
if (rgbFile != NULL)

       
fclose(rgbFile);

   
if (yuvFile != NULL)

       
fclose(yuvFile);

   
return 0;

}

实验结果及分析

在这里插入图片描述在视觉上误差很小,但实际上由于数据转换时产生的计算误差,量化误差和YUV本身的U,V分量舍弃了3/4像素点的数据,两幅图的误差不可避免。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值