环境:Win10 (x64)
编译器:VS2019 (x64)


encode输入图像文件 gray.bmp
生成文件file.dat 和 code.dat


decode输入文件file.dat 和 code.dat
生成图像gary.bmp


encode:

#include"HXLBMPFILE.h"
#include<algorithm>
#include<cstring>
#include<fstream>
#include<vector>
using namespace std;class HuffmanNode
{public:unsigned char symbol;unsigned int freq;unsigned int codeword;unsigned short codewordLen;//二进制长度HuffmanNode* left, * right;HuffmanNode(){left = right = 0; }HuffmanNode(unsigned char s, unsigned int f, HuffmanNode* lf = 0, HuffmanNode* rt = 0){symbol = s;freq = f;left = lf, right = rt;}
};class ListNode
{public:HuffmanNode* tree;ListNode* prev, * next;ListNode(){next = prev = 0;}ListNode(ListNode* p, ListNode* n){prev = p, next = n;}
};//包括HuffmanNode 用来作为链表的节点class DataRec
{public:unsigned char symbol;unsigned int freq; DataRec(){}bool operator == (const DataRec& dr) const{return symbol == dr.symbol;}bool operator < (const DataRec& dr)const{return freq < dr.freq;}
};class HuffmanCoding
{public:const unsigned int ASCII;const unsigned int bits;const unsigned short mask = 0xff;HuffmanNode* HuffmanTree, ** chars;//编码序列unsigned short dataCnt;unsigned int bitsCnt;vector<DataRec> data;HuffmanCoding(): ASCII(256), bits(8){chars = new HuffmanNode * [ASCII + 1];for (int i = 0; i < ASCII; i++)chars[i] = 0;} void encode(HXLBMPFILE*, const char*, const char*);void input(HXLBMPFILE*);void writebytes(ofstream&, unsigned int, int);void createHuffmanTree();void createCodewords(HuffmanNode*, unsigned int, unsigned short);void transformTree2Lists(HuffmanNode*);void outputHeader(HXLBMPFILE*, const char*);void outputData(HXLBMPFILE*, const char*);void saveCode(const char*);
};void  HuffmanCoding::encode(HXLBMPFILE* bmpfile, const char* FileName1, const char* FileName2)
{input(bmpfile);createHuffmanTree();createCodewords(HuffmanTree, 0, 0);transformTree2Lists(HuffmanTree);outputHeader(bmpfile, FileName1);outputData(bmpfile, FileName1);saveCode(FileName2);
} void HuffmanCoding::writebytes(ofstream& fout, unsigned int pack, int bytes)
{unsigned char* s = new unsigned char[bytes];for (int i = bytes - 1; i >= 0; i--){s[i] = pack & mask;pack >>= bits;}for (int i = 0; i < bytes; i++)fout.put(s[i]);
} void HuffmanCoding::input(HXLBMPFILE* bmpfile)
{unsigned char ch;DataRec r;//当前的数据vector<DataRec>::iterator iter;//迭代器r.freq = 1; for (int i = 0; i < (*bmpfile).imageh; i++)for (int j = 1; j < (*bmpfile).imagew; j++){ch = (*bmpfile).pDataAt(i)[j];r.symbol = ch;iter = find(data.begin(), data.end(), r);if (iter == data.end())data.push_back(r);elseiter->freq++;}sort(data.begin(), data.end());dataCnt = data.size();
} void HuffmanCoding::createHuffmanTree()
{//先创建ListNode为节点的双向链表//再将其改为HuffmanTreeListNode* head, * tail;//链表unsigned int newFreq;head = tail = new ListNode;//创建第一个节点head->tree = new HuffmanNode(data[0].symbol, data[0].freq);//创建双向链表的剩余部分for (int i = 1; i < data.size(); i++){tail->next = new ListNode(tail, 0);tail = tail->next;tail->tree = new HuffmanNode(data[i].symbol, data[i].freq);}//创建HuffmanTreewhile (head != tail){newFreq = head->tree->freq + head->next->tree->freq;ListNode* p, * newNode;for (p = tail; p != 0 && p->tree->freq > newFreq; p = p->prev);//在链表中找到新节点插入的位置newNode = new ListNode(p, p->next);p->next = newNode;if (p == tail)//p->next == 0tail = newNode;elsenewNode->next->prev = newNode;newNode->tree = new HuffmanNode('\0', newFreq, head->tree, head->next->tree);head = head->next->next;delete head->prev->prev;delete head->prev;head->prev = 0;}HuffmanTree = head->tree;delete head;
} void HuffmanCoding::createCodewords(HuffmanNode* p, unsigned int codeword, unsigned short codewordLen)
{if (p->left == 0 && p->right == 0){p->codeword = codeword;p->codewordLen = codewordLen;}else{createCodewords(p->left, codeword << 1, codewordLen + 1);//左0createCodewords(p->right, codeword << 1 | 1, codewordLen + 1);//右1}
} void HuffmanCoding::transformTree2Lists(HuffmanNode* p)
{if (p->left == 0 && p->right == 0){p->right = 0;p->left = 0;chars[unsigned char(p->symbol)] = p;}else{transformTree2Lists(p->left);transformTree2Lists(p->right);}
}void HuffmanCoding::outputHeader(HXLBMPFILE* bmpfile, const char* FileName)
{FILE* f;f = fopen(FileName, "w+b");BITMAPFILEHEADER fh;BITMAPINFOHEADER ih;memset(&ih, 0, sizeof(BITMAPINFOHEADER)); fh.bfType = 0x4d42;fh.bfReserved1 = fh.bfReserved2 = 0;fh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (((*bmpfile).iYRGBnum == 1) ? 256 * sizeof(RGBQUAD) : 0); ih.biSize = 40; ih.biPlanes = 1;ih.biWidth = (*bmpfile).imagew;ih.biHeight = (*bmpfile).imageh;ih.biBitCount = 8 * (*bmpfile).iYRGBnum; int w4b = ((*bmpfile).imagew * (*bmpfile).iYRGBnum + 3) / 4 * 4;ih.biSizeImage = ih.biHeight * w4b;fh.bfSize = fh.bfOffBits + ih.biSizeImage; fwrite(&fh, sizeof(BITMAPFILEHEADER), 1, f);fwrite(&ih, sizeof(BITMAPINFOHEADER), 1, f);fwrite((*bmpfile).palette, sizeof(RGBQUAD), ASCII, f);fclose(f);
}void HuffmanCoding::outputData(HXLBMPFILE* bmpfile, const char* FileName)
{ofstream fout;fout.open(FileName, ios::app | ios::out | ios::binary);const int bytes = 3;//codewordLen最大18unsigned int packCnt = 0, maxPack = bytes * bits, pack = 0;unsigned int nowcodeword = 0, nowcodewordLen = 0;unsigned int bitsLeft = 0, hold = 0;unsigned char ch;bitsCnt = 0; for (int i = (*bmpfile).imageh - 1; i >= 0; i--){for (int j = 0; j < (*bmpfile).imagew; j++){//以ASCII码形式存储编码后的文件数据nowcodeword = chars[(*bmpfile).pDataAt(i)[j]]->codeword;nowcodewordLen = chars[(*bmpfile).pDataAt(i)[j]]->codewordLen;if (nowcodewordLen < maxPack - packCnt){pack = (pack << nowcodewordLen) | nowcodeword;//左移并记录当前codewordpackCnt += nowcodewordLen;//更新长度}else{bitsLeft = maxPack - packCnt;pack <<= bitsLeft;//左移if (bitsLeft != nowcodewordLen){hold = nowcodeword;hold >>= nowcodewordLen - bitsLeft;//右移去掉不能进入的位pack |= hold;//记录hold}elsepack |= nowcodeword;//记录当前codewordwritebytes(fout, pack, bytes);bitsCnt += bytes * bits;if (bitsLeft != nowcodewordLen)//处理当前codeword剩下的位{pack = nowcodeword;packCnt = nowcodewordLen - bitsLeft;pack &= (1 << packCnt) - 1;}else{pack = 0;packCnt = 0;}}}}if (packCnt != 0){pack <<= maxPack - packCnt;//左移补0writebytes(fout, pack, bytes);bitsCnt += packCnt;}fout.close();
} void HuffmanCoding::saveCode(const char* FileName)
{ofstream fout;fout.open(FileName, ios::out | ios::binary);char ch, ch2;unsigned long long totalLen = 0;unsigned long long totalFreq = 0;writebytes(fout, dataCnt, 1);writebytes(fout, bitsCnt, 3); for (int i = data.size() - 1; i >= 0; i--){fout.put(data[i].symbol);writebytes(fout, chars[data[i].symbol]->codeword, 3);fout.put(unsigned char(chars[data[i].symbol]->codewordLen));totalLen += unsigned long long(chars[data[i].symbol]->codewordLen) * chars[data[i].symbol]->freq;totalFreq += unsigned long long(chars[data[i].symbol]->freq);}printf("bpp: %lf \n", totalLen * 1.0 / totalFreq); fout.close();
}

调用:

#include"HuffmanCoding.h"
#include"HXLBMPFILE.h"
using namespace std; int main()
{HXLBMPFILE originalfile;HXLBMPFILE source;HuffmanCoding Huffman; if (!originalfile.LoadBMPFILE("gray.bmp"))exit(1); source.imagew = originalfile.imagew;source.imageh = originalfile.imageh;source.iYRGBnum = originalfile.iYRGBnum;*source.palette = *originalfile.palette; if (!source.AllocateMem())exit(1); for (int i = 0; i < originalfile.imageh; i++)for (int j = 0; j < originalfile.imagew; j++)source.pDataAt(i)[j] = originalfile.pDataAt(i)[j]; Huffman.encode(&source, "file.dat", "code.dat"); return 0;
}

decode:

#pragma once
#include"HXLBMPFILE.h"
#include<algorithm>
#include<cstring>
#include<fstream>
#include<vector>
using namespace std; class HuffmanNode
{public:unsigned char symbol;unsigned int codeword;unsigned short codewordLen;//二进制长度HuffmanNode* left, * right; HuffmanNode(){left = right = 0;}HuffmanNode(unsigned char s, HuffmanNode* lf = 0, HuffmanNode* rt = 0){symbol = s;left = lf, right = rt;}
}; class ListNode
{public:HuffmanNode* tree;ListNode* prev, * next; ListNode(){next = prev = 0;}ListNode(ListNode* p, ListNode* n){prev = p, next = n;}
};//包括HuffmanNode 用来作为链表的节点 class HuffmanCoding
{public:const unsigned int ASCII;const unsigned int bits;const unsigned short mask = 0xffff;HuffmanNode* HuffmanTree, ** chars;//编码序列unsigned short dataCnt;unsigned int bitsCnt;HuffmanCoding() : ASCII(256), bits(8){chars = new HuffmanNode * [ASCII + 1];for (int i = 0; i < ASCII; i++)chars[i] = 0;} void decode(HXLBMPFILE*, const char*, const char*);void loadCode(const char*);unsigned int readbytes(ifstream&, int);void rebuildHuffmanNode(unsigned char, HuffmanNode*, unsigned int, unsigned short);void rebuildHuffmanTree();void inputHeader(HXLBMPFILE*, const char*);void inputData(HXLBMPFILE*, const char*);
}; void HuffmanCoding::decode(HXLBMPFILE* bmpfile, const char* FileName1, const char* FileName2)
{loadCode(FileName2);rebuildHuffmanTree();inputHeader(bmpfile, FileName1);inputData(bmpfile, FileName1);
} unsigned int HuffmanCoding::readbytes(ifstream& fin, int bytes)
{unsigned int num;num = unsigned int(fin.get());for (int i = 1; i < bytes; i++){num <<= bits;num |= unsigned int(fin.get());}return num;
} void HuffmanCoding::loadCode(const char* FileName)
{ifstream fin;fin.open(FileName, ios::in | ios::binary);unsigned char ch;if (!fin)exit(1);dataCnt = readbytes(fin, 1);bitsCnt = readbytes(fin, 3); for (int i = 0; i < dataCnt; i++){ch = unsigned char(readbytes(fin, 1));chars[ch] = new HuffmanNode(ch);chars[ch]->codeword = readbytes(fin, 3);chars[ch]->codewordLen = readbytes(fin, 1);}
} void HuffmanCoding::rebuildHuffmanNode(unsigned char ch, HuffmanNode* p, unsigned int codeword, unsigned short codewordLen)
{if (codewordLen == 0){p->codeword = chars[ch]->codeword;p->codewordLen = chars[ch]->codewordLen;p->right = p->left = 0;p->symbol = ch;}else{if ((codeword >> (codewordLen - 1)) & 1){if (p->right == NULL)p->right = new HuffmanNode('\0');rebuildHuffmanNode(ch, p->right, codeword, codewordLen - 1);}else{if (p->left == NULL)p->left = new HuffmanNode('\0');rebuildHuffmanNode(ch, p->left, codeword, codewordLen - 1);}}
} void HuffmanCoding::rebuildHuffmanTree()
{//根据码表中内容左0右1重建Huffman树ListNode* head;head = new ListNode;head->tree = new HuffmanNode;for (int ch = 0; ch < ASCII; ch++){if (chars[unsigned char(ch)] != NULL){rebuildHuffmanNode(ch, head->tree, chars[ch]->codeword, chars[ch]->codewordLen);}}HuffmanTree = head->tree;
} void HuffmanCoding::inputHeader(HXLBMPFILE* bmpfile, const char* FileName)
{FILE* f;f = fopen(FileName, "r+b"); BITMAPFILEHEADER fh;BITMAPINFOHEADER ih; fread(&fh, sizeof(BITMAPFILEHEADER), 1, f);if (fh.bfType != 0x4d42){fclose(f);return;} fread(&ih, sizeof(BITMAPINFOHEADER), 1, f);if ((ih.biBitCount != 8) && (ih.biBitCount != 24)){fclose(f);return;} (*bmpfile).iYRGBnum = ih.biBitCount / 8;(*bmpfile).imagew = ih.biWidth;(*bmpfile).imageh = ih.biHeight; if (!(*bmpfile).AllocateMem()){fclose(f);return;} if ((*bmpfile).iYRGBnum == 1)fread((*bmpfile).palette, sizeof(RGBQUAD), 256, f);fseek(f, fh.bfOffBits, SEEK_SET);fclose(f);
}void HuffmanCoding::inputData(HXLBMPFILE* bmpfile, const char* FileName)
{ifstream fin;fin.open(FileName, ios::in | ios::binary);unsigned char ch = 0;unsigned long long nowbits = 0, nowbitsCnt = 0;int i = (*bmpfile).imageh - 1, j = 0;int mask = 1 << (bits - 1); if (!fin)exit(1);fin.seekg(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (((*bmpfile).iYRGBnum == 1) ? 256 * sizeof(RGBQUAD) : 0), ios::beg); ch = fin.get();while (nowbitsCnt < bitsCnt && i >= 0){for (HuffmanNode* p = HuffmanTree; ;){if (p->left == 0 && p->right == 0){(*bmpfile).pDataAt(i)[j] = p->symbol;if (++j == (*bmpfile).imagew)j = 0, i--;nowbitsCnt += p->codewordLen;break;}else if ((ch & mask) == 0)p = p->left;elsep = p->right;if (++nowbits == bits){ch = fin.get();nowbits = 0;}elsech <<= 1;}} fin.close();
}

调用:

#include"HuffmanCoding.h"
#include"HXLBMPFILE.h"
using namespace std; int main()
{HXLBMPFILE target;HuffmanCoding Huffman;const char* FileName = "gray.bmp"; Huffman.decode(&target, "file.dat", "code.dat");target.SaveBMPFILE(FileName);
}

对bmp灰度图像的Huffman编解码相关推荐

  1. 多媒体技术与应用之图像Huffman编解码

    多媒体技术与应用之图像Huffman编解码 一.实验内容 1.了解BMP图像的格式,实现BMP图片格式的数据域及文件头的分离 2.熟悉Huffman编码原理 3.使用Huffman编码算法对给定图像文 ...

  2. Huffman编解码

    Huffman编解码算法实现与压缩效率分析 一.背景知识及相关公式 1.信源熵 信源熵是信息的度量单位,一般用H表示,单位是比特,对于任意一个随机变量,它的熵定义为,变量的不确定性越大,熵也就越大. ...

  3. 实验三 Huffman编解码算法实现与压缩效率分析

    一.Huffman编解码原理 1. Huffman编码 对原始文件进行Huffman编码,首先需要解决以下几点问题: 文件符号的概率分布情况是怎样的? Huffman树是如何建立的? 建立起Huffm ...

  4. 数据压缩 实验三 Huffman编解码算法实现与压缩效率分析

    实验目的 掌握Huffman编解码实现的数据结构和实现框架, 进一步熟练使用C编程语言, 并完成压缩效率的分析. 实验原理 1.本实验中Huffman编码算法 (1)将文件以ASCII字符流的形式读入 ...

  5. Huffman编解码完全注释

    Huffman编解码完全注释 /** huffman - Encode/Decode files using Huffman encoding.* Copyright (C) 2003 Douglas ...

  6. huffman编解码算法实验与压缩效率分析

    一.基本原理 1.huffman编码原理 huffman编码是一种无失真编码方式,是可变长(VLC)编码的一种. huffman编码基于信源的概率统计模型,基本思路是出现概率大的信源符号编长码,出现概 ...

  7. 实验三—Huffman编解码

    一.实验原理 1.Huffman编码的步骤: (1)首先将所有字符发生的概率从小到大进行排序: (2)将最小的两个概率进行两两一合并,之后继续找最小的两个概率进行合并包括前面已经合并的和数: (3)一 ...

  8. 数据压缩原理 实验三 Huffman编解码算法实现与压缩效率分析

    实验原理 Huffman编码是一种无失真编码方式,是一种可变长编码,它将出现概率大的信源符号短编码,出现概率小的信源符号长编码. 编码步骤: ①将文件以ASCII字符流的形式读入,统计每个符号的发生概 ...

  9. Huffman编解码实现文本压缩

    编码方案设计: 实现最基本的哈夫曼编码,对文件进行两次扫描,第一次统计概率,第二次进行编码.压缩和解压缩时分别重新建立树,重新编码,以减小压缩后文件大小. 系统实现方案: typedef struct ...

最新文章

  1. RTOS之uCOS-II源码下载及源码目录结构、常见的RTOS!
  2. 渗透测试中的一波三折
  3. 第二次作业:王者荣耀软件分析
  4. Springboot如何利用http请求控制器
  5. typora.io使用教程
  6. PHP array_merge_recursive()函数与示例
  7. Windows下Yarn安装与使用
  8. 第四篇 做一个用户登录之后查看学员信息的小例子
  9. 17.Linux 高性能服务器编程 --- 系统检测工具
  10. 在spring管理的类的要注意问题
  11. DoIP(四)—— 时间参数
  12. Unity Recorder的使用讲解
  13. 用matlab做音乐仿真,Matlab课程设计报告--MATLAB GUI的音乐键盘仿真
  14. ❤️数据结构之栈(图文版详解)❤️
  15. Windows开启IIS服务器,并发布网站
  16. Android Send Email 发送邮件
  17. 关于Chrome无法连接网络的问题解决
  18. 【转载】AUTODESK系列专用卸载工具软件推荐排行榜(CAD/3Dmax/Revit/Maya/Inventor)
  19. Win关于Android环境变量的配置
  20. JavaScript原始数据类型

热门文章

  1. 《柳青计算机导论》课后习题答案
  2. npm start 修改启动端口的不同方式
  3. 物理学在计算机中的物理应用题,「试题研究」中考物理综合应用题的特点
  4. uniapp自定义导航栏遮住了手机状态栏问题
  5. 日式减肥食谱1月甩10斤肉
  6. Hype 4 Pro for Mac(HTML5动画制作软件)
  7. C#毕业设计——基于C#+asp.net+sqlserver的网上人才招聘系统设计与实现(毕业论文+程序源码)——人才招聘系统
  8. 路由器NAT功能配置简介
  9. 没有这些强迫症?那你可能是个假的程序员
  10. Chapter7 对称密钥原语的实用构造