使用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.229553 | 7.178462 | 6.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.331819 | 5.126402 | 4.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++语言的使用,为后续进一步学习数据压缩打下了基础。