欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据压缩学习笔记(一)RGB文件读取及RGB分量的概率分布统计

程序员文章站 2022-07-14 22:18:36
...

实验目的

使用C++读取未压缩的,分辨率为256*256的RGB文件,并分别输出该文件R、G、B三个分量的概率分布示意图和熵。
信息熵在这里表示R,G,B三个通道每像素分别平均携带的信息量。

实验过程

示例图片如下:
数据压缩学习笔记(一)RGB文件读取及RGB分量的概率分布统计
对于上述示例图片的RGB文件,其每个像素的三种颜色为8bit,以BGR的顺序逐像素一行一行地储存在文件中。(这个RGB文件基本可视作去掉头部的24bit bmp文件)。
使用C++读取并统计每个颜色值的频率和熵之后,输出至CSV文件,使用excel绘制图形。

C++代码如下:
rgb_raw.h

#pragma once

typedef unsigned char uint1;
typedef unsigned short uint2;
typedef unsigned int uint4;
typedef int int4;

#pragma pack(push)
#pragma pack(2)

typedef struct {
	uint1 b;
	uint1 g;
	uint1 r;
}BGR;

class RGB_raw_image 
{
private:
	int4 width;
	int4 height;
	int4 size;
	BGR* data;

#pragma pack(pop)

public:
	RGB_raw_image(uint4 w, uint4 h, const char* path);
	~RGB_raw_image();
	bool open(uint4 w, uint4 h, const char* path);
	bool clear();
	uint4 get_size();
	uint4 get_width();
	uint4 get_height();
	BGR* get_pixel(uint4 x, uint4 y);
	void show();
};

rgb_raw.cpp

#include "rgb_raw.h"
#include <iostream>
#include <fstream>
#include <conio.h>
#include <easyx.h>	//using easyx to draw picture
using namespace std;

RGB_raw_image::RGB_raw_image(uint4 w, uint4 h, const char* path)
{
	try {
		data = NULL;
		if (!open(w, h, path)) {
			size = 0;
			throw("Fail to load file");
		}
	}
	catch (const char* msg) {
		cerr << msg << "  " << path << endl;
	}
}

RGB_raw_image::~RGB_raw_image()
{
	delete[] data;
}

bool RGB_raw_image::open(uint4 w, uint4 h, const char* path)
{
	width = w;
	height = h;

	ifstream file_in(path, ios::binary);
	if (file_in.is_open())
	{
		istream::pos_type start_pos = file_in.tellg();
		file_in.seekg(0, ios_base::end);
		istream::pos_type end_pos = file_in.tellg();
		file_in.seekg(start_pos);
		istream::pos_type file_size = end_pos - start_pos;
		size = file_size;
		
		if (size != width * height * 3) {
			cerr << __func__ << "  The file's size is wrong!" << endl;
			return false;
		}
		else {
			data = new BGR[width * height];
			file_in.read((char*)data, size);
			return true;
		}
		file_in.close();
	}
	else {
		return false;
	}
}

bool RGB_raw_image::clear()
{
	delete[] data;
	width = 0;
	height = 0;
	size = 0;
	return true;
}

uint4 RGB_raw_image::get_size()
{
	return size;
}

uint4 RGB_raw_image::get_width()
{
	return width;
}

uint4 RGB_raw_image::get_height()
{
	return height;
}

BGR* RGB_raw_image::get_pixel(uint4 x, uint4 y)
{
	if (x < width && y < height) {
		uint4 index = y * width + x;
		return data + index;
	}
	else {
		cerr << __func__ << "  Position out of size!" << endl;
		return NULL;
	}
}

void RGB_raw_image::show()
{
	initgraph(width, height, SHOWCONSOLE);  //easyx
	cout << "Loading..." << endl;
	BGR* bgr;
	for (int i = 0; i < height; i++) {
		for (int j = 0; j < width; j++) {
			bgr = this->get_pixel(j, i);
			putpixel(j, i, RGB(bgr->r, bgr->g, bgr->b));
		}
	}
	cout<<"Finish"<<endl;
}

exercise.cpp

#include "rgb_raw.h"
#include <iostream>
#include <fstream>
#include <math.h>
using namespace std;

typedef struct {
	double r_entropy;
	double g_entropy;
	double b_entropy;
}RGB_entropy;

RGB_entropy calculate_entropy(double* r_p, double* g_p, double* b_p)
{
	double r_e(0), g_e(0), b_e(0);
	for (int i = 0; i < 256; i++) {
		r_e += (r_p[i] == 0) ? 0 : r_p[i] * log2(1 / r_p[i]);
		g_e += (g_p[i] == 0) ? 0 : g_p[i] * log2(1 / g_p[i]);
		b_e += (b_p[i] == 0) ? 0 : b_p[i] * log2(1 / b_p[i]);
	}
	return RGB_entropy{ r_e,g_e,b_e };
}

bool statistic_rgb(RGB_raw_image& rgb_image)
{
	uint4 r[256] = { 0,0,0 }, g[256] = { 0,0,0 }, b[256] = { 0,0,0 };
	double r_p[256] = { 0,0,0 }, g_p[256] = { 0,0,0 }, b_p[256] = { 0,0,0 };
	uint4 width = rgb_image.get_width();
	uint4 height = rgb_image.get_height();
	uint4 size = width * height;
	BGR* bgr;
	RGB_entropy entropy;

	for (int i = 0; i < height; i++) {
		for (int j = 0; j < width; j++) {
			bgr = rgb_image.get_pixel(j, i);
			r[bgr->r]++;
			g[bgr->g]++;
			b[bgr->b]++;
		}
	}
	for (int i = 0; i < 256; i++) {
		r_p[i] = (double)r[i] / size;
		g_p[i] = (double)g[i] / size;
		b_p[i] = (double)b[i] / size;
	}
	entropy = calculate_entropy(r_p, g_p, b_p);

	ofstream csv_out("./result.csv", ios::out);
	if (csv_out.is_open()) {
		csv_out << "R_num" << "," << "G_num" << "," << "B_num" << ",";
		csv_out << "R_%" << "," << "G_%" << "," << "B_%" << "," << endl;
		for (int i = 0; i < 256; i++) {
			csv_out << r[i] << "," << g[i] << "," << b[i] << ",";
			csv_out << r_p[i] << "," << g_p[i] << "," << b_p[i] << endl;
		}
		csv_out.close();

		ofstream csv_out_entropy("./result_entropy.csv", ios::out);
		if (csv_out_entropy.is_open()) {
			csv_out_entropy << "R_entropy" << "," << "G_entropy" 
				<< "," << "B_entropy" << endl;
			csv_out_entropy << entropy.r_entropy << "," 
				<< entropy.g_entropy << "," << entropy.b_entropy << endl;
			csv_out_entropy.close();
			cout<<"The entropy of R,G,B is  "<< entropy.r_entropy 
				<< "," << entropy.g_entropy << "," << entropy.b_entropy << endl;
			return true;
		}
		else {
			return false;
		}
	}
	else {
		return false;
	}
}

int main()
{
	RGB_raw_image rgb_image(256, 256, "./down.rgb");
	rgb_image.show();
	if (statistic_rgb(rgb_image)) {
		cout << "Statistic finished!" << endl;
	}
	else {
		cout << "Can not create CSV file!" << endl;
	}
	system("pause");
	return 0;
}

实验结果

数据压缩学习笔记(一)RGB文件读取及RGB分量的概率分布统计
数据压缩学习笔记(一)RGB文件读取及RGB分量的概率分布统计
熵(以2为底)

R G B
7.22955 7.17846 6.85686