求RGB圖像各分量的概率分佈和熵

求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.hPmf.cppmain.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.csvdown_GStats.csvdown_BStats.csv三個文件中的數據拷貝到Excel中,作出圖像,如下:


R、G、B各分量概率分佈

R、G、B各分量的信源熵
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章