精华内容
下载资源
问答
  • 因此特地分离出了一个简单的视频编码器供学习之用。 此前做过一个YUV420P像素数据编码为H.264码流的例子。对这个例子进行了升级。升级后编码器实现了YUV420P像素数据编码为H.265码流。 尽管该视频编码器的代码十分...
  • 字符编码那些事--彻底理解掌握编码知识

    万次阅读 多人点赞 2020-05-04 16:42:33
    每一个程序员都不可避免的遇到字符编码的问题,很多人在字符编码方面同样遇到不少问题,而且一直对各种编码懵懵懂懂、不清不楚。这篇文章就是针对字符编码中的一些问题进行了详细的阐述,能从根本上理解字符编码

    一、讲述之前我们先来了解一些概念

    1、字符

    字符指类字形单位或符号,包括字母、数字、运算符号、标点符号和其他符号,以及一些功能性符号。一般来说我们称某个字符集里面的字符,叫xx字符,如ASCII字符集里面的ASCII字符,GB2312字符集里面的GB2312字符。

    2、字符集

    字符集(Character Set、Charset),字面上的理解就是字符的集合,是一个自然语言文字系统支持的所有字符的集合。字符是各种文字和符号的总称,包括文字、数字、字母、音节、标点符号、图形符号等。例如ASCII字符集,定义了128个字符;GB2312字符集定义了7445个字符。而字符集准确地来说,指的是已编号的字符的有序集合(但不一定是连续的,后文有详细介绍)。
    常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、 GB18030字符集、Unicode字符集等。

    3、码位

    在字符编码术语中,码位(code point)或称编码位置、码点,是组成码空间(或代码页)的数值。 例如,ASCII码包含128个码位,范围是016进制到7F16进制,扩展ASCII码包含256个码位,范围是016进制到FF16进制,而Unicode包含1,114,112个码位,范围是016进制到10FFFF16进制。Unicode码空间划分为17个Unicode字符平面(基本多文种平面,16个辅助平面),每个平面有65,536(= 216)个码位。因此Unicode码空间总计是17 × 65,536 = 1,114,112. —解释来源于维基百科

    4、字符编码

    字符编码(Character Encoding),是把字符集中的字符按一定方式编码为某指定集合中的某一对象的过程(比如将字符编码为由0和1两个数字所组成的位串模式、由0~9十个数字所组成的自然数序列或电脉冲等),亦即在字符集与指定集合两者之间建立一个对应关系(即映射关系)的过程。这是信息处理的一项基础技术。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII码。
    p.s.这里我们计算机这里字符编码肯定是用二进制来编码的
    看完这四个概念,你应该要明白,它们之间的关系,以ASCII为例,下图解释它们之间关系
    在这里插入图片描述
    这里细说一下,码位就是这个字符集里面字符的一个表示位置,通俗来说,码位就是一般跟字符集绑在一起,字符编码是把字符集中的字符编码为特定的二进制数,以便在计算机中存储。这个二进制数就叫xx码。

    二、字符集编码分类总结

    在说字符集编码之前,先明确一个观点,字符集编码与字符集是两个不同层面的概念:
    (1)charset 是 character set 的简写,即字符集。
    (2)encoding 是 charset encoding 的简写,即字符集编码,简称编码
    在这里插入图片描述

    1、ASCII编码

    ASCII(美国信息交换标准代码)是基于拉丁字母(就是我们现在的英文字母)的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本延伸美国标准信息交换码则可以部分支持其他西欧语言,并等同于国际标准ISO/IEC 646。

    ASCII 由电报码发展而来。第一版标准发布于1963年,1967年经历了一次主要修订,最后一次更新则是在1986年,至今为止共定义了128个字符;其中33个字符无法显示(一些终端提供了扩展,使得这些字符可显示为诸如笑脸、扑克牌花式等8-bit符号),且这33个字符多数都已是陈废的控制字符。控制字符的用途主要是用来操控已经处理过的文字。在33个字符之外的是95个可显示的字符。用键盘敲下空白键所产生的空白字符也算1个可显示字符(显示为空白)。

    每个ASCII字符占用1个字节(8bits),共有128位字符或符号,使用7位二进制数(剩下的1位二进制为0,即高位为0)来表示所有的大写和小写字母,数字0 到9、标点符号,以及在美式英语中使用的特殊控制字符。

    缺点:ASCII的最大缺点是只能显示26个基本拉丁字母、阿拉伯数目字和英式标点符号,因此只能用于显示现代美国英语(而且在处理英语当中的外来词如naïve、café、élite等等时,所有重音符号都不得不去掉,即使这样做会违反拼写规则)。而EASCII(即扩展的ASCII码,利用8位的高位设为1进行扩展)虽然解决了部份西欧语言的显示问题,但对更多其他语言依然无能为力。因此现在的操作系统内码(稍后会讲)基本已经抛弃ASCII码而转用Unicode码。

    ASCII码表 :http://www.asciitable.com

    2、GB2312编码

    前面可以看到ASCII码即使进行了扩展也能表示的字符也很少,尤其是当需要计算机显示存储中文的时候,就需要一种对中文进行编码的字符集,GB 2312就是解决中文编码的字符集,由国家标准委员会发布。那个时候当中国人们得到计算机时,已经没有可以利用的字节状态来表示汉字,况且有6000多个常用汉字需要保存,于是想到把那些ASCII码中127号之后的奇异符号们直接取消掉, 规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。这种汉字方案叫做 “GB2312”。GB2312 是对 ASCII 的中文扩展。兼容ASCII。
    在这里插入图片描述
    这里的A GB2312码是0xA3C1,0xA3和0xC1都是高于127的,所以判断它是个全角字符,另外我们可以观察到所有的GB2312编码表中的GB2312码每个字节都是大于0xA0的,这个就是为了保证能区分是否为ASCII码,小于127的字节就按照ASCII码标准,碰到连续两个大于127字节就组合成一个GB2312码。

    GB2312汉字编码字符集对照表:http://tools.jb51.net/table/gb2312

    3、GBK编码

    但是中国的汉字太多了,我们很快就就发现有许多人的人名没有办法在这里打出来,不得不继续把 GB2312 没有用到的码位找出来用上。后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 “GBK” 标准,GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。

    4、GB18030编码

    后来中国的少数民族也要用电脑了,GBK的两万多字也已经无法满足我们的需求了,还有更多可能你自己从来没见过的汉字需要编码。这时候显然只用2bytes表示一个字已经不够用了(2byte最多只有65536种组合,然而为了和ASCII兼容,最高位不能为0就已经直接淘汰了一半的组合,只剩下3万多种组合无法满足全部汉字要求)。因此GB18030多出来的汉字使用4byte编码。当然,为了兼容GBK,这个四字节的前两位显然不能与GBK冲突(实操中发现后两位也并没有和GBK冲突)。通过多年的发展至此,GB18030编码的中文文件已经有七万多个汉字了。

    GB18030包含三种长度的编码:单字节的ASCII、双字节的GBK(略带扩展)、以及用于填补所有Unicode码位的四字节UTF区块。所以我们说GB18030采用多字节编码,每个字符可以由 1 个、2 个或 4 个字节组成。

    其实我们用到的99%以上的汉字,都在GB2312那一块区域内。在实际使用中,GBK编码已经可以满足大部分场景了,GB18030编码中所有汉字都是我们这辈子都不一定能见到的文字,所以平时经常会使用的就是GBK编码。

    这里额外总结一下这四个兼容性关系是GB18030兼容GBK,GBK兼容GB2312,GB2312兼容ASCII。所谓兼容,你可以简单理解为子集、不冲突的关系。例如GB2312编码的文件中可以出现ASCII字符,GBK编码的文件中可以出现GB2312和ASCII字符,GB18030编码的文件可以出现GBK、GB2312、ASCII字符。

    5、Unicode

    友情建议:看Unicode一些概念解释和历史时,建议看维基百科,而且是英文版的,别用中文版,有些地方讲的模棱两可,容易陷入盲区。

    Unicode(中文:万国码、国际码、统一码、单一码)(全称Universal Multiple-Octet Coded Character Set)它伴随着通用字符集(英语:Universal Character Set, UCS)的标准而发展。所以可以看出他是字符集。

    1.Unicode与ISO 10646

    全世界很多个国家都在为自己的文字编码,并且互不相通,不同的语言字符编码值相同却代表不同的符号(例如:韩文编码EUC-KR中“한국어”的编码值正好是汉字编码GBK中的“茄惫绢”)。因此,同一份文档,拷贝至不同语言的机器,就可能成了乱码,于是人们就想:我们能不能定义一个超大的字符集,它可以容纳全世界所有的文字字符,再对它们统一进行编码,让每一个字符都对应一个不同的编码值,从而就不会再有乱码了。如果说“各个国家都在为自己文字独立编码”是百家争鸣,那么“建立世界统一的字符编码”则是一统江湖,谁都想来做这个武林盟主。早前就有两个机构做了这个事:
    (1) 国际标准化组织(ISO),他们于1984年创建ISO/IEC JTC1/SC2/WG2工作组,试图制定一份“通用字符集”(Universal Character Set,简称UCS),并最终制定了ISO 10646标准。(简单来说ISO 10646标准就是UCS)
    (2) 统一码联盟,他们由Xerox、Apple等软件制造商于1988年组成,并且开发了Unicode标准(The Unicode Standard,这个前缀Uni很牛逼哦—Unique, Universal, and Uniform)。

    Unicode与ISO 10646标准的风风雨雨:

    在1984年,喜欢以繁多的编号糊弄群众的国际标准化组织ISO也开始着手制定解决不同语言字符数量太大问题的解决方案,这一方案被称为Universal Character Set(UCS),正式的编号是ISO-10646(记得么,ASCII是ISO-646,不知这种安排是否是故意的)。还是ISO高瞻远瞩,一开始就确定了UCS是一个31位的编码字符集(即用一个大小不超过2的31次方的整数数字为每个字符编号),这回真的足以容纳古往今来所有国家,所有语言所包含的字符了(是的,任何国家,任何小语种都包括)。虽然后来他们意识到,2的31次方个码位又实在太多了……

    天下大势,分久必合。无论Unicode还是UCS,最初的目的都是杜绝各种各样名目繁多形式各异互不兼容老死不相往来的私用扩展编码(好啰嗦的一句话),结果两方确立标准的同时(最初时这两个标准是不兼容的),因为都是个干个的,肯定不可能一模一样,出现标准不同。1991年,Unicode联盟与ISO的工作组终于开始讨论Unicode与UCS的合并问题,虽然其后的合并进行了很多年,Unicode初版规范中的很多编码都需要被改写,UCS也需要对码空间的使用进行必要限制,但成果是喜人的。最终,两者统一了抽象字符集(即任何一个在Unicode中存在的字符,在UCS中也存在),且最靠前的65535个字符也统一了字符的编码。对于码空间,两者同意以一百一十万为限(即两者都认为虽然65536不够,但2的31次方又太大,一百一十万是个双方都可接受的码空间大小,也够用,当然,这里说的一百一十万只是个约数),Unicode将码空间扩展到了一百一十万,而UCS将永久性的不使用一百一十万以后的码位。也就是说,现在再讲Unicode只包含65536个字符是不对的(虽然大家现在都知道Unicode至少都可以囊括几亿个字符)。除了对已经定义的字符进行统一外,Unicode联盟与ISO工作组也同意今后任何的扩展工作两者均保持同步,因此虽然从历史的意义上讲Unicode与UCS不是一回事(甚至细节上说也不是一回事),但现在提起Unicode,指代两者均无不妥,毕竟因为已经统一了。(现在网上基本上把Unicode字符集叫做UCS,Unicoide 的全称是 Universal Multiple-Octet Coded Character Set简写也是UCS,一看也对上了,害,只能说天注定)

    现在Unicode编码点分为17个平面(plane),每个平面包含216(即65536)个码位(code point)。17个平面的码位可表示为从U+xx0000到U+xxFFFF,其中xx表示十六进制值从0016到1016,共计17个平面。

    这第一个位置(当xx是00的时候)被称为BMP(基本多文种平面,BasicMultilingualPlane)。它包含了最常用的码位从U+0000到U+FFFF(常见的65536个字符)

    其余16个平面(从下面的1号平面到16号平面),你可以叫做非BMP,由此这样分的话里面的字符就有两个概念:BMP字符和非BMP字符,后者也被称为补充字符。(偷偷告诉你们,大家喜闻乐见的Emoji表情都是在1号平面,范围是U+1F600-U+1F64F)
    在这里插入图片描述
    2. UCS-2和UCS-4

    ISO 10646标准为“通用字符集”(UCS)定义了一种16位的编码形式(即UCS-2),UCS-2全称Universal Character Set coded in 2 octets,从英文上就可以看出含义,以2字节编码的通用字符集编码,固定占用2个字节,它包含65536个编码空间(可以为全世界最常用的63K字符编码,为了兼容Unicode,0xD800-0xDFFF之间的码位未使用)。例:“汉”的UCS-2编码为6C49。除此之外ISO 10646标准为“通用字符集”(UCS)还定义了一种31位的编码形式(即UCS-4),UCS-4全称Universal Character Set coded in 4 octets,其编码固定占用4个字节,编码空间为0x00000000 ~0x7FFFFFFF(可以编码20多亿个字符)。随着Unicode与ISO 10646合并统一,Unicode就用UCS通用字符集标准,早期的Unicode编码实现也就采用了UCS-2和UCS-4。(准确来说是UCS-2,UCS-4基本上是理论,没付诸实际,毕竟早期65536个字符已经够用了,我两个字节编码能实现的事,脑子笨的人才会用四个字节实现,你以为存储和带宽有多的)
    在这里插入图片描述这里编码最多也就存在UCS-2(big Endian和Little Endian先不管,后面会讲)

    Unicode字符集只规定了码点和文字之间的对应关系,并没有规定码点在计算机中如何存储。UCS-2和UCS-4就规定了具体的实现,后来改进演变为了UTF-16, UTF-32。然后又创造了一种全新的简单粗暴好用的变长编码UTF-8,于是乎这三哥们就形成了现代Unicode字符集编码实现的三剑客

    3. UTF-16与UTF-32

    Unicode与ISO 10646合并统一后,Unicode与 ISO 10646 的通用字符集概念(UCS)相对应。早期实现Unicode用的编码是UCS-2,后来随着发展发现 216(即 65536)个字符不能满足了,Unicode标准本身发生了变化:65536个字符显得不足,引入了更大的31位空间和一个编码(UCS-4),每个字符需要4个字节。前面已经介绍了。但是统一码联盟对此予以抵制(这就是为什么我之前说UCS-4是一种理论编码,根本就没付诸实际),这是因为每个字符4个字节浪费了很多磁盘空间和内存,并且因为一些制造商已经在每个字符2个字节的技术上投入了大量资金。所以最后通过一系列巴拉巴拉讨论规定形成了一种折衷方案,建立了UTF-16编码方案(此时Unicode标准2.0),它替代了原有的UCS-2,并做了改进。它与UCS-2一样,它使用两个字节为全世界最常用的63K字符编码,不同的是,它使用4个字节对不常用的字符进行编码。目的就是为了支持从17个平面编码1,112,064个代码点。UTF-16属于变长编码。我们可以将UTF-16编码看成是UCS-2编码父集。在没有辅助平面字符(surrogate code points)前,UTF-16与UCS-2所指的是同一意思。但当引入辅助平面字符后,就称为UTF-16了。现在应该认为UCS-2已作废,如果有人还用这种,也不必纠结,它就是表达用定长2字节编码,自己心里清楚就行(基本上你查维基百科上UCS-2都是重定向到UTF-16)。另外当时ISO 10646的UCS-4编码并入了Unicode标准,而UCS-4有20多亿个编码空间,但实际使用范围并不超过0x10FFFF,并且为了兼容Unicode标准,ISO也承诺将不会为超出0x10FFFF的UCS-4编码赋值。由此提出了实实在在的UTF-32编码(现在也应该认为UCS-4像UCS-2一样作废,维基百科上UCS-4也重定向到UTF-32页面),它的编码值与UCS-4相同,只不过其编码空间被限定在了0~0x10FFFF之间。因此也可以说:UTF-32是UCS-4的一个子集。

    (现在若有软件声称自己支持UCS-2,那其实是暗指它不能支持在UTF-16中超过2字节的字集。)

    UTF-16(16 位 Unicode转换格式)是一种字符编码,能够对Unicode的所有1,112,064个有效码点进行编码(实际上,此代码点数由UTF-16的设计决定,这个你细品你就知道什么意思,就好像某个班有55个人,根据55个座位确定55个人,而55个座位这个多少是由55个人决定的,两者是相互的,这是一个哲学道理,hh扯远了,所以其中意味自行明白)。
    前面提到过:Unicode编码点分为17个平面(plane),每个平面包含216(即65536)个码位(code point),而第一个平面称为“基本多语言平面”(Basic Multilingual Plane,简称BMP),其余平面称为“辅助平面”(Supplementary Planes)。其中“基本多语言平面”(00xFFFF)中0xD8000xDFFF之间的码位作为保留,未使用。UCS-2只能编码“基本多语言平面”中的字符,此时UTF-16与UCS-2的编码一样(都直接使用Unicode的码位作为编码值),例:“汉”在Unicode中的码位为6C49,而在UTF-16编码也为6C49。另外,UTF-16还可以利用保留下来的0xD800-0xDFFF区段的码位来对“辅助平面”的字符的码位进行编码,因此UTF-16可以为Unicode中所有的字符编码。

    UTF-16和UTF-32也就是如今Unicode编码的标准之二,他们的区别就是UTF-16是变长编码,大部分是2字节和少部分4字节,UTF-32是定长编码,表示任何字符都用 4 字节

    4. UTF-8

    从前述内容可以看出:无论是UCS-2/4还是UTF-16/32,一个字符都需要多个字节来编码,这对那些英语国家来说多浪费带宽啊!(尤其在网速本来就不快的那个年代。。。),而且我们注意到UTF-16最少2字节和UTF-32不变4字节,这肯定是不兼容ASCII码的,由此,UTF-8产生了。在UTF-8编码中,ASCII码中的字符还是ASCII码的值,只需要一个字节表示,其余的字符需要2字节、3字节或4字节来表示。

    UTF-8的编码规则:
    (1) 对于ASCII码中的符号,使用单字节编码,其编码值与ASCII值相同。其中ASCII值的范围为0~0x7F,所有编码的二进制值中第一位为0(这个正好可以用来区分单字节编码和多字节编码)。
    (2) 其它字符用多个字节来编码(假设用N个字节),多字节编码需满足:第一个字节的前N位都为1,第N+1位为0,后面N-1 个字节的前两位都为10,这N个字节中其余位全部用来存储Unicode中的码位值。
    在这里插入图片描述
    现如今UTF-8 是互联网上使用最广的一种 Unicode 的实现方式,是其他两种无可比拟的(详情请看这篇文章)

    5.UTF的字节序和BOM
    字节序就要先补充一点知识:
    码元(code unit):是能用于处理或交换编码文本的最小比特组合。它代表某种编码中最小的可用来识别一个合法字符的最小字节数序列

    UTF-8使用变长的字节序列来表示字符;某个字符(对应一个码点)可能使用1-4个字节才能表示;在UTF-8中一个字符最小可能一个字节,所以我们规定1个字节就是一个码元;

    UTF-16使用也变长字节序列来表示字符;某个字符(对应一个码点)可能使用2个或者4个字符来表示;因为2个字节序列是最小的能够识别一个码点的单位,同理我们规定2个字节就是一个码元;

    UTF-32使用定长的4个字节表示一个字符;一个字符(对应一个码点)使用4个字符来表示,这样4个字节就是一个码元。

    简单来说,就是“码点”经过映射后得到的二进制串的转换格式单位称之为“码元”。“码点”就是一串二进制数,“码元”就是切分这个二进制数的方法。这些编码每次处理一个码元,你可以把它理解为UTF-8每次读码点的8位,UTF-16每次读码点的16位,UTF-32每次读码点的32位,。当然这也是为什么叫这些叫Unicode转换格式的原因。处理的是同一个字符集,但是处理方式不同。

    字节序
    UTF-8一次一个UTF-8码元,即处理一个字节,没有字节序的问题。UTF-16一次处理一个UTF-16码元,对应两个字节,UTF-32一次一个UTF-32码元,对应处理四个字节,所以这就要考虑到一个字节序问题。以UTF-16w为例,在解释一个UTF-16编码文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?这就考虑大小端问题,所以UTF-16编码包括三种:UTF-16BE(Big Endian),UTF-16LE(Little Endian)、UTF-16(类似的名称UCS-2BE和UCS-2LE用于显示UCS-2的版本。)

    UTF-16BE和UTF-16LE好理解,直接指定了字节序(大小端),但是UTF-16怎么处理呢?

    Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

    在UCS编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。

    同样的类比,UTF-32也是这样的。有UTF-32BE、UTF-32LE、UTF-32。前面UTF-32BE和UTF-32LE直接指定了字节序(大小端),后面的UTF-32也是靠BOM。

    UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

    Windows就是使用BOM来标记文本文件的编码方式的。它就建议所有的 Unicode 文件应该以 ZERO WIDTH NOBREAK SPACE(U+FEFF)字符开头。这作为一个“特征符”或“字节顺序标记(byte-order mark,BOM)”来识别文件中使用的编码和字节顺序。所以用Windows自带的记事本将文件保存为UTF-8编码的时候,记事本会自动在文件开头插入BOM(虽然BOM对UTF-8来说并不是必须的)。但也有一些系统或程序不支持BOM,因此带有BOM的Unicode文件有时会带来一些问题。比如JDK1.5以及之前的Reader都不能处理带有BOM的UTF-8编码的文件,解析这种格式的xml文件时,会抛出异常:Content is not allowed in prolog。Linux/UNIX 并没有使用 BOM,因为它会破坏现有的 ASCII 文件的语法约定。 所以一般我们不建议用Windows自带的记事本编辑UTF-8文件就是这样。

    6. 总结
    (1) 简单地说:Unicode和UCS是字符集,不属于编码UTF-8、UTF-16、UTF-32等是针对Unicode字符集的编码,UCS-2和UCS-4是针对UCS字符集的编码(只是我们习惯把Unicode字符集编码简称为Unicode编码,把UCS字符集编码称为UCS编码)。 Unicode沿用UCS字符集,在UCS-2和UCS-4基础上提出的UTF-16、UTF-32。并发展了UTF-8,发展到现在,就密不可分了,大家基于UCS就把Uniocde维护好就行,发布标准大家统一。以往的UCS-2和UCS-4概念就默认作废了这样一个关系,整个他们的发展长话短说就是这样,懂了吗。
    (2) UTF-8、UTF-16、UTF-32、UCS-2、UCS-4对比:
    在这里插入图片描述
    由于历史方面的原因,你还会在不少地方看到把Unicode称为一种编码的情况,那是因为早期的2字节编码最初称为“ Unicode”,但现在称为“ UCS-2”,这种情况下的 Unicode 通常就是 UTF-16 或者是更早的 UCS-2 编码,只是被一直搞混了,在某些老软件上尤为常见。比如下面editplus里面文件编码设置。
    在这里插入图片描述
    以前的Windows电脑上的记事本(左边)显示的是Unicode,不过现在好像改了变成了UTF-16。
    在这里插入图片描述
    不过由于各种原因,必须承认,在不同的语境下,“Unicode”这个词有着不同的含义。
    它可能指:
    (1)Unicode 标准
    (2)Unicode 字符集
    (3)Unicode 的抽象编码(编号),也即码点、码位(code point)
    (4)Unicode 的一个具体编码实现,通常即为变长的 UTF-16(16 或 32 位),又或者是更早期的定长 16 位的 UCS-2

    所以像我一般有时候非要区分的话都是直接说全,Unicode 标准,Unicode 字符集,Unicode编码等等。你们呢QAQ

    6、ANSI编码

    为使计算机支持更多语言,通常使用0x800~xFF范围的2个字节来表示1个字符。比如:汉字 ‘中’ 在中文操作系统中,使用 [0xD6,0xD0]这两个字节存储。
    不同的国家和地区制定了不同的标准,由此产生了 GB2312、GBK、GB18030、Big5、Shift_JIS 等各自的编码标准。这些使用多个字节来代表一个字符的各种语言延伸编码方式,称为 ANSI 编码。在简体中文Windows操作系统中,ANSI 编码代表 GBK 编码;在繁体中文Windows操作系统中,ANSI编码代表Big5;在日文Windows操作系统中,ANSI 编码代表 Shift_JIS 编码。

    不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。
    在使用ANSI编码支持多语言阶段,每个字符使用一个字节或多个字节来表示(MBCS,Multi-Byte Character System),因此,这种方式存放的字符也被称作多字节字符。比如,“中文123” 在中文 Windows 95 内存中为7个字节,每个汉字占2个字节,每个英文和数字字符占1个字节。

    在非 Unicode 环境下,由于不同国家和地区采用的字符集不一致,很可能出现无法正常显示所有字符的情况。微软公司使用了代码页(Codepage)转换表的技术来过渡性的部分解决这一问题,即通过指定的转换表将非 Unicode 的字符编码转换为同一字符对应的系统内部使用的Unicode 编码。可以在“语言与区域设置”中选择一个代码页作为非 Unicode 编码所采用的默认编码方式,如936为简体中文GBK,950为正体中文Big5(皆指PC上使用的)。在这种情况下,一些非英语的欧洲语言编写的软件和文档很可能出现乱码。而将代码页设置为相应语言中文处理又会出现问题,这一情况无法避免。从根本上说,完全采用统一编码才是解决之道,虽然现在Unicode有了,但由于历史遗留,老软件等等原因,所以系统统一用某种编码格式的Unicode目前尚无法做到这一点。

    代码页技术现在广泛为各种平台所采用。UTF-7 的代码页是65000,UTF-8 的代码页是65001。简体中文上使用的代码页为936,GBK编码。

    以前中文DOS、中文/日文Windows 95/98时代系统内码使用的是ANSI编码(本地化,根据不同地区设置不同的系统内码Windows版本),现在win7,win10等等系统的内码都是用的Unicode,不过微软为了以前的程序兼容性,比如在某些情况下,比如你的程序需要和不支持Unicode的程序交互时,可能还是会需要用到code page,提供代码页服务(就好比微软不能说:“老子支持unicode了,以后不支持Unicode的程序都给我滚粗。”只能撅着屁股让这些老掉牙的程序仍然可以运行,于是只好给他们提供一个“非Unicode默认字符集”) 。可以在cmd下输入chcp查看code page。
    在这里插入图片描述

    • Windows API 的 Wide Char 表达是 UTF-16: Unicode (Windows), L"" 表示是转换为 wide char。
    • Cocoa 的 NSString 和 Core Foundation 的 CFString 内部表达都是 UTF-16,所以其实 OS X 和 iOS 内部处理都用的是 UTF-16。
    • Java String 的内部表达是 UTF-16,所以大量跨平台程序和 Android 程序其实内部也在用 UTF-16。
    • 大部分的操作系统和 UI framework 的内部字符串表达(内码)都是UTF-16,不过Linux系统内使用的内码是UTF-8

    7、Tip:内码和外码

    在计算机科学及相关领域当中,内码指的是“将信息编码后,透过某种方式存储在特定记忆设备时,设备内部的编码形式”。在不同的系统中,会有不同的内码。

    在以往的英文系统中,内码为ASCII。 在繁体中文系统中,当前常用的内码为大五码。在简体中文系统中,内码则为国标码。
    为了软件开发方便,如国际化与本地化,现在许多系统会使用Unicode做为内码,常见的操作系统Windows、Mac OS X、Linux皆如此。许多编程语言也采用Unicode为内码,如Java、Python3。

    外码:除了内码,皆是外码。要注意的是,源代码编译产生的目标代码文件(如果Java可执行文件或class文件)中的编码方式属于外码。

    8、参考文章,引用文章如下:

    必读,真说清的话得结合上面的维基百科上的说法理解:
    https://en.wikipedia.org/wiki/Universal_Coded_Character_Set

    https://en.wikipedia.org/wiki/Unicode

    https://en.wikipedia.org/wiki/UTF-16

    https://en.wikipedia.org/wiki/UTF-32

    除此之外参考引用了下面三篇文章的一些观点:
    http://www.blogjava.net/zhenandaci/archive/2008/12/24/248014.html

    https://www.cnblogs.com/malecrab/p/5300503.html

    https://blog.51cto.com/polaris/377468
    还有一些其他文章的资料就不一一列举了。

    展开全文
  • stm32正交编码器例程

    热门讨论 2016-01-25 17:18:14
    STM32的正交编码器例程,5线编码器A B Z GND和VCC,OC门输出记得接上拉
  • 最简单的基于FFMPEG的视频编码器(修正)

    千次下载 热门讨论 2014-06-08 16:43:09
    因此特地分离出了一个简单的视频编码器供学习之用。 该视频编码器实现了YUV420P像素数据编码为H.264码流 尽管该视频编码器的代码十分简单,但是几乎包含了使用FFMPEG编码一个视频所有必备的API。十分适合FFmpeg的...
  • 平衡小车——编码器原理及其使用

    万次阅读 多人点赞 2019-07-30 15:52:14
    感觉用在平衡小车上的编码器相关的博文和资料都超级多的,不慌不慌

    平衡小车——编码器原理及其使用

    结合了一些帖子以及用的过程中出现的一些问题,然后归纳出来的一个贴子

    一,编码器概述

    编码器是一种将角位移或者角速度转换成一连串电数字脉冲的旋转式传感器,我们可以通过编码器测量到底位移或者速度信息。编码器从输出数据类型上分,可以分为增量式编码器和绝对式编码器。

    从编码器检测原理上来分,还可以分为光学式、磁式、感应式、电容式。常见的是光电编码器(光学式)和霍尔编码器(磁式)。

    二,编码器原理

    光电编码器是一种通过光电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。光电编码器是由光码盘和光电检测装置组成。光码盘是在一 定直径的圆板上等分地开通若干个长方形孔。由于光电码盘与电动机同轴,电动机旋转时,检测装置检测输出若干脉冲信号,为判断转向,一般输出两组存在一 定相位差的方波信号。

    霍尔编码器是一种通过磁电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。霍尔编码器是由霍尔码盘和霍尔元件组成。霍尔码盘是在一 定直径的圆板上等分地布置有不同的磁极。霍尔码盘与电动机同轴,电动机旋转时,霍尔元件检测输出若干脉冲信号,为判断转向,一般输出两组存在一定相位差的方波信号。

    三,电机编码器接线

    然后这下面就是讲的平衡车上的编码器啦。
    车轮上有根线,最边上的两根是电机电源线,配合tb6612驱动,可用来控制电机的转速和转向。然后中间四根是编码器接口,如下图:
    在这里插入图片描述
    要注意哦~小车用的是两个编码器是反过来的,如果测试时车轮同向转,计数值互为相反数,就把AB相调换一下就好啦。或者把其中一个读到的数前面加个负号。

    然后编码器供电是5v,供电问题,这是一款增量式输出的霍尔编码器。编码器有 AB 相输出,所以不仅可以测 速,还可以辨别转向。根据上图的接线说明可以看到,我们只需给编码器电源5V 供电,在电机转动的时候即可通过 AB 相输出方波信号。编码器自带了上拉电阻,所以无需外部上拉,可以直接连接到单片机 IO 读取。

    当然不是说编码器就一定要用定时器做接口,有些单片机没有编码器接口的功能,也是可以用外部中断来代替。把编码器 A 相输出接到单片机的外部中断输入口,这样 就可通过跳变沿触发中断,然后在对应的外部中断服务函数里面,然后通过 B 相的电平来确定正转反转。A相当于一个跳变沿的时候,B相高电平就为是正转,低电平就为是反转。然后,普通io口也是可以处理的。

    but用stm32做编码器接口的好处是计数比较智能,容许接口出现抖动而不影响结果。而且配置的代码超级多,拉过来就可以用啦。所以下面就是stm32定时器做编码器接口的介绍啦

    四,定时器做编码器接口的配置方式

    1,计数模式

    在这里插入图片描述
    在这里插入图片描述
    如上两张图对应着来看呐,显然用T1,T2共同计数比较精确,也就是实现了“四倍频”

    2,滤波等级

    在这里插入图片描述

    3,计数重装载值

    就是对“TIM_TimeBaseStructure.TIM_Period”赋值,
    在这里插入图片描述

    这些都有写在代码的注释里面

    五,stm32代码(库函数版)

    void Encoder_Init_TIM2(void)
    {
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
    	TIM_ICInitTypeDef TIM_ICInitStructure;  
    	GPIO_InitTypeDef GPIO_InitStructure;
    	
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
     
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;	
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
    	GPIO_Init(GPIOA, &GPIO_InitStructure);					      
    
    	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    	TIM_TimeBaseStructure.TIM_Prescaler = 0x0; 
    	TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值,我设的是65536,最大只能是66536,stm32f103的寄存器只有16bit
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
    	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    	TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3,就是四分频计数模式
    	TIM_ICStructInit(&TIM_ICInitStructure);
    	TIM_ICInitStructure.TIM_ICFilter = 10;// TIMx->CCMRx的位7:4,输入捕获1滤波器 ,IC1F用来滤波¨
    	TIM_ICInit(TIM2, &TIM_ICInitStructure);
    	TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位
    	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    
    	TIM_SetCounter(TIM2,0);//设置CNT的值,初始化的时候从0开始计数
    	TIM_Cmd(TIM2, ENABLE); 
    }
    
    /*TIM4初始化为编码器接口*/
    void Encoder_Init_TIM4(void)
    {
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  
    	TIM_ICInitTypeDef TIM_ICInitStructure;  
    	GPIO_InitTypeDef GPIO_InitStructure;
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//使能定时器4的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能PB端口时钟
    
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;	//端口配置
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
    	GPIO_Init(GPIOB, &GPIO_InitStructure);					      //根据设定参数初始化GPIOB
    
    	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
    	TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器 
    	TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM向上计数  
    	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    	TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
    	TIM_ICStructInit(&TIM_ICInitStructure);
    	TIM_ICInitStructure.TIM_ICFilter = 10;
    	TIM_ICInit(TIM4, &TIM_ICInitStructure);
    	TIM_ClearFlag(TIM4, TIM_FLAG_Update);//清除TIM的更新标志位
    	TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
    	//Reset counter
    	TIM_SetCounter(TIM4,0);
    	TIM_Cmd(TIM4, ENABLE); 
    }
    
    /*单位时间编码器计数 输入定时器 输出速度值*/
    int Read_Encoder(u8 TIMX)
    {
    	int Encoder_TIM;    
    	switch(TIMX)
    	{
    		case 2:  Encoder_TIM= (short)TIM2 -> CNT;  TIM2 -> CNT=0;break;//读数据+计数值清零
    		case 3:  Encoder_TIM= (short)TIM3 -> CNT;  TIM3 -> CNT=0;break;	
    		case 4:  Encoder_TIM= (short)TIM4 -> CNT;  TIM4 -> CNT=0;break;	
    		default:  Encoder_TIM=0;
    	}
    	return Encoder_TIM;
    }
    
    
    /*中断服务函数,计数值溢出了就会进入中断,然后又会从0开始计数*/
    void TIM4_IRQHandler(void)
    { 		    		  			    
    	if(TIM4->SR&0X0001)//溢出中断
    	{    				   				     	    	
    	}				   
    	TIM4->SR&=~(1<<0);//清除中断标志位 	    
    }
    
    void TIM2_IRQHandler(void)
    { 		    		  			    
    	if(TIM2->SR&0X0001)//溢出中断
    	{    				   				     	    	
    	}				   
    	TIM2->SR&=~(1<<0);//清除中断标志位 	    
    }
    
    

    六,注意点(这里是用的别人的~)

    1.编码器有个转速上限,超过这个上限是不能正常工作的,这个是硬件的限制,原则上线数越多转速就越低,这点在选型时要注意,编码器的输出一般是开漏的,所以单片机的io一定要上拉输入状态.
    2.定时器初始化好以后,任何时候CNT寄存器的值就是编码器的位置信息,正转他会加反转他会减这部分是不需要软件干预的,初始化时给的TIM_Period 值应该是码盘整圈的刻度值,在减溢出会自动修正为这个数.加超过此数值就回0.
    3.如果要扩展成多圈计数需要溢出中断像楼主说的,程序上圈计数加减方向位就行了.
    4.每个定时器的输入脚可以通过软件设定滤波
    5.应用中如果没有绝对位置信号或者初始化完成后还没有收到绝对位置信号前的计数只能是相对计数.收到绝对位置信号后重新修改一次CNT的值就行了.码盘一般都有零位置信号,结合到定时器捕获输入就行.上电以后要往返运动一下找到这个位置.
    6.即便有滤波计数值偶尔也会有出错误的情况,一圈多计一个或少计一个数都是很正常的特别是转速比较高的时候尤其明显,有个绝对位置信号做修正是很有必要的.绝对位置信号不需要一定在零位置点,收到这个信号就将CNT修正为一个固定的数值即可.
    7.开启定时器的输入中断可以达到每个步计数都作处理的效果,但是高速运转的时候你可能处理不过来.

    参考

    https://blog.csdn.net/qq_17280755/article/details/73770598
    https://blog.csdn.net/qq_38721302/article/details/83448078

    展开全文
  • 最简单的基于FFMPEG的音频编码

    千次下载 热门讨论 2014-05-09 22:19:25
    因此特地分离出了一个简单音频编码器供学习之用。 该图像编码器实现了音频PCM采样数据编码为AAC码流。 尽管该音频编码器的代码十分简单,但是几乎包含了使用FFMPEG编码一个音频所有必备的API。十分适合FFmpeg的...
  • 稀疏自编码器(UFLDL教程)

    热门讨论 2015-07-15 10:51:56
    稀疏自编码器的MATLAB代码实现,按照UFLDL教程给出的教程进行补充编写。
  • Zip解压-可设置压缩文件编码方式

    热门讨论 2015-09-19 22:32:24
    jdk自带的ZipEntry类解压zip文件,中文文件会出现乱码,jar包是根据Apache的解压缩包进行改造的,也适合于Android使用
  • 信源编码和信道编码

    千次阅读 2018-12-06 15:14:59
    但现代通信应用中常见的信源编码方式有:Huffman编码、算术编码、L-Z编码,这三种都是无损编码,另外还有一些有损的编码方式。信源编码的目标就是使信源减少冗余,更加有效、经济地传输,最常见的应用形式就是压缩。...

    一.信源编码和信道编码的发展历程

    信源编码:

        最原始的信院编码就是莫尔斯电码,另外还有ASCII码和电报码都是信源编码。但现代通信应用中常见的信源编码方式有:Huffman编码、算术编码、L-Z编码,这三种都是无损编码,另外还有一些有损的编码方式。信源编码的目标就是使信源减少冗余,更加有效、经济地传输,最常见的应用形式就是压缩。

    相对地,信道编码是为了对抗信道中的噪音和衰减,通过增加冗余,如校验码等,来提高抗干扰能力以及纠错能力。

    信道编码:

    1948年Shannon极限理论

    →1950年Hamming码

    →1955年Elias卷积码

    →1960年 BCH码、RS码、PGZ译码算法

    →1962年Gallager LDPC(Low Density Parity Check,低密度奇偶校验)码

    →1965年B-M译码算法

    →1967年RRNS码、Viterbi算法

    →1972年Chase氏译码算法

    →1974年Bahl MAP算法

    →1977年IMaiBCM分组编码调制

    →1978年Wolf 格状分组码

    →1986年Padovani恒包络相位/频率编码调制

    →1987年Ungerboeck TCM格状编码调制、SiMonMTCM多重格状编码调制、WeiL.F.多维星座TCM

    →1989年Hagenauer SOVA算法

    →1990年Koch Max-Lg-MAP算法

    →1993年Berrou Turbo码

    →1994年Pyndiah 乘积码准最佳译码

    →1995年 Robertson Log-MAP算法

    →1996年 Hagenauer TurboBCH码

    →1996MACKay-Neal重新发掘出LDPC码

    →1997年 Nick Turbo Hamming码

    →1998年Tarokh 空-时卷格状码、AlaMouti空-时分组码

    →1999年删除型Turbo码

         虽然经过这些创新努力,已很接近Shannon极限,例如1997年Nickle的TurboHamming码对高斯信道传输时已与Shannon极限仅有0.27dB相差,但人们依然不会满意,因为时延、装备复杂性与可行性都是实际应用的严峻要求,而如果不考虑时延因素及复杂性本来就没有意义,因为50多年前的Shannon理论本身就已预示以接近无限的时延总容易找到一些方法逼近Shannon极限。因此,信道编码和/或编码调制理论与技术在向Shannon极限逼近的创新过程中,其难点是要同时兼顾考虑好编码及交织等处理时延、比特误码率门限要求、系统带宽、码率、编码增益、有效吞吐量、信道特征、抗衰落色散及不同类别干扰能力以及装备复杂性等要求。从而,尽管人们普遍公认Turbo码确是快速逼近Shannon极限的一种有跃变性改进的码类,但其时延、复杂性依然为其最严峻的挑战因素,看来,沿AlaMouti的STB方式是一种看好的折衷方向。同样,实际性能可比Turbo码性能更优良的LDPC码,从1962年Gallager提出, 当时并未为人们充分理解与重视,至1996年为MACKay—Neal重新发现后掀起的另一股推进其研究、应用热潮, 此又为另一明显示例。LDPC码是一类可由非常稀疏的奇偶校验矩阵或二分图(Bi-PartiteGrapg)定义的线性分组前向纠错码,它具有更简单的结构描述与硬件复杂度,可实现完全并行操作,有利高速、大吞吐能力译码,且译码复杂度亦比Turbo码低,并具更优良的基底(Floor)残余误码性能,研究表明,最好的非正则(Irregular)LDPC码,其长度为106时可获得BER=10-6时与Shannon极限仅相差0.13dB;当码长为107、码率为1/2,与Shannon极限仅差0.04dB;与Turbo码结构不同,这是由另一种途径向“Shannon极限条件”的更有效与更逼真的模拟,从而取得比Turbo码更好的性能。因此,“学习、思考、创新、发展”这一永恒主题中持续“创新”最为关键,MIMO-STC及Turbo/LDPC码的发展历程亦充分证实了这一发展哲理。

     

    二.信源编码和信道编码远离的简要介绍

    信源编码:

    一种以提高通信有效性为目的而对信源符号进行的变换;为了减少或消除信源剩余度而进行的信源符号变换。为了减少信源输出符号序列中的剩余度、提高符号的平均信息量,对信源输出的符号序列所施行的变换。具体说,就是针对信源输出符号序列的统计特性来寻找某种方法,把信源输出符号序列变换为最短的码字序列,使后者的各码元所载荷的平均信息量最大,同时又能保证无失真地恢复原来的符号序列。

      数字信号在传输中往往由于各种原因,使得在传送的数据流中产生误码,从而使接收端产生图象跳跃、不连续、出现马赛克等现象。所以通过信道编码这一环节,对数码流进行相应的处理,使系统具有一定的纠错能力和抗干扰能力,可极大地避免码流传送中误码的发生。误码的处理技术有纠错、交织、线性内插等。

      提高数据传输效率,降低误码率是信道编码的任务。信道编码的本质是增加通信的可靠性。但信道编码会使有用的信息数据传输减少,信道编码的过程是在源数据码流中加插一些码元,从而达到在接收端进行判错和纠错的目的,这就是我们常常说的开销。这就好象我们运送一批玻璃杯一样,为了保证运送途中不出现打烂玻璃杯的情况,我们通常都用一些泡沫或海棉等物将玻璃杯包装起来,这种包装使玻璃杯所占的容积变大,原来一部车能装5000各玻璃杯的,包装后就只能装4000个了,显然包装的代价使运送玻璃杯的有效个数减少了。同样,在带宽固定的信道中,总的传送码率也是固定的,由于信道编码增加了数据量,其结果只能是以降低传送有用信息码率为代价了。将有用比特数除以总比特数就等于编码效率了,不同的编码方式,其编码效率有所不同。

        基于层次树的集分割(SPIHT)信源编码方法是基于EZW而改进的算法,它是有效利用了图像小波分解后的多分辨率特性,根据重要性生成比特流的一个渐进式编码。这种编码方法,编码器能够在任意位置终止编码,因此能够精确实现一定目标速率或目标失真度。同样,对于给定的比特流,解码器可以在任意位置停止解码,而仍然能够恢复由截断的比特流编码的图像。而实现这一优越性能并不需要事先的训练和预存表或码本,也不需要任何关于图像源的先验知识。

      数字电视中常用的纠错编码,通常采用两次附加纠错码的前向纠错(FEC)编码。RS编码属于第一个FEC,188字节后附加16字节RS码,构成(204,188)RS码,这也可以称为外编码。第二个附加纠错码的FEC一般采用卷积编码,又称为内编码。外编码和内编码结合一起,称之为级联编码。级联编码后得到的数据流再按规定的调制方式对载频进行调制。  

      前向纠错码(FEC)的码字是具有一定纠错能力的码型,它在接收端解码后,不仅可以发现错误,而且能够判断错误码元所在的位置,并自动纠错。这种纠错码信息不需要储存,不需要反馈,实时性好。所以在广播系统(单向传输系统)都采用这种信道编码方式。以下是纠错码的各种类型:

     

        既然信源编码的基本目的是提高码字序列中码元的平均信息量,那么,一切旨在减少剩余度而对信源输出符号序列所施行的变换或处理,都可以在这种意义下归入信源编码的范畴,例如过滤、预测、域变换和数据压缩等。当然,这些都是广义的信源编码。  

    一般来说,减少信源输出符号序列中的剩余度、提高符号平均信息量的基本途径有两个:①使序列中的各个符号尽可能地互相独立;②使序列中各个符号的出现概率尽可能地相等。前者称为解除相关性,后者称为概率均匀化。

    第三代移动通信中的信源编码包括语音压缩编码、各类图像压缩编码及多媒体数据压缩编码。

     

    信道编码:

        数字信号在传输中往往由于各种原因,使得在传送的数据流中产生误码,从而使接收端产生图象跳跃、不连续、出现马赛克等现象。所以通过信道编码这一环节,对数码流进行相应的处理,使系统具有一定的纠错能力和抗干扰能力,可极大地避免码流传送中误码的发生。误码的处理技术有纠错、交织、线性内插等。

    提高数据传输效率,降低误码率是信道编码的任务。信道编码的本质是增加通信的可靠性。但信道编码会使有用的信息数据传输减少,信道编码的过程是在源数据码流中加插一些码元,从而达到在接收端进行判错和纠错的目的,这就是我们常常说的开销。

    码率兼容截短卷积(RCPC)信道编码,就是一类采用周期性删除比特的方法来获得高码率的卷积码,它具有以下几个特点:

    (1)截短卷积码也可以用生成矩阵表示,它是一种特殊的卷积码;

    (2)截短卷积码的限制长度与原码相同,具有与原码同等级别的纠错能力;                                            (3)截短卷积码具有原码的隐含结构,译码复杂度降低;

       (4)改变比特删除模式,可以实现变码率的编码和译码。

     

    三.信源编码和信道编码的区别

        信源编码信源编码的作用之一是设法减少码元数目和降低码元速率,即通常所说的数据压缩。码元速率将直接影响传输所占的带宽,而传输带宽又直接反映了通信的有效性。作用之二是,当信息源给出的是模拟语音信号时,信源编码器将其转换成数字信号,以实现模拟信号的数字化传输。模拟信号数字化传输的两种方式:脉冲编码调制(PCM)和增量调制(ΔM)。信源译码是信源编码的逆过程。1.脉冲编码调制(PCM)简称脉码调制:一种用一组二进制数字代码来代替连续信号的抽样值,从而实现通信的方式。由于这种通信方式抗干扰能力强,它在光纤通信、数字微波通信、卫星通信中均获得了极为广泛的应用。增量调制(ΔM):将差值编码传输,同样可传输模拟信号所含的信息。此差值又称“增量”,其值可正可负。这种用差值编码进行通信的方式,就称为“增量调制”,缩写为DM或ΔM,主要用于军方通信中。信源编码为了减少信源输出符号序列中的剩余度、提高符号的平均信息量,对信源输出的符号序列所施行的变换。具体说,就是针对信源输出符号序列的统计特性来寻找某种方法,把信源输出符号序列变换为最短的码字序列,使后者的各码元所载荷的平均信息量最大,同时又能保证无失真地恢复原来的符号序列.信道编码的目的:信道编码是为了保证信息传输的可靠性、提高传输质量而设计的一种编码。它是在信息码中增加一定数量的多余码元,使码字具有一定的抗干扰能力。信道编码的实质:信道编码的实质就是在信息码中增加一定数量的多余码元(称为监督码元),使它们满足一定的约束关系,这样由信息码元和监督码元共同组成一个由信道传输的码字。信源编码很好理解,比如你要发送一个图形,必须把这个图像转成0101的编码,这就是信源编码。

        信道编码数字信号在信道传输时,由于噪声、衰落以及人为干扰等,将会引起差错。为了减少差错,信道编码器对传输的信息码元按一定的规则加入保护成分(监督元),组成所谓“抗干扰编码”。接收端的信道译码器按一定规则进行解码,从解码过程中发现错误或纠正错误,从而提高通信系统抗干扰能力,实现可靠通信。信道编码是针对无线信道的干扰太多,把你要传送的数据加上些信息,来纠正信道的干扰。信道编码数字信号在信道传输时,由于噪声、衰落以及人为干扰等,将会引起差错。为了减少差错,信道编码器对传输的信息码元按一定的规则加入保护成分(监督元),组成所谓“抗干扰编码”。接收端的信道译码器按一定规则进行解码,从解码过程中发现错误或纠正错误,从而提高通信系统抗干扰能力,实现可靠通信。

    信源编码信号:例如语音信号(频率范围300-3400Hz)、图象信号(频率范围0-6MHz)……基带信号(基带:信号的频率从零频附近开始)。在发送端把连续消息变换成原始电信号,这种变换由信源来完成。

    信道编码信号:例如二进制信号、2PSK信号……已调信号(也叫带通信号、频带信号)。这种信号有两个基本特征:一是携带信息;二是适应在信道中传输,把基带信号变换成适合在信道中传输的信号完成这样的变换是调制器。

    信源编码是对输入信息进行编码,优化信息和压缩信息并且打成符合标准的数据包。信道编码是在数据中加入验证码,并且把加入验证码的数据进行调制。两者的作用完全不一样的。信源编码是指信号来源的编码,主要是指从那个接口进来的。信道编码是说的信号通道的编码,一般是指机内的电路。总的来说吧:信源编码是对视频, 音频, 数据进行的编码,即对信息进行编码以便处理,而信道编码是指在信息传输的过程中对信息进行的处理。

     

    四.信源编码和信道编码在现代社会的应用

    1.在现代无线通信中的应用:

        通信的任务是由一整套技术设备和传输媒介所构成的总体——通信系统来完成的。电子通信根据信道上传输信号的种类可分为模拟通信和数字通信。最简单的数字通信系统模型由信源、信道和信宿三个基本部分组成。实际的数字通信系统模型要比简单的数字通信系统模型复杂得多。数字通信系统设备多种多样,综合各种数字通信系统,其构成如图所示:

     

     

        信源编码是以提高通信有效性为目的的编码。通常通过压缩信源的冗余度来实现。采用的一般方法是压缩每个信源符号的平均比特数或信源的码率。

    信道,通俗地说是指以传输媒质为基础的信号通路。具体地说,信道是指由有线或无线电线路提供的信号通路。信道的作用是传输信号,它提供一段频带让信号通过,同时又给信号加以限制和损害。

    信道编码是以提高信息传输的可靠性为目的的编码。通常通过增加信源的冗余度来实现。采用的一般方法是增大码率或带宽。与信源编码正好相反。在计算机科学领域,信道编码(channel code)被广泛用作表示编码错误监测和纠正的术语,有时候也可以在通信和存储领域用作表示数字调制方式。信道编码用来在数据传输的时候保护数据,还可以在出现错误的时候来恢复数据。

    2.在超宽带信道中的应用

    超宽带(Ultra Wideband,以下简称UWB) [1][2]系统具有高传输速率、低功耗、低成本等独特优点,是下一代短距离无线通信系统的有力竞争者。它是指具有很高带宽比射频(带宽与中心频率之比)的无线电技术。近年来,超宽带无线通信在图像和视频传输中获得了越来越广泛的应用,它具有极高的传输速率以及很宽的传输频带,可以提供高达1Gbit/s的数据传输速率,可用在数字家庭网络或办公网络中,实现近距离、高速率数据传输。例如,利用UWB技术可以在家用电器设备之间提供高速的音频、视频业务传输,在数字办公环境中,应用UWB技术可以减少线缆布放的麻烦,提供无线高速互联。  

        联合信源信道编码(Joint Source Channel Coding,以下简称JSCC)[3][4]近几年来日益受到通信界的广泛重视,主要原因是多媒体无线通信变得更加重要。根据Shannon信息论原理,通信系统中信源编码和信道编码是分离的[5],然而,该定理假设信源编码是最优的,可以去掉所有冗余,并且假设当比特率低于信道容量时可纠正所有误码。在不限制码长的复杂性和时延的前提下,可以得到这样的系统。而在实际系统中又必须限制码长的复杂性和时延,这必然会导致性能下降,这和香农编码定理的假设是相矛盾的。因此,在许多情况下,采用独立编码技术并不能获得满意的效果,例如有严重噪声的衰落信道和(移动通信信道),采用独立编码技术不能满足要求。因此需要将信源编码和信道编码联合考虑,在实际的信道条件中获得比信源和信道单独进行编码更好的效果。其中不等差错保护是联合信源信道编码的一种, 是相对于同等差错保护而言的。在网络资源有限的情况下,同等差错保护方案使得重要信息得不到足够的保护而使解码质量严重下降。而不等差错保护根据码流的不同部分对图像重建质量的重要性不同, 而采用不同的信道保护机制, 是信源信道联合编码的一个重要应用。

    不等差错保护(Unequal Error Protection,以下简称UEP)的信源编码主要采用嵌入式信源编码,如SPIHT(Set Partitioning In Hierarchical Trees) [6],EZW,JPEG2000等,信源输出码流具有渐进特性,信道编码采用RCPC[7],RCPT等码率可变的信道编码。文章[8]中研究了在AWGN信道下的不等差错保护的性能; 文章[9]中研究了有反馈的移动信道下的多分辨率联合信源信道编码;文章[10]研究了无线信道下的图像传输,信源编码采用SPIHT,信道编码采用多码率Turbo coder的不等差错保护方案;文章[11]中研究了DS-CDMA多径衰落信道下信源编码为分层视频图像编码,信道编码采用RCPC,解决了在信源编码,信道编码以及各个层之间的码率最优分配; 文章[12]研究了3G网络下MPEG-4视频流的传输,信道编码采用 Turbo编码,提出了用TCP传输非常重要的MPEG-4流,而用UDP传输MPEG-4 audio/video ES (Elementary Streams),并且对UDP传输的码流进行UEP的方案;文章[13]研究在无线频率选择性衰落信道中将MIMO-OFDM和adaptive wavelet pretreatment(自适应小波预处理)结合在一起的联合信源信道编码图像传输。据我们的了解, 现在并无文章研究超宽带无线信道下不等差错保护方案,本文将不等差错保护联合信源信道编码应用于超宽带无线通信中, 信源部分采用基于小波SPIHT 的编码方法,而信道部分采用RCPC编码( Rate Compatible Punctured Convolutional codes) 对SPIHT输出码流按重要程度进行不等错误保护,并基于DS-UWB[14]方案提出双重不等差错保护方案, 研究了不等差错保护给图像在超宽带无线通信中的图像传输所带来性能增益。  

    采用标准LENA256×256图像进行仿真实验, 信源编码采用SPIHT算法,SPIHT 编码速率为0.5bpp, 信道编码采用码率自适应截短卷积码RCPC, 对实验图像进行同等差错保护信道编码( EEP) 和不等差错保护信道编码(UEP), 对于EEP编码采用1/ 2 码率;对于UEP 编码,其重要信息(包括头部语法及图像重要数据) 采用1/ 3码率,对图像次重要数据采用1/ 2码率进行编码,对图像非重要数据不进行编码。信道编码输出码流经过一个(Ns,1)重复编码器,对重要信息Ns取30,次重要数据Ns取20,非重要数据Ns取为10,再用一个周期为Np=Ns的伪随机DS码序列对重复编码器输出序列进行编码,最后对编码输出进行PAM调制和脉冲成形从而形成DS-UWB发送信号波形,其中脉冲参数设置为平均发射功率为-30,抽样频率为50e9,平均脉冲重复时间为2e-9,冲激响应持续时间为0.5e-9,脉冲波形形成因子为0.25e-9。DS-UWB信号经过IEEE802.15.3a CM1信道模型,接收端采用Rake接收机对接收信号进行解调,解调后的码流经过RCPC信道译码和SPIHT信源译码恢复出原始图像。

     

               CMI信道模型下Double-UEP与UEP,EEP的性能比较

    图中给出了IEEE802.15.3a CM1信道模型下双重不等差错保护(Double-UEP)与传统不等差错保护(UEP)与同等差错保护(EEP)的性能比较,其中横轴为超宽带信道中的信噪比Eb/N0,纵轴为重建图像的峰值信噪比PSNR(Peek Signal Noise Ratio)。

      由图可见,在UWB信道中,不等差错保护的性能普遍好于同等差错保护的性能,尤其是在低信噪比的时候,采用不等差错保护能够获得更大的性能增益。在高信噪比时,由于此时信道质量较好,误码率较低,图像中的重要码流基本不会产生误码,此时不等差错保护和同等差错保护性能趋于一致;而在低信噪比时,由于不等差错保护方案对图像的重要信息加入了更多的冗余,从而在不增加传输速率的情况下使图像得以更可靠的传输,提升重建图像的质量。

     

    五.信源编码与信道编码的发展前景

    信息论理论的建立,提出了信息、信息熵的概念,接着人们提出了编码定理。编码方法有较大发展,各种界限也不断有人提出,使多用户信息论的理论日趋完整,前向纠错码(FEC)的码字也在不断完善。但现有信息理论中信息对象的层次区分对产生和构成信息存在的基本要素、对象及关系区分不清,适用于复杂信息系统的理论比较少,缺乏核心的“实有信息”概念,不能很好地解释信息的创生和语义歧义问题。只有无记忆单用户信道和多用户信道中的特殊情况的编码定理已有严格的证明,其他信道也有一些结果,但尚不完善。但近几年来,第三代移动通信系统(3G)的热衷探索,促进了各种数字信号处理技术发展,而且Turbo码与其他技术的结合也不断完善信道编码方案。

    移动通信的发展日新月异,从1978年第一代模拟蜂窝通信系统诞生至今,不过20多年的时间,就已经过三代的演变,成为拥有10亿多用户的全球电信业最活跃、最具发展潜力的业务。尤其是近几年来,随着第三代移动通信系统(3G)的渐行渐近,以及各国政府、运营商和制造商等各方面为之而投入的大量人力物力,移动通信又一次地在电信业乃至全社会掀起了滚滚热潮。虽然目前由于全球电信业的低迷以及3G系统自身存在的一些问题尚未完全解决等因素,3G业务的全面推行并不象计划中的顺利,但新一代移动通信网的到来必是大势所趋。因此,人们对新的移动通信技术的研究的热情始终未减。

    移动通信的强大魅力之所在就是它能为人们提供了固话所不及的灵活、机动、高效的通信方式,非常适合信息社会发展的需要。但同时,这也使移动通信系统的研究、开发和实现比有线通信系统更复杂、更困难。实际上,移动无线信道是通信中最恶劣、最难预测的通信信道之一。由于无线电波传输不仅会随着传播距离的增加而造成能量损耗,并且会因为多径效应、多普勒频移和阴影效应等的影响而使信号快速衰落,码间干扰和信号失真严重,从而极大地影响了通信质量。为了解决这些问题,人们不断地研究和寻找多种先进的通信技术以提高移动通信的性能。特别是数字移动通信系统出现后,促进了各种数字信号处理技术如多址技术、调制技术、纠错编码、分集技术、智能天线、软件无线电等的发展。

     

    结论:

    从文中我们可以清楚的认识到信源编码和信道编码的发展布满艰辛,今天的成就来之不易。随着今天移动通信技术的不断发展和创新,信源编码与信道编码的应用也越来越广泛,其逐步的应用于各个领域,在通信系统中扮演着非常重要的角色,起到了至关重要的作用。但是,现有信息理论也存在一定的缺陷,具体表现在以下几个方面:

    1.现有信息理论体系中缺乏核心的 “实有信息”概念。

    2.适用于复杂信息系统的理论比较少。目前的狭义与广义信息论大多是起源和立足于简单系统的信息理论,即用简单通讯信息系统的方法来类比复杂系统的信息现象,将复杂性当成了简单性来处理。而涉及生命现象和人的认识论层次的信息是很复杂的对象,其中信宿主体内信息的语义歧义和信息创生问题是难点,用现有信息理论难以解释。

    3.对产生和构成信息存在的基本要素、对象及关系区分不清。如将对象的直接存在(对象的物质、能量、相互作用、功能等存在)当成信息存在;将信息的载体存在当成信息存在;将信息与载体的统一体当成信息存在;把信宿获得的“实得信息”当成唯一的信息存在,这是主观信息论。或者把信源和信道信息当成唯一的信息存在,称之为客观信息论。这二种极端的信息理论正是忽略了信息在关系中产生、在关系中存在的复杂本质。忽略了信息存在至少涉及三个以上对象及复杂关系。

    4.现有信息理论不能很好地解释信息的创生和语义歧义问题。

    5.现有信息理论对信宿实得信息的理解过于简单,没有将直接实得信息与间接实得信息区别开来。

    6.信息对象的层次区分没有得到重视。不少研究者将本体论层次的信息与认识论层次的信息混为一谈,将普适性信息范畴与具体科学,特别是技术层次(如通信、控制、计算等)的信息概念混为一谈。抓住信息的某一层次或某一方面当成信息对象的总体。

        因此,在科学技术飞速发展的今天,我们应该加强对信源编码与信道编码的了解和认识,这能让在以后的生活和学习过程中不断完善和改进现有信息论存在的缺陷,更好的应用和了解我们的专业知识,更好更快的做好自己的工作,让自己能从各方面得到满意的结果。

    展开全文
  • 详解自动编码器(AE)

    千次阅读 多人点赞 2019-11-21 11:57:34
    自动编码器(Auto-Encoders,AE) 降噪自编码(Denoising Auto-Encoders, DAE)(2008) 堆叠降燥自动编码器 (Stacked Denoising Auto-Encoders, SAE)(2008) 卷积自动编码器(Convolution Auto-Encoders, CAE)(2011) 变分...

    自动编码器(AE,DAE,CAE,SAE)的方法介绍与简单实现(附代码)

    自动编码器的发展简述

    自动编码器(Auto-Encoders,AE)

    传统的自动编码器是一种数据的压缩算法
    其算法包括编码阶段解码阶段,且拥有对称的结构。

    目前自编码器的应用主要有两个方面,第一是数据去噪,第二是为进行可视化而降维。配合适当的维度和稀疏约束,自编码器可以学习到比PCA等技术更有意思的数据投影。

    传统编码器的编解码过程描述如图:
    在这里插入图片描述
    在这里插入图片描述
    评价:
    传统自编码器的目的是使输出与输入尽量相同,这完全可以通过学习两个恒等函数来完成,但是这样的变换没有任何意义,因为我们真正关心的是隐层表达,而不是实际输出。因此,针对自编码器的很多改进方法都是对隐层表达增加一定的约束,迫使隐层表达与输入不同。

    降噪自编码(Denoising Auto-Encoders, DAE)(2008)

    自编码器真正关心的是隐藏层的特征表达,一个好的表达能够捕获输入信号的稳定结构,以该目的为出发出现了降噪自动编码器。

    降噪自动编码器,首先对干净的输入信号加入噪声产生一个受损的信号。然后将受损信号送入传统的自动编码器中,使其重建回原来的无损信号。

    降噪自编码器的编解码过程描述如图:
    在这里插入图片描述
    在这里插入图片描述
    降噪自编码器与传统的自动编码器的主要区别在于:

    1.降噪自编码器通过人为的增加噪声使模型获得鲁棒性的特征表达

    2.避免使隐层单元学习一个传统自编码器中没有意义的恒等函数

    评价:
    降噪自编码器通过对输入信号人为地进行损坏,主要是为了达到两个目的,首先是为了避免使隐层单元学习一个传统自编码器中没有实际意义的恒等函数,其次就是为了使隐层单元可以学习到一个更加具有鲁棒性的特征表达。
    降噪自编码器最大的优点在于,重建信号对输入中的噪声具有一定的鲁棒性,而最大的缺陷在于每次进行网络训练之前,都需要对干净输入信号人为地添加噪声,以获得它的损坏信号,这无形中就增加了该模型的处理时间。

    堆叠降燥自动编码器 (Stacked Denoising Auto-Encoders, SAE)(2008)

    降噪自编码器的编解码过程描述如图:
    在这里插入图片描述
    堆叠降噪自编码器与降噪自编码器的区别在于:

    1.堆叠降噪自编码器采用了降噪编码器的编码器作为基础单元,并且使用其训练方法进行预训练

    2.降噪自动编码器是无监督学习(自监督)的一种方法,而降噪自编码器是一种有监督方法.
    评价:
    堆叠降噪自编码器是降噪自编码器的一个应用方法.

    卷积自动编码器(Convolution Auto-Encoders, CAE)(2011)

    全卷积网络是一种面向特定应用(图像语义分割)的卷积神经网络,其结构图如下图所示:
    在这里插入图片描述
    与经典的CNN在卷积层之后使用全连接层得到固定长度的特征向量进行分类(全联接层+softmax输出)不同,FCN可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的feature map进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。

    与全卷积网络类似的一种无监督方法称为卷机自动编码器。

    由于卷积神经网络所取得的各种优异表现,直接推动了卷积自编码器的产生。

    卷积自编码器属于传统自编码器的一个特例,它使用卷积层和池化层替代了原来的全连接层,卷积自编码器能很好的保留二维信号的空间信息。

    评价:
    其主要差别在于卷积自编码器采用卷积方式对输入信号进行线性变换,并且其权重是共享的,这点与卷积神经网络一样。因此,重建过程就是基于隐藏编码的基本图像块的线性组合。

    变分自动编码器(Variational Auto-Encoders, VAE)(Kingma, 2014)

    变分自编码器是一种主要用于数据生成的自编码器的变体.当作为生成模型时,首先利用数据训练变分自编码器,然后只使用变分自编码器的解码部分,自动生成与训练数据类似的输出.

    其结构图如图所示:
    在这里插入图片描述
    整个结构可以分成三个部分,分别是编码部分,解码部分和生成部分.编码部分和解码部分同时进行训练,目标函数是从KL散度的概念中推倒得到的.
    在这里插入图片描述
    loss函数的推导过程:
    在这里插入图片描述

    几种算法的改进点表格

    编码器名称提出时间改进点目的
    传统自编码器1986
    降噪自编码器2008将带有噪声的损坏信息作为输入信号使重建信号鲁棒性更强
    堆叠自编码器2008将多层结构和栈式训练引入自编码器使自编码器可以训练更高层数
    卷积自编码器2011将卷积层引入自编码器更好的处理图片数据,得到更好的效果
    变分自编码器2014相当于在传统自编码器的隐层表达上增加一个对隐变量的约束,提出了一种将概率模型和神经网络结构的方法使编码器产生的隐层表达满足正态分布,能够更好的生成图像模型

    实现与Python实现

    传统的自动编码器实验结果

    模型结构与实现代码

    传统的自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:
    在这里插入图片描述
    模型分为三个子模块,由上至下分别为输入层,编码器层和解码器层,编码器将输入维度为784(28 28)的mnint灰度值转化为一个维度为2的值.编码器将维度为2的值解码回维度为784(28 28)的mnint灰度值.

    python-keras代码实现关键代码如下

    def __init__(self, ENCODING_DIM_INPUT=784, ENCODING_DIM_OUTPUT=2, Name = "ae"):
      
            input_image = Input(shape=(ENCODING_DIM_INPUT, ))
      
            # encoding layer
            hidden_layer = Dense(ENCODING_DIM_OUTPUT, activation='relu')(input_image)
            # decoding layer
            decode_output = Dense(ENCODING_DIM_INPUT, activation='relu')(hidden_layer)
      
            # build autoencoder, encoder, decoder
            autoencoder = Model(inputs=input_image, outputs=decode_output)
            encoder = Model(inputs=input_image, outputs=hidden_layer)
      
            # compile autoencoder
            autoencoder.compile(optimizer='adam', loss='mse', metrics=['accuracy'])
      
            self.autoencoder = autoencoder
            self.encoder = encoder
    

    训练过程

    本实验讨论使用relu和tanh两种激活函数的自监督训练的情况.训练的loss函数选择为方均根误差.
    训练过程的loss变化图像如下.

    使用tanh作为激活函数时,loss变化情况如下:
    在这里插入图片描述
    可以观察到,loss收敛到0.0685,效果较好.使用relu作为激活函数同样能够有效收敛,不过误差数值相对较大.由于篇幅原因不将图片在此进行展示.

    编码器输出的可视化结果

    本节将从重建图像和编码器输出层的二维可视化图像两部分进行展示,分别展示使用tanh和relu两种损失函数的训练结果.

    训练好的自动编码器重建图像(使用relu激活函数)如下图:
    在这里插入图片描述
    训练好的自动编码器重建图像(使用tanh激活函数)如下图:
    在这里插入图片描述
    两者对比可以发现relu函数训练出的模型存在一些像素颗粒,这也验证了上一节loss函数较大的实验结果.为了解释该问题,展示编码器输出层的二维可视化图片.

    训练好的编码器输出图像(使用relu激活函数)如下图:
    在这里插入图片描述
    训练好的编码器输出图像(使用tanh激活函数)如下图:
    在这里插入图片描述
    以上两张图片是 编码器-解码器 结构中编码器部分的输出绘制成的二维可视化图片,不同的颜色代表了不同的数字,对应的数字在右边的图例中进行了显示.从以上两张图片中可以得到:

    1.由于relu函数对负数的截断性质,使用relu激活函数训练的模型中有一部分点被限制在x=0,y=0两条边缘线上,这也是上文中提到的训练误差较大和出现像素颗粒的原因.

    2.自动编码器虽然能够对mnist数据集进行编码和解码,但是效果并没有其改进的其他方法理想,这一观点可以从解码图片较为模糊和编码器可视化后各个类别的分类相重合得到验证.

    说明与讨论

    传统自编码器有很大的改进空间,改进空间的可以从几个方面阐述:

    1.解码器输出较为模糊
    2.编码器可视化的类别间的界限不明显
    

    堆叠降噪自编码器

    模型结构与实现代码

    传统的自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:
    在这里插入图片描述
    模型分为三个子模块,由上至下分别为输入层,多层编码器层和多层解码器层,编码器将输入维度为784(28 28)的mnint灰度值转化为一个维度为2的值.编码器将维度为2的值解码回维度为784(28 28)的mnint灰度值

    python-keras代码实现关键代码如下

    class DAE(ae.AE):
      
        def __init__(
            self, ENCODING_DIM_INPUT=784, ENCODING_DIM_LAYER1=128,
            ENCODING_DIM_LAYER2=64, ENCODING_DIM_LAYER3=10,
            ENCODING_DIM_OUTPUT=2,Name="dae" ):
            # input placeholder
            input_image = Input(shape=(ENCODING_DIM_INPUT, ))
      
            # encoding layer
            encode_layer1 = Dense(ENCODING_DIM_LAYER1,
                                  activation='relu')(input_image)
            encode_layer2 = Dense(ENCODING_DIM_LAYER2,
                                  activation='relu')(encode_layer1)
            encode_layer3 = Dense(ENCODING_DIM_LAYER3,
                                  activation='relu')(encode_layer2)
            encode_output = Dense(ENCODING_DIM_OUTPUT)(encode_layer3)
      
            # decoding layer
            decode_layer1 = Dense(ENCODING_DIM_LAYER3,
                                  activation='relu')(encode_output)
            decode_layer2 = Dense(ENCODING_DIM_LAYER2,
                                  activation='relu')(decode_layer1)
            decode_layer3 = Dense(ENCODING_DIM_LAYER1,
                                  activation='relu')(decode_layer2)
            decode_output = Dense(ENCODING_DIM_INPUT,
                                  activation='tanh')(decode_layer3)
      
            # build surprised learning model
            SL_output = Dense(10, activation='softmax')(encode_output)
      
            # build autoencoder, encoder
            autoencoder = Model(inputs=input_image, outputs=decode_output)
            encoder = Model(inputs=input_image, outputs=encode_output)
            SL_model = Model(inputs=input_image, outputs=SL_output)
      
            # compile autoencoder
            autoencoder.compile(optimizer='adam', loss='mse', metrics=['accuracy'])
            SL_model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])
    

    代码定义了三个模型,分别是用于自监督训练的 autoencoder, 用于二维化的编码器 encoder 和用于进行有监督训练的 SL_model.

    训练过程

    堆叠降噪自动编码器分为无监督的预训练过程和有监督的训练过程两部分.
    本部分分别进行说明.

    自监督的预训练过程loss变化情况如下.
    在这里插入图片描述
    无监督的训练过程正确率acc变化情况如下.
    在这里插入图片描述
    可以看到,在两个训练阶段,方法可以有效的达到收敛.

    以下几点需要指出:

    1.多层编码器的训练没有使用栈式编码器的训练方式.
    2.预训练次数20epoch,并不足够模型充分收敛,但是作为预训练部分,已经充分.
    3.预训练部分的误差与传统自编码器相比较大,是因为在初始层加入了噪声的原因.
    4.训练时间与传统编码器相比更长,是其3倍左右.
    5.在有监督学习的开始阶段,分类的正确率并不高,这也印证了上一部分二位可视化的结果,很多点的界限不清晰.

    编码器输出的可视化结果

    本节将从重建图像和编码器输出层的二维可视化图像两部分进行展示

    预训练部分

    重建图像

    下图展示了添加噪声的效果(第一行原图,第二行增加噪声的图).

    image

    下图展示了,对添加噪声的图片进行重构的结果(第一行增加噪声的图,第二行重构图)

    image

    编码器输出层的二维可视化图像

    下图展示了添加噪声的效果(第一行原图,第二行增加噪声的图).

    image

    以下几点需要指出:

    1.本方法可以有效的对随机噪声进行去除
    2.恢复图与原图相比虽然能够识别但是效果更模糊
    3.与传统自动编码器相比,本方法得到的二维图的界限更加清晰

    有监督训练部分
    经过有监督的训练

    重建图像(因为不是目标,所以必然走样)
    下图展示了,对添加噪声的图片进行重构的结果(第一行增加噪声的图,第二行重构图)

    image

    编码器输出层的二维可视化图像

    image

    经过有监督学习,二维可视化图中各个组的界限更加清晰.

    说明与讨论

    堆叠降噪自编码器的改进有以下启发:

    1.使用自监督预训练与有监督训练方式相结合的形式获得更加优秀的效果
    2.使用增加噪声的形式迫使模型学习更加有效的特征
    3.将深度玻尔兹曼姬的思想迁移到自动编码器中

    卷积自编码器

    模型结构与实现代码

    卷积自编码器自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:
    在这里插入图片描述
    python-keras代码实现关键代码如下:

    def __init__(self,CHANNEL_1 = 16,CHANNEL_2 = 8,CHANNEL_OUTPUT = 1,   Name="cae"):
            # input placeholder
            input_image = Input(shape=(28, 28, 1))
      
            # encoding layer
            x = Conv2D(CHANNEL_1, (3, 3), activation='relu', padding="same")(input_image)
            x = MaxPool2D((2, 2), padding='same')(x)
            x = Conv2D(CHANNEL_2, (3, 3), activation='relu', padding='same')(x)
            encode_output = MaxPool2D((2, 2), padding='same')(x)
      
            # decoding layer
            x = Conv2D(CHANNEL_2, (3, 3), activation='relu', padding='same')(encode_output)
            x = UpSampling2D((2, 2))(x)
            x = Conv2D(CHANNEL_1, (3, 3),activation='relu', padding='same')(x)
            x = UpSampling2D((2, 2))(x)
            decode_output = Conv2D(CHANNEL_OUTPUT, (3, 3), activation='sigmoid', padding='same')(x)
      
            # build surprised learning model
            encode_output_flatten = Flatten()(decode_output)
            SL_output = Dense(10, activation='softmax')(encode_output_flatten)
      
            # build autoencoder, encoder
            autoencoder = Model(inputs=input_image, outputs=decode_output)
            encoder = Model(inputs=input_image, outputs=encode_output)
            SL_model = Model(inputs=input_image, outputs=SL_output)
      
            # compile autoencoder
            autoencoder.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
            SL_model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])
    

    训练过程

    堆叠降噪自动编码器分为无监督的预训练过程和有监督的训练过程两部分.
    本部分分别进行说明.

    在自监督的预训练过程loss变化情况如下:
    在这里插入图片描述
    图像显示,自监督的训练loss收敛于0.07左右,该误差比降噪自编码器的0.09要小.与传统自编码器的训练误差相差不多.但是从下文可知其训练效果明显优于传统自动编码器.

    在有监督的训练过程正确率acc变化情况如下:
    在这里插入图片描述
    图像显示,有监督训练过程的正确率上升到0.99,比降噪自动编码器的正确(0.95)率更高.
    因此在mnist数据集中的重建任务和分类任务中,卷积自动编码器有一定优势.

    不过以下几点需要指出:

    1.与sDAE相比,CAE有更高的准确率和更低的损失
    2.更好的效果除了卷积单元能够更好的处理图像数据外,可能与CAE方法的复杂度更高和其瓶颈处通道更宽有关

    编码器输出的可视化结果

    可以看到和stacked AE的主要区别在于局部卷积连接,而不所有层都是全连接。对图像和某些其他数据影响在空间局部的问题,比全连接更合适.因此效果更加优秀.

    于降噪自动编码器相同,首先对图片增加噪声:
    在这里插入图片描述
    然后对增加噪声的图片进行去噪:

    image

    去噪结果比较优秀,与上文中所有的结果相比是最优秀的.

    变分自编码器

    模型结构与实现代码

    变分自动编码器的结构最为复杂,并且在模型中引入了隐变量,和KL散度等概率论概念.对模型的实现造成了一定的影响.
    自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:

    image

    上图中并没有展开编码器和解码器的结构,编码器(encoder) 与 解码器(decoder)的形式分别如下:
    encoder:
    在这里插入图片描述
    decoder:
    在这里插入图片描述

    python-keras代码实现关键代码如下:

    class VAE(ae.AE):
      
        def __init__(
            self,
            ENCODING_DIM_INPUT = 784, 
            intermediate_dim = 512,
            batch_size = 128,
            latent_dim = 2,
            mse_loss = True,
            Name="vae"
        ):
      
            self.name = Name
      
            # input placeholder
            input_image = Input(shape=(ENCODING_DIM_INPUT,), name='encoder_input')
            # VAE model = encoder + decoder
            # encoding layer
            x = Dense(intermediate_dim, activation='relu')(input_image)
            z_mean = Dense(latent_dim, name='z_mean')(x)
            z_log_var = Dense(latent_dim, name='z_log_var')(x)
            z = Lambda(sampling, output_shape=(latent_dim,), name='z')([z_mean, z_log_var])
            # build decoder model
            latent_inputs = Input(shape=(latent_dim,), name='z_sampling')
            x = Dense(intermediate_dim, activation='relu')(latent_inputs)
            outputs = Dense(ENCODING_DIM_INPUT, activation='sigmoid')(x)
      
            # # build surprised learning model
            # SL_output = Dense(10, activation='softmax')()
      
            # build autoencoder, encoder
            encoder = Model(input_image, [z_mean, z_log_var, z], name='encoder')
            decoder = Model(latent_inputs, outputs, name='decoder')
            # SL_model = Model(inputs=input_image, outputs=SL_output)
      
            outputs = decoder(encoder(input_image)[2])
            autoencoder = Model(input_image, outputs, name='vae_mlp')
      
            # compile autoencoder
            # VAE loss = mse_loss or xent_loss + kl_loss
            if mse_loss:
                reconstruction_loss = mse(input_image, outputs)
            else:
                reconstruction_loss = binary_crossentropy(input_image,outputs)
      
            reconstruction_loss *= ENCODING_DIM_INPUT
            kl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(z_log_var)
            kl_loss = K.sum(kl_loss, axis=-1)
            kl_loss *= -0.5
            vae_loss = K.mean(reconstruction_loss + kl_loss)
            autoencoder.add_loss(vae_loss)
            autoencoder.compile(optimizer='adam')
            autoencoder.summary()
      
            # SL_model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])           
            self.autoencoder = autoencoder
            self.encoder = encoder
            self.decoder = decoder
    

    训练过程

    由于,变分自动编码器主要应用于图像生成,而并非是提取与分类,因此变分降噪自动编码器只有自监督的训练过程…

    在自监督的训练过程,使用 KL散度+交叉熵 作为loss函数,loss变化情况如下.

    image

    可以看散度可以收敛到145的情况,能够有效进行收敛.

    在自监督的训练过程,使用 KL散度+方均根 作为loss函数,loss变化情况如下.

    image

    对于两种损失函数效果的讨论在下文中进行.

    自编码器输出的可视化结果

    使用 KL散度+交叉熵 作为损失函数

    基于kl散度的loss训练结果二维可视化如下

    image

    使用生成器对图像进行生成可以得到如下结果.

    image

    使用 KL散度+方均根 作为损失函数

    基于kl散度的loss训练结果二维可视化如下

    image

    使用生成器对图像进行生成可以得到如下结果.

    image

    由于方均根与交叉熵的区别在于 解码器重现误差上面的区别,在编码器部分同样使用kl散度作为loss,因此两者的可视化结果类似.

    以下几点需要指出:

    1.二维可视化的结果中各个类别的界限较为明显,且其分布十分集中方便生成模型的图像生成.
    2.KL散度作为一种新的损失函数无法与其他方法的误差进行对比.

    讨论

    1.自动编码器可能的应用有特征提取,图像分类,图像去燥,图像生成等

    2.在特征提取领域和图像分类领域使用SAE有较优秀的效果

    3.在图像去噪领域可以使用cae方法,CAE方法对二维图片的去燥效果十分优秀,但是由于中间部分是比较复杂的卷机核结构,无法进行有效的可视化

    4.VAE方法在图像生成领域有出色的表现,将中间的隐变量约束为正太分布的形式,十分方便的通过生成器完成图像生成.

    5.在研究角度,VAE方法将概率方法引入神经网络的计算体系中,通过网络完成对概率分布的映射,使用散度的概念构造损失函数,对其他研究有些启发.

    完成代码

    https://github.com/zangzelin/Auto-encoder-AE-SAE-DAE-CAE-DAE-with-keras-in-Mnist-and-report

    展开全文
  • android硬编码h264

    千次下载 热门讨论 2013-12-26 15:20:25
    android 用新api mediacodec硬编码h264, 发送到vlc播放。
  • 编码器及其变形很多,本篇博客目前主要基于普通自编码器、欠完备自编码器、稀疏自编码器和去噪自编码器,会提供理论+实践(有的理论本人没有完全理解,就先没有写上,后更)。另外,关于收缩自编码器、变分自编码...
  • 最简单的视频编码器示例

    千次下载 热门讨论 2014-12-21 21:46:43
    该解决方案包含了几个常见的编码器的使用示例: simplest_vpx_encoder:最简单的基于libvpx的视频编码器 simplest_x264_encoder:最简单的基于libx264的视频编码器 simplest_x265_encoder:最简单的基于libx265的...
  • 百度地图城市编码city_code

    热门讨论 2015-04-02 11:34:44
    百度地图城市编码,city_code,MySQL数据库直接导入
  • 块截断编码图像压缩技术

    千次阅读 2020-10-04 03:20:19
    论文先介绍了当前流行的图像压缩技术,重点介绍块截断编码技术,先从理论上介绍块截断编码原理,块截断编码是一种有效、快速的数字图像压缩技术,作为一种经典的图像压缩编码,块截断编码技术的实时性很强。...
  • STM32——编码器测速原理及STM32编码器模式

    千次阅读 多人点赞 2021-01-19 22:12:53
    本问讲解了编码器测速原理及STM32编码器模式,文末有STM32编码器模式例程。
  • 霍尔编码器原理及测速--PID—arduino

    万次阅读 多人点赞 2020-03-04 17:13:28
    本人目前是一个大一菜鸟,零基础学的编码器方面,希望我的经验对你有些帮助。 分享一下霍尔编码器电机的使用与测速,我用的是25GA-310直流减速电机带霍尔传感器。先来看一下最基本的 接线方法------- ------S1与S2...
  • 基于STM32光电编码器测速

    热门讨论 2014-12-01 18:22:49
    基于STM32f103的欧姆龙的光电码编码器测速,及在12864液晶上显示速度
  • 编码器的工作原理

    万次阅读 多人点赞 2019-11-12 09:03:37
    最近公司项目用到了编码器 选用的编码器 为360脉冲 为了方便其一圈发360个脉冲 ,当然精度只有一度 ,如果为了高精度可以选用其他类型的 首先简述一下编码器的工作原理 编码器可按以下方式来分类。 1、按码盘的...
  • 编码:算术编码

    万次阅读 2020-02-10 11:29:53
    算术编码不是简单的将每个信源符号映射成一个码字,而是对整个输入序列分配一个码字,所以平均意义上可以为每个信源符号分配长度小于1的码字。 算术编码操作简单,下面以一个实例讲解算术编码的原理: 设信源有a,b...
  •   在非监督学习中,最典型的一类神经网络莫过于autoencoder(自编码器),它的目的是基于输入的unlabeled数据X={x(1),x(2),x(3),...}X={x(1),x(2),x(3),...}X=\{x^{(1)}, x^{(2)}, x^{(3)}, ...\},通过训练得到数据...
  • C++ 哈夫曼编码

    万次阅读 多人点赞 2019-03-13 23:51:26
    1.哈夫曼编码的结点类: struct HuffmanNode { int weight; // 权重,出现的次数或者频率 char ch; // 存储符号 string code; // 存储该符号对应的编码 int leftChild, rightChild, parent; // 左、右孩子,父...
  • 图像压缩之算术编码

    千次阅读 2019-04-15 10:43:15
    JPEG中使用了量化、哈夫曼编码等,极大的压缩了图片占用的空间,那么是否可以进一步压缩呢? 从技术角度讲,是可以的。如DropBox开源的lepton,在目前的JPEG压缩基础上,可以再节省22%左右的空间。 lepton中使用算术...
  • Java编码规范

    热门讨论 2014-02-20 17:27:40
    同时,编码规范还可以提高程序代码的安全性和可维护性,提高软件开发的生产效率,所以,编码规范对于程序员而言至关重要。 为使开发项目中所有的JAVA程序代码的风格保持一致,增加代码的可读性,便于维护及内部交流...
  • 基于 MATLAB 的 PCM 编码解码实现

    万次阅读 多人点赞 2019-01-12 12:32:53
    文章目录基于 MATLAB 的 PCM 编码解码实现抽样信号PCM 编码PCM 解码失真度分析 基于 MATLAB 的 PCM 编码解码实现 关于 PCM 的原理在此不过多解释,代码使用的是 A 律 13 折线法。 抽样信号 抽样信号的 MATLAB 代码...
  • 编码器计数原理与电机测速原理——多图解析

    千次阅读 多人点赞 2021-02-10 19:21:40
    编码器,是一种用来测量机械旋转或位移的传感器。它能够测量机械部件在旋转或直线运动时的位移位置或速度等信息,并将其转换成一系列电信号。 编码器分类 按监测原理分类 光电编码器 光电编码器,是一种通过光电转换...
  • 华为C/C++编码规范

    千次下载 热门讨论 2014-01-14 17:15:56
    华为C/C++的编码规范,刚开始编程的程序员们学习一下华为的编码风格哦!
  • 视频编码技术详解

    万次阅读 多人点赞 2020-04-18 14:06:53
    《即时通讯音视频开发(四):视频编解码之预测技术介绍》 《即时通讯音视频开发(五):认识主流视频编码技术H.264》 4、视频编码的实现原理 4.1 视频编码技术的基本原理 前面我们说了,编码就是为了压缩。要实现压缩,...
  • 香农编码,哈夫曼编码与费诺编码的比较

    万次阅读 多人点赞 2018-12-05 16:46:12
    一、香农编码 概念: 香农编码是是采用信源符号的累计概率分布函数来分配字码的。香农编码是根据香农第一定理直接得出的,指出了平均码长与信息之间的关系,同时也指出了可以通过编码使平均码长达到极限值。香农第一...
  • 算数编码详解

    万次阅读 多人点赞 2019-06-07 20:49:02
    算数编码是一种非常有用的无损信源压缩编码方式,以下是它的详解: 转自https://segmentfault.com/a/1190000011561822 编码原理 算数编码的原理我个人感觉其实并不太容易用三言两语直观地表达出来,其背后的数学...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,622,289
精华内容 1,048,915
关键字:

如何编码