图片压缩过程模拟: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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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->num;
            q->count = p->count;
            temp = q;
            return;
        }
        if (temp->count <= p->count)//头结点概率小于或等于p
        {
            q = new HFMP;
            q->num = p->num;
            q->count = p->count;
            q->b[0] = temp;
            /*temp->b[1] = q;*/
            temp = q;
            return;
        }
        if (temp->b[0] == NULL)//只有头结点且头结点概率大于p
        {
            q = new HFMP;
            q->num = p->num;
            q->count = p->count;
            temp->b[0] = q;
            /* q->b[1] = temp;*/
            return;
        }
        q = temp;
        while (q->b[0]) {//存在概率大于p的节点
            if (q->b[0]->count > p->count)
            {
                q = q->b[0];
                continue;
            }
            qq = new HFMP;
            qq->num = p->num;
            qq->count = p->count;
            qq->b[0] = q->b[0];
            /* qq->b[1] = q;*/
            q->b[0] = qq;
            return;
        }
        qq = new HFMP;//所有节点概率都小于p
        qq->num = p->num;
        qq->count = p->count;
        /*qq->b[1] = q;*/
        q->b[0] = qq;
        return;
    }
    void sort1(HFMP* p)
    {
        sort2(p);
        if (p->b[0])
            sort1(p->b[0]);
        if (p->b[1])
            sort1(p->b[1]);
    }
    void sort()//将概率分布由小到大排列为链表存到root;
    {
        cout << "开始概率排序" << endl;
        sort1(root);
        delete root;
        root = temp;
        temp = NULL;
    }

    //生成霍夫曼树
    void plantsort(HFMP* p)//整理和概率结点到temp;
    {
        HFMP* q = p;
        if (temp == NULL)//头结点为空
        {
            temp = p;
            return;
        }
        if (temp->count <= p->count)//头结点概率小于或等于p
        {
            p->b[0] = temp;
            temp = p;
            return;
        }
        if (temp->b[0] == NULL)//只有头结点且头结点概率大于p
        {
            temp->b[0] = p;
            /* q->b[1] = temp;*/
            return;
        }
        q = temp;
        while (q->b[0]) {//存在概率大于p的节点
            if (q->b[0]->count > p->count)
            {
                q = q->b[0];
                continue;
            }
            p->b[0] = q->b[0];
            /* qq->b[1] = q;*/
            q->b[0] = p;
            return;
        }
        q->b[0] = p;
        return;
    }
    void plant1(HFMP* p, HFMP** pp, int l) {
        if (p->tag)
            return;
        plant2(p, pp, l);
        if (p->b[0])
            plant1(p->b[0], pp, l);
        if (p->b[1])
            plant1(p->b[1], pp, l);
    }
    void plant2(HFMP* p, HFMP** pp, int l)
    {
        int i;
        for (i = 0; i < l; i++)
        {
            if ((p->count == pp[i]->count) && pp[i]->b[0] && pp[i]->b[1])
            {
                p->b[0] = pp[i]->b[0];
                pp[i]->b[0] = NULL;
                p->b[1] = pp[i]->b[1];
                pp[i]->b[1] = NULL;
                return;
            }
        }
        cout << "霍夫曼编码plant2()出现问题!" << endl;
    }
    bool plant() {
        cout << "开始生成霍夫曼树" << endl;
        HFMP** proot = NULL;
        temp = root;
        root = NULL;
        HFMP* q;
        int i;
        for (i = 0; temp->b[0]->b[0]->b[0];)//编码至剩下3位
        {
            HFMP* p = new HFMP;
            HFMP* pp = new HFMP;
            //最小概率
            q = temp;
            while (q->b[0]->b[0])
                q = q->b[0];
            p->b[0] = q->b[0];
            q->b[0] = NULL;
            //第二小概率
            q = temp;
            while (q->b[0]->b[0])
                q = q->b[0];
            p->b[1] = q->b[0];
            q->b[0] = NULL;

            p->count = p->b[0]->count + p->b[1]->count;
            pp->count = p->count;
            p->tag = false;
            pp->tag = false;
            if (proot == NULL)
                proot = (HFMP**)malloc(sizeof(HFMP*));
            else
                proot = (HFMP**)realloc(proot, (i + 1) * sizeof(HFMP*));
            proot[i] = p;
            i++;
            plantsort(pp);
            p = NULL;
            pp = NULL;
        }
        HFMP* p = new HFMP;
        HFMP* pp = new HFMP;
        p->b[0] = temp->b[0]->b[0];
        temp->b[0]->b[0] = NULL;
        p->b[1] = temp->b[0];
        temp->b[0] = NULL;
        p->count = p->b[0]->count + p->b[1]->count;
        pp->count = p->count;
        p->tag = false;
        pp->tag = false;
        proot = (HFMP**)realloc(proot, (i + 1) * sizeof(HFMP*));
        proot[i] = p;
        i++;
        plantsort(pp);
        pp = NULL;
        p = new HFMP;
        pp = new HFMP;
        p->b[0] = temp->b[0];
        temp->b[0] = NULL;
        p->b[1] = temp;
        temp = NULL;
        p->count = p->b[0]->count + p->b[1]->count;
        pp->count = p->count;
        if (p->count != count)
        {
            delete p;
            for (; i >= 0; i--)
            {
                delete proot[i];
                free(proot[i]);
            }
            return false;
        }
        p->tag = false;
        pp->tag = false;
        temp = pp;
        pp = NULL;
        proot = (HFMP**)realloc(proot, (i + 1) * sizeof(HFMP*));
        proot[i] = p;
        i++;
        p = NULL;
        //至此,霍夫曼树数据已经记录完毕,开始向霍夫曼树回填数据


        plant1(temp, proot, i);
        code = temp;
        temp = NULL;
        //至此,霍夫曼树生成完毕
        //删除多余数据
        for (; i > 0; i--)
        {
            delete proot[i - 1];
            proot[i - 1] = NULL;
        }
        free(proot);
        return true;
    }


    //计算概率分布,生成霍夫曼树,已经包含前方所有步骤
    void calculatep(int* data) {
        fcount(data);
        sort();
        plant();
        cout << "正式开始计算概率" << endl;
        calculatep1(code);
    }
    void calculatep1(HFMP* p) {
        p->p = ((double)p->count / (double)count);
        if (p->tag)
        {
            H -= (log(p->p) / log(2)) * p->p;
        }
        if (p->b[0])
            calculatep1(p->b[0]);
        if (p->b[1])
            calculatep1(p->b[1]);
    }
    void fcode(int l, int* data, fstream* tlist, fstream* tout) {
        count = l;
        calculatep(data);
        fcode1(code);
        cout << "正在输出霍夫曼编码表" << endl;
        fcode2(code, tlist);
        cout << "正在输出霍夫曼编码文件" << endl;
        fout(data, tout);
    }
    void fcode1(HFMP* p) {//生成编码表
        if (p->b[0])
        {
            p->b[0]->s = p->s + "0";
            fcode1(p->b[0]);
        }
        if (p->b[1])
        {
            p->b[1]->s = p->s + "1";
            fcode1(p->b[1]);
        }
    }
    void fcode2(HFMP* p, fstream* t)//将字典输出到文件
    {
        if (p->b[1])
            fcode2(p->b[1], t);
        if (p->tag)
        {
            *t <num <<"\t"<< " p=" << p->p << "\t\t" << p->s <<  endl;
        }
        if (p->b[0])
            fcode2(p->b[0], t);
    }
    void fout(int* data, fstream* t)
    {
        HFMP* p;
        for (int i = 0; i < count; i++)
        {
            p = findp(data[i], code);
            codelength = codelength + (int)p->s.length();
            *t << p->s;
        }
        cout << "霍夫曼编码所得序列长度为:" << codelength << endl;
    }

    //复制一棵独立的霍夫曼树
    void copyhfmtreeP(HFMP* p, HFMP* q) {
        p->num = q->num;
        p->count = q->count;
        p->p = q->p;
        p->tag = q->tag;
        p->s = q->s;
        p->b[0] = NULL;
        p->b[1] = NULL;
    }
    void copyhfmtree(HFMP* frooty, HFMP* frootx) {
        for (int i = 0; i < 2; i++)
        {
            if (frooty->b[i])
                delete frooty->b[i];
            frooty->b[i] = new HFMP;
            if (frootx->b[i])
            {
                copyhfmtreeP(frooty->b[i], frootx->b[i]);
                copyhfmtree(frooty->b[i], frootx->b[i]);
            }
        }
    }
public:
    int getpnum() {
        return pnum;
    }
    HFMP* gethfmtree() {
        HFMP* p = new HFMP;
        copyhfmtreeP(p, code);
        copyhfmtree(p, code);
        return p;
    }
    double getH() { return H; }
    HFMCODE(int l, int* data, fstream* tlist, fstream* tout) :H(0.0), count(0), codelength(0)//默认存在符号0
    {
        temp = NULL;
        code = NULL;
        root = new HFMP;
        root->num = 0;
        pnum = 1;
        fcode(l, data, tlist, tout);
        cout << "霍夫曼编码信源符号种数:" << pnum << endl;
        cout << "霍夫曼编码信源符号个数:" << count << endl;
        cout << "霍夫曼编码平均码长:" << (double)codelength / count << endl;
        cout << "信源信息熵:" << H << endl;
        cout << "霍夫曼编码编码效率:" << H / (double)codelength * count << endl;
        cout << "霍夫曼编码所得压缩比:" << (double)count * 8 / codelength << endl;
    }
    ~HFMCODE() {
        delete temp;
        delete code;
        delete root;
    }
};

class HFMDECODE {

    HFMP* code;//霍夫曼树
    int count;//符号出现总次数
    int pnum;//符号个数
    int* decode;
public:
    HFMDECODE(HFMP* p, int fpnum, fstream* tin) :count(0), pnum(fpnum), decode(NULL)
    {
        cout << "霍夫曼译码信源符号种数:" << pnum << endl;
        code = p;
        p = NULL;
        char ch;
        string s = "";
        HFMP* q = code;
        int i = 0;
        while (1)
        {
            *tin >> ch;
            s = s + ch;
            if (ch == '1')
                q = q->b[1];
            else
                q = q->b[0];
            if (tin->eof())
                break;
            if (q->tag)//
            {
                decode = (int*)realloc(decode, (count + 1) * sizeof(int));
                if (q->s == s)
                    decode[count] = q->num;
                else
                    cout << "hfm decode error!" << endl;
                count++;
                s = "";
                q = code;
            }
        }
        cout << "霍夫曼译码获得信源符号个数:" << count << endl;
    }
    ~HFMDECODE() {
        if (code)
            delete code;
        free(decode);
    }
};

class LZP {//加一个前置索引则可以将译码器优化
public:
    int num;//信源符号
    int lastposit;//前一个位置
    int posit;//当前位置
    int pnum;//尾巴个数
    LZP** p;//尾巴指针

    LZP() :num(0), posit(0), pnum(0), p(NULL), lastposit(0) {};
    ~LZP() {
        for (; pnum > 0; pnum--)
        {
            if (p[pnum - 1])
                delete p[pnum - 1];
        }
        if (p)
            free(p);
    }
};

class LZCODE
{
    LZP* root;//lz编码表表根
    int* list;//符号编码表,坐标表示当前编号
    int xnum;//信源符号个数
    int** file;//被发送的信息,坐标表示当前段号,0表示前一段号,1表示末尾字符编号//处理后发送
    int ynum;//段数
    double H;
    //查找是否有这样的信源符号串//信源符号数组,数组长度
    LZP* findp1(int* numlist, int length) {

        if (numlist == NULL)
            return NULL;
        if (length < 1)
            return NULL;
        LZP* q = root;
        for (int i = 0; i < length; i++)
        {
            q = findp2(q, numlist[i]);
            if (q == NULL)
                return NULL;
        }
        return q;
    }

    //查找某LZ结点后方是否存在某信源符号,并返回该符号所在指针//某节点地址,某信源符号

    LZP* findp2(LZP* last, int num) {
        int i = 0;
        for (i = 0; i < last->pnum; i++)
        {
            if (last->p[i])
                if (last->p[i]->num == num)
                    return last->p[i];
        }
        return NULL;
    }

    //在某节点后增加一个符号为num,上一位置为lastposit,当前位置为posit的节点
    void newp(LZP* p, int num, int lastposit, int posit) {
        p->pnum++;
        p->p = (LZP**)realloc(p->p, p->pnum * sizeof(LZP*));
        p->p[p->pnum - 1] = new LZP;
        p->p[p->pnum - 1]->num = num;
        p->p[p->pnum - 1]->posit = posit;
        p->p[p->pnum - 1]->lastposit = lastposit;
    }

    //通过霍夫曼编码树生成LZ编码信源字符字典//霍夫曼树根节点,当前列表信源符号个数
    int record(HFMP* p, int i) {
        if (p->tag)
        {
            list = (int*)realloc(list, (i + 1) * sizeof(int));
            list[i] = p->num;
            i++;
        }
        if (p->b[0])
            i = record(p->b[0], i);
        if (p->b[1])
            i = record(p->b[1], i);
        return i;
    }

    int findnumcode(int num)//找到信源符号编号
    {
        for (int i = 0; i < xnum; i++)
        {
            if (list[i] == num)
                return i;
        }
        cout << "LZ编码信源编号出错" << endl;
        return 0;
    }


    //LZ编码
    void fcode(int* line, int length) {
        LZP* q = NULL;
        LZP* p = NULL;
        int i;
        q = root;
        cout << "LZ编码信源符号个数:" << length << endl;
        for (i = 0; i < length; i++)//最后一段可能与前面重复
        {
            p = findp2(q, line[i]);
            if (i == length - 1 && p)
            {
                file = (int**)realloc(file, (ynum + 1) * sizeof(int*));
                file[ynum] = (int*)malloc(2 * sizeof(int));
                file[ynum][0] = q->posit;
                file[ynum][1] = findnumcode(p->num);
                ynum++;
                return;
            }
            else if (p == NULL)
            {
                newp(q, line[i], q->posit, ynum + 1);
                file = (int**)realloc(file, (ynum + 1) * sizeof(int*));
                file[ynum] = (int*)malloc(2 * sizeof(int));
                p = findp2(q, line[i]);
                if (!p)
                {
                    cout << "lz code error!" << endl;
                    return;
                }
                file[ynum][0] = q->posit;
                file[ynum][1] = findnumcode(p->num);
                ynum++;
                q = root;
                p = NULL;
            }
            else
                q = p;
        }
    }
    //输出编码表以及信源符号字典
    void fout(fstream* flist, fstream* ffile)
    {
        cout << "LZ编码信源符号种数:" << xnum << endl;
        cout << "LZ编码段数(不包括0段):" << ynum << endl;
        int xl = (int)(log(xnum) / log(2)) + 1;
        int yl = (int)(log(ynum) / log(2)) + 1;
        int i;
        for (i = 0; i < xnum; i++)
        {
            *flist << inttoox(i, xl) << " " << list[i] << endl;
        }
        for (i = 0; i < ynum; i++)
        {
            *ffile << inttoox(file[i][0], yl) << inttoox(file[i][1], xl);
        }
        cout << "LZ编码所得序列长度:" << (xl + yl) * ynum << endl;
    }
    //给信源符号编码
public:
    LZCODE(HFMCODE& T, int* line, int length, fstream* flist, fstream* ffile) :xnum(0), list(NULL), file(NULL), ynum(0)
    {
        //生成信源字符字典
        xnum = record(T.code, xnum);
        H = T.getH();
        if (xnum != T.pnum)
        {
            cout << xnum << " " << T.pnum << endl;
            cout << "LZ code error!" << endl;
        }
        root = new LZP;
        fcode(line, length);
        fout(flist, ffile);
        int xl = (int)(log(xnum) / log(2)) + 1;
        int yl = (int)(log(ynum) / log(2)) + 1;
        cout << "LZ编码平均码长:" << (double)ynum * (xl + yl) / (double)length << endl;
        cout << "LZ编码编码效率:" << H / (double)ynum / (xl + yl) * (double)length << endl;
        cout << "LZ编码所得压缩比:" << (double)T.count*8 / ynum / (xl + yl) << endl;
    }
    int* getlist()//有内存泄漏风险
    {
        int* p = (int*)malloc(xnum * sizeof(int));
        for (int i = 0; i < xnum; i++)
        {
            p[i] = list[i];
        }
        return p;
    }
    int getxnum() { return xnum; }
    int getynum() { return ynum; }
    ~LZCODE() {
        free(list);
        delete root;
        for (; ynum > 0; ynum--)
            free(file[ynum - 1]);
        free(file);
    }
};

class LZDECODE {
    int** root;//LZ编码,下标为当前段号,前一段号、信源符号
    int ynum;//LZ编码段数
    int* list;//符号编码表//从文件接收
    int xnum;//信源符号个数
    int* code;//译码
    int znum;//译码信源个数
    //在某节点后增加一个符号为num,上一位置为lastposit,当前位置为posit的节点

public:
    //信源编码字典,信源符号种类数,编码输出文件,编码段数
    LZDECODE(int* flist, int fxnum, fstream* ffile, int fynum) :root(NULL), list(NULL), xnum(0), ynum(0), code(NULL), znum(0) {
        list = (int*)malloc(fxnum * sizeof(int));
        while (xnum < fxnum)
        {
            list[xnum] = flist[xnum];
            xnum++;
        }
        int xl = (int)(log(fxnum) / log(2)) + 1;
        int yl = (int)(log(fynum) / log(2)) + 1;
        cout << "LZ译码信源符号种数:" << xnum << endl;
        char ch;
        string ss1 = "";
        string ss2 = "";
        root = (int**)malloc(sizeof(int*));//空出0位
        ynum++;
        while (1)
        {
            for (int i = 0; i < yl; i++)
            {
                ch = ffile->get();
                ss1 = ss1 + ch;
            }
            if (ffile->eof())
                break;
            for (int i = 0; i < xl; i++)
            {
                ch = ffile->get();
                ss2 = ss2 + ch;
            }
            root = (int**)realloc(root, (ynum + 1) * sizeof(int*));
            root[ynum] = (int*)malloc(2 * sizeof(int));
            root[ynum][0] = oxtoint(ss1);//段号
            root[ynum][1] = oxtoint(ss2);//信源符号编号

            ynum++;
            ss1 = "";
            ss2 = "";
        }
        cout << "LZ译码段号个数(包括第0段):" << ynum << endl;
        int* p = NULL;
        int i, j;
        for (i = 1, j = 0; i < ynum; i++)
        {
            j = 0;
            p = (int*)malloc(sizeof(int));
            p[0] = list[root[i][1]];
            int tempposit = root[i][0];
            j++;
            while (tempposit != 0)
            {
                p = (int*)realloc(p, (j + 1) * sizeof(int));
                p[j] = list[root[tempposit][1]];
                tempposit = root[tempposit][0];
                j++;
            }
            code = (int*)realloc(code, (znum + j) * sizeof(int));
            for (int k = 0; k < j; k++)
            {
                code[znum] = p[j - k - 1];
                znum++;
            }
            free(p);
        }
        cout << "LZ译码信源符号个数:" << znum << endl;
    };
    ~LZDECODE()
    {
        free(list);
        free(code);
        for (int i = 1; i < ynum; i++)
        {
            free(root[i]);
        }
        free(root);
    }
};

int main(void)
{
    int sch;
    for (sch = 0; sch < 14; sch++)
    {
        cout << "量化表" << sch << endl;
        clock_t startTime, endTime, time1, time2, time3, time4, time5, time6, time7, time8;
        startTime = clock();//计时开始
        //文件目录预处理
        string ds = to_string(sch);
        char* buffer;//当前目录
        string root;//当前目录
        string src = "\\image_o\\1.jpg";//原始图片目录
        string dstout = "\\image_out" + ds + "\\";//输出根目录
        cout << "正在获得当前路径" << endl;
        //获得当前路径
        if ((buffer = _getcwd(NULL, 0)) == NULL)
        {
            perror("_getcwderror");
            return -1;
        }  //得到当前的工作路径
        else
        {
            root = buffer;
            free(buffer);
            buffer = NULL;
            src = root + src;
            dstout = root + dstout;
        }
        cout << "已经获得当前路径" << endl;
        cout << "正在加载图片" << endl;
        //原始图片处理
        Mat image1 = imread(src, IMREAD_UNCHANGED);//读取图片
        if (image1.empty())//录入原始图片
        {
            cout << "图片加载失败!" << endl;
            CreateDirectory(L"image_o", NULL);
            cout << "请在新生成的image_o目录下放置名为1.jpg的图片" << endl;
            return -1;
        }
        cout << "图片加载完成" << endl;
        cout << "正在初始化图片" << endl;
        if (Initimage(image1) == 0)//图片初始化
        {
            cout << "参数错误!" << endl;
            return -1;
        }
        cout << "图片初始化完成,正在创建输出目录image_out"+ds << endl;
        //创建输出文件夹
        CreateDirectory(L"image_out" + (CString)ds.c_str(), NULL);

        //存储格式化后的图片
        imwrite(dstout + "o.jpg", image1);
        //压缩,获得并存储数据
        ofstream out;
        string txtname = "sch.txt";
        out.open(dstout + txtname, ios::out);
        if (!out.is_open())
        {
            cout << "txt open fail!";
        }
        string imageoutdst2 = dstout + "sch.jpg";//量化图
        string imageoutdst3 = dstout + "decode.jpg";//解压后的图片
        Mat image2, image3;
        int* imageline = NULL;
        int** imageint = NULL;


        cout << "开始压缩,请等待" << endl;
        //正式开始压缩
        time1 = clock();
        if (fhasaki(image1, image2, imageline, imageint, sch) != 1)
        {
            cout << "图片压缩失败!" << endl;
            return -1;
        }
        cout << "图片压缩完成,正在保存数据" << endl;
        imwrite(imageoutdst2, image2);

        time2 = clock();
        cout << "压缩用时:" << (double)(time2 - time1) / CLOCKS_PER_SEC << "s" << endl;
        int i, k;
        for (i = 0, k = 0; i < image1.rows * image1.cols; i++, k++)
        {
            if (k >= NUM * NUM)
            {
                k = 0;
                out << endl;
            }
            /*out << imageline[i] << " ";*/
            out << setw(5) << imageline[i];
        }




        //霍夫曼编码
        cout << "正在进行霍夫曼编码" << endl;
        time3 = clock();
        fstream thfmout, thfmlist;
        thfmlist.open(dstout + "hfmlist.txt", ios::out);
        thfmout.open(dstout + "hfmout.txt", ios::out);
        HFMCODE hfm(image1.rows * image1.cols, imageline, &thfmlist, &thfmout);
        thfmout.close();
        thfmout.open(dstout + "hfmout.txt");
        time4 = clock();
        cout << "霍夫曼编码用时:" << (double)(time4 - time3) / CLOCKS_PER_SEC << "s" << endl;

        cout << "正在进行霍夫曼译码" << endl;

        HFMP* hfmtree = hfm.gethfmtree();
        HFMDECODE dhfm(hfmtree, hfm.getpnum(), &thfmout);
        hfmtree = NULL;//防火防盗防泄漏

        time5 = clock();
        cout << "霍夫曼译码用时:" << (double)(time5 - time4) / CLOCKS_PER_SEC << "s" << endl;



        //LZ编码
        cout << "正在进行LZ编码" << endl;
        fstream tlzlist, tlzout;
        tlzlist.open(dstout + "lzlist.txt", ios::out);
        tlzout.open(dstout + "lzout.txt", ios::out);
        LZCODE lz(hfm, imageline, image1.rows * image1.cols, &tlzlist, &tlzout);
        tlzout.close();
        time6 = clock();
        cout << "LZ编码用时:" << (double)(time6 - time5) / CLOCKS_PER_SEC << "s" << endl;
        tlzout.open(dstout + "lzout.txt");
        cout << "正在进行LZ译码" << endl;
        int* lzlist = lz.getlist();
        LZDECODE dlz(lzlist, lz.getxnum(), &tlzout, lz.getynum());
        time7 = clock();
        cout << "LZ译码用时:" << (double)(time7 - time6) / CLOCKS_PER_SEC << "s" << endl;
        free(lzlist);



        //解压缩
        fdehasaki(image1.rows * image1.cols, image1.cols / NUM, image1.rows / NUM, imageline, image3, sch);
        time8 = clock();
        cout << "解压缩用时:" << (double)(time8 - time7) / CLOCKS_PER_SEC << "s" << endl;
        imwrite(imageoutdst3, image3);
        //误差直方图

        cout << "原图灰度值数最大值" << gethistogram(dstout + "ho.jpg", image1) << endl;
        cout << "解压后灰度值数最大值" << gethistogram(dstout + "hdecode.jpg", image3) << endl;
        cout << "灰度差值数最大值" << gethistogram(dstout + "hdelta1.jpg", image1, image3) << endl;
        cout << "灰度值数变化量差值" << gethistogram(image1, image3, dstout + "hdelta2.jpg") << endl;

        //防止内存泄露及后续扫尾工作
        out.close();
        thfmout.close();
        thfmlist.close();
        tlzlist.close();
        tlzout.close();
        free(imageline);
        for (i = 0; i < image1.rows; i++)
        {
            free(*(imageint + i));
        }
        free(imageint);
        cout << "程序结束" << endl;

        endTime = clock();//计时结束
        cout << "总共用时: " << (double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
    }
    return 0;
}

int Initimage(Mat& imagein)
{
    if (NUM != 8 && NUM != 16)
        return 0;
    int h, w;
    Mat imageout;
    h = imagein.rows / NUM;//行数
    w = imagein.cols / NUM;//列数
    imageout = Mat::zeros(h * NUM, w * NUM, CV_8UC1);
    resize(imagein, imageout, imageout.size());//休整大小
    cvtColor(imageout, imageout, COLOR_RGB2GRAY);//转灰度图

    if (imageout.empty())
        return 0;
    imagein = imageout;
    return 1;
}
void DCT(int data[NUM][NUM])
{
    int output[NUM][NUM];
    double alpha, beta;//C(k)  C(l)
    int m = 0, n = 0, k = 0, l = 0;
    for (k = 0; k < NUM; k++)
    {
        for (l = 0; l < NUM; l++)
        {
            if (k == 0)
            {
                alpha = sqrt(1.0 / NUM);
            }
            else
            {
                alpha = sqrt(2.0 / NUM);
            }
            if (l == 0)
            {
                beta = sqrt(1.0 / NUM);
            }
            else
            {
                beta = sqrt(2.0 / NUM);
            }
            double temp = 0.0;
            for (m = 0; m < NUM; m++)
            {
                for (n = 0; n < NUM; n++)
                {
                    temp += data[m][n] * cos((2 * m + 1) * k * PI / (2.0 * NUM)) * cos((2 * n + 1) * l * PI / (2.0 * NUM));
                }
            }
            output[k][l] = around(alpha * beta * temp);
        }
    }
    memset(data, 0, sizeof(int) * NUM * NUM);
    std::memcpy(data, output, sizeof(int) * NUM * NUM);
}
void IDCT(int data[NUM][NUM])
{
    int output[NUM][NUM];
    double alpha, beta;
    int m = 0, n = 0, k = 0, l = 0;
    for (m = 0; m < NUM; m++)
    {
        for (n = 0; n < NUM; n++)
        {
            double temp = 0.0;
            for (k = 0; k < NUM; k++)
            {
                for (l = 0; l < NUM; l++)
                {
                    if (k == 0)
                    {
                        alpha = sqrt(1.0 / NUM);
                    }
                    else
                    {
                        alpha = sqrt(2.0 / NUM);
                    }
                    if (l == 0)
                    {
                        beta = sqrt(1.0 / NUM);
                    }
                    else
                    {
                        beta = sqrt(2.0 / NUM);
                    }

                    temp += alpha * beta * data[k][l] * cos((2 * m + 1) * k * PI / (2 * NUM)) * cos((2 * n + 1) * l * PI / (2 * NUM));

                }
            }
            output[m][n] = around(temp);
        }
    }
    memset(data, 0, sizeof(int) * NUM * NUM);
    std::memcpy(data, output, sizeof(int) * NUM * NUM);

}
int SCH(int data[NUM][NUM], int k)
{
    if (NUM == 8)
    {
        for (int i = 0; i < NUM; i++)
        {
            for (int j = 0; j < NUM; j++)
            {
                data[i][j] /= F8[k][i][j];
            }
        }
        return 1;
    }
    else
        return 0;
}
int ISCH(int data[NUM][NUM], int k)
{
    if (NUM == 8)
    {
        for (int i = 0; i < NUM; i++)
        {
            for (int j = 0; j < NUM; j++)
            {
                data[i][j] *= F8[k][i][j];
            }
        }
        return 1;
    }
    else
        return 0;
}
int around(double a)
{
    if (a >= 0)
    {
        return int(a + 0.5);
    }
    else
    {
        return int(a - 0.5);
    }

}
int fhasaki(Mat image, Mat& imageout1, int*& image1line, int**& image1int, int sch) {
    if (image.cols % NUM != 0 || image.rows % NUM != 0)
        return -1;
    int h = image.rows / NUM;
    int w = image.cols / NUM;
    imageout1 = Mat::zeros(h * NUM, w * NUM, CV_8UC1);
    //imageout2 = Mat::zeros(h * NUM, w * NUM, CV_8UC1);
    /*cout << h << w;*/
    image1line = (int*)malloc(h * w * NUM * NUM * sizeof(int));//Z字扫描后所得一维序列//申请空间
    image1int = (int**)malloc(h * NUM * sizeof(int*));//量化后图片的二维数组
    int k;
    for (k = 0; k < h * NUM; k++)
    {
        image1int[k] = (int*)malloc((int)w * NUM * sizeof(int));
    }
    int i, j, m, n;
    for (i = 0; i < w; i++)
    {
        for (j = 0; j < h; j++)
        {
            int piceline[NUM * NUM];
            int piceint[NUM][NUM];
            for (m = 0; m < NUM; m++)
            {
                for (n = 0; n < NUM; n++)
                {
                    piceint[m][n] = (int)image.at(j * NUM + m, i * NUM + n);//图片部分录入
                }
            }
            DCT(piceint);
            SCH(piceint, sch);

            for (m = 0; m < NUM; m++)
            {
                for (n = 0; n < NUM; n++)
                {
                    image1int[j * NUM + m][i * NUM + n] = piceint[m][n];//量化后的矩阵部分录入
                    imageout1.at(j * NUM + m, i * NUM + n) = (uchar)piceint[m][n];//量化后的图片部分录入
                }
            }
            Zscan(piceint, piceline);
            for (k = 0; k < NUM * NUM; k++)
            {
                image1line[i * h * NUM * NUM + j * NUM * NUM + k] = piceline[k];//Z字扫描后的一维数组录入
            }
            //ISCH(piceint);
            //IDCT(piceint);
            //for (m = 0; m < NUM; m++)
            //{
            //    for (n = 0; n < NUM; n++)
            //    {
            //        imageout2.at(j * NUM + m, i * NUM + n) = (uchar)piceint[m][n];//解压后的图片录入
            //    }
            //}
        }
    }
    return 1;
}
int fdehasaki(int length, int w, int h, int* imageline, Mat& imageout2, int sch)
{
    imageout2 = Mat::zeros(h * NUM, w * NUM, CV_8UC1);
    int i, j, m, n;
    for (i = 0; i < w; i++)
    {
        for (j = 0; j < h; j++)
        {
            int piceline[NUM * NUM];
            int piceint[NUM][NUM];
            for (int k = 0; k < NUM * NUM; k++)
            {
                piceline[k] = imageline[i * h * NUM * NUM + j * NUM * NUM + k];//Z字扫描后的一维数组录入
            }
            IZscan(piceline, piceint);
            ISCH(piceint, sch);
            IDCT(piceint);
            for (m = 0; m < NUM; m++)
            {
                for (n = 0; n < NUM; n++)
                {
                    imageout2.at(j * NUM + m, i * NUM + n) = (uchar)piceint[m][n];//解压后的图片录入
                }
            }
        }
    }
    cout << "图片解压完成!" << endl;
    return 0;
}
//当返回值为0时说明发生错误,返回值为1时,运行正常
int Zscan(int datain[NUM][NUM], int dataout[NUM * NUM])
{
    int i, j, k, c;
    for (i = 0, j = 0, k = 0, c = 0; k < NUM * NUM; k++)
    {
        dataout[k] = datain[i][j];
        if (i == 0 && j == 0)
            c = 0;
        else if (c == 0 && j == 0)
            c = 1;
        else if (c == 0 && j == (NUM - 1))
            c = 3;
        else if (c == 1 && j == NUM - 1)
            c = 0;
        else if (c == 1 && i == 0)
            c = 2;
        else if (c == 1)
            c = 1;
        else if (c == 2 && i == 0)
            c = 3;
        else if (c == 2 && i == (NUM - 1))
            c = 1;
        else if (c == 3 && i == (NUM - 1))
            c = 2;
        else if (c == 3 && j == 0)
            c = 0;
        else if (c == 3)
            c = 3;
        else
            return 0;
        if (c == 0)//水平向右
        {
            i++;
        }
        else if (c == 1)//斜向左下
        {
            i--;
            j++;
        }
        else if (c == 2)//垂直向下
        {
            j++;
        }
        else if (c == 3)//斜向右上
        {
            i++;
            j--;
        }
        else
        {
            cout << "Zscan error" << endl;
            return 0;//error
        }
    }
    return 1;
}
int IZscan(int datain[NUM * NUM], int dataout[NUM][NUM])
{
    int i, j, k, c;
    for (i = 0, j = 0, k = 0, c = 0; k < NUM * NUM; k++)
    {
        dataout[i][j] = datain[k];
        if (i == 0 && j == 0)
            c = 0;
        else if (c == 0 && j == 0)
            c = 1;
        else if (c == 0 && j == (NUM - 1))
            c = 3;
        else if (c == 1 && j == NUM - 1)
            c = 0;
        else if (c == 1 && i == 0)
            c = 2;
        else if (c == 1)
            c = 1;
        else if (c == 2 && i == 0)
            c = 3;
        else if (c == 2 && i == (NUM - 1))
            c = 1;
        else if (c == 3 && i == (NUM - 1))
            c = 2;
        else if (c == 3 && j == 0)
            c = 0;
        else if (c == 3)
            c = 3;
        else
            return 0;
        if (c == 0)//水平向右
        {
            i++;
        }
        else if (c == 1)//斜向左下
        {
            i--;
            j++;
        }
        else if (c == 2)//垂直向下
        {
            j++;
        }
        else if (c == 3)//斜向右上
        {
            i++;
            j--;
        }
        else
        {
            cout << "IZscan error" << endl;
            return 0;//error
        }
    }
    return 1;
}

string inttoox(int x, int width)
{
    string s = "";
    if (x == 0)
    {
        s = "0";
    }
    while (x != 0)
    {
        if (x % 2 == 0)
            s = "0" + s;
        else
            s = "1" + s;
        x /= 2;
    }
    if (s.length() < width)
    {
        int i = width - (int)s.length();
        for (; i > 0; i--)
            s = "0" + s;
    }
    return s;
}
int oxtoint(string s)
{
    int x = 0;
    for (int i = 0; i < s.length(); i++)
    {
        x *= 2;
        x += s[i] - '0';
    }
    return x;
}
int gethistogram(string dst, Mat image)
{
    int h = 300;
    int w = 512;
    int count[256] = { 0 };
    if (image.channels() != 1)
        Initimage(image);
    int i, j;
    for (i = 0; i < image.cols; i++)
        for (j = 0; j < image.rows; j++)
        {
            count[(int)image.at(j, i)]++;
        }

    int max = count[0];
    for (i = 0; i < 256; i++)
        if (count[i] > max)
            max = count[i];
    for (i = 0; i < 256; i++)
    {
        count[i] = max - count[i];
        count[i] = (count[i] * h / max);
    }

    Size s(w, h);
    Mat out(s, CV_8UC1);
    for (i = 0; i < 256; i++)
        for (j = 0; j < h; j++)
        {
            if (j < count[i])
            {
                out.at(j, 2 * i) = 200;
                out.at(j, 2 * i + 1) = 200;
            }
            else
            {
                out.at(j, 2 * i) = 0;
                out.at(j, 2 * i + 1) = 0;
            }
        }
    imwrite(dst, out);
    return max;
}
int gethistogram(string dst, Mat image1, Mat image2)
{
    double m=0;
    int h = 300;
    int w = 512;
    int count[256 + 255] = { 0 };
    if (image1.channels() != 1)
        Initimage(image1);
    if (image2.channels() != 1)
        Initimage(image2);
    if (image1.size() != image2.size())
    {
        cout << "图片不匹配" << endl;
        return 0;
    }
    int i, j;
    for (i = 0; i < image1.cols; i++)
        for (j = 0; j < image1.rows; j++)
        {
            int x = image1.at(j, i) - image2.at(j, i);
            count[255 + x]++;
        }


    int max = count[0];
    for (i = 0; i < 256 + 255; i++)
    {
        if (count[i] > max)
            max = count[i];
        m += (i - 255) * (i - 255) * count[i];
    }
    for (i = 0; i < 256 + 255; i++)
    {
        count[i] = max - count[i];
        count[i] = (count[i] * h / max);
    }

    Size s(w, h);
    Mat out(s, CV_8UC1);
    for (i = 0; i < 256 + 255; i++)
        for (j = 0; j < h; j++)
        {
            if (j < count[i])
            {
                out.at(j, i) = 200;
            }
            else
            {
                out.at(j, i) = 0;
            }
        }
    imwrite(dst, out);
    cout << "方差:"<(j, i)]++;
        }
    for (i = 0; i < image1.cols; i++)
        for (j = 0; j < image1.rows; j++)
        {
            count2[(int)image2.at(j, i)]++;
        }
    for (i = 0; i < 256; i++)
        count[i] = count1[i] - count2[i];
    int max = count[0];
    int min = count[0];
    for (i = 0; i < 256; i++)
    {
        if (count[i] > max)
            max = count[i];
        if (count[i] < min)
            min = count[i];
    }
   
    Size s(w, h);
    int v = (max*h / (max - min));
    Mat out(s, CV_8UC1);
    for (i = 0; i < 256; i++)
    {
        count[i] = -(count[i] * h / (max - min)) + v;
        for (j = 0; j < h; j++)
        {
            if (count[i] < v)
            {
                if (j < count[i] || j>v)
                {
                    out.at(j, 2 * i) = 200;
                    out.at(j, 2 * i + 1) = 200;
                }
                else
                {
                    out.at(j, 2 * i) = 0;
                    out.at(j, 2 * i + 1) = 0;
                }
            }
            else if (count[i] > v)
            {
                if (j > count[i] || j < v)
                {
                    out.at(j, 2 * i) = 200;
                    out.at(j, 2 * i + 1) = 200;
                }
                else
                {
                    out.at(j, 2 * i) = 0;
                    out.at(j, 2 * i + 1) = 0;
                }
            }
            else
            {
                out.at(j, 2 * i) = 200;
                out.at(j, 2 * i + 1) = 200;
            }
        }
    }
    imwrite(dst, out);
    return max-min;
}


 

 

你可能感兴趣的:(图片压缩过程模拟:dct离散余弦变换+量化+哈夫曼编码+LZ编码+上述反变换及译码c++)