磨刀不误砍柴工,在进行此项任务之前,你需要了解以下内容:
问题:对down.rgb和down.yuv分析三个通道的概率分布,并计算各自的熵
拆解
视频帧的宽和高分别为w和h,那么一帧YUV420P(即上述YUV12)像素数据一共占用w×h×3/2。其中前w×h存储Y,接着的w×h×1/4存储U,最后w×h×1/4 存储V。
在此问题背景下,可以理解为:
YUV数据的(0~256×256)字节是Y分量值;(256×256~256×256×5/4)字节是U分量;(256×256×5/4~256×256×3/2)字节是V分量。
C++
分别导入down.rgb,并提取所有数据存在一个Array里面备用,YUV文件处理思路类似,不再赘述;背景拆解
中的顺序,利用for
循环将Array中的数据分别存储到B、G、R数组中;for
循环,统计[0,256]各数值像素个数存入num_r,num_g,num_b,计算H(R ),H(G),H(B),同时将概率freq存入txt
文件;python
处理txt文件,并实现可视化概率分布曲线图。一堆定义
#include
#include
#include
using namespace std;
const int width = 256;
const int height = 256;
int num_b[256] = {
0 };
int num_g[256] = {
0 };
int num_r[256] = {
0 };
unsigned char Array[width * height * 3];
unsigned char R[width * height];
unsigned char G[width * height];
unsigned char B[width * height];
double en_r = 0;
double en_g = 0;
double en_b = 0;
int main()
{
FILE* Down_rgb;
fopen_s(&Down_rgb,"down.rgb", "rb");
FILE* RED = NULL;
fopen_s(&RED,"R.txt", "w");
FILE* GREEN = NULL;
fopen_s(&GREEN,"G.txt", "w");
FILE* BLUE = NULL;
fopen_s(&BLUE, "B.txt", "w");
//存储down.rgb中的全部数据到Array中
fread(Array, sizeof(unsigned char), width * height * 3, Down_rgb);
for (int i = 0; i < width * height; i++)
{
B[i] = Array[i * 3];
G[i] = Array[i * 3 + 1];
R[i] = Array[i * 3 + 2];
}//将rgb数据分别保存在3个数组中
//统计三通道像素值频数
for (int i = 0; i < 256; i++)
{
for (int j = 0; j < width * height; j++)
{
if (R[j] == i)
{
num_r[i]++;
}
}
for (int m = 0; m < width * height; m++)
{
if (G[m] == i)
{
num_g[i]++;
}
}
for (int n = 0; n < width * height; n++)
{
if (B[n] == i)
{
num_b[i]++;
}
}
}
//求信息熵
for (int i = 0; i < 256; i++)
{
if (num_b[i] != 0)
{
en_b += (double)num_b[i] / (width * height) * (log(width * height) - log(num_b[i])) / log(2);
}
if (num_g[i] != 0)
{
en_g += (double)num_g[i] / (width * height) * (log(width * height) - log(num_g[i])) / log(2);
}
if (num_r[i] != 0)
{
en_r += (double)num_r[i] / (width * height) * (log(width * height) - log(num_r[i])) / log(2);
}
}
//打印导出,后续工作
cout << "H(Red) = " << en_r << endl;
cout << "H(Green) = " << en_g << endl;
cout << "H(Blue) = " << en_b << endl;
fprintf(BLUE, "symbol\tfreq\n");
fprintf(GREEN, "symbol\tfreq\n");
fprintf(RED, "symbol\tfreq\n");
for (int i = 0; i < 256; i++)
{
fprintf(BLUE, "%d\t%f\n", i, (double)num_b[i] / (width * height));
fprintf(GREEN, "%d\t%f\n", i, (double)num_g[i] / (width * height));
fprintf(RED, "%d\t%f\n", i, (double)num_r[i] / (width * height));
}
fclose(RED);
fclose(GREEN);
fclose(BLUE);
fclose(Down_rgb);
system("pause");
return 0;
}
我也是平平无奇的Jupyter选手哈哈(代码在后面,一起写的,懒得切分了):
直接贴不一样的地方吧,其他都差不多:
fread(Array, sizeof(unsigned char), width * height * 3 / 2, Down_yuv);//存储down.rgb中的全部数据到A中
for (int i = 0; i < width * height; i++)
{
Y[i] = Array[i];
}
int m = 0;
for (int i = width * height; i < width * height * 5 / 4; i++)
{
U[m] = Array[i];
m++;
}
int k = 0;
for (int i = width * height * 5 / 4; i < width * height * 3 / 2; i++)
{
V[k] = Array[i];
k++;
}
for (int i = 0; i < 256; i++)
{
for (int j = 0; j < width * height; j++)
{
if (Y[j] == i)
{
num_y[i]++;
}
}
}
for (int i = 0; i < 256; i++)
{
for (int m = 0; m < width * height / 4; m++)
{
if (U[m] == i)
{
num_u[i]++;
}
}
}
for (int i = 0; i < 256; i++)
{
for (int n = 0; n < width * height / 4; n++)
{
if (V[n] == i)
{
num_v[i]++;
}
}
}
//求信息熵
for (int i = 0; i < 256; i++)
{
if (num_y[i] != 0)
{
en_y += (double)num_y[i] / (width * height) * (log(width * height) - log(num_y[i])) / log(2);
}
}
for (int i = 0; i < 256; i++)
{
if (num_u[i] != 0)
{
en_u += (double)num_u[i] / (width * height / 4) * (log(width * height / 4) - log(num_u[i])) / log(2);
}
if (num_v[i] != 0)
{
en_v += (double)num_v[i] / (width * height / 4) * (log(width * height / 4) - log(num_v[i])) / log(2);
}
}
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
y_data = pd.read_table("D:\\C++\\datacompression\\homework1\\yuv\\Y_data.txt")
u_data = pd.read_table("D:\\C++\\datacompression\\homework1\\yuv\\U_data.txt")
v_data = pd.read_table("D:\\C++\\datacompression\\homework1\\yuv\\V_data.txt")
dic1 = {
'Y':y_data.freq,'U':u_data.freq,'V':v_data.freq};
yuv_df = pd.DataFrame(dic1)
yuv_df.plot()
plt.show()
# RBG代码不说好像,简直一模一样
虽然我说要提前准备好,但是实际上自己是边做边学的,写程序和写博客的时间差不多(我的脖子啊……),在上述内容之外,我补充几个自己很生疏的知识点吧(如果有大佬看到了,“别骂了别骂了,在学了在学了”)。:)
fread
fread(void *buffer, size_t size, size_t count, FILE *stream)
buffer 是读取的数据存放的内存的指针(可以是数组,也可以是新开辟的空间,buffer就是一个索引);
size 是每次读取的字节数;
count 是读取次数;
strean 是要读取的文件的指针;
fopen
和 fopen_s
fp = fopen(filename,“w”)。
err = fopen_s(&fp,filename,“w”)
返回值: fopen打开文件成功,返回文件指针赋值给fp,打开失败则返回NULL值; fopen_s打开文件成功返回0,失败返回非0,赋值给err。
绝对不要提前看大家的进度!!!
不然真的会崩溃的:哇,大佬好多,做得那么快,还用了各种各样的方法;啊,我就是个小垃圾……
自从老师刚在群里发了正式公告后,我第一次点开云文档的时候就有蓝莹莹的博客链接。在编程中途我又想去瞅两眼,还好理智拉住了我这头牛:看了又如何呢,看了也不可能加快进度,资源虽多,还是需要自己好好辨别的,真酒可贵难得,假酒害人不浅。共勉。