专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »VB教程 » vb编程:用VB语言编程实现JPEG数据压缩 »正文

vb编程:用VB语言编程实现JPEG数据压缩

来源: 发布时间:星期四, 2009年1月15日 浏览:39次 评论:0
  JPEG压缩格式是目前图像处理领域里面用得最广泛种图像压缩方式实现主要分成 4个步骤:

  1.颜色模式转换及采样;

  2.DCT变换(离散余弦变换);

  3.量化;

  4.编码(有算术编码和霍夫曼编码两种这里采用霍夫曼编码)用VB语言编程实现以上 4个步骤即完成了JPEG压缩过程这里假设给定源图像是幅24位真彩色BMP图像

  、颜色转换及采样

  1.颜色转换:对BMP图像中颜色数据进行由RGBYCbCr转换Y表示亮度CbCr分别表示蓝色度和红色度

  转换公式:

  Y=0.2990R+0.5870G+0.1140B
  Cb=-0.1687R-0.3313G+0.5000B
  Cr=0.5000R-0.4187G-0.0813B
  这样转换以后就得到 3个新基色值对这 3个基色值来讲都可以当作

  个独立图像平面来进行压缩编码

  2.采样:颜色转换后保留每亮度值Y而色度值CbCr则是每两点保留在图像行和列方向上都可执行颜色采样这里采用采样比是行列方向都是2:1:1在行方向每两点保留列方向也是每两点保留这样如果假设原来CbCr矩阵大小为M*S则经过2:1:1抽样的后成了M/2*s/2=1/4M*S只有原来1/4了图像大大缩小如果想减小图像失真度则可行方向不抽样或列方向不抽样

  实现:

  1.读取BMP图像信息获取图像行像素和列像素数值在BMP图像中图像数据是以倒序存放亦即实际图像第行资料存放在BMP图像数据矩阵最后依次类推所以取资料时候要从BMP图像数据矩阵最后行开始读起把数据存放在新建(或称矩阵)直取完BMP图像行像素和列像素数值分别存于文件头信息第18和22字节用Get语句可得到Pwidth(图像宽度)和Phight(图像高度)数值

  2.得到Pwidth*Phight后便得知BMP图像像素点大小而数据矩阵( 3基色RGB矩阵)大小是Pwidth*Phight*3个像素点都含有RGB 3个数据我们要处理是数据矩阵而不是像素点矩阵所以新建大小是(Pwidth*3)*Phight

  在BMP图像数据矩阵中 3原色RGB排列顺序是这样:

  B. G. R. B. G. R...........R

  B. G. R....................R

  B........

  .             .

  B. G. R....................R

  接下来把这个矩阵(包含BGR)拆分成 3个独立B、G、R矩阵得到 3个新矩阵(只包含B矩阵只包含G矩阵只包含R矩阵)简称为B矩阵、G矩阵、R矩阵(大小为Pwidth*Phight)实现拆分只要依次取原矩阵第1、4、7、10、13......个资料即得到B矩阵依次读取第2、5、8、11......个数据即得到G矩阵依次读第3、6、9、12......个资料即得到R矩阵

  得到B、G、R矩阵后再利用颜色转换公式很容易就可得到YCbCr矩阵

Y(n)=0.114B(n)+0.587G(n)+0.299R(n)
  Cb(n)=0.5B(n)-0.3313G(n)-0.1687R(n)
  Cr(n)=0.0813B(n)-0.14187G(n)+0.5R(n)
  (For n=1 To PW*PH)


  其中PW为Pwidth简写PH为Phight简写

  得Y、Cb、Cr矩阵后先判断下 3个矩阵行数和列数是否都被16整除

  如果不能则以最后行或资料填充到能被16整除为止所需填充数目

  为:行方向:16-(Pwidth mod 16)

  列方向:16-(Phight mod 16)

  填充以后YCbCr矩阵大小成为M*S其中设M=Pwidth+16-(Pwidth mod

  16);S=Phight+16-(Phight mod 16)

  3、抽样:Y矩阵不动CbCr矩阵行列方向上相邻两点只保留资料值

  (只要在其行方向取第1、3、5、7......个数值列方向也取1、3、5、7......

  个资料即可完成2:1:1采样),行、列方向都进行2:1:1抽样后Cb、Cr矩阵大小

  变成原来1/4(M/2*S/2)

  现在结果是Y矩阵大小为M*SCb,Cr为M/2*S/2至此已经完成了颜色转换及采样接下来做第 2步--DCT变换

   2、DCT变换

  在DCT变换的前得做些准备工作由于DCT变换次只能做64个资料因此首先得把Y、Cb、Cr矩阵分成个8*8小块;其次由于离散余弦变换公式所能接受数值范围是-128至127的间因此还得把Y、Cb、Cr矩阵中每个资料减去128

  分块是项比较烦琐工作尤其是对于Y矩阵Cb、Cr矩阵好办直接

  按顺序分成8*8块就可以了而Y块为了保证4个8*8Y块对应个8*8Cb块和个8*8Cr块不致打乱顺序得先把Y矩阵分成个个16*16这样得到个16*16Y块对应个8*8Cb块和个8*8Cr块然后再把每个16*16块分成 4个8*8小块图标如下:

  上图中每个标有数字小块表示个8*8块小块中数字表示分块以

  后该8*8小块在矩阵中位置顺序

   2维DCT变换公式为:

  其中x,y代表图像数据矩阵中某个资料值坐标位置

  f(x,y)指图像数据矩阵中该点资料值

  u,v指经过DCT变换后矩阵中某数值点坐标位置在这里u=x,v=y

  F(u,v)指经过DCT变换后该坐标点资料值

  当u=0,v=0时C(u)C(v)=1.414/2

  当u>0,v>0时C(u)C(v)=1,经过变换后数据值F(u,v)称为频率系数(或

  称DFT系数)

  由于VB汇编中都无法实现 2维DCT计算公式所以只有把 2维变换变

  成先做再做另变换维DCT变换公式见附图

  在我个大小为8SL(8),元素计数从1开始而不是通常0开始先读取个8*8块行资料值赋给SL(8),对SL(8)进行维DCT变换后得到个新SL(8)再把SL(8)覆盖到原来8*8块中相应地方去做完第行后再做第 2行直做完8行个8*8块维DC即告完成然后再做列方向第 2维DCT变换变换公式只是由SL(8)取8*8块行资料变成取列数值做完后覆盖回原值即得到个8*8块DFT系数块再重复这两个过程做第 2个8*8块......直到做完全部8*8块(YCbCr)这样就得到Y、Cb、CrDFT系数矩阵要做到DCT系数矩阵还得把DFT系数矩阵以个系数矩阵Y矩阵用个系数矩阵Cb、Cr合用另个系数矩阵这两个系数矩阵见附录 2这两个系数矩阵可以直接得到第 3步量化结果

   3、量化

  本来第 2步骤最后得到DFT系数矩阵乘以个给定系数矩阵得到DCT系数矩阵DCT系数矩阵再除以个量化矩阵得到量化后DCT系数矩阵而我们把这两步合成步来做即由系数矩阵和量化矩阵得到个新系数矩阵亦即附录所列矩阵这样把DFT系数数矩阵乘以新系数矩阵就直接得到量化后DCT矩阵

  量化过程实质上是把亮度资料和色度资料由室域转变成频域并滤除高频分量过程由于人眼对高频分量不敏感所以可以滤除高频分量经过量化以后个8*8数据块中个元素数据值为直流分量称为DC其余63个资料为交流分量称为AC

  用实现量化过程除了系数矩阵推算比较麻烦的外其余都比较简

  单读取Y矩阵中第个8%块和量化系数矩阵中对应相乘得到值覆盖回原矩阵然后做第 2个8*8块直到做完全部8*8块然后做CbCr矩阵量化用另外个系数矩阵

  经过量化后DCT系数矩阵除DC值般不为零外AC系数大多是在零点附近浮点数

  由于霍夫曼编码对象是整数所以在做霍夫曼编码的前还得对量化后

  DCT系数矩阵进行取整

  利用VB中Int可以实现YcbCrDCT量化后系数炬阵进行取整

  经过取整以后个8*8块中有大量AC系数值为0为了把尽可能多其值为0AC系数串在以利于第 4步AC编码及提高压缩比还必须把YcbCr矩阵中个8*8块中64个元素进行"的"字形排序(这样就可以做到把尽可能多0串在起)其过程示意图如下:假设SB(1)-SB(64)为个8*8块中64个元素元素位置计数从1开始:

  箭头方向表示"的"字形排序以后原8%中元素位置顺序亦即经过 "的"字形排序以下8*8块中元素值如下:等式左边表示元素位置等式右边表示元素值为排序的前某位置中元素值:如SB(15)=SB(5)则左边表示排序后8*8块中第15个元素值等于排序的前第5个元素

  SB(1)=SB(1)  SB(2)=SB(2)
  SB(3)=SB(9)  SB(4)=SB(17)
  SB(5)=SB(10)  SB(6)=SB(3)
  SB(7)=SB(4)  SB(8)=SB(11)
  SB(9)=SB(18)  SB(10)=SB(25)
  SB(11)=SB(33) SB(12)=SB(26)
  SB(13)=SB(19) SB(14)=SB(12)
  SB(15)=SB(5)  SB(12)=SB(6)
  ......
  SB(61)=SB(48) SB(62)=SB(56)
  SB(63)=SB(63) SB(64)=SB(64)


  用实现:再新开个大小为64SC把SB值赋给SC再把以上等式右边SB换成SC即可例如SB(15)=CB(5)换成SB(15)=SC(5)换完以后即完成个8*8块的字形变换这里为什么要新开SC呢?这是:例如把SB(9)值赋给排序后SB(3)则SB(3)值就被SB(9)值覆盖掉了到后面需把SB (3)值赋给SB(6)如果不新开保留元素原来则赋给SB(6)就成了是SB(9)值而不是SB(3)故要新开保留8*8块中原值

  完成"的"字形排序的后就开始做第 4步工作:霍夫曼编码

   4、霍夫曼编码

  前面说到变换后个8*8频率系数矩阵由个DC值和63个AC值构成编码时对DC值和AC值用区别霍夫曼编码表对亮度和色度也需用区别霍夫曼编码表所以必须使用 4张区别霍夫曼编码表才能完成JPEG编码

  DC编码:在做DC编码的前还必须对DC值进行脉冲差值运算具体做法是在Y、Cb、Cr频率系数矩阵中个8*8块DC值减去前个8*8块DC作为后个8*8块新DC值并保留后个8*8块DC原值用于后个8*8块差值DC运算亦即每次后个8*8块DC值减去是第个8*8块原来DC值而不是经运算后差值

  DC编码=霍夫曼识别码(或称标志码)+DC差值 2进制代码

  下面给出Y、CbCr矩阵DC差值霍夫曼编码表

  举例:例如Y矩阵中个8*8块DC值=10 2进制值为1010码长为4查第张表得霍夫曼识别长为3识别码为101则其霍夫曼编码为1011010

  负数编码是取其绝对值反码进行编码如DC=-10则其绝对值为10

   2进制仍为1010反码为0101霍夫曼编码为1010101

  AC编码:AC编码原理和思路方法跟DC相似所区别是AC编码中多了项RLE压缩编码前面说到经过量化取整以后有许多AC值为0并经过"的"字形排序把原可能多0串行在在这里RLE压缩编码就是用个数值表示为0AC值前有几个AC值为0例如在[MN]这组RLE编码中N表示不为0AC值M则表示在这不为0AC值N的前0个数M最多只能为15如果AC资料值N的前有17个AC值为0则先以[150]代表有16个值为0再以[1N]表示N前有个值为0如果在某个AC资料值的后(该值不为0)所有AC值皆为0则这串资料可以用[00]表示

  做完RLE压缩后再对不为0AC值进行霍夫曼编码跟DC值样进行只不过用是另两张霍夫曼编码表完整AC编码如下:

  (完整AC编码码串包括 3部分:(1)位置记录"0"个数;(2)位置为霍夫曼识别码;(3)位置AC值 2进制代码值)这样个码串才算是个完整AC霍夫曼码串

  做到这里就完成了整个JPEG压缩过程

  在整个压缩过程中最难部分就是第 4步霍夫曼编码用实现起

  非常繁琐必须判断个个DC(AC)以及转换成 2进制代码后码长

  再去对照霍夫曼编码表进行编码比如对个DC值编码首先得先判断该DC

  值在哪段范围内在某段范围内数值其 2进制代码长相等并要让程

  序知道该DC值到底为多少然后才能进行编码(这里面还涉及到个数

  制转换过程即由十进制数转换成 2进制数)

  压缩过程完成以后接下去要做工作便是码串存贮存贮时需要注意

  -点是在抽样过程中得到4个Y块对应1个Cb块个Cr块对应关系在存贮时也要按这种对应关系存贮即4个Y块码串后面紧接着存放和其对应个Cb块码串及个Cr块码串循环往复存完所有串这样4个Y8*8块+1个Cb块+1个Cr简称为MCU是JPEG格式最小存贮处理单元

  附录1:维DCT变换公式

  C1 C2 C3 C4 C5 C6 C7为常数
  C1=0.9808
  C2=0.9239
  C3=0.8315
  C4=0.7071
  C5=0.5556
  C6=0.3827
  C7=0.1951
  S18=SL(1)+SL(8)
  S27=SL(2)+SL(7)
  S36=SL(3)+SL(6)
  S45=SL(4)+SL(5)
  S1845=S18+S45
  S2736=S27+S36
  D18=SL(1)+SL(8)
  D27=SL(2)+SL(7)
  D36=SL(3)+SL(6)
  D45=SL(4)+SL(5)
  D1845=S18-S45
  D2736=S27-S36
  SL(1)=0.5*(C4*(S1845+S2736))
  SL(2)=0.5*(C1*D18+C3*D27+C5*D36+C7*D45)
  SL(3)=0.5*(C2*D1845+C6*D2736)
  SL(4)=0.5*(C3*D18-C7*D27-C1*D36-C5*D45)
  SL(5)=0.5*(C4*(S1845-S2736))
  SL(6)=0.5*(C5*D18-C1*D27+C7*D36+C3*D45)
  SL(7)=0.5*(C6*D1845-C2*D2736)
SL(8)=0.5*(C7*D18-C5*D27+C3*D36-C1*D45)


0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: