c语言实现图像的旋转与平移.docx
- 文档编号:4815759
- 上传时间:2022-12-09
- 格式:DOCX
- 页数:18
- 大小:19.62KB
c语言实现图像的旋转与平移.docx
《c语言实现图像的旋转与平移.docx》由会员分享,可在线阅读,更多相关《c语言实现图像的旋转与平移.docx(18页珍藏版)》请在冰豆网上搜索。
c语言实现图像的旋转与平移
实验二图象的几何变换参考资料
1平移
平移(translation)变换是几何变换中最简单的一种。
初始坐标为(x,y)的点经过平移(t,t)(以向
0
0
xy
右,向下为正方向)后,坐标变为(x,y)。
这两点之间的关系是x=x+t,y=y+t。
1
1
1
0
x
1
0
y
下面给出Translation的源代码。
算法的思想是先将所有区域填成白色,然后找平移后显示
区域的左上角点(x,y)和右下角点(x,y),分几种情况进行处理。
0
0
1
1
先看x方向(width指图象的宽度)
(1)
(2)
tx≤-width:
很显然,图象完全移出了屏幕,不用做任何处理;
-width 图象区域的x范围从0到width-|tx|,对应原图的范围从|tx|到width; (3)0 图象区域的x范围从t到width,对应原图的范围从0到width-t; xxx (4) tx≥width: 图象完全移出了屏幕,不用做任何处理。 y方向是对应的(height表示图象的高度): (1) (2) (3) (4) ty≤-height,图象完全移出了屏幕,不用做任何处理; -height y y y 0 y y y ty≥height,图象完全移出了屏幕,不用做任何处理。 这种做法利用了位图存储的连续性,即同一行的象素在内存中是相邻的。 利用memcpy函数, 从(x,y)点开始,一次可以拷贝一整行(宽度为x-x),然后将内存指针移到(x,y+1)处,拷 0 0 1 0 0 0 贝下一行。 这样拷贝(y-y)行就完成了全部操作,避免了一个一个象素的计算,提高了效率。 1 0 Translation的源代码如下: int xOffset=0,yOffset=0; BOOLTranslation(HWNDhWnd) { DLGPROC dlgInputBox=NULL; OffBits,BufSize; lpImgData; DWORD LPBITMAPINFOHEADER LPSTR lpPtr; HLOCAL hTempImgData; lpTempImgData; lpTempPtr; LPBITMAPINFOHEADER LPSTR int SrcX0,SrcY0,SrcX1,SrcY1; DstX0,DstY0,DstX1,DstY1; RectWidth,RectHeight; xVisible,yVisible; hDc; int int BOOL HDC HFILE int hf; 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,"Errorallocmemory! ","ErrorMessage",MB_OK| MB_ICONEXCLAMATION); returnFALSE;//失败,返回 } //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; elseif(xOffset<=0){ DstX0=0;//表示移动后,有图区域的左上角点的x坐标 DstX1=bi.biWidth+xOffset;//表示移动后,有图区域的右下角点的x坐标 } elseif(xOffset DstX0=xOffset; 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; elseif(yOffset<=0){ DstY0=0;//表示移动后,有图区域的左上角点的y坐标 DstY1=bi.biHeight+yOffset;//表示移动后,有图区域的右下角点的y坐标 } elseif(yOffset 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 //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(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); returnTRUE; } 2旋转 首先给出变换矩阵。 在我们熟悉的坐标系中,将一个点顺时针旋转a角后的坐标变换,r为 该点到原点的距离,在旋转过程中,r保持不变;b为r与x轴之间的夹角。 旋转前: x=rcosb;y=rsinb 0 0 旋转a角度后: x1=rcos(b-a)=rcosbcosa+rsinbsina=xcosa+ysina; 0 0 y1=rsin(b-a)=rsinbcosa-rcosbsina=-xsina+ycosa; 0 0 上面的公式中,坐标系xoy是以图象的中心为原点,向右为x轴正方向,向上为y轴正方向。 设图象的宽为w,高为h。 把变换分成三步: 1.将坐标系o’变成o; 2.将该点顺时针旋转a角; 3.将坐标系o变回o’,这样,我们就得到了变换矩阵,是上面三个矩阵的级联。 w,h,wnew,hnew分别表示原图(old)和新图(new)的宽、高。 wnew=max(|x-x|,|x-x|); old old 4 1 3 2 hnew=max(|y-y|,|y-y|)。 4 1 3 2 源程序如下: #definePI3.1415926535 #defineRADIAN(angle)((angle)*PI/180.0)//角度到弧度转化的宏 BOOLRotation(HWNDhWnd) { DLGPROC dlgInputBox=NULL; DWORD OffBits,SrcBufSize,DstBufSize,DstLineBytes; LPBITMAPINFOHEADER lpImgData; LPSTR lpPtr; HLOCAL hTempImgData; lpTempImgData; lpTempPtr; LPBITMAPINFOHEADER LPSTR float SrcX1,SrcY1,SrcX2,SrcY2; SrcX3,SrcY3,SrcX4,SrcY4; DstX1,DstY1,DstX2,DstY2; DstX3,DstY3,DstX4,DstY4; Wold,Hold,Wnew,Hnew; hDc; float float float DWORD HDC HFILE hf; DWORD x0,y0,x1,y1; float cosa,sina;//cos(a),sin(a); num1,num2; float BITMAPFILEHEADER BITMAPINFOHEADER DstBf; DstBi; //出现对话框,输入旋转角度(顺时针方向) dlgInputBox=(DLGPROC)MakeProcInstance((FARPROC)InputBox,ghInst); DialogBox(ghInst,"INPUTBOX",hWnd,dlgInputBox); FreeProcInstance((FARPROC)dlgInputBox); //角度到弧度的转化 RotateAngle=(float)RADIAN(RotateAngle); cosa=(float)cos((double)RotateAngle); sina=(float)sin((double)RotateAngle); //原图的宽度和高度 Wold=bi.biWidth; Hold=bi.biHeight; //原图的四个角的坐标 SrcX1=(float)(-0.5*Wold); SrcY1=(float)(0.5*Hold); SrcX2=(float)(0.5*Wold); SrcY2=(float)(0.5*Hold); SrcX3=(float)(-0.5*Wold); SrcY3=(float)(-0.5*Hold); SrcX4=(float)(0.5*Wold); SrcY4=(float)(-0.5*Hold); //新图四个角的坐标 DstX1=cosa*SrcX1+sina*SrcY1; DstY1=-sina*SrcX1+cosa*SrcY1; DstX2=cosa*SrcX2+sina*SrcY2; DstY2=-sina*SrcX2+cosa*SrcY2; DstX3=cosa*SrcX3+sina*SrcY3; DstY3=-sina*SrcX3+cosa*SrcY3; DstX4=cosa*SrcX4+sina*SrcY4; DstY4=-sina*SrcX4+cosa*SrcY4; //计算新图的宽度,高度 Wnew=(DWORD)(max(fabs(DstX4-DstX1),fabs(DstX3-DstX2))+0.5); Hnew=(DWORD)(max(fabs(DstY4-DstY1),fabs(DstY3-DstY2))+0.5); //计算矩阵(2.9)中的两个常数,这样不用以后每次都计算了 num1=(float)(-0.5*Wnew*cosa-0.5*Hnew*sina+0.5*Wold); num2=(float)(0.5*Wnew*sina-0.5*Hnew*cosa+0.5*Hold); //OffBits为BITMAPINFOHEADER结构长度加调色板的大小 OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER); SrcBufSize=OffBits+bi.biHeight*LineBytes; //显示时,采用新图的宽度和高度, ImgWidth=Wnew; ImgHeight=Hnew; //新图每行占用的字节 DstLineBytes=(DWORD)WIDTHBYTES(Wnew*bi.biBitCount); DstBufSize=(DWORD)(sizeof(BITMAPINFOHEADER)+ NumColors*sizeof(RGBQUAD)+ (DWORD)DstLineBytes*Hnew);//要开的缓冲区的大小 //为新产生的位图分配缓冲区内存 if((hTempImgData=LocalAlloc(LHND,DstBufSize))==NULL) { MessageBox(hWnd,"Errorallocmemory! ","ErrorMessage", MB_OK|MB_ICONEXCLAMATION); returnFALSE;//失败,返回 } //lpImgData为指向原来位图数据的指针 lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData); //lpTempImgData为指向新产生位图数据的指针 lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData); lpPtr=(char*)lpImgData; lpTempPtr=(char*)lpTempImgData; //将新的缓冲区中的每个字节都填成255,这样以后未处理的象素就是白色 memset(lpTempPtr,(BYTE)255,DstBufSize); //拷贝头和调色板信息 memcpy(lpTempPtr,lpPtr,OffBits); //得到新的BITMAPFILEDER和BITMAPINFOHERDER memcpy((char*)&DstBf,(char*)&bf,sizeof(BITMAPFILEHEADER)); memcpy((char*)&DstBi,(char*)&bi,sizeof(BITMAPINFOHEADER)); //做一些必要的改变,这一点特别要注意 DstBf.bfSize=DstBufSize+sizeof(BITMAPFILEHEADER); DstBi.biWidth=Wnew; DstBi.biHeight=Hnew; //用新的BITMAPINFOHERDER覆盖原来的那个 memcpy(lpTempPtr,(char*)&DstBi,sizeof(BITMAPINFOHEADER)); for(y1=0;y1 for(x1=0;x1 //x0,y0为对应的原图上的坐标 x0=(DWORD)(x1*cosa+y1*sina+num1); y0=(DWORD)(-1.0f*x1*sina+y1*cosa+num2); if((x0>=0)&&(x0 //在原图范围内 { lpPtr=(char*)lpImgData+ (SrcBufSize-LineBytes-y0*LineBytes)+x0; lpTempPtr=(char*)lpTempImgData+ (DstBufSize-DstLineBytes-y1*DstLineBytes)+x1; *lpTempPtr=*lpPtr;//进行象素的复制 } } 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: \\rotation.bmp",0); _lwrite(hf,(LPSTR)&DstBf,sizeof(BITMAPFILEHEADER)); _lwrite(hf,(LPSTR)lpTempImgData,DstBufSize); _lclose(hf); //释放资源和内存 ReleaseDC(hWnd,hDc); LocalUnlock(hTempImgData); LocalFree(hTempImgData); GlobalUnlock(hImgData); returnTRUE; } 3缩放 假设放大因子为ratio,(为了避免新图过大或过小,我们在程序中限制0.25≤ratio≤4)。 缩放变换的源代码如下。 floatZoomRatio=0.25f;//缩放比例,初始化为0.25 BOOLZoom(HWNDhWnd) { DLGPROC dlgInputBox=NULL; DWORD OffBits,SrcBufSize,DstBufSize,DstLineBytes; LPBITMAPINFOHEADER LPSTR lpImgData; lpPtr; HLOCAL hTempImgData; LPBITMAPINFOHEADER lpTempImgData; LPSTR lpTempPtr; DWORD HDC Wold,Hold,Wnew,Hnew; hDc; hf; HFILE DWORD x0,y0,x1,y1; num1; float BITMAPFILEHEADER BITMAPINFOHEADER //出现对话框,输入缩放比例 DstBf; DstBi; dlgInputBox=(DLGPROC)MakeProcInstance((FARPROC)InputBox,ghInst); DialogBox(ghInst,"INPUTBOX",hWnd,dlgInputBox); FreeProcInstance((FARPROC)dlgInputBox); num1=(float)(1.0/ZoomRatio); //原图宽度和高度 Wold=bi.biWidth; Hold=bi.biHeight; //新图宽度和高度 Wnew=(DWORD)(Wold*ZoomRatio+0.5); Hnew=(DWORD)(Hold*ZoomRatio+0.5); OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER); SrcBufSize=OffBits+bi.biHeight*LineBytes; ImgWidth=Wnew; ImgHeight=Hnew; DstLineBytes=(DWORD)WIDTHBYTES(Wnew*bi.biBitCount); DstBufSize=(DWORD)(sizeof(BITMAPINFOHEADER)+ NumColors*sizeof(RGBQUAD)+ (DWORD)DstLineBytes*Hnew); if((hTempImgData=LocalAlloc(LHND,DstBufSize))==NULL) { MessageBox(hWnd,"Errorallocmemory! ","ErrorMessage",MB_OK| MB_ICONE
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 实现 图像 旋转 平移