求RGB图像各分量的概率分布和熵
功能
该程序可以实现读入一个24bit RGB文件(以down.rgb
为例,分辨率为256×256),计算R、G、B三个分量(各8bit表示)的概率分布和熵,并输出到csv(Comma-Separated Values)文件中(相比于txt文件,将csv文件数据导入到Excel中更加方便)。
down.rgb
需要注意的是,与YUV文件不同,RGB文件是按照每个像素的b、g、r分量依次排列而成。
代码
为了清晰,将程序写在globalVariables.h
、Pmf.cpp
、main.cpp
三个文件中。
globalVariables.h
#pragma once
extern const char* inPath; // 原始图像路径及文件
extern const char* outPathR; // R分量统计结果
extern const char* outPathG; // G分量统计结果
extern const char* outPathB; // B分量统计结果
extern int w; // 图像宽
extern int h; // 图像高
void Pmf(unsigned char* buffer,int size, FILE* outFile);
Pmf.cpp
#include <iostream>
#include "globalVariables.h"
using namespace std;
const char* inPath = "C:\\Users\\s.z.zheng\\OneDrive\\文档\\CUC课程 - OD\\大三下学期课程 - OD\\数据压缩原理与应用A - OD\\作业\\作业3:RGB文件的概率分布\\down.rgb"; // 原始图像路径及文件
const char* outPathR = "C:\\Users\\s.z.zheng\\OneDrive\\文档\\CUC课程 - OD\\大三下学期课程 - OD\\数据压缩原理与应用A - OD\\作业\\作业3:RGB文件的概率分布\\down_RStats.csv"; // R分量统计结果
const char* outPathG = "C:\\Users\\s.z.zheng\\OneDrive\\文档\\CUC课程 - OD\\大三下学期课程 - OD\\数据压缩原理与应用A - OD\\作业\\作业3:RGB文件的概率分布\\down_GStats.csv"; // G分量统计结果
const char* outPathB = "C:\\Users\\s.z.zheng\\OneDrive\\文档\\CUC课程 - OD\\大三下学期课程 - OD\\数据压缩原理与应用A - OD\\作业\\作业3:RGB文件的概率分布\\down_BStats.csv"; // B分量统计结果
int w = 256; // 图像宽
int h = 256; // 图像高
void Pmf(unsigned char* buffer, int size, FILE* outFile)
{
int count[256] = { 0 }; // 计数器
double freq[256] = { 0 }; // 频率
double entropy = 0; // 该分量的熵
// 统计某一分量
for (int i = 0; i < size / 3; i++)
{
int index = (int)buffer[i];
count[index]++;
}
// 计算该分量的频率,并输出该分量
for (int i = 0; i < 256; i++)
{
freq[i] = (double)count[i] / (w * h); //分子分母都为int型,进行类型转换,保证结果为double类型
if (freq[i] != 0)
{
entropy += (-freq[i]) * log(freq[i]) / log(2);
}
}
fprintf(outFile, "Symbol,Frequency\n");
for (int i = 0; i < 256; i++)
{
fprintf(outFile, "%-3d,%-8.2e\n", i, freq[i]); // 将数据输出到文件中(csv文件以“,”作为分隔符)
}
fprintf(outFile, "%.4lf", entropy);
}
main.cpp
#include <iostream>
#include "globalVariables.h"
using namespace std;
int main()
{
FILE* img;
FILE* outR; // 存储R分量数据的文件
FILE* outG; // 存储G分量数据的文件
FILE* outB; // 存储B分量数据的文件
int imgSize; // 图像总字节数
// 打开文件
if (fopen_s(&img, inPath, "rb") == 0)
{
cout << "Successfull opened the original image." << endl;
}
else
{
cout << "Failed to open the original image." << endl;
}
fopen_s(&outR, outPathR, "w");
fopen_s(&outG, outPathG, "w");
fopen_s(&outB, outPathB, "w");
// 计算图片总字节数
fseek(img, 0L, SEEK_END); // 使文件指针指向文件末尾
imgSize = ftell(img); // 文件总字节数
rewind(img); // 使文件指针再回到文件起始(若不回到起始,无法将img中的数据读入到缓冲区中)
cout << "The space that original image accounts for: " << imgSize << " Bytes = " << imgSize / 1024 << " kB" << endl;
// 建立缓冲区
unsigned char* imgBuffer = new unsigned char[imgSize]; // 图像缓冲区
unsigned char* rBuffer = new unsigned char[imgSize / 3]; // R分量缓冲区
unsigned char* gBuffer = new unsigned char[imgSize / 3]; // G分量缓冲区
unsigned char* bBuffer = new unsigned char[imgSize / 3]; // B分量缓冲区
// 将数据读入缓冲区
fread(imgBuffer, sizeof(unsigned char), imgSize, img); // 先将全部像素的RGB三个分量读入图像缓冲区
for (int i = 0; i < imgSize / 3; i++)
{
// 再分别将图像缓冲区的内容对应地分配给R、G、B缓冲区(注意:img中存储的顺序为G、B、R)
bBuffer[i] = imgBuffer[3 * i];
gBuffer[i] = imgBuffer[3 * i + 1];
rBuffer[i] = imgBuffer[3 * i + 2];
}
// 分别统计R、G、B分量的概率分布
Pmf(rBuffer, imgSize, outR);
Pmf(gBuffer, imgSize, outG);
Pmf(bBuffer, imgSize, outB);
// 关闭文件
fclose(img);
fclose(outR);
fclose(outG);
fclose(outB);
// 释放内存
delete[]imgBuffer;
delete[]rBuffer;
delete[]gBuffer;
delete[]bBuffer;
}
结果
将down_RStats.csv
、down_GStats.csv
、down_BStats.csv
三个文件中的数据拷贝到Excel中,作出图像,如下:
R、G、B各分量概率分布
R、G、B各分量的信源熵