1.2 分析RGB和YUV文件三个通道的概率分布,并计算各自的熵(编程实现)
一、作业要求
分析down.rgb和down.yuv三个通道的概率分布,并计算各自的熵。
- 两个文件的分辨率均为256*256。
- yuv为4:2:0采样空间。
- rgb文件按每个像素BGR分量依次存放;YUV格式按照全部像素的Y数据块、U数据块和V数据块依次存放。
二、分析思路
(一)RGB文件
“rgb文件按每个像素BGR分量依次存放”,即文件中的数据为BGRBGR……
“文件的分辨率均为256256”,即R、G、B分别有256256=65536个数值,且据自己前一个数据的偏移量都是3。
(二)YUV文件
“yuv为4:2:0采样空间”,如下图所示。
图片来源于网络
“文件的分辨率均为256256,YUV格式按照全部像素的Y数据块、U数据块和V数据块依次存放”,即YUV文件中的数据依次是256256个Y分量,256256~2562561.25为U分量数据,2562561.25~256256*1.50为V分量数据。
三、代码实现
(一)down.rgb文件
#include<iostream>
using namespace std;
const int width = 256; //图像宽度
const int height = 256; //图像高度
int main(void)
{
FILE *p_rgb=NULL; //设置文件指针
FILE *R=NULL; //设置分量指针
FILE *G=NULL;
FILE *B=NULL;
int err1;
err1=fopen_s(&p_rgb,"C:\\Users\\user\\Desktop\\down.rgb","rb"); //打开down.rgb文件
fopen_s(&R,"C:\\Users\\user\\Desktop\\R_result.txt","w"); //打开各分量结果存储文件
fopen_s(&G,"C:\\Users\\user\\Desktop\\G_result.txt","w");
fopen_s(&B,"C:\\Users\\user\\Desktop\\B_result.txt","w");
unsigned char *RGB_buffer = NULL;
RGB_buffer=(unsigned char *)malloc(sizeof(unsigned char)*3*width*height); //动态分配指针地址内存
if(RGB_buffer==NULL){printf("WRONG RGB_buffer!!\n");}
fread(RGB_buffer,sizeof(unsigned char),3*width*height,p_rgb); //读取文件数据
unsigned char RR[width*height]={0}; //定义各分量从文件中读出后使用的数组
unsigned char GG[width*height]={0};
unsigned char BB[width*height]={0};
int r=0;
int g=0;
int b=0;
//将读出的各分量数据依次放入相应的数组
int i=0;
for(i;i<3*width*height;i++)
{
if(i%3==0)
{
BB[b]=*(RGB_buffer+i);
b++;
}
else if(i%3==1)
{
GG[g]=*(RGB_buffer+i);
g++;
}
else
{
RR[r]=*(RGB_buffer+i);
r++;
}
}
//统计各分量数据概率并写入txt文件
double Bnum[256]={0};
double Bre[256]={0};
for(int j=0;j<256;j++)
{
for(int k=0;k<width*height;k++)
{
if(j==BB[k])
Bnum[j]++;
}
Bre[j]=Bnum[j]/(width*height);
fprintf(B,"%d\t%lf\n",j,Bre[j]);
}
double Gnum[256]={0};
double Gre[256]={0};
for(int j=0;j<256;j++)
{
for(int k=0;k<width*height;k++)
{
if(j==GG[k])
Gnum[j]++;
}
Gre[j]=Gnum[j]/(width*height);
fprintf(G,"%d\t%lf\n",j,Gre[j]);
}
double Rnum[256]={0};
double Rre[256]={0};
for(int j=0;j<256;j++)
{
for(int k=0;k<width*height;k++)
{
if(j==RR[k])
Rnum[j]++;
}
Rre[j]=Rnum[j]/(width*height);
fprintf(R,"%d\t%lf\n",j,Rre[j]);
}
//计算分量熵值
double H_R=0,H_G=0,H_B=0;
for(int i=0;i<256;i++)
{
if(Rre[i]!=0)
{
H_R=H_R-Rre[i]*(log(Rre[i])/log(double(2)));
}
if(Gre[i]!=0)
{
H_G=H_G-Gre[i]*(log(Gre[i])/log(double(2)));
}
if(Bre[i]!=0)
{
H_B=H_B-Bre[i]*(log(Bre[i])/log(double(2)));
}
}
printf("R的熵=%f\n",H_R);
printf("G的熵=%f\n",H_G);
printf("B的熵=%f\n",H_B);
free(RGB_buffer);
fclose(p_rgb);
fclose(R);
fclose(G);
fclose(B);
system("pause");
return 0;
}
(二)down.yuv文件
#include<iostream>
using namespace std;
const int width = 256; //图像宽度
const int height = 256; //图像高度
int main(void)
{
FILE *p_yuv=NULL;//设置文件指针
FILE *Y;//设置分量指针
FILE *U;
FILE *V;
fopen_s(&p_yuv,"down.yuv","rb");//打开down.yuv文件
fopen_s(&Y,"Y_result.txt","w");//打开各分量结果存储文件
fopen_s(&U,"U_result.txt","w");
fopen_s(&V,"V_result.txt","w");
unsigned char *YUV_buffer = (unsigned char *)malloc(sizeof(unsigned char) *1.5*width*height); //动态分配指针地址内存
if(YUV_buffer==NULL){printf("WRONG YUV_buffer!!\n");}
fread(YUV_buffer,sizeof(unsigned char),1.5*width*height,p_yuv);//读取文件数据
unsigned char YY[width*height]={0};//定义各分量从文件中读出后使用的数组
unsigned char UU[width*height/4]={0};
unsigned char VV[width*height/4]={0};
//将读出的各分量数据依次放入相应的数组
for(int i=0,j=0;i<width*height;i++,j++)
{
YY[j]=YUV_buffer[i];
}
for(int i=width*height,j=0;i<width*height*1.25;i++,j++)
{
UU[j]=YUV_buffer[i];
}
for(int i=width*height*1.25,j=0;i<width*height*1.5;i++,j++)
{
VV[j]=YUV_buffer[i];
}
int y=0;
int u=0;
int v=0;
//统计各分量数据概率并写入txt文件
double Ynum[256]={0};
double Yre[256]={0};
for(int j=0;j<width*height;j++)
{
y=YY[j];
Ynum[y]++;
}
for(int k=0;k<256;k++)
{
Yre[k]=Ynum[k]/(width*height);
fprintf(Y,"%d\t%lf\n",k,Yre[k]);
}
double Unum[256]={0};
double Ure[256]={0};
for(int j=0;j<width*height/4;j++)
{
u=UU[j];
Unum[u]++;
}
for(int k=0;k<256;k++)
{
Ure[k]=Unum[k]/(width*height/4);
fprintf(U,"%d\t%lf\n",k,Ure[k]);
}
double Vnum[256]={0};
double Vre[256]={0};
for(int j=0;j<width*height/4;j++)
{
v=VV[j];
Vnum[v]++;
}
for(int k=0;k<256;k++)
{
Vre[k]=Vnum[k]/(width*height/4);
fprintf(V,"%d\t%lf\n",k,Vre[k]);
}
//计算分量熵值
double H_Y=0,H_U=0,H_V=0;
for(int i=0;i<256;i++)
{
if(Yre[i]!=0)
{
H_Y=H_Y-Yre[i]*(log(Yre[i])/log(double(2)));
}
if(Ure[i]!=0)
{
H_U=H_U-Ure[i]*(log(Ure[i])/log(double(2)));
}
if(Vre[i]!=0)
{
H_V=H_V-Vre[i]*(log(Vre[i])/log(double(2)));
}
}
printf("Y的熵=%f\n",H_Y);
printf("U的熵=%f\n",H_U);
printf("V的熵=%f\n",H_V);
free(YUV_buffer);
fclose(p_yuv);
fclose(Y);
fclose(U);
fclose(V);
system("pause");
return 0;
}
四、结果分析
(一)down.rgb文件
输出的熵值结果:
R、G、B统计概率分布的txt文件:(部分截图)
将三个txt文件导入excel,并绘制折线图:
(二)down.yuv文件
输出的熵值结果:
Y、U、V统计概率分布的txt文件:(部分截图)
将三个txt文件导入excel,并绘制折线图:
结果分析:
- 由程序运行结果可知,RGB三个通道的熵值比YUV三个通道的熵值大。
- 由折线图可知,RGB三个分量的概率分布比YUV三个分量的概率分布更均匀。
- 即RGB去相关性更好,YUV冗余度更大。