数据压缩学习笔记(一)RGB文件读取及RGB分量的概率分布统计
程序员文章站
2022-07-14 22:18:36
...
实验目的
使用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为底)
R | G | B |
---|---|---|
7.22955 | 7.17846 | 6.85686 |
上一篇: Java实现QQ机器人
下一篇: ros2 源更新有误问题