图片压缩过程模拟:dct离散余弦变换+量化+哈夫曼编码+LZ编码+上述反变换及译码c++

《信息论》的课程设计,要求完成标题所述内容

//仅供参考

使用matlab或更方便简洁,但如果想过一遍流程的话可以参考下面的代码,编译需要安装opencv

代码还有很大优化的空间,可以用向量解决代码中指针较多的问题。也可以用多线程优化运行速度,LZ编码类可以试着增加独立性,取消与霍夫曼编码的关联,建议试运行时使用较小的图片,过一下main函数。

文中参考网址及部分代码来源:

dct变换及逆变换的代码及量化部分的参考代码

https://blog.csdn.net/u014518566/article/details/46432621?ops_request_misc=&request_id=&biz_id=102&utm_term=dct%E7%A6%BB%E6%95%A3%E4%BD%99%E5%BC%A6%E5%8F%98%E6%8D%A2%E9%87%8F%E5%8C%96c++&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-46432621

量化矩阵的来源:

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->
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值