1.2| 分析rgb和yuv文件三个通道的概率分布并计算各自的熵

分析rgb和yuv文件三个通道的概率分布并计算各自的熵

  • 两个文件的分辨率均为256*256;
  • yuv为4:2:0采样空间;
  • 存储格式为:rgb文件按每个像素BGR分量依次存放;YUV格式按照全部像素的Y数据块、U数据块和V数据块依次存放。

一、原理分析

  1. rgb文件按每个像素BGR分量依次存放:

来自网络
可知RGB分别有256×256=65536个,排列为BGRBGRBGR…的形式,rgb分别距离自己的前一个数据偏移量为3,rgb图像总共256×256×3个像素。

  1. yuv文件按4:2:0采样,且按Y数据块、U数据块和V数据块依次存放:
    1.2| 分析rgb和yuv文件三个通道的概率分布并计算各自的熵_第1张图片摘自现代电视原理课件

可知UV分量是Y分量的1/4,即256×256÷4=16384个;U的首数据距离第一个数据的偏移量为256×256;V的首数据距离第一个数据的偏移量为256×256×(1+1/4)=81920;yuv图像总共256×256×(1+1/2)=98304个像素。

根据这些偏移量,可以利用循环和数组的基本思想求得每个通道的概率分布。

二、步骤设想

  1. 读取rgb&yuv文件数据到三个数组中存储
  2. 分别计算三个通道(RGB&YUV)的频数
  3. 分别计算三个通道的概率(频数/总数)并写入新创建的文件
  4. 计算各自的熵在这里插入图片描述

读取和写入文件的方式参考《数字视音频处理实验一》,因此采用fread、fwrite、fopen、fclose来实现文件的读取、写入、打开、关闭的操作。
注:后续发现fwrite写入不成功

三、编程实现

rgb文件

#include
#include
using namespace std;

int main()
{
     
	//定义宽高
	int w = 256;   
	int h = 256;  

	//动态分配地址,定义BGR三通道分量
	unsigned char *BGR_buffer=(unsigned char *)malloc(sizeof(unsigned char) * w*h*3);
	unsigned char B_buffer[256*256]={
     0};
	unsigned char G_buffer[256*256]={
     0};
	unsigned char R_buffer[256*256]={
     0};

	//设置文件指针
	FILE *fp;  
	FILE *fp_B;
	FILE *fp_G;
	FILE *fp_R;

	
	//指针指向rgb文件和三个新建的txt文件
    fopen_s(&fp,"C:\\Users\\user\\Desktop\\down.rgb", "rb");
	fopen_s(&fp_B,"C:\\Users\\user\\Desktop\\R.txt", "w");
	fopen_s(&fp_G,"C:\\Users\\user\\Desktop\\G.txt", "w");
	fopen_s(&fp_R,"C:\\Users\\user\\Desktop\\B.txt", "w");

	//读文件
	fread(BGR_buffer,sizeof(unsigned char), w*h*3,fp);
	//memcpy(BGR_buffer, w*h*3);   //检验文件打开是否成功
	//将数据读入三个数组中
	for(int i=0,j=0;i<w*h*3;i=i+3,j++)//RGB分别与相邻数据偏移3
	{
     
		B_buffer[j]=*(BGR_buffer+i);
		G_buffer[j]=*(BGR_buffer+i+1);
		R_buffer[j]=*(BGR_buffer+i+2);
	}
	//计算三个通道的频数
	double B[256]={
     0},G[256]={
     0},R[256]={
     0};//有256种不同灰度级
	for(int i=0;i<w*h;i++)
	{
     
		B[B_buffer[i]]++;//计算每相同灰度级的出现次数
		G[G_buffer[i]]++;
		R[R_buffer[i]]++;
	}
	//计算三个通道的概率
	double Bp[256]={
     0},Gp[256]={
     0},Rp[256]={
     0};
	for(int i=0;i<256;i++)
	{
     
		Bp[i]=B[i]/(w*h);
		Gp[i]=G[i]/(w*h);
		Rp[i]=R[i]/(w*h);
	}
	
	//写文件
    fwrite(Bp,sizeof(unsigned char), 256, fp_B);
	fwrite(Gp,sizeof(unsigned char), 256, fp_G);
	fwrite(Rp,sizeof(unsigned char), 256,fp_R);

	//计算熵
	double Bs=0,Gs=0,Rs=0;
	for(int i=0;i<256;i++)
	{
     
		if (Bp[i] != 0) {
     Bs += -Bp[i]*log(Bp[i])/log(double(2));}
		if (Gp[i] != 0) {
     Gs += -Gp[i]*log(Gp[i])/log(double(2));}
		if (Rp[i] != 0) {
     Rs += -Rp[i]*log(Rp[i])/log(double(2));}
	}

	cout<<"B的熵:"<<Bs<<endl;
	cout<<"G的熵:"<<Gs<<endl;
	cout<<"R的熵:"<<Rs<<endl;

	//关文件
    fclose(fp);
	fclose(fp_B);
	fclose(fp_G);
	fclose(fp_R);

	//释放文件
	free(BGR_buffer);

	system("pause");
	return 0;
}

求得熵:
1.2| 分析rgb和yuv文件三个通道的概率分布并计算各自的熵_第2张图片

yuv文件

#include
#include
using namespace std;

int main()
{
     
	//定义宽高
	int w = 256;   
	int h = 256;  

	//动态分配地址,定义YUV三通道分量
	unsigned char *YUV_buffer=(unsigned char *)malloc(sizeof(unsigned char) * 98304);
	unsigned char Y_buffer[256*256]={
     0};
	unsigned char U_buffer[16384]={
     0};//Y的1/4
	unsigned char V_buffer[16384]={
     0};

	//设置文件指针
	FILE *fp;  
	FILE *fp_Y;
	FILE *fp_U;
	FILE *fp_V;

	
	//指针指向yuv文件和三个新建的txt文件
    fopen_s(&fp,"C:\\Users\\user\\Desktop\\down.yuv", "rb");
	fopen_s(&fp_Y,"C:\\Users\\user\\Desktop\\Y.txt", "w");
	fopen_s(&fp_U,"C:\\Users\\user\\Desktop\\U.txt", "w");
	fopen_s(&fp_V,"C:\\Users\\user\\Desktop\\V.txt", "w");

	//读文件
	fread(YUV_buffer,sizeof(unsigned char), 98304,fp);
	//memcpy(YUV_buffer, 98304);   //检验文件打开是否成功
	//将数据读入三个数组中
	for(int i=0;i<w*h;i++)//Y从1~256*256
	{
     
		Y_buffer[i]=*(YUV_buffer+i);
	}
	for(int i=w*h;i<81920;i++)//U从256*256~256*256*(1+1/4)
	{
     
		U_buffer[i-256*256]=*(YUV_buffer+i);
	}
	for(int i=81920;i<98304;i++)//V从256*256*(1+1/4)~256*256*(1+1/2)
	{
     
		V_buffer[i-81920]=*(YUV_buffer+i);
	}
	//计算三个通道的频数
	double Y[256]={
     0},U[256]={
     0},V[256]={
     0};//有256种不同灰度级
	for(int i=0;i<w*h;i++)
	{
     
		Y[Y_buffer[i]]++;//计算每相同灰度级的出现次数
	}
	for(int i=0;i<16384;i++)
	{
     
		U[U_buffer[i]]++;
		V[V_buffer[i]]++;
	}
	//计算三个通道的概率
	double Yp[256]={
     0},Up[256]={
     0},Vp[256]={
     0};
	for(int i=0;i<256;i++)
	{
     
		Yp[i]=Y[i]/(w*h);
		Up[i]=U[i]/16384;
		Vp[i]=V[i]/16384;
	}
	
	//写文件
    fwrite(Yp,sizeof(unsigned char), 256, fp_Y);
	fwrite(Up,sizeof(unsigned char), 256, fp_U);
	fwrite(Vp,sizeof(unsigned char), 256,fp_V);

	//计算熵
	double Ys=0,Us=0,Vs=0;
	for(int i=0;i<256;i++)
	{
     
		if (Yp[i] != 0) {
     Ys += -Yp[i]*log(Yp[i])/log(double(2));}
		if (Up[i] != 0) {
     Us += -Up[i]*log(Up[i])/log(double(2));}
		if (Vp[i] != 0) {
     Vs += -Vp[i]*log(Vp[i])/log(double(2));}
	}

	cout<<"Y的熵:"<<Ys<<endl;
	cout<<"U的熵:"<<Us<<endl;
	cout<<"V的熵:"<<Vs<<endl;

	//关文件
    fclose(fp);
	fclose(fp_Y);
	fclose(fp_U);
	fclose(fp_V);

	//释放文件
	free(YUV_buffer);

	system("pause");
	return 0;
}

求得熵:
在这里插入图片描述

四、问题解决

fwrite&fprintf:
使用fwrite写入得到的txt文件是乱码,于是查资料发现fwrite函数的数据是以二进制方式写入的 ,而fprintf是将格式化的数据写入文件,因此参考csdn上其他博主的fprintf写法,修改如下:

    fprintf(fp_B, "灰度值\t概率\n");
    for (int i = 0; i < 256; i++)
	{
     
	    fprintf(fp_B, "%d\t%f\n", i, Bp[i]); 
	}
	fprintf(fp_G, "灰度值\t概率\n");
    for (int i = 0; i < 256; i++)
	{
     
	    fprintf(fp_G, "%d\t%f\n", i, Gp[i]); 
	}
	fprintf(fp_R, "灰度值\t概率\n");
    for (int i = 0; i < 256; i++)
	{
     
		fprintf(fp_R, "%d\t%f\n", i, Rp[i]); 
	}
    fprintf(fp_Y, "灰度值\t概率\n");
    for (int i = 0; i < 256; i++)
	{
     
		fprintf(fp_Y, "%d\t%f\n", i, Yp[i]); 
	}
	fprintf(fp_U, "灰度值\t概率\n");
    for (int i = 0; i < 256; i++)
	{
     
		fprintf(fp_U, "%d\t%f\n", i, Up[i]); 
	}
	fprintf(fp_V, "灰度值\t概率\n");
    for (int i = 0; i < 256; i++)
	{
     
		fprintf(fp_V, "%d\t%f\n", i, Vp[i]); 
	}

最终获得了rgb和yuv的概率分布表txt文件。
txt文件如图:(以B.txt为例)
1.2| 分析rgb和yuv文件三个通道的概率分布并计算各自的熵_第3张图片

五、概率分布图

将txt文件导入wps,得到概率分布图:
1.2| 分析rgb和yuv文件三个通道的概率分布并计算各自的熵_第4张图片

1.2| 分析rgb和yuv文件三个通道的概率分布并计算各自的熵_第5张图片
从图上可以直观看出rgb文件的各通道概率分布比yuv文件均匀一些,这也印证了编程求得的结果:rgb的熵更大。

你可能感兴趣的:(c++)