精华内容
下载资源
问答
  • matlab开发-图像编码的小波变换。图像编码的小波变换
  • 图像编码哈夫曼压缩编码
  • 图像编码系统模型模型主要包括2个通过信道级连接的结构模块 :编码器和解码器 。当一幅输入图像送入编码 器后 ,编码器根据输入数据进行信源编码产生一组信号 。这组信号在进一步被信道编码器编码后进入信道 。通过...
  • 5、了解图像编码的具体应用。 二、实验要求: 1. 分析附件程序中的Huffman编码程序,修改该程序,使程序可以对彩色图像的亮度信息进行编码,并求出压缩比、编码效率。 2. 参照附件中的Huffman编码程序,实现...
  • 图像编码
  • 随着机器视觉、模式识别、图像处理等技术的发展,图像编码与采集技术也显得越来越重要。针对图像采集系统的开发成本、开发难度以及所采集图像的清晰度方面的问题,本文采用意法半导体公司的STM32F407单片机作为主控...
  • 视频图像编码VLSI设计

    2018-02-01 11:51:46
    视频图像编码VLSI设计,视频图像编码VLSI设计.视频图像编码VLSI设计.,视频图像编码VLSI设计.
  • 问题1: 实现行程编码压缩, 计算原图和压缩以后的尺寸,计算压缩率并比较分析; 问题2: 实现哈夫曼压缩, 计算原图和压缩以后的尺寸,计算压缩率并比较分析.
  • 基于matlab的jpeg图像编码解码,每部分都有注释,可以直接运行,很好的资源
  • 本书系统全面的介绍了图像编码标准H.264的各项标准,有助于读者了解H.264标准,数字视频信号处理,以及数字电视传输的全面认识和了解。
  • 小波图像编码和分形图像编码是两种不同的图像编码方法,二者各有其特点,又都存在一定的局限性。一幅图像经过小波变换后,其相同方向但不同分辨率的子图像具有较强的相似性,这种相似性正好与分形编码的特点具有互补...
  • MATLAB编写的基于DCT变换的图像编码,包含DCT变换和DCT反变换,Z扫描等操作。
  • DNA编码方法,可以更有效的保护图像信息,提高加密系统的安全性。
  • JPEG图像编码

    2018-03-12 19:56:31
    经典JPEG编码 可实现灰色图像、彩色图像编码 调试可通过
  • 哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。
  • 图像编码MATLAB 程序

    2015-04-28 23:53:06
    matlab程序 医学图像处理 编码
  • 图像编码 写在前面,这一次的实验相当有难度,完全自己写体会很深刻,把C/C++对于文件读写部分的内容相当全面的覆盖到了,并且也对算法的设计有较高要求。 按照惯例我们还是先说说为什么要对图像进行编码。现在4K...

    图像编码

    写在前面,这一次的实验相当有难度,完全自己写体会很深刻,把C/C++对于文件读写部分的内容相当全面的覆盖到了,并且也对算法的设计有较高要求。

    按照惯例我们还是先说说为什么要对图像进行编码。现在4K逐渐开始普及了,8K的产品也开始销售了,但是这些超高清背后的数据量,你有考虑过嘛?
    我们拿现在已经不算稀奇的FullHD(1080p)来做一笔计算:
    一幅(帧)图像的字节数: 1920 ∗ 1080 ∗ 3 = 6.22 M 1920*1080*3=6.22M 192010803=6.22M
    120分钟的电影: 6.22 M ∗ 60 ∗ 60 ∗ 120 = 2687 G 6.22M*60*60*120=2687G 6.22M6060120=2687G
    如果我们用比较好的50G蓝光光盘保存,需要: 2687 / 50 = 54 2687/50=54 2687/50=54张蓝光光碟。
    可见,除非Sony宣布蓝光光盘免费,否则看一场电影的门槛可能都要上百了。正因如此,我们才要将图像进行“压缩”,图像能够被压缩的客观条件,就是“冗余”的存在。
    一幅图片从不同角度来看会存在多种多样的冗余信息(可以参考这篇科普),我们适当的删减掉不容易被人眼注意到的部分,就可以在不减少信息量的情况下压缩图片的大小。当然这个压缩的具体效果肯定还是与删去的冗余信息量有关的,一幅JPEG压缩的图像在多数情况下都会比原图片看起来“糊”不少,就是因为JPEG的压缩比能够达到26:1左右。
    图像编码有非常多的方式,这次的实验内容,就是完成一种基于熵编码的算法——赫夫曼编码。原理这方面不再赘述了,大把的博客以及书籍可供参考,我们直接进入实验内容。

    一、实验内容

    将一幅给定的灰度图像进行Huffman编解码

    众所周知,字数越少,事情越大,这短短一行的实验要求耗费了我三整天的时间。根据我做这个实验过程中遇到的问题,我来将这个实验内容拆分一下:

    1. 编写函数,获得赫夫曼编码表
    2. 根据赫夫曼编码,将像素数据用编码表示
    3. 将编码后的图片数据写入文件
    4. 读取压缩后的图像文件和赫夫曼编码表
    5. 利用赫夫曼编码表还原图像文件

    二、代码实现与分析

    1、编写函数,获得赫夫曼编码表

    别看这是唯一一个和标题名字重合的步骤,实际上却是最简单的,当然这也是因为我上学期学习数据结构时就已经完成了赫夫曼树、赫夫曼编码的函数,这里我只进行了简单的修改,便得到了码表。
    简单的讲一下代码,为什么这么写可以参考我老师的mooc

    typedef struct {
    	float weight;	//结点权值
    	int parent, lchild, rchild;	//指向双亲和左右孩子的指针
    }HTNode,*HuffmanTree;	//动态分配数组赫夫曼树
    
    typedef char **HuffmanCode;	//动态分配数组存储赫夫曼编码
    
    typedef struct {
    	HuffmanCode code;	//码字数组,从下标1开始
    	int *length;		//码长数组,从下标1开始
    }HuffmanCodeTable;	//赫夫曼编码表
    

    上面是结构体的定义,我们的思路是先构造赫夫曼树,再根据赫夫曼树从根节点开始走到各个结点的路径得到赫夫曼编码(左0右1)。上这门课的时候要求使用C实现,实际上用C++的string类型可能更加方便。

    void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, HuffmanCodeTable &HCT, float *w, int n)
    {	//w存放n个字符的权值,构造赫夫曼树HT,并求出w中n个数据对应的赫夫曼编码表HCT
    	int i, j, m, s1, s2;
    	if (n <= 1)
    		return;
    	HTNode *p;	//指针
    	m = 2 * n - 1;	//m是总的结点数
    	HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));  //0号单元作为标记
    	for (p = HT + 1, i = 1; i <= n; i++, p++, w++)
    	{
    		*p = { *w,0,0,0 };	//叶子结点初始化
    	}
    	for (i = n + 1; i <= m; i++, p++)
    	{
    		*p = { 0,0,0,0 };	//非叶子结点初始化
    	}
    	for (i = n + 1; i <= m; i++)
    	{
    		Select(HT, i - 1, s1, s2);	//寻找最小值下标s1和次小值下标s2
    		HT[s1].parent = i;
    		HT[s2].parent = i;
    		HT[i].lchild = s1;
    		HT[i].rchild = s2;
    		HT[i].weight = HT[s1].weight + HT[s2].weight;
    	}	//赫夫曼树建立完毕
    
    	//求赫夫曼编码的准备工作
    	HC = (HuffmanCode)malloc((n+1) * sizeof(char*));  //分配n个字符串编码的头指针向量
    	char *cd = (char*)malloc(n * sizeof(char)); //分配求当前编码的工作空间
    	cd[n - 1] = '\0';	//从右向左逐位存放编码,首先存放编码结束符
    
    	int start, c, f;
    	for (i = 1; i <= n; i++)	//按照w中的顺序给出赫夫曼编码
    	{
    		start = n - 1;	//初始化编码起始指针
    		for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)	 //从叶子结点到根结点逆向求编码
    		{
    			if (HT[f].lchild == c)
    				cd[--start] = '0';	//左分支标0
    			else
    				cd[--start] = '1';	//右分支标1
    		}
    		HC[i] = (char*)malloc((n - start) * sizeof(char));	//为第i个编码分配空间,(n-start)为编码长度
    		strcpy(HC[i], &cd[start]);	//从cd复制编码串到HC
    	}
    	free(cd);
    
    	//对赫夫曼编码的码字求长度,得到赫夫曼编码表
    	HCT.code = HC;
    	HCT.length = (int*)malloc(sizeof(int)*(n+1));
    	int count;
    	for (i = 1; i <= n; i++)
    	{
    		count = 0;	//实际上可以用strlen()
    		for (j = 0; HC[i][j] != '\0'; j++)
    		{
    			count += 1;
    		}
    		HCT.length[i] = count;
    	}
    }
    

    赫夫曼编码中有一个Select函数是用来求所有没有父结点的结点中权值最小的两个,从而构成新的结点。我的实现写复杂了,想参考可以见文末传送门,建议写一个排序来实现,效率会更高。

    2、根据赫夫曼编码,将像素数据用编码表示

    上面的函数只是能够实现赫夫曼编码,实际上我们还没有开始调用,下面来说一下对图像调用赫夫曼编码的想法。我们压缩压的是像素数据域的内容,显然,如果我们把出现次数多的像素值赋予短编码,出现次数少的像素值赋予长编码,那么从均值的角度看,我们还是成功的减小了总长度,也就实现了压缩的目的。
    因此,我们应当统计图像中各个像素值(我们这里只考虑灰度图像,故为灰度值)出现的频率,然后对频率进行赫夫曼编码。

    	for (i = 0; i < src.imagew; i++)	//统计像素出现次数
    		for (j = 0; j < src.imageh; j++)
    		{
    			count_pixel[src.pDataAt(i)[j]] += 1;
    		}
    	
    	for (i = 0; i < 256; i++)	//计算像素出现频率
    	{
    		p[i] = (float)count_pixel[i] / (float)n;
    	}
    
    	HuffmanCoding(HT, HC, HCT, p, 256);	//赫夫曼编码函数
    

    这样我们就成功的获得了HCT,赫夫曼编码表,它由一个码字数组和一个码长数组构成(均从下标1开始),将其写入文件后,如下:(使用'\t'分隔码字与码长)

    赫夫曼编码表

    下面我们用它来将像素数据域的内容编码。不过在转换编码前,我们应该先做一个思考,应当用什么格式来存储编码后的内容呢?
    首先我们要明确,写入文件一定是以二进制形式完成的,因为ASCII码表示的'0''1'本身就占一个字节,如果以文本格式输出则完全是与压缩的初衷背向而驰。所以,我们要选一个很容易转换为二进制的格式,字符数组便成了首选。
    其次,char*也可以表示字符数组,string也可以表示字符数组,具体用哪个更好呢。我们需要将所有像素编码后的结果合并到一个大字符串中,因此对于char*而言,我们要用strcat(des,src),对于string而言,我们可以用s1+=s2。经过我的实测,strcat执行时间超过40s,string的+=只需要2s,这么大的差异也确实出乎我的意料,不过这篇博客中的测试也显示了strcat的效率不尽人意。

    string data;
    for (i = 0; i < src.imagew; i++)
    	for (j = 0; j < src.imageh; j++)
    	{
    		data += HCT.code[src.pDataAt(i)[j] + 1];
    	}
    

    3、将编码后的图片数据写入文件

    好了,编码已经完成了,下面需要把压缩后的图片数据写入文件了。首先我们把信息头、文件头、调色板的数据先写入:

    //下面开始将信息头、文件头,这部分没有编码
    	FILE *f;
    	f = fopen("encode_Image.bmp","w+b");
    	if (f == NULL)
    		return false;
    	BITMAPFILEHEADER fh;
    	BITMAPINFOHEADER ih;
    	memset(&ih, 0, sizeof(BITMAPINFOHEADER));
    	fh.bfType = 0x4d42;
    	fh.bfReserved1 = fh.bfReserved2 = 0;
    	fh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + ((src.iYRGBnum == 1) ? 256 * sizeof(RGBQUAD) : 0);
    	ih.biSize = 40;
    	ih.biPlanes = 1;
    	ih.biWidth = src.imagew;
    	ih.biHeight = src.imageh;
    	ih.biBitCount = 8 * src.iYRGBnum;
    	int w4b = (src.imagew * src.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);
    	if (src.iYRGBnum == 1)	//因为我们只处理灰度图像,所以这里会需要写入调色板
    		fwrite(src.palette, sizeof(RGBQUAD), 256, f);
    	fclose(f);
    

    下面,我们要处理像素数据域的数据了。刚才第二步中我们把用赫夫曼编码表示的像素数据存到了string data;这个大字符串中,下面我们要把这个’1’、'0’构成的字符串,当成10二进制码写入文件了。
    要完成这个操作还是有些困难的,我在尝试将字符转换为bitset无果后,还是去搜寻了一番大神的博客,真的被我找到了一个可以实现我们目标的函数,这里放上博客地址(额,这篇博客404了,大家直接看gitee仓库中我写的代码好了,本身不难理解),感谢这位大大。
    需要注意的是,我们是在写完信息头、文件头等信息的文件中续写像素数据,因此需要将"wb"模式改为"ab"模式。

    writeBit(data, "encode_Image.bmp");	//记得修改writeBit参数为string
    

    可以用sublime text等软件查看其数据:(灰度图像有54字节的信息头和文件头,1024字节的调色板,因此像素数据域从第45行倒数第二个字节开始,如果你和我一样用的1.bmp这张图,其值应为4c)

    压缩图像

    至此,我们已经完成了对原始图像的赫夫曼编码。

    4、读取压缩后的图像文件和赫夫曼编码表

    之后是解码的操作,首先我们要从文件读回赫夫曼编码表,以及图像数据,再根据编码表还原出原始数据。

    4.1 读取赫夫曼编码表

    回顾一下我们写的编码表文件,其格式为一行之中,码字'\t'码长'\n',我们需要读取这个文件来恢复出一个HuffmanCodeTable HCT;
    根据上述的需求,我们可以按行读取,将遇到'\t'之前的部分赋值给码字,将'\t'之后的部分,转换为数字,赋值给码长。代码如下:

    bool readHuffmanTable(const char* cFilename,HuffmanCodeTable &HCT)	//从文件读取赫夫曼码表
    {
    	HCT.code = (HuffmanCode)malloc((256 + 1) * sizeof(char*));	//为HCT分配空间
    	HCT.length = (int*)malloc((256 + 1) * sizeof(int));
    	memset(HCT.length, 0, 257 * sizeof(int));
    
    	FILE *f;
    	f = fopen(cFilename, "r");
    	if (f == NULL)
    		return false;
    
    	char buffer[50];
    	int i=1, j=0, length;
    	while (fgets(buffer, 50, f) != NULL)
    	{
    		length = strlen(buffer);
    		HCT.code[i] = (char*)malloc(sizeof(char)*(length+1));
    		for (j = 0; j < length; j++)
    		{
    			if (buffer[j] == '\t')
    			{
    				HCT.code[i][j] = '\0';
    				while (buffer[++j] != '\n')
    				{
    					HCT.length[i] += (int)((buffer[j] - '0')*(pow((double)10, (double)(length - (j + 1) - 1))));
    				}
    				break;
    			}
    			else
    				HCT.code[i][j] = buffer[j];
    		}
    		i++;
    	}
    	return true;
    }
    

    可以注意到,对于码长的赋值,我自己推导了一个公式。举一个简单的例子,很容易搞清楚这个公式。
    假设,某一行内容如下:1111100110 10,那么该行的长度length为14('\t'和结尾的'\n'不要忘记)。读到'\t'时的下标j为10,说明下一位开始表示的就是码长了。但是码长不一定只有一位,因此我们写一个内部循环来求码长。

    while (buffer[++j] != '\n')
    

    j=11时指向的是1,这个1应该是个位、十位还是百位呢(如果有的话,实际上百位不太可能)?显然,我们可以通过length与j的值来推导出指数。j=11时指向的'1',表示的是:
    1 0 ( 14 − ( 11 + 1 ) − 1 ) = 1 0 1 10^{(14-(11+1)-1)}=10^{1} 10(14(11+1)1)=101
    同理,j=12时指向的'0'表示的是:
    1 0 ( 14 − ( 12 + 1 ) − 1 ) = 1 0 0 10^{(14-(12+1)-1)}=10^{0} 10(14(12+1)1)=100
    因此我们就得到了这个通式:
    H C T . l e n g t h [ i ] HCT.length[i] HCT.length[i] += 1 0 ( l e n g t h − ( j + 1 ) − 1 ) 10^{(length-(j+1)-1)} 10(length(j+1)1)

    4.2 读取图像数据

    就像写入时一样,我们将信息头、文件头、调色板先读取出来,确定图像的长、宽、位数等基本信息。

    	FILE *f;
    	if ((f = fopen(cFilename, "r+b")) == NULL)
    	{
    		return false;
    	}
    	//文件头、信息头的读取,和LoadBMPFILE函数一致
    	BITMAPFILEHEADER fh;	//文件头
    	BITMAPINFOHEADER ih;	//信息头
    	fread(&fh, sizeof(BITMAPFILEHEADER), 1, f);		//从文件中读取文件头
    	if (fh.bfType != 0x4d42)	//如果不是"BM"文件,直接退出
    	{
    		fclose(f);
    		return false;
    	}
    	fread(&ih, sizeof(BITMAPINFOHEADER), 1, f);		//从文件中读取信息头
    	if ((ih.biBitCount != 8) && (ih.biBitCount != 24))	//如果不是8位灰度图,或24位彩图,则退出
    	{
    		fclose(f);
    		return false;
    	}
    	des.iYRGBnum = ih.biBitCount / 8;	//1为灰度图,3为彩图
    	des.imagew = ih.biWidth;
    	des.imageh = ih.biHeight;
    	if (!des.AllocateMem())	//如果分配内存失败,退出
    	{
    		fclose(f);
    		return false;
    	}
    	if (des.iYRGBnum == 1)	//灰度图需要调色板
    		fread(des.palette, sizeof(RGBQUAD), 256, f);
    	//信息头、文件头读取完毕
    

    下面我们要处理像素数据了,之前写入时我们把字符串以二进制输出,现在我们要把这些二进制的01重新存为字符串。好在这学期的另一门课《计算机组成原理》中我曾经做过将float型按位输出以检验是否符合IEEE754标准的实验,因此我有一个函数可以将输入的东西以二进制输出。

    char* Byte2Binary(unsigned char buffer)	//将一个字节转换成8bit保存到字符串
    {
    	char *s = (char*)malloc(sizeof(char) * 9);	//返回字符串,记得给'\0'预留位置
    	s[0] = '\0';
    	unsigned char *p, ch;
    	int i, j;
    	p = (unsigned char *)(&buffer);
    	for (i = sizeof(buffer) - 1; i >= 0; i--)
    	{
    		ch = *(p + i);
    		for (j = 0; j < 8; j++)
    		{
    			if ((ch << j) & 0x80)	//0x80即128,二进制表示1000 0000,这里操作目的是取最高位
    				s[j] = '1';
    			else
    				s[j] = '0';
    		}
    		s[j] = '\0';
    	}
    	return s;
    }
    

    用这个函数,我们只需要按一个字节的大小(恰好是一个unsigned char)来读取文件,再将其返回的字符数组拼接起来即可。

    	unsigned char buf;	//注意char是1字节,char*是4字节
    	int rc;
    	string data;	//获得编码数据
    	while ((rc = fread(&buf, sizeof(unsigned char), 1, f) != 0))
    	{
    		data += Byte2Binary(buf);	//按字节读入,按位输出,存入字符串data
    	}
    

    5、利用赫夫曼编码表还原图像文件

    我已经在gitee仓库中提交了一种快速解码的方法,主要思路是通过码表逆向构建赫夫曼树,然后每次从根结点开始遍历赫夫曼树来找到解码。(解码均为叶子结点)
    如果看过我最早版本的代码,并且运行过,那么你一定还记得这里我解码一幅57kb的图像耗时都高达40s。这里我告诉大家问题所在:字符串的相关操作!
    最初我为了偷懒,用了string的自带函数substr(index,length),然后与码表中的码字compare()。这种算法的最大问题就在于substr需要不断的开辟空间(说不断其实是不准确的,具体的解释可以自行查找),因此不仅占用空间,而且相当费时。下面的版本中,我老老实实的逐字符比较,并且极力避免有关出现string类型的构造,最终达到了5s出结果的成绩。代码如下:

    bool decode(HXLBMPFILE &des,HuffmanCodeTable &HCT,string data)	//解码函数
    {
    	int i, j, k;
    	int min = HCT.length[1], max = HCT.length[1];	//求最短码长和最大码长
    	for (i = 1; i <= 256; i++)
    	{
    		if (HCT.length[i] < min)
    		{
    			min = HCT.length[i];
    		}
    		if (HCT.length[i] > max)
    		{
    			max = HCT.length[i];
    		}
    	}
    
    	int index = 0;	//字符串的下标标识
    	int flag;	//匹配标志
    	int data_length = data.length();	//数据总长度
    	for (i = 0; i < des.imagew; i++)	// 解码,给每个像素赋值
    		for (j = 0; j < des.imageh; j++)
    		{
    			flag = 0;	//标志置0
    			if ((data_length - (index + 1)) >= min)	//当剩余字符数大于最小码长时
    			{
    				for (k = 1; k <= 256; k++)	//遍历码表
    				{
    					int temp = index;	//备份初始下标
    					for (int n = 0; n < HCT.length[k]; n++)
    					{
    						if (data[index] == HCT.code[k][n])	//如果匹配,下标移动,标志置1
    						{
    							flag = 1;
    							index++;
    						}
    						else
    						{
    							index = temp;	//不匹配则下标回到初始位置
    							flag = 0;	//标志回置0
    							break;
    						}
    					}
    					if (flag == 1)
    					{
    						des.pDataAt(i)[j] = k-1;
    						break;
    					}
    					/*
    					//substr()需要分配空间,大量耗费时间,已用上面的方法取代,快了一倍
    					if (!data.substr(index, HCT.length[k]).compare(code))	//注意string的compare方法,相等返回0
    					{
    						des.pDataAt(i)[j] = k;	//赋予像素值
    						flag = 1;	//成功找到解码,标志置1
    						index += HCT.length[k];	//下标移动
    						break;
    					}
    					*/
    				}
    				if (flag == 0)
    				{
    					printf("编码数据与码表无法匹配!\n");
    					return false;
    				}
    			}
    		}
    	return true;
    }
    

    结语

    这一次的实验终于是充满挑战性了,其实这篇博客已经把难点都规避掉了,因为真正的难点在于无从下手,在于走上了错误的解决道路却不自知,我和另外两名同学一起,花了整整三天时间,走遍了岔路才最终得到了结果。当然,收获确实是满满,就是头发又稀了不少。。。
    本次实验完整的项目文件与代码可见我的gitee

    展开全文
  • 行程编码 算法 压缩效果好,matlab语言1欢迎下载
  • 小波图像编码和分形图像编码是两种不同的图像编码方法,二者各有其特点,又都存在一定的局限性。一幅图像经过小波变换后,其相同方向但不同分辨率的子图像具有较强的相似性,这种相似性正好与分形编码的特点具有互补...
  • 图像处理(15)–图像编码

    千次阅读 2019-07-28 17:06:00
    图像的每个像素用不同的灰度级来表示,在计算机中进行编码,然后使用0和1的01串来进行存储和传输等。本文将介绍数字图像中的各种编码格式。 1. B编码 B编码中每个码字由延伸比特C和信息比特...

    图像处理系列笔记: https://blog.csdn.net/qq_33208851/article/details/95335809


    前言
    图像的每个像素用不同的灰度级来表示,在计算机中进行编码,然后使用0和1的01串来进行存储和传输等。本文将介绍数字图像中的各种编码格式。
    平均编码长度(Average length)
    在这里插入图片描述
    注:下文中出现的符号一词与灰度值等同


    1. B编码

    B编码中每个码字由延伸比特C和信息比特组成,延伸比特的作用是实现码字分隔。延伸比特C的一般取值为0和1。两个相邻的码字通过延伸码C的不同取值(0和1)来区分,同一个码字中C的值是相同的(见下例)。

    • 【注】什么叫码字?
      例如0和1的编码分别是C0和C1,那么C0是一个码字,同样的,C1也是一个码字

    编码的步骤
    在这里插入图片描述
    例如:
    在这里插入图片描述
    说明:

    1. 在编码时候需要先对灰度级出现的概率(根据直方图)做出按从高到低的排序(上图中灰度级的顺序0,1,2,3,4,5,6只是偶然)然后再进行编码(灰度级出现概率大的编码 长度小,反之,灰度级概率小的编码的长度大)
    2. B1就是B编码
    3. B1编码格式中,每个码字的一个小元素由C+一位信息比特组成,最少为C0或C1,之后是C0C0,C0C1,…,C1C1,然后是C0C0C0,…,C1C1C1.
    4. C从0开始或者从1开始都可以,只要每两个相邻的码字C的取值不同即可(0和1换着取)。注意同一个码字中的C的取值是相同的。
    5. 在解码时,去掉C的信息(不管C,C的作用只是为了区分不同的码字),得到信息比特的信息。然后参照编码表进行解码。比如0001取出信息部分是01,对应这编码表中的C0C1,那么0001解码后得到3.同样的,1011取出信息比特也是01.

    2. B2编码

    在这里插入图片描述
    说明:

    1. B2编码格式中,每个码字的一个小元素由C+2位信息比特组成,最少为C00或C01,之后是C00C00,C00C01,…,C11C11,然后是C00C00C00,…,C11C11C11.
    2. C从0开始或者从1开始都可以,只要每两个相邻的码字C的取值不同即可(0和1换着取)。注意同一个码字中的C的取值是相同的。
    3. 在解码时,去掉C的信息(不管C,C的作用只是为了区分不同的码字),得到信息比特的信息。然后参照编码表进行解码。比如110取出信息部分是10,对应这编码表中的C10,那么110解码后得到2.同样的,010取出信息比特也是10.

    3. Huffman编码

    在这里插入图片描述
    例:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    需要注意的问题:
    在这里插入图片描述

    • 截尾霍夫曼编码(Truncated Huffman)
      当信源发出的符号类型较多时,编码的过程可能较繁琐,利用截尾霍夫曼编码可以降低编码的复杂性,代价是编码效率的降低。截尾霍夫曼编码是通过对信洚的具有最大概率的n个符号进行霍夫曼编码产生的,n是小于J 的正整数.其它的概率较小的符号利用前缀编码和适当的固定长度编码表示.
      在这里插入图片描述
      对Truncated Huffman一列的说明:
    • a1 ~a21是按照出现概率从高到低进行排好序的
    • Truncated Huffman的平均长度是4.24,Huffman只有1.05,但Truncated Huffman带来的是编码效率的提升
    • 概率出现最小的9个(a13~ a21)之和为0.2,记为a。将a与之前的a1 ~a12进行霍夫曼编码,这个a的编码为10。但是这个a中还有9个需要进行区分,9是介于23 ~24之间,所以至少需要4位才能将这9个进行区分。下面进行的工作是将(a13 ~ a21)进行二进制编码,然后高位拼接上10,结果如表中所示。如果高位是10,说明这个编码是a中的某一个(a13~ a21)。

    4. 移位码(S码)

    这种移位码是自然的二值移位码
    在这里插入图片描述
    例子:
    在这里插入图片描述
    说明:

    • 在本例中,n=2。所以将按照出现概率从高到低排好序的符号(这里指的是灰度值)分块:22-1=3,即三个灰度级作为一个块。这里分块的结果是;0,1,2作为第一个块,3,4,5作为第二个块。
    • 然后对块进行编码:第一个块不需要在前面添加移位码字,对;0,1,2进行自然二进制编码,结果如表中所示。然后是对第二个块进行编码:第二个块需要在前面添加一组移位码字,添加的码字是第一组中没有使用的11.然后同样的对第二个块内的3个符号(灰度级)进行自然二进制编码,两者拼接就是第二个块的编码结果,如表中所示。

    例子:
    在这里插入图片描述
    这里n=3,每一块 中后面的3位是对应相等的,如a2,a9和a16的001.其他同理不再赘述

    5. 霍夫曼移位编码(Huffman Shift)

    将自然二值移位码与霍夫曼编码相结合得到另一种新的编码方式, 霍夫曼移位编码(Huffman Shift)

    霍夫曼移位码与自然二值移位码的区别

    1. 分块的大小不一定是2n-1
    2. 基准块中符号和移位符号的编码不是采用自然二进制编码,而是使用霍夫曼编码.这意味着对基准块进行编码之前要分配移位符号的概率.
      两种分配概率二点方法:
      1.移位符号的概率=非基准块中符号的概率和
      2.移位符号的概率=第二块中符号的概率和+2 x第三块中符号的概率和+ 3x第四块中符号的概率和+…

    例子:
    在这里插入图片描述
    说明:

    • 这里n=3,分为3块,每一块7个
    • 每一块后面的几位是对应相等的
    • 第二块前面的移位码是一组00,第三块前面的移位码是两组00(00 00)
    • 移位符号00是如何确定的?这里是通过计算非基准块(除了第一块的其他块叫非基准块)中符号的概率和(=1-基准块中符号的概率和)=1-0.61=0.39。然后用0.39(记为a)与a1 ~a7一共8个进行霍夫曼编码,最终得到的a的编码是00(因为0.39这个概率比a1 ~a7中任何一个的概率都要大,所以得到的编码结果是00也在情理之中。注:概率越大编码长度越短,对应的值越小)

    6. 算数编码

    算术编码是一种非块码,信源符号(灰度值)和码字之间不存在一一对应的关系。
    算术编码是给整个信源符号(或消息)序列分配 一个单一的算术码字。这个码字本身定义了一 个介于0和1之间的实数。
    因为这种技术不像霍夫曼编码方法那样要求将每个信源符号转换成整数的编码(即,每次对一个符号进行编码),所以这种技术达到了 (仅在理论上)由无噪声编码准則所设定的界限。
    算术编码用到的两个基本的参数:符号的概率和它的编码间距
    参照以下例子:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    译码的过程:
    在这里插入图片描述

    7. 词典编码

    词典编码不需要了解有关被编码符号的出现的概率
    词典编码的根据是数据本身包含有重复代码这个特性。例如文本文和图像就具有这种特性。
    词典编码法的种类很多,归纳起来大致有两类

    1. 第一类
      第一类词典编码的想法是企图查找正在压缩的字符序列是否在以前输入的数据中出现过,然后用己经出现过的字符串替代重复的部分,它的输出仅仅是指向早期出现过的字符串的“指针”。这一类词典编码所指的“词典”是指用以前处理过的数据来表示编码过程中遇到的重复部分。
      在这里插入图片描述
    2. 第二类
      第二类算法的想法是企图从输入的数据中创建一个“短语词典”,这种短语不一定是具有具体含义的短语,它可以是任意信源符号的组合.编码数据过程中当遇到己经在词典中出现的“短语”时,编码器就输出这个词典中的短语的“索引号”,而不是短语本身
      在这里插入图片描述
      LZW编码(属于第二类的词典编码):
      对信号源的可变长度序列分配固定长度的码字,不需要了解被编码符号的出现的概率
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

    8. 位平面编码

    9. 无损预测编码

    10. 变换编码

    展开全文
  • huffman图像编码

    2011-06-30 01:25:51
    对原始输入的bmp格式的彩色图像进行转换灰度图像,统计灰度出现的概率和累加概率,进行huffman编码进行压缩
  • 立体图像编码解码

    千次阅读 2020-09-28 15:17:24
    根据相关参考资料说明,图像编码解码的大致结构框图如下所示: 本系统,我们主要将完成这个结构框图中介绍的各个模块。 2.各个模块设计与仿真 function im_encode(left_name, right_name, parameter); 发送...

         根据相关参考资料说明,图像编码解码的大致结构框图如下所示:

        本系统,我们主要将完成这个结构框图中介绍的各个模块。

    2.各个模块设计与仿真

    function im_encode(left_name, right_name, parameter);

    发送端的说明

    2.1 获得左右两个图像

    ·MATLAB代码

    imag_L = imread('stereo_images/corridor1.pgm');

    imag_R = imread('stereo_images/corridor2.pgm');

    figure(1);

    subplot(121),imshow(imag_L);title('left');

    subplot(122),imshow(imag_R);title('right');

    ·仿真效果

    图2 左右眼睛看到的图像

    ·代码说明

        通过读取两个图片,来模拟人两个眼睛所看到的图像。

    2.2 Transform模块

        这个模块主要使用DCT变换,但是这里设计到一个问题,就是将两个图片信号变为一路信号的问题。就本课题而言,这里有以下几个方法实现;

    ·由于这两个图片是双目信号,所以可以先进行立体匹配得到一个图片,然后再接收端分解成两个双目图片;

    ·由小波分解进行融合得到一路信号,然后在接收端进行反变换,但是这种做法也较复杂。

    ·进行图片的采样处理,对两个图片进行间隔采样,然后在接收端进行内插得到原图像,这种方法比较简单,本模块采用这个方法。

        其代码如下所示:

     

    [R,L] = size(imag_L);

    for i = 1:R

        for j = 1:L

             if mod(i+j,2)==0

             image(i,j) =  imag_L(i,j);

             else

             image(i,j) =  imag_R(i,j);   

             end

        end

    end

     

    2.3 DCT变换

       我们在这里使用MATLAB内部的dct2函数。这里就不多做介绍了。其仿真结果如下所示:

    其代码如下所示:

    DCT_out = dct2(image);

     

    2.4 ZIGZAG算法

        其基本原理如下所示:

    通过这个方法,我们可以将一个图像的二维数据变为一个串行的数据流。

    其对应的代码如下所示:

    function [y]=toZigzag(x)

    % transform a matrix to the zigzag format

     [row col]=size(x);

     

    if row~=col

       disp('toZigzag() fails!! Must be a square matrix!!');

       return

    end

    y=zeros(row*col,1);

    count=1;

    for s=1:row

       if mod(s,2)==0

          for m=s:-1:1

             y(count)=x(m,s+1-m);

             count=count+1;

          end;

       else

          for m=1:s

             y(count)=x(m,s+1-m);

             count=count+1;

          end

       end

    end

    if mod(row,2)==0

       flip=1;

    else

       flip=0;

    end

    for s=row+1:2*row-1

       if mod(flip,2)==0

          for m=row:-1:s+1-row

             y(count)=x(m,s+1-m);

             count=count+1;

          end

       else

          for m=row:-1:s+1-row

             y(count)=x(s+1-m,m);

             count=count+1;

          end;

       end;

       flip=flip+1;

    end

     

      μ律(m-Law)压扩主要用在北美和日本等地区的数字电话通信中。m为确定压缩量的参数,它反映最大量化间隔和最小量化间隔之比,通常取100≤m≤500。由于m律压扩的输入和输出关系是对数关系,所以这种编码又称为对数PCM。

      A律(A-Law)压扩主要用在欧洲和中国大陆等地区的数字电话通信中。A为确定压缩量的参数,它反映最大量化间隔和最小量化间隔之比。A律压扩的前一部分是线性的,其余部分与μ律压扩相同。

    15折线特性给出的小信号的信号量噪比约是13折线特性的两倍。      但是,对于大信号而言,15折线特性给出的信号量噪比要比13折线特性时稍差。在保证小信号的量化间隔相等的条件下,均匀量化需要11比特编码,而非均匀量化只要7比特就够了。

        其对应的待明如下所示:

    function ypcm=mulaw(yn)

    x=yn;

    s=sign(x);                            

    x=abs(x);                            

    ypcm=zeros(length(x),1);

    %进行基于15折线的分段映射

    for i=1:length(x)                  

        if x(i)<1/255              %序列值位于第1折线

            ypcm(i)=255/8*x(i);

        elseif x(i)<3/255           %序列值位于第2折线

            ypcm(i)=255/16*x(i)+1/16;

        elseif x(i)<7/255           %序列值位于第3折线

            ypcm(i)=255/32*x(i)+5/32;

        elseif x(i)<15/255          %序列值位于第4折线

            ypcm(i)=255/64*x(i)+17/64;

        elseif x(i)<31/255          %序列值位于第5折线

            ypcm(i)=255/128*x(i)+49/128;

        elseif x(i)<63/255          %序列值位于第6折线

            ypcm(i)=255/256*x(i)+129/256;

        elseif x(i)<127/255         %序列值位于第7折线

            ypcm(i)=255/512*x(i)+321/512;

        else                     %序列值位于第8折线

            ypcm(i)=255/1024*x(i)+769/1024;

        end

    end

    ypcm=ypcm.*(2^7);   

    ypcm=floor(ypcm);

    ypcm=ypcm.*s;

    2.6 编码模块

        发送的最后我们需要将量化后的数据进行压缩,得到二进制比特率进行发送,这里我们使用huffman编码。Huffman编码的基本原理如下所示:

    哈夫曼编码是用于数据文件压缩的一个十分有效的编码方法,其压缩率通常在20%~90%之间。哈夫曼编码算法使用字符在文件中出现的频率表来建立一个0,1串,以表示各个字符的最优表示方式。

          它是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。 Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长 度最短的码字,有时称之为最佳编码,一般就叫作Huffman编码。 以哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。 在计算机信息处理中,“哈夫曼编码”是一种一致性编码法(又称"熵编码法"),用于数据的无损耗压缩。这一术语是指使用一张特殊的编码表将源字符(例如某文件中的一个符号)进行编码。这张编码表的特殊之处在于,它是根据每一个源字符出现的估算概率而建立起来的(出现概率高的字符使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均期望长度降低,从而达到无损压缩数据的目的)。这种方法是由David.A.Huffman发展起来的。 例如,在英文中,e的出现概率很高,而z的出现概率则最低。当利用哈夫曼编码对一篇英文进行压缩时,e极有可能用一个位(bit)来表示,而z则可能花去25个位(不是26)。用普通的表示方法时,每个英文字母均占用一个字节(byte),即8个位。二者相比,e使用了一般编码的1/8的长度,z则使用了3倍多。倘若我们能实现对于英文中各个字母出现概率的较准确的估算,就可以大幅度提高无损压缩的比例。

    根据变长最佳编码定理,Huffman编码步骤如下:

    (1)将信源符号xi按其出现的概率,由大到小顺序排列。

    (2)将两个最小的概率的信源符号进行组合相加,并重复这一步骤,始终将较大的概率分支放在上部,直到只剩下一个信源符号且概率达到1.0为止;

    (3)对每对组合的上边一个指定为1,下边一个指定为0(或相反:对上边一个指定为0,下边一个指定为1);

    (4)画出由每个信源符号到概率1.0处的路径,记下沿路径的1和0;

    (5)对于每个信源符号都写出1、0序列,则从右到左就得到非等长的Huffman码。

    其对应的代码如下所示:

    function [compression,dict] = huffman_module(image);

    s = image;

    %entropy

    p = hist(s,length(s)); 

    idx=find(p~=0); 

    prob=p(idx)/length(s);

    entropy=-prob*log2(prob)';

    %redundancy

    entropymax=log2(length(prob));

    redundancy=(entropymax-entropy)/entropymax;

    reff=sort(s);

    ref2=reff(2:end);

    ref=reff(1:end-1);

    chg=ref2-ref;

    idx2=find(chg~=0);

    sig=ref2(idx2);

    symbols=[ref(1);sig];

    %huffman table

    set(0,'RecursionLimit',2000);

    [dict,avglen] = huffmandict(symbols,prob);

    % %huffman encoder

    compression = huffmanenco(s,dict);

    3.各个模块设计与仿真

    3.系统总体仿真说明

        系统的仿真结果如下所示:

     

    读入两个图片

     

     

     

     

     

    DCT变换值

     

    量化值

     

    压缩比特流

     

     

    最后接收到的双目图片。

    最后我们可以得到PSNR值为

     

     

    展开全文
  • 最简单的基于FFmpeg的图像编码

    千次下载 热门讨论 2014-05-09 00:08:53
    因此特地分离出了一个简单图像编码器供学习之用。 该图像编码器实现了YUV420P的数据编码为JPEG图片。 尽管该图像编码器的代码十分简单,但是几乎包含了使用FFMPEG编码一个图像所有必备的API。十分适合FFmpeg的初学者...
  • 图像编码算法

    2013-07-05 17:31:09
    图像编码算法 JPEG编码 DCT变换 哈夫曼编码
  • 查阅JPEG编码的有关资料,对图像进行JPEG压缩,算法步骤必须包括如下几个部分:图像分块,离散余弦变换,量化,ac和dc系数的Z字形编排。 问题1: 质量因子分别选为20,60,80,对比显示原图与不同质量因子下解码后的...
  • 3. 源编码与信道编码 4. 有损压缩与无损压缩 2. 图像压缩的必要性 常见的压缩标准 图像压缩的基本流程 JPEG的压缩方法 3. 量化 4. 常用编码方法 1.KLT 2. DCT 5. Huffman编码与信息熵 为什么要进行编码?...

    Table of Contents

    1.图像压缩简介

    2.图像压缩用途

    3. 源编码与信道编码

    4. 有损压缩与无损压缩

    2. 图像压缩的必要性

    常见的压缩标准

    图像压缩的基本流程

    JPEG的压缩方法

    3. 量化

    4. 常用编码方法

    1.KLT

    2. DCT

    5. Huffman编码与信息熵

    为什么要进行编码?

    概率高的符号用短码,概率低的符号用长码

    Huffman编码生成方式

    理论最小平均码长(信息熵)

    三叉Huffman编码方法

    6. OpenCV+C++语言实现图像压缩


    PART I 图像编码

    1.图像压缩简介

    • 图像编码是指在空间域下对图像像素值进行编码,其典型的用途是:
    1. 图像压缩
    2. 图像加密
    3. 图像水印等
    • 图像编码压缩的主要目的是用尽可能少的bits去表示一副图像,于此同时,图像的质量和信息得以保留。
    • 衡量压缩质量的主要标准:MSE(Mean Square Error)均方误差、PSNR(Peak Signal to Noise Ratio)峰值信噪比、SSIM(Structural similarity index)等。

    2.图像压缩用途

    1. 减少信道传输时所需的带宽;
    2. 减少存储时所需的磁盘空间。

    3. 源编码与信道编码

    4. 有损压缩与无损压缩


    2. 图像压缩的必要性

    图像压缩


      某天陈老师要录动作大片,经过长期艰苦奋斗,他制成了这样一段视频:画面大小1000×1000pixel,24位真彩色,每秒30帧,时长2小时。
      如果不进行任何压缩,存储这段视频需要1000*1000*24*30*60*120=5.184 ×1012 bit ≈ 648GB的空间。(2014年4月5日,500GB硬盘最低价格是299元~)
      用4M宽带下载这部大片,最少需要360小时 = 15天。
      可见,要保障人民群众的切身利益,压缩技术非常有必要。

    压缩的可能性

    图像压缩
      就单幅图像而言,压缩的可能性是显而易见的。
      如上面三幅小图,图a每个形状里面都填充着相同的颜色,图b每一行的颜色是相同的,更过分的图c整幅图只填充了一种颜色。
      压缩前:第1个点灰色,第2个点灰色,第3个点灰色,第4个点灰色,第5个点灰色,第6个点灰色......第89个点灰色,第90个点黑色......
      最简单的压缩后:第1到89个点灰色,第90个点黑色。

    常见的压缩标准

    图像压缩
      JPEG是广泛使用的照片存储格式,它适应人的视觉,用更多的数据来存储人眼敏感的图像低频部分,用很少的数据存储人眼不关心的高频部分。维基百科有很详尽的讲解http://zh.wikipedia.org/wiki/JPEG
      JPEG 2000是基于小波变换的图像压缩标准,可以获得比JPEG更大的压缩比,通常它被认为是未来取代JPEG的标准。http://zh.wikipedia.org/wiki/JPEG_2000

    图像压缩的基本流程

    图像压缩
    图像压缩基本按照以下流程进行:
    原图像 -> 映射 -> 量化 -> 符号编码 -> 存储/传输 -> 符号解码 -> 反映射 -> 图像
    映射(Mapper):对原图像进行变换,使之更容易被压缩。(比如傅里叶变换)
    量化(Quantizer):量化是压缩的主要图像,主要也是它引入误差的。比如有一个以2为单位的量化器,看到原图像值是17,将它除2向下取整,量化得到8;图像还原的时候,用8×2=16得到还原值,与真实值相差了1。
    符号编码(Symbol encoder):图像已经变换量化完了,该为存储和传输作准备了。符号编码可以进一步地压缩文件大小:将重复出现次数多的数据,用简短的符号进行编码;出现次数少的数据,用较长的符号进行编码;后面的哈夫曼(Huffman)编码会详细讲到~

    JPEG的压缩方法

    图像压缩
      鉴于图像压缩的每个步骤都能有不同的方法,所以有必要制定统一的标准,使得图像在每台电脑每部手机中都能正常使用。
      JPEG是其中一个标准,它的压缩套路如下:
      原图像 -> 分解成一个个小图像 -> 变换 -> 量化 -> 符号编码 -> 压缩后的图像
      分解图像:JPEG会将一幅大图像分解成8×8的小图像。至于为什么是8×8呢,嗯,欢迎各位同学剧透;
      变换:JPEG使用DCT变换(离散余弦变换),类似傅里叶变换,不过它是取实部。(不由感慨,学好“信号与系统”也是很有必要的...)
      量化:JPEG通过各种除法来进行量化,不过对于不同重要程度的信息,它所除的数的大小会有所不同;
      符号编码:JPEG使用常见的哈夫曼(Huffman)编码。
      图像还原,就是反过来进行这些步骤。
      JPEG的实现方法比较简单,也因为简单高效,所以JPEG的应用范围相当广泛。


    3. 量化

    数字图像与模拟图像的重要区别,在与它是数字的。(还能有更废的话吗...)数字,意味着它的离散的:图像空间上的像素点是离散的,像素点的灰度值(颜色值)也是离散的。相反,模拟图像(比如胶卷)出来的图像空间上和数值上都是连续的。

    下图是JPEG的压缩编码流程,本节介绍的,是其中的“量化”(Quantizer)部分。
    JPEG压缩流程
    JPEG的压缩方法,可以所是非常聪明。
    人眼看图像,不会太注重细节。左边一个像素与右边一个像素灰度值相差10或是11,基本不会影响理解。
    简单地说,JPEG用最多的空间,来存储对人理解最重要的信息,而一些微乎其微的小细节,基本不会储存。

    打个比方,JPEG是这样描述一个图像的:
    1. 这是一个人;
    2. 是一个女人;
    3. 1.7米高,三围Beep——
    4. 肤色棕黑;
    5. 眼睛大大,鼻子高高;
    6. 牙齿奶黄色,身上有不显眼的体毛;
    7. 体毛长度介于1.2cm-1.3cm;
    8. 体毛的弧度可以用这个函数表示(省略);
    9. 毛上面有这么些粗糙的细节;
    10. 毛上面粗糙的细节的纹路是这样字的。
    11. (更加细微和揪心的...)
    上面是从对人理解的重要性高到低排序的,只要看到1-9,人就能很好地理解这个图像了。(不是我喜欢的类型~!) 那些微观的细节,对人理解没有太大帮助,而存储它占据的空间是跟存储前面宏观内容是一样的。
    所以,

    JPEG是用更多空间存储“大”的东西,而用更少空间存储“微小的细节”,这样图像大小就能大大地被压缩,而不影响人的理解。
    JPEG压缩
    JPEG
    JPEG量化
    JPEG

    Lloyd—Max quantizer

    JPEG量化

     


    4. 常用编码方法

    1.KLT

    KLT的不足:

    2. DCT

     


    5. Huffman编码与信息熵

    JPEG用哈夫曼编码(Huffman Encoder)作为其符号编码。哈弗曼编码是压缩算法中的经典,它理论上可以将数据编成平均长度最小的无前缀码(Prefix-Free Code)。

    为什么要进行编码?

    图像处理


    关于Lena:莱娜图(Lenna)是指刊于1972年11月号《花花公子》(Playboy)杂志上的一张裸体插图照片的一部分,是一张大小为512x512像素的标准测试图。该图在数位影像处里学习与研究中颇为知名,常被用作数位影像处里各种实验(例如资料压缩和降噪)及科学出版物的例图。(几乎每一本图像处理相关的书都会出现这张图片~)
    Lena的直方图(Histogram):从Lena的直方图中可以看出,图片中每个灰度值出现的概率是不相同的。这里,中间灰度值部分出现的概率比较高,两边灰度值出现概率非常低。所以,如果每个灰度值都进行同样长度的编码,似乎就太浪费了。

     

    概率高的符号用短码,概率低的符号用长码


    正是因为每个灰度值出现的概率不一样,我们用更短的编码来表示经常出现的灰度值,用更长的编码来表示几乎不出现的灰度值,平均下来编码长度就会比等长编码短,从而节省了空间。

    Huffman编码生成方式


    1. 将要编码的符号按出现概率高到低排列;
    2. 将出现概率最低的两个符号进行组合,两者概率加起来得到组合概率;
    3. 将得到的组合概率与其他符号的概率再进行排序;
    4. 重复(2),直到出现组合概率为1。

    图片1
    首先,按照各符号出现概率大小进行排列;
    图片2
    找到概率最小的两个符号,进行组合。这里是a3和a5最小,两者组合起来概率为0.1;
    图片3
    将组合好的两个符号看作一个新的符号,与其他符号再进行一次排列,找到出现概率最小的两个;
    图片4
    将两个出现概率小的符号再进行一次组合,有得到一个组合概率;
    图片5
    如此进行下去,知道组合到概率为1;
    图片6
    至此,这棵哈夫曼“树”算是画完了,可以进行编码了;
    从概率为1(最右)开始,上面分叉编号1,下面分叉编号0(反过来也可以),编号到最左边。
    从右到左读数:


    a2 = 1;
    a6 = 01;
    a1 = 001;
    a4 = 0001;
    a3 = 00001;
    a5 = 00000;


    哈夫曼编码的一大好处是,它是Prefix-Free的,也就是每个符号之间不加分隔符,解码器也能识别;
    对上面6个符号,如果采用统一长度编码,一个符号需要3bit;
    用哈夫曼进行编码,


    平均码长 = 1*0.4 + 2*0.3 + 3*0.1 + 4*0.1 + 5*0.06 + 5*0.04 = 2.2bit;
    压缩比 = 2.2/3=0.7333333333;


    如果概率分布更集中,压缩效果更明显。

     

    理论最小平均码长(信息熵)


    我还依稀记得,香农老人家语重心长地教诲我:哈夫曼编码的最小平均码长,是熵(信息论)
    不过实践经验告诉我,一般哈夫曼编码出来的平均码长,会比这个理论值大那么一丢丢

    三叉Huffman编码方法

    经历完上学期的“信息论”考试,我才知道,地球上还存在N叉哈夫曼编码。
    一般二叉都会使用二叉哈夫曼编码,也就是用0、1作为分叉。
    但考试非要考三叉哈夫曼编码,也就是用0、1、2来进行编码。
    方法很简单:方法与二叉Huffman编码一致,如果待编码的符号数不是3的倍数,就自行补上几个“概率为0”的符号,使符号的总个数为3的倍数。

    JPEG分块对图像进行处理

      JPEG压缩图像的第一步,是将图像分解成一个个8×8小图像,之后再分别对这些小图像进行变换量化编码。
    02_03 - Video -[00_04_23][20140407-001045-0]

    为什么JPEG要使用8×8的分块?

    1. 分块小,比如2×2,图像还原质量差;
    2. 分块大,比如将整幅图作为一块,消耗计算资源多;

    平衡质量和资源,JPEG默认使用8×8的分块。当然,我觉得一定是有更深层原因的....
    02_04 - Video -[00_21_06][20140408-233518-0]

    用YCrCb表示颜色

      JPEG是“色盲”的,它不能直接作用于彩色图像要处理彩色图像,显而易见的解决办法是分别对RGB三个通道进行处理,后果是,图像中三种颜色的联系被活活的拆散了。因此,JPEG采用YCrCb来表示颜色。
      想当年,黑白电视占主流,彩色电视刚面世。为了使黑白电视也能看到彩色电视信号装载的节目,聪明的人类想到了一种办法:用Y通道表示图像的亮度CrCb表示色差,这样黑白电视只接收Y通道的信号,就能看到黑白图像彩色电视则通过YCbCr,来获得彩色图像。因为人对图像的亮度比较敏感,可以用更多数据来传输Y通道,用更少数据来传送CbCr通道,从而提升图像压缩率。


    6. OpenCV+C++语言实现图像压缩

    见另一篇博客

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • 根据图像子块的像素分布特征,提出了一种基于方差和DCT变换的混合快速分形图像编码算法,并在此基础上引入了平滑块的概念。该算法在大幅度提高分形图像编码速度的同时,很好地改善了压缩率和解码图像的质量。实验...
  • (2)将彩色图像的像素 R、G、B 值作为独立符号,进行哈夫曼编码和解码,计算熵和码字平均码长。 (3)将彩色图像的像素 R、G、B 值作为联合符号,进行哈夫曼编码和解码,计算熵和码字的平均码长。
  • ICASSP2021:端到端的图像编码方法

    千次阅读 2021-08-15 17:34:06
    本文提出基于神经网络(NN)的端到端学习的面向机器的图像编码器(Image Coding for Machines,ICM)。 本文算法 本文ICM模型的优化目标是机器任务的性能而不是像素保真度,模型包含一个自编码器,一
  • 图像编码的原因: 数据时信息传递的手段,相同的信息可以通过不同的数据量去表示,尝试用不同的表达方式以减少表示图像的数据量,对图像的压缩可以通过对图像的编码实现。 数据压缩 减少表示给定信息所需要的数据量...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 244,268
精华内容 97,707
关键字:

图像编码