高质量的快速图像缩放――二次线性插值和三次卷积插值_第1页
高质量的快速图像缩放――二次线性插值和三次卷积插值_第2页
高质量的快速图像缩放――二次线性插值和三次卷积插值_第3页
高质量的快速图像缩放――二次线性插值和三次卷积插值_第4页
高质量的快速图像缩放――二次线性插值和三次卷积插值_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、高质量的快速的图像缩放二次线性插值和三次卷积插值限制条件:为了便于讨论,这里只处理32bit的ARGB颜色;代码使用C+;涉及到汇编优化的时候假定为x86平台;使用的编译器为vc2005;为了代码的可读性,没有加入异常处理代码;测试使用的CPU为AMD64x2 4200+(2.37G) 和 Intel Core2 4400(2.00G);速度测试说明:只测试内存数据到内存数据的缩放测试图片都是800*600缩放到1024*768; fps表示每秒钟的帧数,值越大表示函数越快A: 近邻取样插值、二次线性插值、三次卷积插值 缩放效果对比 原图 近邻取样缩放到0.6倍 近邻取样缩放到1.6倍 二次线

2、性插值缩放到0.6倍 二次线性插值缩放到1.6倍 三次卷积插值缩放到0.6倍 三次卷积插值缩放到1.6倍 原图 近邻取样缩放到8倍 二次线性插值缩放到8倍 三次卷积插值缩放到8倍 二次线性插值(近似公式)近邻取样插值缩放简单、速度快,但很多时候缩放出的图片质量比较差(特别是对于人物、景色等),图片的缩放有比较明显的锯齿;使用二次或更高次插值有利于改善缩放效果;B: 首先定义图像数据结构:#define asm _asmtypedef unsigned char TUInt8; / 0.255struct TARGB32 /32 bit color TUInt8 b,g,r,a; /a is a

3、lpha;struct TPicRegion /一块颜色数据区的描述,便于参数传递 TARGB32* pdata; /颜色数据首地址 long byte_width; /一行数据的物理宽度(字节宽度); /abs(byte_width)有可能大于等于width*sizeof(TARGB32); long width; /像素宽度 long height; /像素高度;/那么访问一个点的函数可以写为:inline TARGB32& Pixels(const TPicRegion& pic,const long x,const long y) return ( (TARGB32*)(TUInt8*

4、)pic.pdata+pic.byte_width*y) )x;二次线性差值C: 二次线性插值缩放原理和公式图示: 缩放后图片 原图片 (宽DW,高DH) (宽SW,高SH)缩放映射原理: (Sx-0)/(SW-0)=(Dx-0)/(DW-0) (Sy-0)/(SH-0)=(Dy-0)/(DH-0) = Sx=Dx*SW/DW Sy=Dy*SH/DH聚焦看看(Sx,Sy)坐标点(Sx,Sy为浮点数)附近的情况; 对于近邻取样插值的缩放算法,直接取Color0颜色作为缩放后点的颜色;二次线性插值需要考虑(Sx,Sy)坐标点周围的4个颜色值Color0Color1Color2Color3,把(Sx

5、,Sy)到ABCD坐标点的距离作为系数来把4个颜色混合出缩放后点的颜色;(u=Sx-floor(Sx); v=Sy-floor(Sy); 说明:floor函数的返回值为小于等于参数的最大整数 ) 二次线性插值公式为: tmpColor0=Color0*(1-u) + Color2*u; tmpColor1=Color1*(1-u) + Color3*u; DstColor =tmpColor0*(1-v) + tmpColor2*v; 展开公式为: pm0=(1-u)*(1-v); pm1=v*(1-u); pm2=u*(1-v); pm3=u*v; 则颜色混合公式为: DstColor =

6、Color0*pm0 + Color1*pm1 + Color2*pm2 + Color3*pm3;参数函数图示:二次线性插值函数图示对于上面的公式,它将图片向右下各移动了半个像素,需要对此做一个修正;= Sx=(Dx+0.5)*SW/DW-0.5; Sy=(Dy+0.5)*SH/DH-0.5;而实际的程序,还需要考虑到边界(访问源图片可能超界)对于算法的影响,边界的处理可能有各种方案(不处理边界或边界回绕或边界饱和或边界映射或用背景颜色混合等;文章中默认使用边界饱和来处理超界);比如: 边界饱和函数: /访问一个点的函数,(x,y)坐标可能超出图片边界; /边界处理模式:边界饱和inline

7、 TARGB32 Pixels_Bound(const TPicRegion& pic,long x,long y) /assert(pic.width0)&(pic.height0); bool IsInPic=true; if (x=pic.width ) x=pic.width -1; IsInPic=false; if (y=pic.height) y=pic.height-1; IsInPic=false; TARGB32 result=Pixels(pic,x,y);if (!IsInPic) result.a=0;return result;D: 二次线性插值缩放算法的一个参考实

8、现:PicZoom_BilInear0该函数并没有做什么优化,只是一个简单的浮点实现版本;inline void Bilinear0(const TPicRegion& pic,float fx,float fy,TARGB32* result) long x=(long)fx; if (xfx) -x; /x=floor(fx); long y=(long)fy; if (yfy) -y; /y=floor(fy); TARGB32 Color0=Pixels_Bound(pic,x,y); TARGB32 Color2=Pixels_Bound(pic,x+1,y); TARGB32 Co

9、lor1=Pixels_Bound(pic,x,y+1); TARGB32 Color3=Pixels_Bound(pic,x+1,y+1); float u=fx-x; float v=fy-y; float pm3=u*v; float pm2=u*(1-v); float pm1=v*(1-u); float pm0=(1-u)*(1-v); result-a=(pm0*Color0.a+pm1*Color1.a+pm2*Color2.a+pm3*Color3.a); result-r=(pm0*Color0.r+pm1*Color1.r+pm2*Color2.r+pm3*Color3.

10、r); result-g=(pm0*Color0.g+pm1*Color1.g+pm2*Color2.g+pm3*Color3.g); result-b=(pm0*Color0.b+pm1*Color1.b+pm2*Color2.b+pm3*Color3.b); void PicZoom_Bilinear0(const TPicRegion& Dst,const TPicRegion& Src) if ( (0=Dst.width)|(0=Dst.height) |(0=Src.width)|(0=Src.height) return; unsigned long dst_width=Dst.

11、width; TARGB32* pDstLine=Dst.pdata; for (unsigned long y=0;yDst.height;+y) float srcy=(y+0.)*Src.height/Dst.height-0.5; for (unsigned long x=0;x16; long y=y_1616; TARGB32 Color0=Pixels_Bound(pic,x,y); TARGB32 Color2=Pixels_Bound(pic,x+1,y); TARGB32 Color1=Pixels_Bound(pic,x,y+1); TARGB32 Color3=Pixe

12、ls_Bound(pic,x+1,y+1); unsigned long u_8=(x_16 & 0xFFFF)8; unsigned long v_8=(y_16 & 0xFFFF)8; unsigned long pm3_16=(u_8*v_8); unsigned long pm2_16=(u_8*(unsigned long)(255-v_8); unsigned long pm1_16=(v_8*(unsigned long)(255-u_8); unsigned long pm0_16=(255-u_8)*(255-v_8); result-a=(pm0_16*Color0.a+p

13、m1_16*Color1.a+pm2_16*Color2.a+pm3_16*Color3.a)16); result-r=(pm0_16*Color0.r+pm1_16*Color1.r+pm2_16*Color2.r+pm3_16*Color3.r)16); result-g=(pm0_16*Color0.g+pm1_16*Color1.g+pm2_16*Color2.g+pm3_16*Color3.g)16); result-b=(pm0_16*Color0.b+pm1_16*Color1.b+pm2_16*Color2.b+pm3_16*Color3.b)16); void PicZoo

14、m_Bilinear1(const TPicRegion& Dst,const TPicRegion& Src) if ( (0=Dst.width)|(0=Dst.height) |(0=Src.width)|(0=Src.height) return; long xrIntFloat_16=(Src.width)16)/Dst.width+1; long yrIntFloat_16=(Src.height)16)/Dst.height+1; const long csDErrorX=-(11); const long csDErrorY=-(11); unsigned long dst_w

15、idth=Dst.width; TARGB32* pDstLine=Dst.pdata; long srcy_16=csDErrorY; long y; for (y=0;yDst.height;+y) long srcx_16=csDErrorX; for (unsigned long x=0;xdst_width;+x) Bilinear1(Src,srcx_16,srcy_16,&pDstLinex); /border srcx_16+=xrIntFloat_16; srcy_16+=yrIntFloat_16; (TUInt8*&)pDstLine)+=Dst.byte_width;

16、/速度测试:/=/ PicZoom_BilInear1 17.7 fps/F: 边界访问超界的问题二次线性插值需要考略边界访问超界的问题,我们可以将边界区域和内部区域分开处理,这样就可以优化内部的插值实现函数了:比如不需要判断访问超界、减少颜色数据复制、减少一些不必要的重复坐标计算等等inline void Bilinear2_Fast(TARGB32* PColor0,TARGB32* PColor1,unsigned long u_8,unsigned long v_8,TARGB32* result) unsigned long pm3_16=u_8*v_8; unsigned long

17、 pm2_16=(u_88)-pm3_16; unsigned long pm1_16=(v_88)-pm3_16; unsigned long pm0_16=(1a=(pm0_16*PColor00.a+pm2_16*PColor01.a+pm1_16*PColor10.a+pm3_16*PColor11.a)16); result-r=(pm0_16*PColor00.r+pm2_16*PColor01.r+pm1_16*PColor10.r+pm3_16*PColor11.r)16); result-g=(pm0_16*PColor00.g+pm2_16*PColor01.g+pm1_1

18、6*PColor10.g+pm3_16*PColor11.g)16); result-b=(pm0_16*PColor00.b+pm2_16*PColor01.b+pm1_16*PColor10.b+pm3_16*PColor11.b)16); inline void Bilinear2_Border(const TPicRegion& pic,const long x_16,const long y_16,TARGB32* result) long x=(x_1616); long y=(y_1616); unsigned long u_16=(unsigned short)(x_16);

19、unsigned long v_16=(unsigned short)(y_16); TARGB32 pixel4; pixel0=Pixels_Bound(pic,x,y); pixel1=Pixels_Bound(pic,x+1,y); pixel2=Pixels_Bound(pic,x,y+1); pixel3=Pixels_Bound(pic,x+1,y+1); Bilinear2_Fast(&pixel0,&pixel2,u_168,v_168,result); void PicZoom_Bilinear2(const TPicRegion& Dst,const TPicRegion

20、& Src) if ( (0=Dst.width)|(0=Dst.height) |(0=Src.width)|(0=Src.height) return; long xrIntFloat_16=(Src.width)16)/Dst.width+1; long yrIntFloat_16=(Src.height)16)/Dst.height+1; const long csDErrorX=-(11); const long csDErrorY=-(11); unsigned long dst_width=Dst.width; /计算出需要特殊处理的边界 long border_y0=-csDE

21、rrorY/yrIntFloat_16+1; /y0+y*yr=0; y0=csDErrorY = y=-csDErrorY/yr if (border_y0=Dst.height) border_y0=Dst.height; long border_x0=-csDErrorX/xrIntFloat_16+1; if (border_x0=Dst.width ) border_x0=Dst.width; long border_y1=(Src.height-2)16)-csDErrorY)/yrIntFloat_16+1; /y0+y*yr y=(height-2-csDErrorY)/yr

22、if (border_y1border_y0) border_y1=border_y0; long border_x1=(Src.width-2)16)-csDErrorX)/xrIntFloat_16+1; if (border_x1border_x0) border_x1=border_x0; TARGB32* pDstLine=Dst.pdata; long Src_byte_width=Src.byte_width; long srcy_16=csDErrorY; long y; for (y=0;yborder_y0;+y) long srcx_16=csDErrorX; for (

23、unsigned long x=0;xdst_width;+x) Bilinear2_Border(Src,srcx_16,srcy_16,&pDstLinex); /border srcx_16+=xrIntFloat_16; srcy_16+=yrIntFloat_16; (TUInt8*&)pDstLine)+=Dst.byte_width; for (y=border_y0;yborder_y1;+y) long srcx_16=csDErrorX; long x; for (x=0;x8; TARGB32* PSrcLineColor= (TARGB32*)(TUInt8*)(Src

24、.pdata)+Src_byte_width*(srcy_1616) ; for (unsigned long x=border_x0;x16; TARGB32* PColor1=(TARGB32*)(TUInt8*)(PColor0)+Src_byte_width); Bilinear2_Fast(PColor0,PColor1,(srcx_16 & 0xFFFF)8,v_8,&pDstLinex); srcx_16+=xrIntFloat_16; for (x=border_x1;xdst_width;+x) Bilinear2_Border(Src,srcx_16,srcy_16,&pD

25、stLinex);/border srcx_16+=xrIntFloat_16; srcy_16+=yrIntFloat_16; (TUInt8*&)pDstLine)+=Dst.byte_width; for (y=border_y1;yDst.height;+y) long srcx_16=csDErrorX; for (unsigned long x=0;x=2;SH=2)证明这个公式不会造成内存访问超界: 要求Dx=DW-1时: sx+1=int( (dw-1)/dw*(dw-1) ) +1 = (sw-1) 有: int( (sw-1)*(dw-1)/dw ) =sw-2 (sw-1

26、)*(dw-1)/dw (sw-1) (dw-1) /dw1 (dw-1) Src.width)|(2Src.height) return; long xrIntFloat_16=(Src.width-1)16)/Dst.width; long yrIntFloat_16=(Src.height-1)16)/Dst.height; unsigned long dst_width=Dst.width; long Src_byte_width=Src.byte_width; TARGB32* pDstLine=Dst.pdata; long srcy_16=0; for (unsigned lon

27、g y=0;y8; TARGB32* PSrcLineColor= (TARGB32*)(TUInt8*)(Src.pdata)+Src_byte_width*(srcy_1616) ; long srcx_16=0; for (unsigned long x=0;x16; Bilinear_Fast_Common(PColor0,(TARGB32*)(TUInt8*)(PColor0)+Src_byte_width),(srcx_16 & 0xFFFF)8,v_8,&pDstLinex); srcx_16+=xrIntFloat_16; srcy_16+=yrIntFloat_16; (TU

28、Int8*&)pDstLine)+=Dst.byte_width; G: 模拟单指令多数据处理利用单指令多数据处理的MMX指令一般都可以加快颜色的运算;在使用MMX改写之前,利用32bit寄存器(或变量)来模拟单指令多数据处理;数据储存原理:一个颜色数据分量只有一个字节,用2个字节来储存单个颜色分量的计算结果,对于很多颜色计算来说精度就够了;那么一个32bit寄存器(或变量)就可以储存2个计算出的临时颜色分量;从而达到了单个指令两路数据处理的目的;单个指令两路数据处理的计算:乘法: (0x00AA*a)16) | (0x00BB*a) = 0x00AA00BB * a可见只要保证0x00AA*

29、a和0x00BB*a都小于(116)那么乘法可以直接使用无符号数乘法了加法: (0x00AA+0x00CC)16) | (0x00BB+0x00DD) = 0x00AA00BB + 0x00CC00DD可见只要0x00AA+0x00CC和0x00BB+0x00DD小于(18; unsigned long pm2_8=u_8-pm3_8; unsigned long pm1_8=v_8-pm3_8; unsigned long pm0_8=256-pm1_8-pm2_8-pm3_8; unsigned long Color=*(unsigned long*)(PColor0); unsigned

30、 long BR=(Color & 0x00FF00FF)*pm0_8; unsigned long GA=(Color & 0xFF00FF00)8)*pm0_8; Color=(unsigned long*)(PColor0)1; GA+=(Color & 0xFF00FF00)8)*pm2_8; BR+=(Color & 0x00FF00FF)*pm2_8; Color=*(unsigned long*)(PColor1); GA+=(Color & 0xFF00FF00)8)*pm1_8; BR+=(Color & 0x00FF00FF)*pm1_8; Color=(unsigned

31、long*)(PColor1)1; GA+=(Color & 0xFF00FF00)8)*pm3_8; BR+=(Color & 0x00FF00FF)*pm3_8; *(unsigned long*)(result)=(GA & 0xFF00FF00)|(BR & 0xFF00FF00)8); inline void Bilinear_Border_Common(const TPicRegion& pic,const long x_16,const long y_16,TARGB32* result) long x=(x_1616); long y=(y_1616); unsigned lo

32、ng u_16=(unsigned short)(x_16); unsigned long v_16=(unsigned short)(y_16); TARGB32 pixel4; pixel0=Pixels_Bound(pic,x,y); pixel1=Pixels_Bound(pic,x+1,y); pixel2=Pixels_Bound(pic,x,y+1); pixel3=Pixels_Bound(pic,x+1,y+1); Bilinear_Fast_Common(&pixel0,&pixel2,u_168,v_168,result); void PicZoom_Bilinear_C

33、ommon(const TPicRegion& Dst,const TPicRegion& Src) if ( (0=Dst.width)|(0=Dst.height) |(0=Src.width)|(0=Src.height) return; long xrIntFloat_16=(Src.width)16)/Dst.width+1; long yrIntFloat_16=(Src.height)16)/Dst.height+1; const long csDErrorX=-(11); const long csDErrorY=-(11); unsigned long dst_width=D

34、st.width; /计算出需要特殊处理的边界 long border_y0=-csDErrorY/yrIntFloat_16+1; /y0+y*yr=0; y0=csDErrorY = y=-csDErrorY/yr if (border_y0=Dst.height) border_y0=Dst.height; long border_x0=-csDErrorX/xrIntFloat_16+1; if (border_x0=Dst.width ) border_x0=Dst.width; long border_y1=(Src.height-2)16)-csDErrorY)/yrIntFlo

35、at_16+1; /y0+y*yr y=(height-2-csDErrorY)/yr if (border_y1border_y0) border_y1=border_y0; long border_x1=(Src.width-2)16)-csDErrorX)/xrIntFloat_16+1; if (border_x1border_x0) border_x1=border_x0; TARGB32* pDstLine=Dst.pdata; long Src_byte_width=Src.byte_width; long srcy_16=csDErrorY; long y; for (y=0;

36、yborder_y0;+y) long srcx_16=csDErrorX; for (unsigned long x=0;xdst_width;+x) Bilinear_Border_Common(Src,srcx_16,srcy_16,&pDstLinex); /border srcx_16+=xrIntFloat_16; srcy_16+=yrIntFloat_16; (TUInt8*&)pDstLine)+=Dst.byte_width; for (y=border_y0;yborder_y1;+y) long srcx_16=csDErrorX; long x; for (x=0;x8; TARGB32* PSrcLineColor= (TARGB32*)(TUInt8*)(Src.pdata)+Src_byte_width*(srcy_1616) ; for (unsigned long x=border_x0;x16; TARGB32* PColor1=(TARGB32*)(TUInt8*)(PColor0)+Src_byte_width); Bilinear_Fast_Common(PColor0,PColor1,(srcx_16 & 0x

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论