编程实现对rgb和yuv的概率及信息熵的分析
*已知文件down.rgb和down.yuv两个文件
- 分辨率均为256*256
- YUV为4:2:0采样空间
- 存储格式为:
RGB文件按每个像素BGR分量依次存放;YUV格式按照全部像素的Y数据块、U数据块和V数据块依次存放
注:
数字电视系统基于三基色原理工作,图像源把彩色场景或图像转换为**红(R)、绿(G)和蓝(B)**三个模拟基色视频信号,将这三个基色信号数字化后,经种种处理,传送给终端。**YUV(亦称YCrCb)**是被欧洲电视系统所采用的一种颜色编码方法(属于PAL)。其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V”表示的则是色度(Chrominance或Chroma)。
与RGB视频信号传输相比,它最大的优点在于只需占用极少的带宽(RGB要求三个独立的视频信号同时传输)。
在水平和垂直方向上,两个色差信号取样点数,都减少到亮度信号取样点数的一半,即4个亮度信号取样点,对应两个色差信号的各一个取样点,称为4:2:0格式
一、实验目的
已知文件down.rgb和down.yuv两个文件,通过编程分析二者的三个通道的概率分布,并计算各自的熵。
二、实验流程
-
打开、创建所需文件
-
定义文件读取、存储数组
-
计算三通道数值的出现概率
-
定义并求解三通道信源熵
-
将数据导入matlab,绘制概率分布图
三、实验代码
1.RGB代码
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;
int main()
{
int w = 256;
int h = 256;
int fileLength = w * h * 3;
//打开、创建所需文件
FILE* file = fopen("down.rgb", "rb");
//动态分配地址
unsigned char* dataArray = (unsigned char*)malloc(sizeof(unsigned char) * fileLength);
unsigned char* r = (unsigned char*)malloc(w * h * sizeof(unsigned char));
unsigned char* g = (unsigned char*)malloc(w * h * sizeof(unsigned char));
unsigned char* b = (unsigned char*)malloc(w * h * sizeof(unsigned char));
//读取文件
fread(dataArray, sizeof(unsigned char), fileLength, file);
//定义不同颜色通道计数
int k = 0;
int m = 0; //b
int n = 0; //g
int p = 0; //r
//定义参照数组跟三通道计数数组
unsigned char item[256];
double countR[256];
double countG[256];
double countB[256];
for (int i = 0; i < 256; i++)
{
item[i] = (unsigned char)i;
countR[i] = 0;
countG[i] = 0;
countB[i] = 0;
}
//分离RGB通道并对各通道的灰度值出现次数计数
for (int i = 0; i < fileLength; i++)
{
if (i % 3 == 0)
{
b[m] = dataArray[i];
while (b[m] != item[k])
{
k++;
}
countB[k]++;
k = 0;
m++;
}
else if (i % 3 == 1)
{
g[n] = dataArray[i];
while (g[n] != item[k])
{
k++;
}
countG[k]++;
k = 0;
n++;
}
else
{
r[p] = dataArray[i];
while (r[p] != item[k])
{
k++;
}
countR[k]++;
k = 0;
p++;
}
}
//计算三通道数值的出现概率
for (int i = 0; i < 256; i++)
{
countR[i] = countR[i] / (256 * 256);
countG[i] = countG[i] / (256 * 256);
countB[i] = countB[i] / (256 * 256);
}
for (int i = 0; i < 256; i++)
{
//cout << countR[i] << " ";
//cout << countG[i] << " ";
//cout << countB[i] << " ";
}
cout << endl;
//定义并利用公式求信源熵
double rEntropy = 0;
double gEntropy = 0;
double bEntropy = 0;
for (int i = 0; i < 256; i++)
{
if (countR[i] != 0)
{
rEntropy = rEntropy + countR[i] * (log(1 / countR[i]) / log(2));
}
if (countG[i] != 0)
{
gEntropy = gEntropy + countG[i] * (log(1 / countG[i]) / log(2));
}
if (countB[i] != 0)
{
bEntropy = bEntropy + countB[i] * (log(1 / countB[i]) / log(2));
}
}
cout << "R的熵为 " << rEntropy << "\n";
cout << "G的熵为 " << gEntropy << "\n";
cout << "B的熵为 " << bEntropy << "\n";
return 0;
}
2.YUV代码
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <fstream>
#include <cmath>
using namespace std;
int main()
{
int w = 256;
int h = 256;
int fileLength = w * h * 1.5;
//打开、创建所需文件
FILE* file = fopen("down.yuv", "rb");
//动态分配地址
unsigned char* dataArray = (unsigned char*)malloc(sizeof(unsigned char) * fileLength);
unsigned char* v = (unsigned char*)malloc(w * h / 4 * sizeof(unsigned char));
unsigned char* u = (unsigned char*)malloc(w * h / 4 * sizeof(unsigned char));
unsigned char* y = (unsigned char*)malloc(w * h * sizeof(unsigned char));
//读取文件
fread(dataArray, sizeof(unsigned char), fileLength, file);
//定义不同颜色通道计数
int k = 0;
int m = 0; //b
int n = 0; //g
int p = 0; //r
//定义参照数组跟三通道计数数组
unsigned char item[256];
double countV[256];
double countU[256];
double countY[256];
for (int i = 0; i < 256; i++)
{
item[i] = (unsigned char)i;
countV[i] = 0;
countU[i] = 0;
countY[i] = 0;
}
//分离RGB通道并对各通道的灰度值出现次数计数
for (int i = 0; i < w * h; i++)
{
y[m] = dataArray[i];
while (y[m] != item[k])
{
k++;
}
countY[k]++;
k = 0;
m++;
}
for (int i = w * h; i < w * h * 1.25; i++)
{
u[n] = dataArray[i];
while (u[n] != item[k])
{
k++;
}
countU[k]++;
k = 0;
n++;
}
for (int i = w * h * 1.25; i < w * h * 1.5; i++)
{
v[p] = dataArray[i];
while (v[p] != item[k])
{
k++;
}
countV[k]++;
k = 0;
p++;
}
//计算三通道数值的出现概率
for (int i = 0; i < 256; i++)
{
countV[i] = countV[i] / (256 * 256 / 4);
countU[i] = countU[i] / (256 * 256 / 4);
countY[i] = countY[i] / (256 * 256);
}
for (int i = 0; i < 256; i++)
{
//cout << countY[i] << " ";
//cout << countU[i] << " ";
//cout << countV[i] << " ";
}
cout << endl;
//定义并利用公式求信源熵
double yEntropy = 0;
double uEntropy = 0;
double vEntropy = 0;
for (int i = 0; i < 256; i++)
{
if (countV[i] != 0)
{
vEntropy = vEntropy + countV[i] * (log(1 / countV[i]) / log(2));
}
if (countU[i] != 0)
{
uEntropy = uEntropy + countU[i] * (log(1 / countU[i]) / log(2));
}
if (countY[i] != 0)
{
yEntropy = yEntropy + countY[i] * (log(1 / countY[i]) / log(2));
}
}
cout << "Y的熵为 " << yEntropy << "\n";
cout << "U的熵为 " << uEntropy << "\n";
cout << "V的熵为 " << vEntropy << "\n";
return 0;
}
四、实验分析
将cpp代码中的数据分别导入到matlab中,绘制概率分布曲线。
同理可得YUV概率分布图:
由上可得,rgb文件概率分布曲线与yuv文件的概率分布曲线相比,分布更加均匀。当概率分布较为均匀时,熵最大。
因而rgb文件熵比yuv文件的熵更大,同时符合编程得出的结果。