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

实验目的

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

实验过程

示例图片如下:
示例图片
对于上述示例图片的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;
}

实验结果

在这里插入图片描述
在这里插入图片描述
熵(以2为底)

RGB
7.229557.178466.85686
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值