当前位置:高等教育资讯网  >  中国高校课件下载中心  >  大学文库  >  浏览文档

《数字图象处理》第二章 图象的几何变换

资源类别:文库,文档格式:DOC,文档页数:23,文件大小:443.5KB,团购合买
这一章我们将介绍图象的几何变换,包括图象的平移、旋转、镜象变换、转置、放缩等。如 果你熟悉矩阵运算,你将发现,实现这些变换是非常容易的。
点击下载完整版文档(DOC)

第2章图象的几何变换 这一章我们将介绍图象的几何变换,包括图象的平移、旋转、镜象变换、转置、放缩等。如 果你熟悉矩阵运算,你将发现,实现这些变换是非常容易的 21平移 平移( translation)变换大概是几何变换中最简单的一种了 如图2.1所示,初始坐标为(X,yo)的点经过平移tt以向右,向下为正方向)后,坐标变为 (x1y1)。这两点之间的关系是x1=x0+t,y=yo+t。 图21平移的示意图 以矩阵的形式表示为 1010 (2.1) 我们更关心的是它的逆变换: y1]-{x1y 01t 这是因为:我们想知道的是平移后的图象中每个象素的颜色。例如我们想知道,新图中左上 角点的RGB值是多少?很显然,该点是原图的某点经过平移后得到的,这两点的颜色肯定 是一样的,所以只要知道了原图那点的RGB值即可。那么到底新图中的左上角点对应原图 中的哪一点呢?将左上角点的坐标(0,0)入公式(22),得到x=t,yo=t;所以新图中的(00) 点的颜色和原图中(-tk,t)的一样。 这样就存在一个问题:如果新图中有一点(x1,y),按照公式(22)得到的(xyo)不在原图中该 怎么办?通常的做法是,把该点的RGB值统一设成(0,0,0)或者(255,255,255

第 2 章 图象的几何变换 这一章我们将介绍图象的几何变换,包括图象的平移、旋转、镜象变换、转置、放缩等。如 果你熟悉矩阵运算,你将发现,实现这些变换是非常容易的。 2.1 平移 平移(translation)变换大概是几何变换中最简单的一种了。 如图 2.1 所示,初始坐标为(x0,y0)的点经过平移(tx,ty)(以向右,向下为正方向)后,坐标变为 (x1,y1)。这两点之间的关系是 x1=x0+tx ,y1=y0+ty。 图 2.1 平移的示意图 以矩阵的形式表示为 (2.1) 我们更关心的是它的逆变换: (2.2) 这是因为:我们想知道的是平移后的图象中每个象素的颜色。例如我们想知道,新图中左上 角点的 RGB 值是多少?很显然,该点是原图的某点经过平移后得到的,这两点的颜色肯定 是一样的,所以只要知道了原图那点的 RGB 值即可。那么到底新图中的左上角点对应原图 中的哪一点呢?将左上角点的坐标(0,0)入公式(2.2),得到 x0=-tx ,y0=-ty;所以新图中的(0,0) 点的颜色和原图中(-tx , -ty)的一样。 这样就存在一个问题:如果新图中有一点(x1,y1),按照公式(2.2)得到的(x0,y0)不在原图中该 怎么办?通常的做法是,把该点的 RGB 值统一设成(0,0,0)或者(255,255,255)

另一个问题是:平移后的图象是否要放大?一种做法是不放大,移出的部分被截断。例如, 图22为原图,图23为移动后的图。这种处理,文件大小不会改变 图22移动前的图 图23移动后的图 还有一种做法是:将图象放大,使得能够显示下所有部分,如图24所示 图24移动后图象被放大 这种处理,文件大小要改变。设原图的宽和高分别是w,h则新图的宽和高变为w+tx和 h+,加绝对值符号是因为txt有可能为负(即向左,向上移动)。 下面的函数 Translation采用的是第一种做法,即移出的部分被截断。在给出源代码之前, 先说明一个问题

另一个问题是:平移后的图象是否要放大?一种做法是不放大,移出的部分被截断。例如, 图 2.2 为原图,图 2.3 为移动后的图。这种处理,文件大小不会改变。 图 2.2 移动前的图 图 2.3 移动后的图 还有一种做法是:将图象放大,使得能够显示下所有部分,如图 2.4 所示。 图 2.4 移动后图象被放大 这种处理,文件大小要改变。设原图的宽和高分别是 w1,h1 则新图的宽和高变为 w1+|tx|和 h1+|ty|,加绝对值符号是因为 tx, ty 有可能为负(即向左,向上移动)。 下面的函数 Translation 采用的是第一种做法,即移出的部分被截断。在给出源代码之前, 先说明一个问题

如果你用过 Photoshop, Corel PhotoPaint等图象处理软件,可能听说过“灰度图”( grayscale) 这个词。灰度图是指只含亮度信息,不含色彩信息的图象,就象我们平时看到的黑白照片: 亮度由暗到明,变化是连续的。因此,要表示灰度图,就需要把亮度值进行量化。通常划分 成0到255共256个级别,其中0最暗(全黑),255最亮(全白)。bmp格式的文件中,并没 有灰度图这个概念,但是,我们可以很容易在bmp文件中表示灰度图。方法是用256色的 调色板,只不过这个调色板有点特殊,每一项的RGB值都是相同的。也就是说RGB值从(0, 0,0),(1,1,1)一直到(255,255,255)。(0,0,0)是全黑色,(255,255,255是全白色 中间的是灰色。这样,灰度图就可以用256色图来表示了。为什么会这样呢?难道是一种巧 合?其实并不是 在表示颜色的方法中,除了RGB外,还有一种叫YUV的表示方法,应用也很多。电视信 号中用的就是一种类似于YUV的颜色表示方法 在这种表示方法中,Y分量的物理含义就是亮度,U和V分量代表了色差信号(你不必了解 什么是色差,只要知道有这么一个概念就可以了)。使用这种表示方法有很多好处,最主要 的有两点: (1)因为Y代表了亮度,所以Y分量包含了灰度图的所有信息,只用Y分量就能完全能够 表示出一幅灰度图来。当同时考虑U,V分量时,就能够表示出彩色信息来。这样,用同 种表示方法可以很方便的在灰度和彩色图之间切换,而RGB表示方法就做不到这一点了。 (2)人眼对于亮度信号非常敏感,而对色差信号的敏感程度相对较弱。也就是说,图象的主 要信息包含在Y分量中。这就提示我们:如果在对YUV信号进行量化时,可以“偏心 点,让Y的量化级别多一些(谁让它重要呢?)而让UV的量化级别少一些,就可以实现图象 信息的压缩。这一点将在第9章介绍图象压缩时仔细研究,这里就不深入讨论了。而RGB 的表示方法就做不到这一点,因为RGB三个分量同等重要,缺了谁也不行。YUV和RGB 之间有着如下的对应关系 299-0.1480.615 pu- IGBo.37-0289-0551 0.11404 0.100 (23) RGB]-pU003952032 1.140-05810 (2.4) 当RGB三个分量的大小一样时,假设都是a,代入公式(23),得到Y=a,U=0,V=0。你 现在该明白我前面所说不是巧合的原因了吧 使用灰度图有一个好处,那就是方便。首先RGB的值都一样;其次,图象数据即调色板索 引值,也就是实际的RGB值,也就是亮度值;另外,因为是256色调色板,所以图象数据 中一个字节代表一个象素,很整齐。如果是2色图或16色图,还要拼凑字节,很麻烦。如 果是彩色的256色图,由于图象处理后有可能会产生不属于这256种颜色的新颜色,就更麻

如果你用过 Photoshop,Corel PhotoPaint 等图象处理软件,可能听说过“灰度图”(grayscale) 这个词。灰度图是指只含亮度信息,不含色彩信息的图象,就象我们平时看到的黑白照片: 亮度由暗到明,变化是连续的。因此,要表示灰度图,就需要把亮度值进行量化。通常划分 成 0 到 255 共 256 个级别,其中 0 最暗(全黑),255 最亮(全白)。.bmp 格式的文件中,并没 有灰度图这个概念,但是,我们可以很容易在.bmp 文件中表示灰度图。方法是用 256 色的 调色板,只不过这个调色板有点特殊,每一项的 RGB 值都是相同的。也就是说 RGB 值从(0, 0,0),(1,1,1)一直到(255,255,255)。(0,0,0)是全黑色,(255,255,255)是全白色, 中间的是灰色。这样,灰度图就可以用 256 色图来表示了。为什么会这样呢?难道是一种巧 合?其实并不是。 在表示颜色的方法中,除了 RGB 外,还有一种叫 YUV 的表示方法,应用也很多。电视信 号中用的就是一种类似于 YUV 的颜色表示方法。 在这种表示方法中,Y 分量的物理含义就是亮度,U 和 V 分量代表了色差信号(你不必了解 什么是色差,只要知道有这么一个概念就可以了)。使用这种表示方法有很多好处,最主要 的有两点: (1) 因为 Y 代表了亮度,所以 Y 分量包含了灰度图的所有信息,只用 Y 分量就能完全能够 表示出一幅灰度图来。当同时考虑 U,V 分量时,就能够表示出彩色信息来。这样,用同一 种表示方法可以很方便的在灰度和彩色图之间切换,而 RGB 表示方法就做不到这一点了。 (2) 人眼对于亮度信号非常敏感,而对色差信号的敏感程度相对较弱。也就是说,图象的主 要信息包含在 Y 分量中。这就提示我们:如果在对 YUV 信号进行量化时,可以“偏心”一 点,让 Y 的量化级别多一些(谁让它重要呢?)而让 UV 的量化级别少一些,就可以实现图象 信息的压缩。这一点将在第 9 章介绍图象压缩时仔细研究,这里就不深入讨论了。而 RGB 的表示方法就做不到这一点,因为 RGB 三个分量同等重要,缺了谁也不行。YUV 和 RGB 之间有着如下的对应关系 (2.3) (2.4) 当 RGB 三个分量的大小一样时,假设都是 a,代入公式(2.3),得到 Y=a,U=0,V=0 。你 现在该明白我前面所说不是巧合的原因了吧。 使用灰度图有一个好处,那就是方便。首先 RGB 的值都一样;其次,图象数据即调色板索 引值,也就是实际的 RGB 值,也就是亮度值;另外,因为是 256 色调色板,所以图象数据 中一个字节代表一个象素,很整齐。如果是 2 色图或 16 色图,还要拼凑字节,很麻烦。如 果是彩色的 256 色图,由于图象处理后有可能会产生不属于这 256 种颜色的新颜色,就更麻

烦了:这一点,今后你就会有深刻体会的。所以,做图象处理时,一般采用灰度图。为了将 重点放在算法本身上,今后给出的程序如不做特殊说明,都是针对256级灰度图的。其它 颜色的情况,你可以自己想一想,把算法补全。 如果想得到一幅灰度图,可以使用Sea或者 PhotoShop等软件提供的颜色转换功能将彩色图 转换成灰度图。 好了,言归正传,下面给出 Translation的源代码。算法的思想是先将所有区域填成白色, 然后找平移后显示区域的左上角点(xo,yo)和右下角点(x1,y),分几种情况进行处理。 先看ⅹ方向( width指图象的宽度) (1)t≤- width:很显然,图象完全移出了屏幕,不用做任何处理 (2) width<tx≤0:如图2.5所示。容易看出,图象区域的ⅹ范围从0到wdth-tx,对应原图 的范围从tx到 width Meoe 图2.5tx≤0,ty≤0的情况 (3)0<tx< width:如图26所示。容易看出,图象区域的x范围从t到 width,对应原图的 范围从0到 width-tx;

烦了;这一点,今后你就会有深刻体会的。所以,做图象处理时,一般采用灰度图。为了将 重点放在算法本身上,今后给出的程序如不做特殊说明,都是针对 256 级灰度图的。其它 颜色的情况,你可以自己想一想,把算法补全。 如果想得到一幅灰度图,可以使用 Sea 或者 PhotoShop 等软件提供的颜色转换功能将彩色图 转换成灰度图。 好了,言归正传,下面给出 Translation 的源代码。算法的思想是先将所有区域填成白色, 然后找平移后显示区域的左上角点(x0,y0) 和右下角点(x1,y1) ,分几种情况进行处理。 先看 x 方向(width 指图象的宽度) (1) tx≤-width:很显然,图象完全移出了屏幕,不用做任何处理; (2) -width<tx≤0:如图 2.5 所示。容易看出,图象区域的 x 范围从 0 到 width-|tx|,对应原图 的范围从|tx|到 width; 图 2.5 tx≤0,ty≤0 的情况 (3) 0< tx <width:如图 2.6 所示。容易看出,图象区域的 x 范围从 tx 到 width,对应原图的 范围从 0 到 width - tx ;

图260 tx<width,0< ty<height的情况 (4)ts≥ width:很显然,图象完全移出了屏幕,不用做任何处理。 y方向是对应的 height表示图象的高度) (1)t≤- height,图象完全移出了屏幕,不用做任何处理; (2)- height<t≤0,图象区域的y范围从0到 height-It对应原图的范围从到 height: (3)0<t< height,图象区域的y范围从t到 heigh对应原图的范围从0到 height-t, (4)t≥ height,图象完全移出了屏幕,不用做任何处理。 这种做法利用了位图存储的连续性,即同一行的象素在内存中是相邻的。利用 memcpy函数, 从(x0yo)点开始,一次可以拷贝一整行(宽度为x-xo),然后将内存指针移到(x,yo+1)处,拷 贝下一行。这样拷贝(y1-yo)行就完成了全部操作,避免了一个一个象素的计算,提高了效率。 Translation的源代码如下: int xOffset=0, yOffset=0 BOOL Translation( HWND hWnd) DLGPROC dIglnput Box=NULL LPBITMAPINFOHEADER IplmgData; LPSTR HLOCAL hTemplmgData LPBITMAPINFOHEADER IpTemplmg Data LPSTR IpTempPtr SrcXo. SrcYo. SrcXl. SrcY1 DstXo. DstYo. DstXl. styl

图 2.6 0< tx<width,0<ty<height 的情况 (4) tx ≥width:很显然,图象完全移出了屏幕,不用做任何处理。 y 方向是对应的(height 表示图象的高度): (1) ty≤-height,图象完全移出了屏幕,不用做任何处理; (2) -height<ty≤0,图象区域的 y 范围从 0 到 height-|ty|,对应原图的范围从|ty|到 height; (3) 0<ty<height ,图象区域的 y 范围从 ty 到 height,对应原图的范围从 0 到 height-ty; (4) ty≥height,图象完全移出了屏幕,不用做任何处理。 这种做法利用了位图存储的连续性,即同一行的象素在内存中是相邻的。利用 memcpy 函数, 从(x0,y0)点开始,一次可以拷贝一整行(宽度为 x1-x0),然后将内存指针移到(x0,y0+1)处,拷 贝下一行。这样拷贝(y1-y0)行就完成了全部操作,避免了一个一个象素的计算,提高了效率。 Translation 的源代码如下: int xOffset=0,yOffset=0; BOOL Translation(HWND hWnd) { DLGPROC dlgInputBox = NULL; DWORD OffBits,BufSize; LPBITMAPINFOHEADER lpImgData; LPSTR lpPtr; HLOCAL hTempImgData; LPBITMAPINFOHEADER lpTempImgData; LPSTR lpTempPtr; int SrcX0,SrcY0,SrcX1,SrcY1; int DstX0,DstY0,DstX1,DstY1; int RectWidth,RectHeight;

BOOL vIsible, y Visible: HDC HFILE ∥出现对话框,输入ⅹ偏移量 XOffset,和y偏移量 yOffset dIglnput Box=(DLGPROC) Make Proclnstance((FARPROC)Input Box, ghlnst ) Dialog Box(ghInst, "INPUTBOX",hWnd, dIglnput Box) FreeProclnstance((FARPROC)dIglnput Box ) OffBits为 BITMAPINFOHEADER结构长度加调色板的大小 OffBits=bf. bfOffBits-sizeof( BITMAPFILEHEADER) Bufsizes= OffBits+ bi. biHeight*LineBytes,/要开的缓冲区的大小 ∥新产生的位图分配缓冲区内存 if(hTemplmg Data=Local Alloc(LHND, BufSize))==NULL Message Box(hWnd, Error alloc memory! ", "Error Message", MB OK MB ICONEXCLAMATION) return false;∥失败,返回 IpIng Data为指向原来位图数据的指针 Iplmg Data=(LPBITMAPINFOHEADER)GlobalLock(hlmg Data) pTemplmg Data为指向新产生位图数据的指针 IpTemplmg Data=(LPBITMAPINFOHEADER)I ock(tEmp lpPtr(char *)lplmg Data lpTempPtr=(char *)Ip Data ∥将新的缓冲区中的每个字节都填成255,这样以后未处理的象素就是白色 memset(lpTempPtr, (BYTE)255, BufSize) ∥两幅图之间的头信息,包括调色板都是相同的,所以直接拷贝头和调色板 memcpy(lp TempPtr, IpPtr, OffBits); ∥ Visible为 FALSE时,表示x方向已经移出了可显示的范围 vIsible=trUe if( xOffset<=-bi bi Width) xVisiblesfalsI else if( xOffset<=0)1 DsXO=0,∥表示移动后,有图区域的左上角点的x坐标 DsX1=bi. bi width+ xOffset示移动后,有图区域的右下角点的x坐标 else if( xOffset<bi bi width)t DstXo=xoffset

BOOL xVisible,yVisible; HDC hDc; HFILE hf; int i; //出现对话框,输入 x 偏移量 xOffset,和 y 偏移量 yOffset dlgInputBox = (DLGPROC) MakeProcInstance ( (FARPROC)InputBox,ghInst ); DialogBox (ghInst, "INPUTBOX", hWnd, dlgInputBox); FreeProcInstance ( (FARPROC) dlgInputBox ); //OffBits 为 BITMAPINFOHEADER 结构长度加调色板的大小 OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER); BufSize=OffBits+bi.biHeight*LineBytes;//要开的缓冲区的大小 //为新产生的位图分配缓冲区内存 if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL) { MessageBox(hWnd,"Error alloc memory!","Error Message",MB_OK| MB_ICONEXCLAMATION); return FALSE; //失败,返回 } //lpImgData 为指向原来位图数据的指针 lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData); //lpTempImgData 为指向新产生位图数据的指针 lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData); lpPtr=(char *)lpImgData; lpTempPtr=(char *)lpTempImgData; //将新的缓冲区中的每个字节都填成 255,这样以后未处理的象素就是白色 memset(lpTempPtr,(BYTE)255,BufSize); //两幅图之间的头信息,包括调色板都是相同的,所以直接拷贝头和调色板 memcpy(lpTempPtr,lpPtr,OffBits); //xVisible 为 FALSE 时,表示 x 方向已经移出了可显示的范围 xVisible=TRUE; if( xOffset<= -bi.biWidth ) xVisible=FALSE; else if( xOffset<=0){ DstX0=0; //表示移动后,有图区域的左上角点的 x 坐标 DstX1=bi.biWidth+xOffset; //表示移动后,有图区域的右下角点的 x 坐标 } else if ( xOffset<bi.biWidth){ DstX0=xOffset;

DstXl=bi bi width else vIsible=fAlSE SrcX0=DstX0- XOffset;(应DstX0在原图中的x坐标 SrcX1=DstX1- xOffset应Dstx1在原图中的x坐标 Rect width=DsX1- IstO,∥有图区域的宽度 / y Visible为 FALSE时,表示y方向已经移出了可显示的范围 if( yoffset<=-bi bi Height y Visible=FALSE else if( yoffset<= DsYO=0,∥表示移动后,有图区域的左上角点的y坐标 DstY1= bi. biHeight+yOffset示移动后,有图区域的右下角点的y坐标 else if yOffset<bi. biHeight)( StyL=bi. biHeight else y Visible=FALSE SrcYo= DstYo- yOffset)应DstY0在原图中的y坐标 SrcY1= Styl- yOffset;应DstY1在原图中的y坐标 RectHeight=DsY1-DstY0;∥有图区域的高度 if( VIsible&& y Visible){/xy方向都没有完全移出可显示的范围 for(i=0;j< Rectheight: i++){∥拷贝每一行 pPr指向要拷贝的那一行的最左边的象素对应在原图中的位 ∥置。特别要注意的是,由于bmp是上下颠倒的,偏移是 ∥ Outsize- Line Bytes.(i+ SrcYo)+ Line Bytes)+SrcX0,而不是 ∥i+ SrcYo)+ Line bytes)+ SrcXO,你试着举个例子就明白了 lpPtr=(char*)Iplmg Data+(BufSize-Line Bytes- (i+SrcYO)*Line Bytes)+SrcX0; pTempPtr指向要拷贝的那一行的最左边的象素对应在新图中∥的位置。同样要注意上面∥ 的问题 IpTempPtr=(char )IpTemplmg Data+ BufSize-LineBytes-(i+Dst YO)*Line Bytes)+DstX0; ∥拷贝一行(宽度为 Rect width) memcpy(p TempPtr, IpPtr, RectWidth

DstX1=bi.biWidth; } else xVisible=FALSE; SrcX0=DstX0-xOffset; //对应 DstX0 在原图中的 x 坐标 SrcX1=DstX1-xOffset; //对应 DstX1 在原图中的 x 坐标 RectWidth=DstX1-DstX0; //有图区域的宽度 //yVisible 为 FALSE 时,表示 y 方向已经移出了可显示的范围 yVisible=TRUE; if( yOffset<= -bi.biHeight ) yVisible=FALSE; else if( yOffset<=0){ DstY0=0; //表示移动后,有图区域的左上角点的 y 坐标 DstY1=bi.biHeight+yOffset; //表示移动后,有图区域的右下角点的 y 坐标 } else if ( yOffset<bi.biHeight){ DstY0=yOffset; DstY1=bi.biHeight; } else yVisible=FALSE; SrcY0=DstY0-yOffset; //对应 DstY0 在原图中的 y 坐标 SrcY1=DstY1-yOffset; //对应 DstY1 在原图中的 y 坐标 RectHeight=DstY1-DstY0; //有图区域的高度 if( xVisible && yVisible){ //x,y 方向都没有完全移出可显示的范围 for(i=0;i<RectHeight;i++){ //拷贝每一行 //lpPtr 指向要拷贝的那一行的最左边的象素对应在原图中的位 //置。特别要注意的是,由于.bmp 是上下颠倒的,偏移是 //(BufSize-LineBytes-(i+SrcY0)*LineBytes)+SrcX0,而不是 //(i+SrcY0)*LineBytes)+SrcX0,你试着举个例子就明白了。 lpPtr=(char*)lpImgData+(BufSize-LineBytes- (i+SrcY0)*LineBytes)+SrcX0; //lpTempPtr 指向要拷贝的那一行的最左边的象素对应在新图中//的位置。同样要注意上面// 的问题。 lpTempPtr=(char*)lpTempImgData+ (BufSize-LineBytes-(i+DstY0)*LineBytes)+DstX0; //拷贝一行(宽度为 RectWidth) memcpy(lpTempPtr,lpPtr,RectWidth);

hDc=GetDC(hWnd) if(hBitmapl=NULL) DeleteObject( hBitmap),∥释放原来的位图句柄 ∥产生新的位图 hBitmap=CreateDI Bitmap(hDc, (LPBITMAPINFOHEADER)IpTemplmg Data, (LONG )CBM INIT (LPSTR)lp Templmg Data+ sizeof( BI TMAPINFOHEADER)+ Num Colors*sizeof(RGBQUAD) (LPBITMAPINFOIp TemplmgData DIB RGB COLORS) ∥将平移后的图象存成文件 hf- creat("c: I translation. bmp",O) Iwrite(hf, ( LPSTR)&bf, sizeof( BITMAPFILEHEADER)) Iwrite(hf, LPSTR)lp Templmg Data, BufSize) Iclose(hf); ∥释放资源和内存 ReleaseDC(hWnd, hDc) LocalUnlock(hTemplmg Data); ocal Free(hTemplmg Data) GlobalUnlock(hlmg Data) return trUE 22旋转 旋转( rotation)有一个绕着什么转的问题,通常的做法是以图象的中心为圆心旋转,举个例子, 图27旋转30度(顺时针方向)后如图28所示: 图27旋转前的图

} } hDc=GetDC(hWnd); if(hBitmap!=NULL) DeleteObject(hBitmap); //释放原来的位图句柄 //产生新的位图 hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData, (LONG)CBM_INIT, (LPSTR)lpTempImgData+ sizeof(BITMAPINFOHEADER) + NumColors*sizeof(RGBQUAD), (LPBITMAPINFO)lpTempImgData, DIB_RGB_COLORS); //将平移后的图象存成文件 hf=_lcreat("c:\\translation.bmp",0); _lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER)); _lwrite(hf,(LPSTR)lpTempImgData,BufSize); _lclose(hf); //释放资源和内存 ReleaseDC(hWnd,hDc); LocalUnlock(hTempImgData); LocalFree(hTempImgData); GlobalUnlock(hImgData); return TRUE; } 2.2 旋转 旋转(rotation)有一个绕着什么转的问题,通常的做法是以图象的中心为圆心旋转,举个例子, 图 2.7 旋转 30 度(顺时针方向)后如图 2.8 所示: 图 2.7 旋转前的图

图28旋转后的图 可以看出,旋转后图象变大了。另一种做法是不让图象变大,转出的部分被裁剪掉。如图 29所示。 我们采用第一种做法,首先给出变换矩阵。在我们熟悉的坐标系中,将一个点顺时针旋转a 角后的坐标变换公式,如图210所示,r为该点到原点的距离,在旋转过程中,r保持不变 b为r与ⅹ轴之间的夹角。 2(x1,yl) 图29旋转后保持原图大小, 转出的部分被裁掉 图210旋转示意图 旋转前:xo= cost;yo= rsinb 旋转a角度后: Xi=rcos(b-a)-rcosbcosatrsinbsina=xocosatyosina: yI=rsin(b-a) =rsinbcosa-rcosbsina-Xosina+yocosa 以矩阵的形式表示: xo vo sin a cosa 上面的公式中,坐标系Xoy是以图象的中心为原点,向右为x轴正方向,向上为y轴正方向 它和以图象左上角点为原点o,向右为x轴正方向,向下为y轴正方向的坐标系x'oy'之间 的转换关系如何呢?如图211所示。 图211两种坐标系间的转换关系 设图象的宽为w,高为h,容易得到

图 2.8 旋转后的图 可以看出,旋转后图象变大了。另一种做法是不让图象变大,转出的部分被裁剪掉。如图 2.9 所示。 我们采用第一种做法,首先给出变换矩阵。在我们熟悉的坐标系中,将一个点顺时针旋转 a 角后的坐标变换公式,如图 2.10 所示,r 为该点到原点的距离,在旋转过程中,r 保持不变; b 为 r 与 x 轴之间的夹角。 图 2.9 旋转后保持原图大小, 转出的部分被裁掉 图 2.10 旋转示意图 旋转前:x0=rcosb;y0=rsinb 旋转 a 角度后: x1=rcos(b-a)=rcosbcosa+rsinbsina=x0cosa+y0sina; y1=rsin(b-a)=rsinbcosa-rcosbsina=-x0sina+y0cosa; 以矩阵的形式表示: (2.5) 上面的公式中,坐标系 xoy 是以图象的中心为原点,向右为 x 轴正方向,向上为 y 轴正方向。 它和以图象左上角点为原点 o’,向右为 x’轴正方向,向下为 y’轴正方向的坐标系 x’o’y’之间 的转换关系如何呢?如图 2.11 所示。 图 2.11 两种坐标系间的转换关系 设图象的宽为 w,高为 h,容易得到:

0.5w0.5k 逆变换为: 0.50.5k1 (2.7) 有了上面的公式,我们可以把变换分成三步: 1将坐标系o变成o: 2将该点顺时针旋转a角; 3将坐标系o变回o’,这样,我们就得到了变换矩阵,是上面三个矩阵的级联。 K, 3 1=[y 05H05} Sina 0.5w cosa+0.5h sina+0.5wnew-05we sina-0 5hy cosa+0.5h (28) 要注意的是,因为新图变大,所以上面公式中出现了wo,hos,we,hew,它们分别表示 原图(od)和新图(new)的宽、高。我们从图28中容易看出:wnew=max(x4-x|kx-x2) new=max(ly4-y1l, ly3-y2)) (2.8)的逆变换为 cosa Sin a [oy。1]=[z1乃1 10 sina cosa 0‖l0 -05w-05-址 5w0.5 coSa - Sin a 0.5wnew cos a-0. hnew, sin a+0. Swo 0. wnew sin a-0.5hmewC0sa+0.how 1) (2.9) 这样,对于新图中的每一点,我们就可以根据公式(29)求出对应原图中的点,得到它的灰度。 如果超出原图范围,则填成白色。要注意的是,由于有浮点运算,计算出来点的坐标可能不 是整数,采用取整处理,即找最接近的点,这样会带来一些误差(图象可能会出现锯齿)。更 精确的方法是采用插值,将在图象缩放时介绍 源程序如下: # define pl3.1415926535

(2.6) 逆变换为: (2.7) 有了上面的公式,我们可以把变换分成三步: 1.将坐标系 o’变成 o; 2.将该点顺时针旋转 a 角; 3.将坐标系 o 变回 o’,这样,我们就得到了变换矩阵,是上面三个矩阵的级联。 (2.8) 要注意的是,因为新图变大,所以上面公式中出现了 wold,hold,wnew,hnew,它们分别表示 原图(old)和新图(new)的宽、高。我们从图 2.8 中容易看出:wnew=max(|x4-x1|,|x3-x2|) ; hnew=max(|y4-y1|,|y3-y2|)。 (2.8)的逆变换为 (2.9) 这样,对于新图中的每一点,我们就可以根据公式(2.9)求出对应原图中的点,得到它的灰度。 如果超出原图范围,则填成白色。要注意的是,由于有浮点运算,计算出来点的坐标可能不 是整数,采用取整处理,即找最接近的点,这样会带来一些误差(图象可能会出现锯齿)。更 精确的方法是采用插值,将在图象缩放时介绍。 源程序如下: #define PI 3.1415926535

点击下载完整版文档(DOC)VIP每日下载上限内不扣除下载券和下载次数;
按次数下载不扣除下载券;
24小时内重复下载只扣除一次;
顺序:VIP每日次数-->可用次数-->下载券;
共23页,试读已结束,阅读完整版请下载
相关文档

关于我们|帮助中心|下载说明|相关软件|意见反馈|联系我们

Copyright © 2008-现在 cucdc.com 高等教育资讯网 版权所有