音频文件分析与RGB文件熵的计算
写在前面
受数据压缩老师的提示,还是挺想把每次的作业发出来的。
可能作业里面有部分工作借鉴了之前哥姐发的文章里的内容,因此如果哥姐看到有相似内容的话希望可以多多包涵,谢谢哥姐。(手动比个大心心)
音频分析
浊音
-
a
-
时域:
-
时域放大后观察:
-
频谱图:
-
-
ao
-
时域:
-
时域放大后观察:
-
频谱图:
-
-
分析:
- 一般将发声时声带振动的音称为浊音
- 观察发现浊音时域呈现周期性,能量较高
- 频谱中能量主要集中在低频段,具有明显的共振峰特性
清音
-
s
-
时域:
-
时域放大后观察:
-
频谱图:
-
-
c
-
时域:
-
时域放大后观察:
-
频谱图:
-
-
分析
- 发音时声带不振动的音称为清音
- 清音时域没有周期性,分布更像随机噪声信号
- 频域能量分布较为均匀
爆破音
-
t
-
时域:
-
时域放大后观察:
-
频谱图:
-
-
k
-
时域:
-
时域放大后观察:
-
频谱图:
-
-
分析:
- 爆破音是指发音器官在口腔中形成阻碍,然后气流冲破阻碍而发出的音。
- 爆破音时域有一个明显的脉冲,之后逐渐减弱
- 频域能量较为集中,低频处分布较为平均,到高频逐渐减弱
计算RGB文件的熵
分析
-
计算熵的公式: H ( X ) = − ∑ i = 1 m p i l o g 2 ( p i ) H(X)=-\sum\limits_{i=1}^{m}p_ilog_2(p_i) H(X)=−i=1∑mpilog2(pi)
-
test.rgb文件分辨率为256×256,数据格式为每个像素占用3字节,存储格式为BGRBGR…。
-
首先打开文件并计算文件的大小
-
//打开文件 FILE* fp = fopen("E:\\大学学习\\数据压缩\\预习作业\\2\\test.rgb", "rb"); //读取rgb文件 if (fp == NULL) { cout << 0; } //查看文件大小 //由于之前没有学习过查看文件大小的方法,因此这段代码是从网上借鉴的 //链接:https://vegetable-chicken.blog.csdn.net/article/details/105073524?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7EHighlightScore-1.queryctrv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7EHighlightScore-1.queryctrv2&utm_relevant_index=2 fseek(fp, 0, SEEK_SET); //指针:移动到文件头部 long begin = ftell(fp); fseek(fp, 0, SEEK_END); //指针:移动到文件尾部 long end = ftell(fp); long fileSize = end - begin; cout << fileSize / 256 / 256 << endl; //=3,即文件大小是256*256的3倍 fseek(fp, 0, SEEK_SET); //指针:移动到文件头部
-
需要注意,在vs2019中使用fopen函数需要在程序开始添加:
\#pragma warning(disable:4996);
-
另外,在计算文件大小时,由于将文件的指针移到了文件的最后,因此需要在计算结束后将文件的指针再移动到文件头部,否则在后续计算过程中会出现读入的图片文件值全为0的情况
-
-
之后将图片的数据按照BGR的顺序分别存到相应的数组中,并分别计算RGB三个通道每个像素值的个数、出现的概率
-
//数据按照BGRBGR...保存 for (int i = 0, j = 0; i < fileSize; i = i + 3, j++) { B[j] = *(image + i); G[j] = *(image + i + 1); R[j] = *(image + i + 2); } //计算每个通道各像素的次数 for (int i = 0; i < image_size; i++) { int valr = int(*(R + i)); pmfr[valr]++; int valg = int(*(G + i)); pmfg[valg]++; int valb = int(*(B + i)); pmfb[valb]++; } //计算每个通道各像素的概率 for (int i = 0; i < 256; i++) { pmfr[i] = pmfr[i] / (256 * 256); pmfg[i] = pmfg[i] / (256 * 256); pmfb[i] = pmfb[i] / (256 * 256); }
-
一定要注意在”.rgb“文件中RGB的存储顺序,否则后续计算会出错
-
-
接下来分别计算RGB三个通道的熵
-
//计算熵并输出 for (int i = 0; i < 256; i++) { if (pmfr[i] != 0) { sr += (-1) * pmfr[i] * log(pmfr[i]) / log(2); }; if (pmfg[i] != 0) { sg += (-1) * pmfg[i] * log(pmfg[i]) / log(2); }; if (pmfb[i] != 0) { sb += (-1) * pmfb[i] * log(pmfb[i]) / log(2); }; } cout << "R的熵为" << sr << endl; cout << "G的熵为" << sg << endl; cout << "B的熵为" << sb << endl;
-
-
最后将每个通道的概率和计算得到的熵的结果存入文件中
完整代码
#include<iostream>
#include <STDIO.H>
#include <STDLIB.H> //exit(0);
using namespace std;
#pragma warning(disable:4996); //使得fopen在编译时可以通过
int main()
{
//打开文件
FILE* fp = fopen("E:\\大学学习\\数据压缩\\预习作业\\2\\test.rgb", "rb"); //读取rgb文件
FILE* fr = fopen("E:\\大学学习\\数据压缩\\预习作业\\2\\pmfr.txt", "w"); //存储r的概率和熵
FILE* fg = fopen("E:\\大学学习\\数据压缩\\预习作业\\2\\pmfg.txt", "w"); //存储g的概率和熵
FILE* fb = fopen("E:\\大学学习\\数据压缩\\预习作业\\2\\pmfb.txt", "w"); //存储b的概率和熵
if (fp == NULL) { cout << 0; }
//查看文件大小
//由于之前没有学习过查看文件大小的方法,因此这段代码是从网上借鉴的
//链接:https://vegetable-chicken.blog.csdn.net/article/details/105073524?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7EHighlightScore-1.queryctrv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7EHighlightScore-1.queryctrv2&utm_relevant_index=2
fseek(fp, 0, SEEK_SET); //指针:移动到文件头部
long begin = ftell(fp);
fseek(fp, 0, SEEK_END); //指针:移动到文件尾部
long end = ftell(fp);
long fileSize = end - begin;
cout << fileSize / 256 / 256 << endl; //=3,即文件大小是256*256的3倍
fseek(fp, 0, SEEK_SET); //指针:移动到文件头部
int image_size = 256 * 256;
unsigned char image[256 * 256 * 3] = { 0 };
unsigned char R[256 * 256] = { 0 };
unsigned char G[256 * 256] = { 0 };
unsigned char B[256 * 256] = { 0 };
//存放RGB中每个像素值(0~255)的概率
double pmfr[256] = { 0 }, pmfg[256] = { 0 }, pmfb[256] = { 0 };
//分别计算RGB的熵
double sr = 0, sg = 0, sb = 0;
//读入图像
fread(image, sizeof(unsigned char), 256 * 256 * 3, fp);
//数据按照BGRBGR...保存
for (int i = 0, j = 0; i < fileSize; i = i + 3, j++)
{
B[j] = *(image + i);
G[j] = *(image + i + 1);
R[j] = *(image + i + 2);
}
//计算每个通道各像素的次数
for (int i = 0; i < image_size; i++)
{
int valr = int(*(R + i));
pmfr[valr]++;
int valg = int(*(G + i));
pmfg[valg]++;
int valb = int(*(B + i));
pmfb[valb]++;
}
//计算每个通道各像素的概率
for (int i = 0; i < 256; i++)
{
pmfr[i] = pmfr[i] / (256 * 256);
pmfg[i] = pmfg[i] / (256 * 256);
pmfb[i] = pmfb[i] / (256 * 256);
}
//计算熵并输出
for (int i = 0; i < 256; i++)
{
if (pmfr[i] != 0) { sr += (-1) * pmfr[i] * log(pmfr[i]) / log(2); };
if (pmfg[i] != 0) { sg += (-1) * pmfg[i] * log(pmfg[i]) / log(2); };
if (pmfb[i] != 0) { sb += (-1) * pmfb[i] * log(pmfb[i]) / log(2); };
}
cout << "R的熵为" << sr << endl;
cout << "G的熵为" << sg << endl;
cout << "B的熵为" << sb << endl;
//写入概率和熵
fprintf(fr, "值\t概率\n");
fprintf(fg, "值\t概率\n");
fprintf(fb, "值\t概率\n");
for (int i = 0; i < 256; i++)
{
fprintf(fr, "%d\t%f\n", i, pmfr[i]);
fprintf(fg, "%d\t%f\n", i, pmfr[i]);
fprintf(fb, "%d\t%f\n", i, pmfb[i]);
}
fprintf(fr, "熵=%f\n", sr);
fprintf(fg, "熵=%f\n", sg);
fprintf(fb, "熵=%f\n", sb);
fclose(fp);
fclose(fr);
fclose(fg);
fclose(fb);
return 0;
}
实验结果
-
-
r:
-
g:
-
b:
写在后面
文章可能会不定期更新,如有错误还请各位大神批评指正,谢谢大家