首页 MFC空间几何变换之图像平移、镜像、旋转、缩放详解

MFC空间几何变换之图像平移、镜像、旋转、缩放详解

举报
开通vip

MFC空间几何变换之图像平移、镜像、旋转、缩放详解MFC空间几何变换之图像平移、镜像、旋转、缩放详解 一. 图像平移 前一篇文章讲述了图像点运算(基于像素的图像变换),这篇文章讲述的是图像几何变换:在不改变图像内容的情况下对图像像素进行空间几何变换的处理方式。 点运算对单幅图像做处理,不改变像素的空间位置;代数运算对多幅图像做处理,也不改变像素的空间位置;几何运算对单幅图像做处理,改变像素的空间位置,几何运算包括两个独立的算法:空间变换算法和灰度级插值算法。 空间变换操作包括简单空间变换、多项式卷绕和几何校正、控制栅格插值和图像卷绕,这里主要讲述简单的空间变换,...

MFC空间几何变换之图像平移、镜像、旋转、缩放详解
MFC空间几何变换之图像平移、镜像、旋转、缩放详解 一. 图像平移 前一篇文章讲述了图像点运算(基于像素的图像变换),这篇文章讲述的是图像几何变换:在不改变图像内容的情况下对图像像素进行空间几何变换的处理方式。 点运算对单幅图像做处理,不改变像素的空间位置;代数运算对多幅图像做处理,也不改变像素的空间位置;几何运算对单幅图像做处理,改变像素的空间位置,几何运算包括两个独立的算法:空间变换算法和灰度级插值算法。 空间变换操作包括简单空间变换、多项式卷绕和几何校正、控制栅格插值和图像卷绕,这里主要讲述简单的空间变换,如图像平移、镜像、缩放和旋转。主要是通过线性代数中的齐次坐标变换。 图像平移坐标变换如下: 运行效果如下图所示,其中BMP图片(0,0)像素点为左下角。 其代码核心算法: 1.在对话框中输入平移坐标(x,y) m_xPY=x,m_yPY=y 2.定义Place=dlg.m_yPY*m_nWidth*3 表示当前m_yPY行需要填充为黑色 3.新建一个像素矩阵 ImageSize=new unsigned char[m_nImage] 4.循环整个像素矩阵处理 for(int i=0 ; i=Place && countWidth=Place && countWidth>=dlg.m_xPY*3) {//图像像素平移区域 ImageSize[i]=m_pImage[m_pImagePlace];//原(0,0)像素赋值过去 m_pImagePlace++; countWidth++; if(countWidth==m_nWidth*3) { //一行填满 m_pImagePlace走到(0,1) number++; m_pImagePlace=number*m_nWidth*3; } } } 5.写文件绘图fwrite(ImageSize,m_nImage,1,fpw) 第一步:在ResourceView资源视图中,添加Menu子菜单如下:(注意ID号) 第二步:设置平移对话框。将试图切换到ResourceView界面--选中Dialog,右键鼠标新建一个Dialog,并新建一个名为IDD_DIALOG_PY。编辑框(X)IDC_EDIT_PYX 和(Y)IDC_EDIT_PYY,确定为默认按钮。设置成下图对话框: 第三步:在对话框资源模板空白区域双击鼠标—Create a new class创建一个新类--命名为CImagePYDlg。会自动生成它的.h和.cpp文件。打开类向导(Ctrl W),选择类名:CImagePYDlg添加成员变量如下图所示,同时在Message Maps中生成ID_JHBH_PY实现函数。 第四步:在CImageProcessingView.cpp中添加头文件#include "ImagePYDlg.h",并实现平移。[cpp]view plain copy 1./********************************************************/ 2./* 图像空间几何变换:图像平移 ID_JHBH_PY(几何变换-平移) 3./* 使用平移对话框:CImagePYDlg dlg 4./* 算法:f(x,y)=f(x+x0,y+y0)图像所有点平移,空的补黑'0' 5./* 注意该图像平移方法只是从左上角(0,0)处开始平移 6./* 其他方向原理相同自己去实现 7./********************************************************/ 8. 9.void CImageProcessingView::OnJhbhPy() 10.{ 11.if(numPicture==0) { 12. AfxMessageBox("载入图片后才能空间平移!",MB_OK,0); 13.return; 14. } 15.//定义采样对话框也是用来空间变换平移的坐标 16. CImagePYDlg dlg; 17.if( dlg.DoModal()==IDOK ) //显示对话框 18. { 19.//采样坐标最初为图片的自身像素 20.if( dlg.m_xPY>m_nWidth || dlg.m_yPY>m_nHeight ) { 21. AfxMessageBox("图片平移不能为超过原图长宽!",MB_OK,0); 22.return; 23. } 24. AfxMessageBox("图片空间变换-平移!",MB_OK,0); 25. 26.//打开临时的图片读写文件 27.FILE *fpo = fopen(BmpName,"rb"); 28.FILE *fpw = fopen(BmpNameLin,"wb+"); 29. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo); 30. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo); 31. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw); 32. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw); 33. fread(m_pImage,m_nImage,1,fpo); 34. 35./************************************************************/ 36./* 图片空间变换-平移 37. /* 坐标(dlg.m_xPY,dlg.m_yPY)表示图像平移的坐标 38. /* 先用Plave计算出平移后的起始坐标,其他的坐标赋值为'0'黑色 39. /* 然后依次平移坐标,空的赋为黑色,否则填充 40. /************************************************************/ 41. 42./******************************************************************/ 43./* 严重错误1:数组变量赋值相等 44. /* 在View.h中定义变量 BYTE *m_pImage 读入图片数据后的指针 45. /* 建立临时变量数组,让它平移变换 unsigned char *ImageSize 46. /* ImageSize=m_pImage(错误) 47. /* 会导致ImageSize赋值变换时m_pImage也产生了变换,所以输出全为黑色 48. /* 因为它俩指向了相同的数组地址 49. /* 解决方法:使用下面C++的new方法动态分配或for循环i=m_nImage赋值 50. /******************************************************************/ 51. 52./*临时变量存储的像素与m_pImage相同,便于处理图像*/ 53. unsigned char *ImageSize; 54. ImageSize=new unsigned char[m_nImage]; //new和delete有效的进行动态内存的分配和释放 55. 56.int Place; //建立临时坐标记录起始坐标(0,0)平移过来的位置 57.int m_pImagePlace; //原始图像平移为(0,0) 图像把它平移到Place位置 58. unsigned char black; //填充黑色='0' 59. 60./************************************************************/ 61./* for(int i=0 ; i=Place && countWidth=Place && countWidth>=dlg.m_xPY*3) 120. { 121. ImageSize[i]=m_pImage[m_pImagePlace]; 122. m_pImagePlace++; 123. countWidth++; 124.if(countWidth==m_nWidth*3) 125. { 126. number++; 127. m_pImagePlace=number*m_nWidth*3; 128. } 129. } 130. } 131. 132. fwrite(ImageSize,m_nImage,1,fpw); 133. fclose(fpo); 134. fclose(fpw); 135. numPicture = 2; 136. level=200; //200表示几何变换 137. Invalidate(); 138. } 139.} 同时在ShowBitmap中添加level标记重新绘制图片,代码如下: [cpp]view plain copy 1.else//图像几何变换 2.if(level=200) 3.{ 4. m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0, 5. LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION); 6.} 运行时需要注意一点:BMP图像在处理过程中可能会出现一些斜线,而平移(40,60)位移量时可能出现如下。他是因为BMP 格式有个非常重要的规定,要求每一扫描的字节数据必须能被4整除,也就是Dword对齐(长度4字节),如果图像的一行字节数不能被4整除,就需要在每行末尾不起0达到标准。 例如一行像素为97字节,我们就需要补3个字节吗,数值可以是0,但是我们在BMP格式的信息头里说明了其宽度,所以补齐后对我们没有影响,所以后面补若干个字节的0即可直到被4整除。 通过后面的图像缩放后,我从学做了一遍这个补齐的缩放。代码如下,能够实现完美平移。nice啊~ copy 1.void CImageProcessingView::OnJhbhPy() 2.{ 3.if(numPicture==0) { 4. AfxMessageBox("载入图片后才能空间平移!",MB_OK,0); 5.return; 6. } 7.//定义采样对话框也是用来空间变换平移的坐标 8. CImagePYDlg dlg; 9.if( dlg.DoModal()==IDOK ) //显示对话框 10. { 11.//采样坐标最初为图片的自身像素 12.if( dlg.m_xPY>m_nWidth || dlg.m_yPY>m_nHeight ) { 13. AfxMessageBox("图片平移不能为超过原图长宽!",MB_OK,0); 14.return; 15. } 16. AfxMessageBox("图片空间变换-平移!",MB_OK,0); 17. 18.//打开临时的图片读写文件 19.FILE *fpo = fopen(BmpName,"rb"); 20.FILE *fpw = fopen(BmpNameLin,"wb+"); 21. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo); 22. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo); 23. 24.int num; //记录每行多余的图像素数个数 25.int sfSize; //补齐后的图像大小 26.//重点:图像的每行像素都必须是4的倍数:1*1的图像为 r g b 00H 27.if(m_nWidth*3%4!=0) 28. { 29. num=(4-m_nWidth*3%4); 30. sfSize=(m_nWidth*3+num)*m_nHeight; //每行多number个 31. } 32.else 33. { 34. num=0; 35. sfSize=m_nWidth*m_nHeight*3; 36. } 37.//注意:假如最后一行像素不足,我默认处理为完整的一行,不足补00H 38.//总之处理后的图像总是m*n且为4倍数,每行都完整存在 39. 40./*更改文件头信息定义临时文件头结构变量*/ 41. BITMAPFILEHEADER bfhsf; 42. BITMAPINFOHEADER bihsf; 43. bfhsf=bfh; 44. bihsf=bih; 45. bfhsf.bfSize=sfSize+54; 46. fwrite(&bfhsf,sizeof(BITMAPFILEHEADER),1,fpw); 47. fwrite(&bihsf,sizeof(BITMAPINFOHEADER),1,fpw); 48. fread(m_pImage,m_nImage,1,fpo); 49. 50. CString str; 51. str.Format("补齐=%d",num); 52. AfxMessageBox(str); 53. 54./*临时变量存储的像素与sfSize相同 new和delete有效的进行动态内存的分配和释放*/ 55. unsigned char *ImageSize; 56. ImageSize=new unsigned char[sfSize]; 57. 58.int Place; //建立临时坐标记录起始坐标(0,0)平移过来的位置 59.int m_pImagePlace; //原始图像平移为(0,0) 图像把它平移到Place位置 60. unsigned char black=0; //填充黑色='0' 61. unsigned char other=0; //补码00H='\0' 62. 63. Place=dlg.m_yPY*(m_nWidth*3+num); //前m_yPY行都要填充为黑色 64. m_pImagePlace=0; //图像处事位置为(0,0),把该点像素平移过去 65.int countWidth=0; //记录每行的像素个数,满行时变回0 66.int number=0; //数字记录使用的像素行数,平移时使用 67. 68.for(int i=0 ; i=Place && countWidth=Place && countWidth>=dlg.m_xPY*3) 87. { 88. ImageSize[i]=m_pImage[m_pImagePlace]; 89. m_pImagePlace++; 90. countWidth++; 91.if(countWidth==m_nWidth*3) 92. { 93.if(num==0) 94. { 95. countWidth=0; 96. number++; 97. m_pImagePlace=number*m_nWidth*3; 98. } 99.else//num为补0 100. { 101.for(int j=0;j=0 && XPlace<=m_nWidth) && (YPlace>=0 && YPlace<=m_nHeight) ) 64. { 65. Place=YPlace*m_nWidth*3+XPlace*3; 66.//在图像范围内赋值为该像素 67.if(Place+2StretchBlt(m_nWindowww.baiyuewang.netwWidth-m_nDrawWidthSF,0, 42. m_nDrawWidthSF,m_nDrawHeightSF,&dcBmp,0,0,m_bmp.bmWidth,m_bmp.bmHeight, SRCCOPY); 43.else 44. pDC->StretchBlt(m_nWindowWidth-640,0,640,640,&dcBmp,0,0, 45. m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY); //显示大小为640*640 46. } 47.else { 48.//如果图片太大显示大小为固定640*640 否则显示原图大小 49.if(m_nDrawWidth<650 && m_nDrawHeight<650) 50. pDC->StretchBlt(m_nWindowWidth-m_nDrawWidth,0, 51. m_nDrawWidth,m_nDrawHeight,&dcBmp,0,0,m_bmp.bmWidth,m_bmp.bmHeight,SRCC OPY); 52.else 53. pDC->StretchBlt(m_nWindowWidth-640,0,640,640,&dcBmp,0,0, 54. m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY); 55. } 56.//恢复临时DC的位图 57. dcBmp.SelectObject(pbmpOld); 58.} 运行效果如下图所示,采用最近邻插值法缩放大了会出现失帧。 但是同时当图片缩小是总是报错,图片缩放确实有点难,因为像素需要补齐4整数倍,同时需要修改消息头,同时像素矩阵的变换都非常复杂。 最后还是希望文章对你有所帮助,如果文章有不足或错误之处,请海涵。
本文档为【MFC空间几何变换之图像平移、镜像、旋转、缩放详解】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_266065
暂无简介~
格式:doc
大小:31KB
软件:Word
页数:0
分类:互联网
上传时间:2019-08-19
浏览量:55