《信息论》的课程设计,要求完成标题所述内容
//仅供参考
使用matlab或更方便简洁,但如果想过一遍流程的话可以参考下面的代码,编译需要安装opencv
代码还有很大优化的空间,可以用向量解决代码中指针较多的问题。也可以用多线程优化运行速度,LZ编码类可以试着增加独立性,取消与霍夫曼编码的关联,建议试运行时使用较小的图片,过一下main函数。
文中参考网址及部分代码来源:
dct变换及逆变换的代码及量化部分的参考代码
量化矩阵的来源:
http://blog.sina.com.cn/s/blog_8bb885610102vizk.html
程序输出文件注释:
image_outi文件夹中包含使用量化矩阵i进行压缩编码的输出文件,其中:
decode.jpg为解压后的图片。
hdecode.jpg为解压后的图片的灰度统计直方图,横轴表示由0到255的灰度值,纵轴表示横轴对应灰度值在解压后中的统计次数,做了归一化处理。
hdelta1.jpg为1类误差直方图,横轴表示由-255到255的灰度值差值,纵轴表示对应差值的频率分布,做了归一化处理。
hdelta2.jpg为2类误差直方图,横轴表示原图由0到255的灰度值,纵轴表示原图对应灰度值相对解压后的图片的灰度值频数的变化,同样做了归一化处理,由于存在正负,x轴为图片中的分界线,y轴为图片左边框。
hfmlist.txt为霍夫曼编码生成的字典。
hfmout.txt为霍夫曼编码的输出序列。
ho.jpg为初始化后图片的灰度统计直方图,横轴表示由0到255的灰度值,纵轴表示横轴对应灰度值在原始图片中的统计次数,做了归一化处理。
lzlist.txt为LZ编码中信源符号的编码字典。
lzout.txt为LZ编码的输出序列。
o.jpg为初始化后的图片(原图片为三通道图长宽任意的图片,初始化后修改为单通道灰度图,长宽均为8或16的倍数的图片)。
sch.jpg为压缩量化后的图片,其中值为负值的像素由于数据溢出变更为正值。
sch.txt为压缩量化后图片各个矩阵的像素值数据,保留了负值。
1.jpg为程序运行时输入的图片,必须为三通道图片,否则报错,其它任意。
控制台输出.txt为程序运行结束后控制台输出的文字,其中包含有各步运行时间、信源符号数据,编码数据,图片数据等信息。
编译需要安装opencv。
//QQ:2048728358
//2020/05/10
#include <direct.h>
#include <windows.h>
#include <string.h>
#include <atlstr.h>
#include <stdio.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#include <fstream>
#include <iomanip>
using namespace std;
using namespace cv;
#define NUM 8
#define PI 3.1415926
//霍夫曼树结点
class HFMP;
//霍夫曼编码器
class HFMCODE;
//霍夫曼译码器
class HFMDECODE;
//LZ编码结点
class LZP;
//LZ编码器//对霍夫曼编码具有依赖性
class LZCODE;
//LZ译码器
class LZDECODE;
//JPEG量化矩阵
//N=8时量化表
int F8[14][8][8] = {
//100
{
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1},
{1,1,1,1,1,1,1,1}
},
//98
{
{1,1,1,1,1,2,2,2},
{1,1,1,1,1,2,2,2},
{1,1,1,1,2,2,3,2},
{1,1,1,1,2,3,3,2},
{1,1,1,2,3,4,4,3},
{1,1,2,3,3,4,5,4},
{2,3,3,3,4,5,5,4},
{3,4,4,4,4,4,4,4}
},
//96
{
{1,1,1,1,2,3,4,5},
{1,1,1,2,3,5,6,4},
{1,1,1,2,3,5,6,4},
{1,1,2,2,4,7,6,5},
{1,2,3,4,5,9,8,6},
{2,3,4,5,6,8,9,7},
{4,5,6,7,8,10,10,8},
{6,7,8,8,9,8,8,8}
},
//94
{
{2,1,1,2,3,5,6,7},
{1,1,2,2,3,7,7,7},
{2,2,2,3,5,7,8,7},
{2,2,3,3,6,10,10,7},
{2,3,4,7,8,13,12,9},
{3,4,7,8,10,12,14,11},
{6,8,9,10,12,15,14,12},
{9,11,11,12,13,12,12,12}
},
//92
{
{3,2,2,3,4,6,8,10},
{2,2,2,3,4,9,10,9},
{2,2,3,4,6,9,11,9},
{2,3,4,5,8,14,13,10},
{3,4,6,9,11,17,16,12},
{4,6,9,10,13,17,18,15},
{8,10,12,14,16,19,19,16},
{12,15,15,16,18,16,16,16}
},
//90
{
{3,2,2,3,5,8,10,12},
{2,2,3,4,5,12,12,11},
{3,3,3,5,8,11,14,11},
{3,3,4,6,10,17,16,12},
{4,4,7,11,14,22,21,15},
{5,7,11,13,16,21,23,18},
{10,13,16,17,21,24,24,20},
{14,18,19,20,22,20,21,20}
},
//88
{
{4,3,2,4,6,10,12,15},
{3,3,3,5,6,14,14,13},
{3,3,4,6,10,14,17,13},
{3,4,5,7,12,21,19,15},
{4,5,9,13,16,26,25,18},
{6,8,13,15,19,25,27,22},
{12,15,19,21,25,29,26,24},
{17,22,23,24,27,24,25,24}
},
//86
{
{4,3,3,4,7,11,14,17},
{3,3,4,5,7,16,17,15},
{4,4,4,7,11,16,19,16},
{4,5,6,8,14,24,22,17},
{5,6,10,16,19,31,29,22},
{7,10,15,18,23,29,32,26},
{14,18,22,24,29,34,34,28},
{20,26,27,27,31,28,29,28}
},
//84
{
{5,4,3,5,8,13,16,20},
{4,4,4,6,8,19,19,18},
{4,4,5,8,13,18,22,18},
{4,5,7,9,16,28,26,20},
{6,7,12,18,22,35,33,25},
{8,11,18,20,26,33,36,29},
{16,20,25,28,33,39,38,32},
{23,29,30,31,36,32,33,32}
},
//82
{
{6,4,4,6,9,14,18,12},
{4,4,5,7,9,21,22,20},
{5,5,6,9,14,21,25,20},
{5,6,8,10,18,31,29,22},
{6,8,13,20,24,39,37,28},
{9,13,20,23,29,37,41,33},
{18,23,28,31,37,44,43,36},
{26,33,34,35,40,36,37,36}
},
//80
{
{6, 4, 4, 6, 10, 16, 20, 24},
{ 5,5,6,8,10,23,24,22 },
{ 6,5,6,10,16,23,28,22 },
{ 6,7,9,12,20,35,32,25 },
{ 7,9,15,22,27,44,41,31 },
{ 10,14,22,26,32,42,45,37 },
{ 20,26,31,35,41,48,48,40 },
{ 29,37,38,39,45,40,41,40 }
},
//课设矩阵
{
{16,11,10,16,24,40,51,61},
{12,12,14,19,26,58,60,55},
{14,13,16,24,40,57,69,56},
{14,17,22,29,51,87,80,62},
{18,22,37,56,68,109,103,77},
{24,35,55,64,81,104,113,92},
{49,64,78,87,103,121,120,101},
{72,92,95,98,112,100,103,99}
},
//系数保留法量化,6
{
{1,1,1,512,512,512,512,512},
{1,1,512,512,512,512,512,512},
{1,512,512,512,512,512,512,512},
{512,512,512,512,512,512,512,512},
{512,512,512,512,512,512,512,512},
{512,512,512,512,512,512,512,512},
{512,512,512,512,512,512,512,512},
{512,512,512,512,512,512,512,512}
},
//系数保留法量化,10
{
{ 1,1,1,1,512, 512, 512, 512},
{ 1,1,1,512,512,512,512,512 },
{ 1,1,512,512,512,512,512,512 },
{ 1,512,512,512,512,512,512,512 },
{ 512,512,512,512,512,512,512,512 },
{ 512,512,512,512,512,512,512,512 },
{ 512,512,512,512,512,512,512,512 },
{ 512,512,512,512,512,512,512,512 }
}
};
//实验用8*8输入矩阵
int input[8][8] = {
{89, 101, 114, 125, 126, 115, 105, 96},
{97, 115, 131, 147, 149, 135, 123, 113},
{114, 134, 159, 178, 175, 164, 149, 137},
{121, 143, 177, 196, 201, 189, 165, 150},
{119, 141, 175, 201, 207, 186, 162, 144},
{107, 130, 165, 189, 192, 171, 144, 125},
{97, 119, 149, 171, 172, 145, 117, 96},
{88, 107, 136, 156, 155, 129, 97, 75}
};//实验用输入矩阵
//对图片初始化处理
int Initimage(Mat& imagein);
//DCT变换
void DCT(int data[NUM][NUM]);
//DCT反变换
void IDCT(int data[NUM][NUM]);
//四舍五入
int around(double a);
//量化
void DCT(int data[NUM][NUM]);
//DCT反变换
void IDCT(int data[NUM][NUM]);
//量化
int SCH(int data[NUM][NUM], int k);
//反量化
int ISCH(int data[NUM][NUM], int k);
//Z字扫描
int Zscan(int datain[NUM][NUM], int dataout[NUM * NUM]);
//反Z字扫描
int IZscan(int datain[NUM * NUM], int dataout[NUM][NUM]);
//压缩
int fhasaki(Mat image, Mat& imageout1, int*& image1line, int**& image1int, int sch);
//解压缩
int fdehasaki(int length, int w, int h, int* imageline, Mat& imageout2, int sch);
//int转二进制字符
string inttoox(int x, int width);
//二进制字符转int
int oxtoint(string s);
//获取图像灰度直方图
int gethistogram(string dst, Mat image);
int gethistogram(string dst, Mat image1, Mat image2);
int gethistogram(Mat image1, Mat image2, string dst);
class HFMP {
public:
int num;//信源符号(数字)
int count;//出现次数
double p;//概率
bool tag;//标签,默认为true,用于霍夫曼树中辨别是否为原概率
string s;//霍夫曼码
HFMP* b[2];
HFMP() :num(0), count(0), p(0.0), tag(true) {
s = "";
b[0] = NULL;
b[1] = NULL;
}
~HFMP() {
if (b[0])
delete b[0];
if (b[1])
delete b[1];
if (this == NULL)
return;
}
};
class HFMCODE {
friend LZCODE;
HFMP* root;//概率分布
HFMP* code;//霍夫曼树
HFMP* temp;//临时存储点
int count;//符号出现总次数
int pnum;//符号个数
int codelength;//输出序列长度
double H;
void init() {///初始化
delete code;
delete root;
delete temp;
temp = NULL;
code = NULL;
root = new HFMP;//
root->num = 0;
pnum = 1;
count = 0;
}
//计数
void fcount(int* data)
{
cout << "正在统计数据" << endl;
cout << "共计信源符号个数:" << count << endl;
int i = 0;
for (i = 0; i < count; i++)
{
HFMP* q = findp(data[i], root);
if (q)
q->count++;
else
{
newp(data[i], root);
pnum++;
}
}
}
HFMP* findp(int data, HFMP* p) {
if (p->num == data && p->tag)
return p;
if (p->b[1] != NULL)
{
HFMP* q = findp(data, p->b[1]);
if (q != NULL)
return q;
}
if (p->b[0] != NULL)
return findp(data, p->b[0]);
return NULL;
}
void newp(int data, HFMP* p)
{
if (data < p->num && p->b[0])
newp(data, p->b[0]);
if (data > p->num && p->b[1])
newp(data, p->b[1]);
if (data < p->num && p->b[0] == NULL)
{
p->b[0] = new HFMP;
p->b[0]->num = data;
p->b[0]->count++;
}
if (data > p->num && p->b[1] == NULL)
{
p->b[1] = new HFMP;
p->b[1]->num = data;
p->b[1]->count++;
}
if (p->num == data)
cout << "霍夫曼概率计数发生错误!" << endl;
}
//概率分布排序
void sort2(HFMP* p)//不能优化为双链表,与析构函数冲突//整理到temp;
{
HFMP* q = NULL;
HFMP* qq = NULL;
if (temp == NULL)//头结点为空
{
q = new HFMP;
q->num = p->