数据压缩第三次作业-RGB文件的读取
读入一个24bitRGB文件(以down.rgb为例,其分辨率为256*256),输出该数据文件中R、G、B三个分量(各8bit表示)的概率分布示意图和熵。
一、思路及代码
结合上个小学期视频处理的练习,在C中打开处理文件的思路主要分为以下几个部分:
1.创建文件-fopen
2.创建内存空间-buffer malloc
3.读取文件-fread
4.处理-measure
5.写文件-fwrite
6.释放内存空间-free malloc
7.关闭文件-fclose
其中第4部分 处理-measure 对于不同的具体任务而不同,在本例子中meas部分包含三基色存储、计算频率、计算香农熵三个小部分
#include <stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<math.h>
int main()
{
errno_t err;
FILE* photo;
FILE* pBsat;
FILE* pGsat;
FILE* pRsat;
constexpr auto width = 256;;
constexpr auto height = 256;;
//fopen
err= fopen_s(&photo, "down.rgb", "rb");
if (err == 0) {
printf("打开文件成功!\n");
}
else {
printf("打开文件失败!\n");
}
err= fopen_s(&pBsat, "B_sat.txt", "w");
if (err == 0) {
printf("创建B_sat.txt成功!\n");
}
else {
printf("创建B_sat.txt失败!\n");
}
err= fopen_s(&pGsat, "G_sat.txt", "w");
if (err == 0) {
printf("创建G_sat.txt成功!\n");
}
else {
printf("创建G_sat.txt失败!\n");
}
err= fopen_s(&pRsat, "R_sat.txt", "w");
if (err == 0) {
printf("创建R_sat.txt成功!\n");
}
else {
printf("创建R_sat.txt失败!\n");
}
//buffer malloc
unsigned char* buffer = NULL;
buffer= (unsigned char*)malloc(sizeof(unsigned char) * 3 * width *
height);
if (NULL != buffer)
{
printf("申请内存成功!\n");
}
else
{
printf("申请内存失败!\n");
}
//fread
fread(buffer,sizeof(unsigned char), 3 * width * height, photo);
//measure
//分成三基色存储
unsigned char B[width * height] ={ 0 };
unsigned char G[width * height] ={ 0 };
unsigned char R[width * height] ={ 0 };
int pB = 0;
int pG = 0;
int pR = 0;
for (int i = 0; i <3*width*height; i++)
{
if (i % 3 == 0)
{
B[pB]= *(buffer+i);
pB++;
}
else if(i % 3 == 1)
{
G[pG]= *(buffer + i);
pG++;
}
else if (i % 3 == 2)
{
R[pR]= *(buffer + i);
pR++;
}
}
if (pB == width *height && pG == width * height && pR == width * height)
{
printf("RGB数据读取成功!\n");
}
else
{
printf("RGB数据读取失败!\n");
}
//计算频率
int numB[256] = { 0 };
for (int i = 0; i < 256;i++)
{
for (int j = 0; j < width* height; j++)
{
if (i == B[j])
{
numB[i]++;
}
}
}
double freqB[256] = { 0 };
for (int i = 0; i < 256;i++)
{
freqB[i]= double(numB[i]) / (width *height);
}
int numG[256] = { 0 };
for (int i = 0; i < 256;i++)
{
for (int j = 0; j < width* height; j++)
{
if (i == G[j])
{
numG[i]++;
}
}
}
double freqG[256] = { 0 };
for (int i = 0; i < 256;i++)
{
freqG[i]= double(numG[i]) / (width *height);
}
int numR[256] = { 0 };
for (int i = 0; i < 256;i++)
{
for (int j = 0; j < width* height; j++)
{
if (i == R[j])
{
numR[i]++;
}
}
}
double freqR[256] = { 0 };
for (int i = 0; i < 256;i++)
{
freqR[i]= double(numR[i]) / (width *height);
}
//计算香农熵
double HB = 0;
double HG = 0;
double HR = 0;
for (int i = 0; i < 256;i++)
{
if (freqB[i] != 0)
{
HB= HB - freqB[i] * log(freqB[i]) / log(2);
}
if (freqG[i] != 0)
{
HG= HG - freqG[i] * log(freqG[i]) / log(2);
}
if (freqR[i] != 0)
{
HR= HR - freqR[i] * log(freqR[i]) / log(2);
}
}
printf("B基色的香农熵是%f\n",HB);
printf("G基色的香农熵是%f\n", HG);
printf("R基色的香农熵是%f\n", HR);
//fwrite
fprintf(pBsat,"symbol\tfreq\n");
for (int i = 0; i < 256;i++)
{
fprintf(pBsat,"%d\t%f\n",i,freqB[i]);
}
fprintf(pGsat,"symbol\tfreq\n");
for (int i = 0; i < 256;i++)
{
fprintf(pGsat,"%d\t%f\n", i,freqG[i]);
}
fprintf(pRsat,"symbol\tfreq\n");
for (int i = 0; i < 256;i++)
{
fprintf(pRsat,"%d\t%f\n", i,freqR[i]);
}
//free malloc
free(buffer);
//fclose
fclose(photo);
fclose(pBsat);
fclose(pGsat);
fclose(pRsat);
printf("文件关闭!\n");
//system pause
system("pause");
return 0;
}
在visual studio 2019中运行上述代码,可以得到一下结果:
从图中可以看出,RGB三种基色符号在down.rgb文件中的香农熵依次为7.23、7.18、6.86。
ps:上述代码有几个要注意的点
1.目标文件down.rgb要和源文件cpp放在同一路径中。
2.在vs2019中,使用fopen_s代替fopen,相应的使用方法也不一样
3.计算freq时,因为要做除法,所以要把int型数据转为double型,否则结果会都变为0
二、绘图
使用excel打开生成的txt文件,框选相应的数据,绘制条形图,可以得到以下结果:
三、使用matlab的简单代码
matlab自带的读取文件函数和绘图函数可以非常简介的完成读取文件数据以及绘制精美图像的操作。
例如在C中十分复杂、需要占用大量篇幅的读取文件操作,在matlab中可以仅用三行代码实现将rgb文件的数据存储到矩阵A中,然后进行后续的作图处理
fileID = fopen('down.rgb');
A = fread(fileID);
fclose(fileID);