使用C++分析RGB和YUV格式图像的三个通道的概率分布及其熵

一、使用C++计算熵的方法

首先,我们要知道如何计算熵,下面给出熵的计算公式
在这里插入图片描述
按照此公式我们可以写出计算熵的函数,方便在后续计算熵时进行调用:

//计算熵的函数,shang=−∑gailv*log2(gailv)
double shang(double gailv[256])
{
    double shang = 0;
	
    for (int i = 0; i < 256; i++)
    {
        if (gailv[i] == 0)
            continue;
        shang = shang - gailv[i]*log(gailv[i])/log(2.0);//c中log函数为以e为底,所以须换底公式
    }
    return shang;
}

二、使用C++分析RGB格式的图像

1、读取图像并分离RGB三通道

rgb文件按每个像素BGR分量以此存储,所以读取方式为b,g,r,b,g,r…;并且图像分辨率为256* 256,所以b,g,r分量各分配256* 256空间

//读取图像
	unsigned char* b = new unsigned char[256*256];
	unsigned char* g = new unsigned char[256*256];
	unsigned char* r = new unsigned char[256*256];
	unsigned char* img = new unsigned char[256*256*3];
	FILE* fp = fopen("C:\\Users\\10202\\Desktop\\down.rgb", "rb");
	fread(img, sizeof(unsigned char), 256*256*3, fp);
	fclose(fp);
	for (int i = 0;i < 256*256; i++)//rgb文件按每个像素BGR分量以此存储,所以读取方式为b,g,r,b,g,r........
	{
		b[i] = img[3*i];
		g[i] = img[3*i+1];
		r[i] = img[3*i+2];
	}

2、计算RGB三通道的概率分布

因为图像是8bit,所以R,G,B分量都是0-255的256个值。所以我们可以通过代码来分别计算R、G、B中0-255各值的数量,并除以整张图像像素总数量计算其概率分布。(RGB格式图像R,G,B分量的总数为数都为256*256)


	//计算分布概率:gailv=i/256/256
	double gailvb[256] = {0};
	double gailvg[256] = {0};
	double gailvr[256] = {0};
	for (int i = 0; i < 256; i++)
	{
	    int ib = 0, ig = 0, ir = 0;
		for (int j = 0; j < 256 * 256; j++)
		{
			if ((int)b[j] == i)
				ib ++;
			if ((int)g[j] == i)
				ig ++;
			if ((int)r[j] == i)
				ir++;
		}
		gailvb[i] = (double)ib/256/256;
		gailvg[i] = (double)ig/256/256;
		gailvr[i] = (double)ir/256/256;
	}

3、计算RGB三通道的熵

可以使用在第二步计算出的R,G,B三分量的概率,并调用“熵函数”来计算熵

double shangb = 0, shangg = 0, shangr = 0;
	shangb = shang(gailvb);
	shangg = shang(gailvg);
	shangr = shang(gailvr);

4、输出RGB分量概率分布及熵值

以.txt格式分别输出R,G,B三分量的概率分布及熵值

//输出BGR分量概率分布及熵值
	FILE* datab = fopen("C:\\Users\\10202\\Desktop\\B.txt","w");//建立存放B数据
	fprintf(datab, "值	概率\n");
	FILE* datag = fopen("C:\\Users\\10202\\Desktop\\G.txt","w");//建立存放G数据
	fprintf(datag, "值	概率\n");
	FILE* datar = fopen("C:\\Users\\10202\\Desktop\\R.txt.","w");//建立存放R数据
	fprintf(datar, "值	概率\n");
	for (int i = 0;i < 256; i++)//输出概率
	{
		fprintf(datab,"%d\t%f\n",i, gailvb[i]);
		fprintf(datag,"%d\t%f\n",i, gailvg[i]);
		fprintf(datar,"%d\t%f\n",i, gailvr[i]);
	}
	fprintf(datab,"B的熵 = %f",shangb);//输出B的熵
    fprintf(datag,"G的熵 = %f",shangg);//输出G的熵
    fprintf(datar,"R的熵 = %f",shangr);//输出R的熵

得到的txt文件截图如下:
R:
在这里插入图片描述

在这里插入图片描述
G:
在这里插入图片描述

在这里插入图片描述
B:
在这里插入图片描述

在这里插入图片描述
因为未找到如何使用C++来直接生成概率分布图,所以将txt文件导入excel里之后绘制概率分布图,概率分布图如下:
在这里插入图片描述
计算出的熵值如下:

H( R )H( G )H( B )
7.2295537.1784626.856861

5、完整代码

#include "iostream"
#include"stdio.h"
#include"math.h"
using namespace std;

//计算BGR的熵函数,shang=−∑gailv*log2(gailv)
double shang(double gailv[256])
{
    double shang = 0;
	
    for (int i = 0; i < 256; i++)
    {
        if (gailv[i] == 0)
            continue;
        shang = shang - gailv[i]*log(gailv[i])/log(2.0);//c中log函数为以e为底,所以须换底公式
    }
    return shang;
}

int main()
{
	//读取图像
	unsigned char* b = new unsigned char[256*256];
	unsigned char* g = new unsigned char[256*256];
	unsigned char* r = new unsigned char[256*256];
	unsigned char* img = new unsigned char[256*256*3];
	FILE* fp = fopen("C:\\Users\\10202\\Desktop\\down.rgb", "rb");
	fread(img, sizeof(unsigned char), 256*256*3, fp);
	fclose(fp);
	for (int i = 0;i < 256*256; i++)//rgb文件按每个像素BGR分量以此存储,所以读取方式为b,g,r,b,g,r........
	{
		b[i] = img[3*i];
		g[i] = img[3*i+1];
		r[i] = img[3*i+2];
	}

	//计算分布概率:gailv=i/256/256
	double gailvb[256] = {0};
	double gailvg[256] = {0};
	double gailvr[256] = {0};
	for (int i = 0; i < 256; i++)
	{
	    int ib = 0, ig = 0, ir = 0;
		for (int j = 0; j < 256 * 256; j++)
		{
			if ((int)b[j] == i)
				ib ++;
			if ((int)g[j] == i)
				ig ++;
			if ((int)r[j] == i)
				ir++;
		}
		gailvb[i] = (double)ib/256/256;
		gailvg[i] = (double)ig/256/256;
		gailvr[i] = (double)ir/256/256;
	}

	//计算熵,引用熵函数
	double shangb = 0, shangg = 0, shangr = 0;
	shangb = shang(gailvb);
	shangg = shang(gailvg);
	shangr = shang(gailvr);

	//输出BGR分量概率分布及熵值
	FILE* datab = fopen("C:\\Users\\10202\\Desktop\\B.txt","w");//建立存放B数据
	fprintf(datab, "值	概率\n");
	FILE* datag = fopen("C:\\Users\\10202\\Desktop\\G.txt","w");//建立存放G数据
	fprintf(datag, "值	概率\n");
	FILE* datar = fopen("C:\\Users\\10202\\Desktop\\R.txt.","w");//建立存放R数据
	fprintf(datar, "值	概率\n");
	for (int i = 0;i < 256; i++)//输出概率
	{
		fprintf(datab,"%d\t%f\n",i, gailvb[i]);
		fprintf(datag,"%d\t%f\n",i, gailvg[i]);
		fprintf(datar,"%d\t%f\n",i, gailvr[i]);
	}
	fprintf(datab,"B的熵 = %f",shangb);//输出B的熵
    fprintf(datag,"G的熵 = %f",shangg);//输出G的熵
    fprintf(datar,"R的熵 = %f",shangr);//输出R的熵


	fclose(datab);
	fclose(datag);
	fclose(datar);
}

三、使用C++分析YUV格式的图像

1、读取图像并分离RGB三通道

YUV按照全部像素Y数据块、U数据块、V数据块依次存放,且为4:2:0采样,所以读取方式为YYYY…,U…,V…;并且图像分辨率为256* 256,所以Y分配空间为256* 256,U、V分配空间为256*256/4

//读取图像
	unsigned char* y = new unsigned char[256*256];
	unsigned char* u = new unsigned char[256*256/4];
	unsigned char* v = new unsigned char[256*256/4];
	unsigned char* img = new unsigned char[256*256*3/2];
	FILE* fp = fopen("C:\\Users\\10202\\Desktop\\down.yuv", "rb");
	fread(img, sizeof(unsigned char), 256*256*3/2, fp);
	fclose(fp);
	for (int i = 0;i < 256*256; i++)//YUV按照全部像素Y数据块、U数据块、V数据块依次存放,且为4:2:0采样,所以读取方式为YYYY...,U...,V...
	{
		y[i] = img[i];
	}
	for (int i = 0;i < 256*256/4; i++)
	{
		u[i] = img[i+256*256];
		v[i] = img[i+256*256*5/4];
	}

2、计算YUV三通道的概率分布

因为图像是8bit,所以Y,U,V分量都是0-255的256个值。所以我们可以通过代码来分别计算Y、U、V中0-255各值的数量,并分别各自除以各自的总数量计算其概率分布。(要注意的是与RGB格式图像不同,YUV格式图像Y分量的总数为256* 256,U分量的总数为256* 256/4,V分量的总数为256* 256/4)

//计算分布概率:gailv=i/总数(Y为256*256,U、V为256*256/4)
	double gailvy[256] = {0};
	double gailvu[256] = {0};
	double gailvv[256] = {0};
	for (int i = 0; i < 256; i++)
	{
	    int iy = 0;
		for (int j = 0; j < 256 * 256; j++)
		{
			if ((int)y[j] == i)
				iy ++;
		}
		gailvy[i] = (double)iy/256/256;
	}
	for (int i = 0; i < 256; i++)
	{
	    int iu = 0, iv = 0;
		for (int j = 0; j < 256*256/4 ; j++)
		{
			if ((int)u[j] == i)
				iu ++;
			if ((int)v[j] == i)
				iv++;
		}
	
		
		gailvu[i] = (double)iu/256/256*4;
		gailvv[i] = (double)iv/256/256*4;
	}

3、计算YUV三通道的熵

可以使用在第二步计算出的Y,U,V三分量的概率,并调用“熵函数”来计算熵

//计算熵,引用熵函数
	double shangy = 0, shangu = 0, shangv = 0;
	shangy = shang(gailvy);
	shangu = shang(gailvu);
	shangv = shang(gailvv);

4、输出RGB分量概率分布及熵值

以.txt格式分别输出Y,U,V三分量的概率分布及熵值

//输出YUV分量概率分布及熵值
	FILE* datay = fopen("C:\\Users\\10202\\Desktop\\Y.txt","w");//建立存放Y数据
	fprintf(datay, "值	概率\n");
	FILE* datau = fopen("C:\\Users\\10202\\Desktop\\U.txt","w");//建立存放U数据
	fprintf(datau, "值	概率\n");
	FILE* datav = fopen("C:\\Users\\10202\\Desktop\\V.txt","w");//建立存放V数据
	fprintf(datav, "值	概率\n");
	for (int i = 0;i < 256; i++)//输出概率
	{
		fprintf(datay,"%d\t%f\n",i, gailvy[i]);
		fprintf(datau,"%d\t%f\n",i, gailvu[i]);
		fprintf(datav,"%d\t%f\n",i, gailvv[i]);
	}
	fprintf(datay,"Y的熵 = %f",shangy);//输出B的熵
    fprintf(datau,"U的熵 = %f",shangu);//输出G的熵
    fprintf(datav,"V的熵 = %f",shangv);//输出R的熵

得到的txt文件截图如下:
Y:
在这里插入图片描述

在这里插入图片描述
U:
在这里插入图片描述

在这里插入图片描述
V:
在这里插入图片描述

在这里插入图片描述
因为未找到如何使用C++来直接生成概率分布图,所以将txt文件导入excel里之后绘制概率分布图,概率分布图如下:
在这里插入图片描述
计算出的熵值如下:

H( Y )H( U )H( V )
6.3318195.1264024.113143

5、完整代码

#include "iostream"
#include"stdio.h"
#include"math.h"
using namespace std;

//计算YUV的熵函数,shang=−∑gailv*log2(gailv)
double shang(double gailv[256])
{
    double shang = 0;
	
    for (int i = 0; i < 256; i++)
    {
        if (gailv[i] == 0)
            continue;
        shang = shang - gailv[i]*log(gailv[i])/log(2.0);//c中log函数为以e为底,所以须换底公式
    }
    return shang;
}

int main()
{
	//读取图像
	unsigned char* y = new unsigned char[256*256];
	unsigned char* u = new unsigned char[256*256/4];
	unsigned char* v = new unsigned char[256*256/4];
	unsigned char* img = new unsigned char[256*256*3/2];
	FILE* fp = fopen("C:\\Users\\10202\\Desktop\\down.yuv", "rb");
	fread(img, sizeof(unsigned char), 256*256*3/2, fp);
	fclose(fp);
	for (int i = 0;i < 256*256; i++)//YUV按照全部像素Y数据块、U数据块、V数据块依次存放,且为4:2:0采样,所以读取方式为YYYY...,U...,V...
	{
		y[i] = img[i];
	}
	for (int i = 0;i < 256*256/4; i++)
	{
		u[i] = img[i+256*256];
		v[i] = img[i+256*256*5/4];
	}
	
	//计算分布概率:gailv=i/总数(Y为256*256,U、V为256*256/4)
	double gailvy[256] = {0};
	double gailvu[256] = {0};
	double gailvv[256] = {0};
	for (int i = 0; i < 256; i++)
	{
	    int iy = 0;
		for (int j = 0; j < 256 * 256; j++)
		{
			if ((int)y[j] == i)
				iy ++;
		}
		gailvy[i] = (double)iy/256/256;
	}
	for (int i = 0; i < 256; i++)
	{
	    int iu = 0, iv = 0;
		for (int j = 0; j < 256*256/4 ; j++)
		{
			if ((int)u[j] == i)
				iu ++;
			if ((int)v[j] == i)
				iv++;
		}
	
		
		gailvu[i] = (double)iu/256/256*4;
		gailvv[i] = (double)iv/256/256*4;
	}

	//计算熵,引用熵函数
	double shangy = 0, shangu = 0, shangv = 0;
	shangy = shang(gailvy);
	shangu = shang(gailvu);
	shangv = shang(gailvv);

	//输出YUV分量概率分布及熵值
	FILE* datay = fopen("C:\\Users\\10202\\Desktop\\Y.txt","w");//建立存放Y数据
	fprintf(datay, "值	概率\n");
	FILE* datau = fopen("C:\\Users\\10202\\Desktop\\U.txt","w");//建立存放U数据
	fprintf(datau, "值	概率\n");
	FILE* datav = fopen("C:\\Users\\10202\\Desktop\\V.txt","w");//建立存放V数据
	fprintf(datav, "值	概率\n");
	for (int i = 0;i < 256; i++)//输出概率
	{
		fprintf(datay,"%d\t%f\n",i, gailvy[i]);
		fprintf(datau,"%d\t%f\n",i, gailvu[i]);
		fprintf(datav,"%d\t%f\n",i, gailvv[i]);
	}
	fprintf(datay,"Y的熵 = %f",shangy);//输出B的熵
    fprintf(datau,"U的熵 = %f",shangu);//输出G的熵
    fprintf(datav,"V的熵 = %f",shangv);//输出R的熵


	fclose(datay);
	fclose(datau);
	fclose(datav);
}

四、总结

由计算结果不难看出,YUV格式的三分量的熵要小于RGB格式的三分量的熵,且YUV为4:2:0格式,可知YUV格式图像占空间更小。实际情况下此次两张图YUV格式图像大小98,304 字节,RGB格式图像大小196,608 字节,YUV格式图像大小小于RGB格式图像大小,占用空间更少,与计算结果相吻合。
通过此次实验进一步验证了两种图像格式,并且熟悉巩固了C++语言的使用,为后续进一步学习数据压缩打下了基础。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值