您好, 访客   登录/注册

数字图像的几何运算

来源:用户上传      作者:

  摘要:目前,数字图像处理民已广泛应用于工业、医疗保健、航空航天、军事等领域。随着信息高速公路、数字地球概念的提出以及Intemet的飞速发展,数字图像处理由于具有信息量大、传输速度快、作用距离远等一系列优点,必将成为人类获取信息的重要来源和利用信息的重要手段。该文介绍了数字图像的基本知识,数字图像的几何运算系统的开发原理,主要实现功能、子模块设计及实现技术。其中,重点介绍了通过对像素的几何运算实现图像的各种几何变换的原理和算法实现。
  关键词:数字图像;像素;几何运算
  中图分类号:TP391 文献标识码:A
  文章编号:1009-3044(2020)03-0209-04
  数字图像处理技术与理论是计算机应用的一个重要领域,数字图像的几何运算是数字图像处理的一个重要组成部分。人类感知图像是通过视觉系统接收物体透射光或反射光在大脑中形成的印象或认识。人类获取外界信息约80%左右是来自视觉所接收的图像信息。图像的几何运算就是对其进行平移、缩放、镜像、旋转、转置等处理,用于满足实际需要。用计算机对图像进行各种处理我们称之为数字图像处理。本文就是讨论如何利用微软的Visual C++开发工具来实现一些常用的数字图像处理算法——数字图像的几何运算。
  图像分为黑白图像和彩色图像,其中黑白图像又包括单色图像和灰度图像,灰度图像是用0表示黑,255表示白,中间值表示灰色,用该字节的数值表示对应像素的灰度值或亮度值。彩色图像一般使用RGB模式,其中R表示红色,G表示绿色,B表示蓝色,统称为“三基色”,用这三种色彩的不同搭配,就可以形成各种不同的色彩。形成的图像文件一般用BMP、JPEG、GIF等格式表示。
  本系统的开发以图像像素的几何运算为原理,综合了各学科(如数学、物理学、计算机学、系统工程等)较先进的成果形成的计算机图像处理主要防采用两大类方法:一类是在图像空间中对图像进行各种处理;另一类方法是把图像进行变换,经过傅立叶变换或小波变换,变换到频率域,在频率域中进行各种处理,然后再变换回图像的空间域,形成处理后的图像。
  图像的几何运算也称为空间变换,是建立一幅图像与其变换后的图像中所有各点之间映射关系的函数。这些函数能唯一确定输入图像和输出图像中所有像素点之间的几何对应关系。即:[x,y]-[X(u,v),Y(u,v)] 或[u,v]-[U(x,y),V(x,y)]
  其中,[u,v]表示输入图像的像素坐标,[x,y]表示输出图像的像素坐标。X、Y、U、V表示空间几何变换的映射函数,该函数唯一定义了输入和输出图像中所有点之间的几何对应关系。X、Y将输入映射到输出,称为前向映射(Forward Mapping);U、V将输出映射到输入,称为逆向映射(Inverse Mapping)。图像的几何运算应用得非常普遍,已广泛应用于医学成像、遥感图像处理、计算机视觉以及电视、电影、多媒体广告等影像处理中。本文介绍一些常用的图像变换技术,包括图像的平移、镜像、转置、旋转、缩放等。
  1)判断并打开一幅256色BMP位图显示出来;
  2)图像平移:通过所给X、Y方向平移参数进行相应位移量的平行移动;
  3)图像缩放:通过所给X、Y方向的缩放参数进行相应倍数的缩小或放大;
  4)图像旋转:通过所给旋转度数进行顺时针方向的旋转;
  5)图像镜像:实现对数字图像的垂直镜像或水平镜像;
  6)图像转置:通过把图像的x坐标与y坐标互换实现图像的转置。
  利用数学公式对图像像素进行几何运算和VC++的数字图像处理技术为理论基础,完成对图像进行平移、镜像、缩放、旋转、转置等几何变换的算法实现,并实际设计实现上述功能。
  1 打开位图模块
  因灰度图像每个像素位数正好是8位(1个字节),因此在进行图像处理时不用考虑拼凑字节的问题。而且由于灰度图调色板的特殊性,进行灰度图像处理时不必考虑调色板的问题。这样在介绍图像处理时,一般采用灰度图,为的是将重点放在算法本身。
  系统调用Ondraw0函数,用GetDocument0获取文檔,然后调用GetHDIBO获取DIB,该函数主要用来绘制DIB对象。其中调用了StretchDIBits0或者SetDIBitsToDevice0来绘制DIB对象。输出的设备由参数hDC指定;绘制的矩形区域由参数lpDCRect指定;输出DIB的区域由参数lpDIBRect指定。再调用Paint-DIBO函数,在PaintDIBO中先锁定DIB找到DIB图像象素起始位置,获取DIB调色板,并选中它,设置好显示模式,最后判断是原始大小,不用拉伸调用StretchDIBits0若不是原始大小,则调用SetDIBitsToDevice0来绘制DIB对象。
  2 图像平移
  2.1 基本原理
  所有的点都按照指定的平移量水平、垂直移动。如图所示,设(x0,y0)为原图像上的一点,图像水平平移量为x,垂直平移量为v,则平移后点(x0,y0)坐标将变为(xl,yl)。
  平移后图像的每一个点都可以在原图像中找到相对应的点。例如,对于新图中的(0,0)像素,代人上面的方程组,可以求出对应原图中的像素(-x,-y)。如果x大于0,则点(-x,-y)不在原图中。对于不在原图中的点,可以直接将它的像素值统一设置为255。同样,若有点不在原图中,也就说明原图中有点被移出显示区域。如果不想丢失被移出的部分图像,可以将新生成的图像宽度扩大lxl.高度扩大lyl。
  2.2 平移模块实现
  首先取得原图的数据区指针.通过对话框输入偏移量x,y,开辟一个同样大小的缓冲区,再对原图依次循环每个像素,每读入一个像素点(x0,y0),根据它的坐标(x0,y0)找到目标图像的位置(xl=xO+x,yl=yO+y),将像素(x0,y0)处的颜色值赋给新图中的(xl,yl)。   for(i=0;i
  {
  for(j=0;j
  {
  //指向新DIB第i行,第j个象素的指针
  //由于DIB中图像第一行其实保存在最后一行的位置,因此lpDst
  //值不是(char *)lpNewDIBBits+ lLineBytes{i+j,而是
  //(char *)lpNewDIBBits+ lLineBytes*(lHeight -1 -i)+j
  lpDst= (char *)lpNewDIBBits+ ILineBytes半(IHeight -1 -i)+j;
  //计算该象素在源DIB中的坐标
  i0=i- lYOffset;
  j0=j- lXOffset;
  //判断是否在源图范围内
  if(00>=0)&&(j0< IWidth)&&(i0>=0)&&(i0< IHeight》
  {
  //指向源DIB第i0行,第j0个象素的指针
  //同样要注意DIB上下倒置的问题
  lpSrc=(char *)lpDIBBits+lLineBytes*(lHeight -1- i0)+j0;
  *lpDst= *lpSrc; //复制象素
  )
  elsef
  *《unsigned char*)lpDst)= 255; 11源图中没有的象素,直接赋值255
  )))
  3 图像缩放模块
  3.1 基本原理
  图像x轴方向缩放比率nx,y軸方向缩放比率是ny,那么原图中点(x0,y0)对应与新图中的点(xl,v1)的转换矩阵为:
  例如当nx=ny=0.5时,图像被缩到原图一半大小,此时缩小后图像中的(0,0)像素对应于原图中的(0,0)像素;(0,1)像素对应于原图中的(0,2)像素,(1,0)像素对应于原图中的(2,o)像素,以此类推。在原图基础上,每行隔一个像素取一点,每隔一行进行操作。同理,当nx=ny=2时,图像就会放大2倍,放大后图像中的(0,0)对应于原图中的(0,0);(0,1)对应于原图中的(0,0.5),该像素不存在,可以近似为(0,0)也可以近似为(0,1);(0,2)对应于原图中的(0,1);(1,0)对应于原图中的(0.5,0)-(0,0)或(1,0);(2,0)对应于原图中的(1,0)。其实就是将原图每行中的像素重复取值一遍,然后每行重复一次。
  如图3、图4分别是放大前和放大后的图像。
  3.2 缩放模块实现
  先取得原图的数据区指针,通过对话框获得放大整数比例:nx,ny,更改图像的宽度和高度,每个像素依次循环。计算该像素在原图中的坐标,将原图的像素值赋给目标像素相应位置nxXny个值。
  for(i=0;i
  {
  //针对图像每列进行操作
  for(j=0;j
  {
  ,/指向新DIB第i行,第j个象素的指针
  //此处宽度和高度是新DIB的宽度和高度
  lpDst=(char *)lpNewDIBBits+lNewLineBytes* (lNe-wHeight -1 -i)+j;
  //计算该象素在源DIB中的坐标
  i0= (LONG)(i/fYZoomRatio+ 0.5);
  j0= (LONG)(j /fXZoomRatio+ 0.5)
  //判断是否在源图范围内
  if( (j0>=o)&&(j0< IWidth)&&(i0>=0)&&(i0< lHeight》
  {
  //指向源DIB第i0行,第j0个象素的指针
  lpSrc=(char *)lpDIBBits+lLineBytes木(lHeight -1-i0)+j0;
  *lpDst= *lpSrc; //复制象素
  1else
  {
  *《unsigned char*)lpDst)= 255; 11对源图中没有的象素,直接赋值255
  )))
  4 图像镜像模块
  4.1 基本原理
  设图像高度为IHeight,宽度为IWidth,原图中(x0,y0)经过水平镜像后坐标将变为(lWidth-x0,y0),其矩阵表达式为:
  4.2 镜像模块实现
  首先取得原图的数据区指针,开辟一个同样大小的缓冲区,每个像素依次循环。在水平镜像中,将原图中的像素点的水平坐标变成镜像后的坐标(用图像的宽度减去坐标值)再显示到图像上。垂直镜像中,则对垂直坐标做相应的处理。
  按照上面的变换公式,实现水平和垂直镜像的算法,bdi-rection真时表示水平镜像,否则为垂直镜像:
  //判断镜像方式
  if (bDirection)
  {
  //水平镜像
  //针对图像每行进行操作
  for(i=0;i
  {
  //针对每行图像左半部分进行操作
  for(j=0;j
  {
  //指向倒数第i行,第j个象素的指针
  lpSrc= (char *)lpDIBBits+ lLineBytes*i+j;   //指向倒数第i行,倒数第j个象素的指针
  lpDst= (char *)lpDIBBits+ lLineBytes*(i+1)-j;
  //|备份—个象素
  *lpBits= *lpDst;
  //将倒数第i行第j个象素复制到倒数第i行倒数第j个象素
  *lpDst= *lpSrc;
  //将倒数第i行倒数第j个象素复制到倒数第i行第j个象素
  *lpSrc= *lpBits;
  )})
  else//垂直镜像
  {//针对上半图像进行操作
  for(i=0;i
  {//指向倒数第i行象素起点的指针
  lpSrc= (char *)lpDIBBits+ ILineBytes*i;
  //指向第i行象素起点的指针
  lpDst= (char *)lpDIBBits+ lLineBytes*(lHeight -i -1);
  //备份一行,宽度为lWidth
  memcpy(lpBits, lpDst, lLineBytes);
  //将倒数第i行象素复制到第i行
  memcpy(lpDst, lpSrc, lLineBytes);
  //将第i行象素复制到倒数第i行
  memcpy(lpSrc, lpBits, lLineBytes);
  }}
  5 图像旋转模块
  5.1 旋转基本原理
  图像的旋转是以图像的中心为原点,旋转一定的角度。旋转后,图像的大小一般会改变我们可以把转出显示区的图像截去,也可以扩大图像范围以显示所有的图像,这里我们实现后者。如图5所示,点(x0,y0)经过旋转0度后坐标变成(xl,yl)。
  上述旋转是绕坐标轴原点(0,0)进行的,如果是绕一个指定点(a,b)旋转,则先要将坐标系平移到该点,再进行旋转,然后平移回新的坐标原点,在此不再詳述。
  5.2 旋转模块实现
  //针对图像每行进行操作
  for(i=0;i
  {
  //针对图像每列进行操作
  for(j=0;j
  {//指向新DIB第i行,第j个象素的指针,此处宽度和高度是新DIB的宽度和高度
  lpDst=(char *)lpNewDIBBits+lNewLineBytes* (lNe-wHeight -l -i) +j;
  //计算该象素在源DIB中的坐标
  i0= (LONG) (-《float)j)4f'Sina+《float)i)4fCosa+ f2+ 0.5);
  j0= (LONG)(《float)j)4 fCosa+《float)i)4 fSina +fl+ 0.5);
  //判断是否在源图范围内
  if((j0>=0)&&(j0< IWidth)&&(i0>=0)&&(i0< IHeight》
  {
  //指向源DIB第i0行,第j0个象素的指针
  lpSrc=(char *)lpDIBBits+lLineBytes*(IHeight -1-i0)+j0;
  //复制象素
  *lpDst= *lpSrc;
  1else
  {
  //对于源图中没有的象素,直接赋值为255
  *《unsigned char*)lpDst)= 255;
  }}}
  6 图像转置模块
  6.1 转置基本原理
  图像的转置(transpose)操作是将图像像素的x坐标和y坐标互换。该操作将改变图像的高度和宽度,转置后图像的高度和宽度将互换。即:
  x0= yl
  yo= xl
  6.2 转置模块实现
  图像的转置的实现和图像镜像变换类似,不同之处在于图像转置后DIB的头文件也要进行相应的改变,主要是将头文件中图像高度和宽度信息更新。因此传递给图像转置函数的参数是直接指向DIB的指针,而不是直接指向DIB像素的指针。下面给出图像转置函数的算法。
  //针对图像每行进行操作
  for(i=0;i
  {for(j=0;j
  {//指向源DIB第i行,第j个象素的指针
  lpSrc= (char *)lpDIBBits+ lLineBytes*(lHeight -1 -i)+j;
  //指向转置DIB第j行,第i个象素的指针
  //注意此处lWidth和lHeight是源DIB的宽度和高度,应该互换
  lpDst= (char *)lpNewDIBBits+ lNewLineBytes*(IWidth -1一j)+i;
  //复制象素
  *lpDst= *lpSrc;
  }}
  数字图像处理技术博大精深,不但需要熟练掌握一门程序开发语言,还需要深厚的数学功底,自20世纪60年代第三代数字计算机问世以后,数字图像处理技术出现了空前的发展,在诸如航空航天、生物医学工程、通信工程、文化艺术、电子商务等等领域都有广泛应用。本文利用Visual C++这个开发平台只是抛砖引玉,希望和广大读者共同交流学习。
  参考文献:
  [1]杨淑莹,边奠英.VC++图像处理程序设计[M].北京:清华大学出版社,2003.
  [2]欧珊瑚,王倩丽,朱哲瑜.Visual C++.NET数字图像处理技术与应用[M].北京:清华大学出版社,2004.
  [3]陈兵旗,孙明.Visual C++实用图像处理[M].北京:清华大学出版社,2004.
  [4]钟志光,卢君,刘伟荣.Visual C++.NET数字图像处理实例与解析[M].北京:清华大学出版社,2003.
  [5]何斌,马天予,王运坚,等.Visual C++数字图像处理[M].北京:人民邮电出版社,2002.
  [6]谭浩强.Visual C++ 6.0实用教程[M].北京:电子工业出版社。2001.
  [7]朱志刚,林学訚,石定机,等,数字图像处理[M].北京:电子工业出版社。2002.
  [8]谭浩强.Visual C++ 6.0实用教程[M].北京:电子工业出版社,2001.
  [9]郑阿奇.Visual C++实用教程[M].2版.北京:电子工业出版社,2003.
转载注明来源:https://www.xzbu.com/8/view-15151972.htm