图像的配准及在VC++中实现

图像配准是对取自不同时间、不同传感器或者不同视角的同一场景的两幅图像或者多幅图像匹配的过程,它被广泛地应用在遥感图像、医学影像、三维重构、机器人视觉等诸多领域中.而匹配就是在一幅大图像中搜寻目标,已知该图中有要找的目标,且该目标同模板有相同的尺寸、方向和图像,通过一定的算法可以在图中找到目标,确定其坐标位.利用模板匹配可以在一幅图像中找到已知的物体.比如抓拍到了一张射门的照片,要在该照片中找到足球的位置.这时就可以采用模板匹配的方法.

目前已经开发了许多处理各种不同种类的数据和问题的技术,总的来讲,按照图像的不同可分为三类:

第一类:由于获取图像的不同,造成图像之间的错位.为了配准这些图像,可以采用空域的方法来去除这些差别.

第二类:由于获取图像的不同而造成的,不过这主要是由于光照或者天气条件不同而造成的差别.这样的图像在亮度上有所区别,也有的会在空域中产生差别,例如透视变形.

第三类:图像的差别是由于目标的运动,生长或者其他景物的变化而引起的.

第二类和第三类图像差别并不是直接通过配准消除的,但这给图像配准带来了很大的困难.对于图像的配准技术,可以把它看作是以下4点选择的组合.

·特征空间

·搜索空间

·搜索策略

·相似度测量

特征空间指的是从图像中提取出来的用来匹配的信息;搜索空间则是指用来校准图像的图像变换集;搜索策略决定如何在这个空间中选择下一个变换,如何测试并搜索出最优的变换;相似度测量则决定了每一个配准测试中的相关特性.

在图像配准中,特征空间、相似度测量、搜索空间以及搜索策略等的选择都会影响到最后配准的精确度.所有的图像配准方法都可以认为是这些选择的组合.这个框架对于我们理解现在存在的各种各样的配准方法的特点以及其之间的关系是相当有用的.

因为主要要用到匹配技术,所以下面我们先介绍一下图像的匹配,再介绍一些图像配准中所用到的理论基础和配准方法.

1.图像的模板匹配

1.1 模板匹配的基本概念

图像匹配技术是数字图像处理领域的一项重要研究,并已在计算机视觉、虚拟现实场景生成、航空航天遥感测量、医学影像分析、光学和雷达跟踪、景物制导等领域得到了广泛的应用.根据已知模式(模板图),到另一幅图中搜索相匹配的子图像的过程,称为模板匹配.

模板就是一幅已知的小图像.模板匹配就是在一幅大图像中搜寻目标,已知该图中

有要找的目标,且该目标同模板有相同的尺寸、方向和图像,通过一定的算法可以在图中找到目标,确定其坐标位置.

以8 位图像(其1个像素由1个字节描述)为例,模板T( 个像素)叠放在被搜索图 ( 个像素)上平移,模板覆盖被搜索图的那块区域叫子图 . 为子图左上角在被搜索图 上的坐标.搜索范围是:

通过比较 和 的相似性,完成模板匹配过程.

注意:图像的数据是从下到上、从左到右排列的.

可以用下式衡量 和 相似性:

      =

上式的第一项为子图的能量,第三项为模板的能量,都与模板匹配无关.第二项是模板和子图的互相关,随 而改变.当模板和子图匹配时,该项有极大值.将其归一化,得模板匹配的相关系数:

当模板和子图完全一样时,相关系数 .在被搜索图S 中完成全部搜索后,找出  的最大值 ,其对应的子图 即为匹配目标.显然,用这种公式做图像匹配计算量大、速度较慢.

另一种算法是衡量T 和Sij 的误差,其公式为:

为最小值处即为匹配目标.为提高计算速度,取一个误差阈值 ,当 > 时就停止该点的计算,继续下一点计算.

试验结果如下

结果表明:被搜索图越大,匹配速度越慢;模板越小,匹配速度越快.误差法速度较快,阈值的大小对匹配速度影响大,和模板的尺寸有关.

1.2 改进模板匹配算法

在误差算法的基础上设计了二次匹配误差算法:

第一次匹配是粗略匹配.取模板的隔行隔列数据,即四分之一的模板数据,在被搜索图上进行隔行隔列扫描匹配,即在原图的四分之一范围内匹配.由于数据量大幅度减少,匹配速度显著提高.

为了合理的给出一个误差阈值 ,我们设计了一个确定误差阈值 的准则:

式中: 为各点平均的最大误差,一般取40~50 即可; 为模板的长和宽.

第二次匹配是精确匹配.在第一次误差最小点 的邻域内,即在对角点为 , 的矩形内,进行搜索匹配,得到最后结果.

下表是相关法、误差法、二次匹配误差法这三种模板匹配算法对两幅图像进行模板匹配的结果比较,二次匹配误差法的速度比其它算法快了10倍左右.

使用二次匹配误差法对256*256 像素的被搜索图进行模板匹配的结果如下:

从上图结果可看出,第一次匹配位置是偶数,因为是隔行隔列进行搜索的;第二次则是精确位置.

1.3 二次匹配误差法的主要代码

#define AvEthreshold 40 // 各点平均误差

int Ethreshold; // 误差阈值

//计算误差阈值

Ethreshold=AvEthreshold*((lTemplateHeight+1)/2)*((lTemplateWidth+1)/2);

// 第一次粗略匹配,找出误差最小位置(nMaxHeight,nMaxWidth)

// 仅使用模板中隔行隔列的数据,在被搜索图中隔行隔列匹配

nMinError = 99999999;

for (i = 0; i < lHeight - lTemplateHeight +1; i=i+2)

{

for(j = 0; j < lWidth - lTemplateWidth + 1; j=j+2)

{

nError = 0;

for (m = 0; m < lTemplateHeight; m=m+2)

{

for(n = 0; n < lTemplateWidth; n=n+2)

{

// 指向被搜索图像倒数第i+m行,第j+n个象素的指针

lpSrc = (char *)lpDIBBits + lLineBytes * (i+m) + (j+n);

// 指向模板图像倒数第m行,第n个象素的指针

lpTemplateSrc = (char *)lpTemplateDIBBits + lTemplateLineBytes * m + n;

pixel = (unsigned char)*lpSrc;

templatepixel = (unsigned char)*lpTemplateSrc;

nDelta=(int)pixel-templatepixel;

if (nDelta<0) // 做绝对值运算

{nError = nError-nDelta;}

else{nError = nError+nDelta;}

}

if (nError>(Ethreshold)) break; // 误差大于阈值,进入下一点计算

}

if (nError < nMinError) //与最小误差比较

{

nMinError = nError; // 记录最小误差及其坐标

nMaxWidth = j;

nMaxHeight = i;

}

}

}

2 图像的配准技术

2.1 图像配准理论基础

我们先介绍图像配准中经常用到的图像变换、相似性测度、插值算法以及最小二乘法.

2.1.1 图像变换

将一幅图像与另一幅图像对准,常需对一幅图像进行一系列的变换,这些变换可分为刚体变换、仿射变换、投影变换和非线形变换.

一.刚体变换

如果第一幅图像中的两点间的距离经变换到第二幅图像中后仍保持不变,则这种变换称为刚体变换.刚体变换可分解为平移、旋转和反转(镜像).在二维空间中,点 经过刚体变换到点 的变换公式为:

其中 为旋转角, 为平移向量.

二.仿射变换

经过变换后第一幅图像上的直线映射到第二幅图像仍为直线,并且保持平衡关系,这样的变换称为仿射变换.仿射变换可以分解为线形(矩阵)变换和平移变换.在2D空间中,变换公式为:

其中 为实矩阵.

三. 投影变换

经过变换后第一幅图像上的直线映射到第二幅图像仍为直线,并且保持平行关系,这样的变换称为投影变换.投影变换可用高维空间上的线形(矩阵)变换来表示.变换公式为:

四. 非线形变换

非线形变换可把直线变为曲线.在2D空间中,可以用以下公式表示:

其中,F表示把第一幅图像映射到第二幅图像上的任意一种函数形式.典型的非线形变换如多项式变换,在2D空间中,多项式函数可写为如下形式:

非线形变换比较适用于那些具有全局性形变的图像配准问题,以及整体近似刚体但局部有形变的配准情况.

2.1.2 相似性测度

相似性测度主要有互相关相似性测度、序贯相似性测度、相位相关测度以及一些变形等.

一  互相关相似性测度

最基本的相似性测度就是互相关相似性测度了.假设有模板T和搜索图S, 表示模板覆盖下的那块搜索图,其中i,j表示位置.则其互相关相似性测度为:

或者归一化为:

二  基于傅立叶分析的测度

基于傅立叶分析的测度主要有两种,一个是将空域中的互相关在频域中进行计算,另一个是相位相关法.

由基于傅立叶分析中的相关定理可知,两个函数在定义域中的卷积等于它在频域中的乘积,而相关则是卷积的一种特定形式.因此,可以利用快速傅立叶变换来求解相似度.

对 和 分别求DFT,可得到相关的离散傅立叶变换 为:

其中 和 分别是 和 的傅立叶变换.其中*为共扼运算的符号.

对 求傅立叶反变换,就可以得出空间域中的相关函数 为:

相位相关法可以用力计算两幅图像的平移.图像的傅立叶变换由实部和虚部组成,即:

其中 为虚部算子.这也可以表示为:

相位相关则是基于傅立叶变换的这个性质来建立的.两幅图像的平移可以认为是其傅立叶变换的角度差别 .这样计算两幅图像的互功率谱就可以得到两幅图像的角度差别:

其中 和 分别表示 和 上的平移量.

三  序贯相似性检测

序贯相似性检测算法实际上是基于互相关法,是为了快速计算而设计的算法.其基本思路就是设计一个阀值,在计算相似性的时候,累计误差大于阀值则停止计算,这样可以减少在误配准点上的计算量.

在序贯相似性检测算法的基础上,也有不少的变形,例如基于排序的序贯相似性检测算法,分层的序贯相似性检测算法等.

2.1.3 插值

在图像配准中,还需要涉及到许多的插值算法.由于粗配后所得出的像素坐标位置可能不在整数像素上,因此需要用灰度插值的方法对像素值进行估计.灰度插值的发建立在信号抽样理论基础上.现实世界中的图像可以看作是一个连续函数 ,数字图像是对这个函数的采样,恢复连续函数可以用一个理想低通滤波器对离散化的图像进行滤波,在空域上就表现为与Sinc函数的卷积.但是Sinc函数计算比较复杂,一般用比较容易计算的函数来逼近,常用的方法包括最近邻法、双线形法,但是它们的精度对于细化比较丰富的图像来说还不够.在本问中,采用3次插值的方法用当前像素周围的4×4个像素进行插值,用如下所示的核函数对图像进行卷积操作:

下图是 函数和Sinc函数的图像.从图中可以看出 函数是Sinc函数的3次良好逼近.

2.1.4 最小二乘法

最小二乘法(LSM)是一种有效的统计方法,它可以用多个配准点找出最优参数解.设对应配准点的坐标分别为 和 .

由仿射模型可得如下方程组:

配准需要解决的问题就是求出线形最小二乘解 和 ,其中 和 为仿射变换参数,以6参数的仿射变换为例

.

可以证明,只要 的秩大于6,则存在 和 的最小二乘解:

2.2  图像配准中常用的技术

图像配准涉及到的技术比较多,总的说来,配准的方法主要有互相关法、傅立叶变换法、点映射法和弹性模型法.前两种方法前面的理论基础已经进行了介绍,下面我们就介绍一下点映射法和基于弹性模型的配准方法,再回头叙述一下配准着需要注意的问题,包括特征空间的选择,相似性的选择以及搜索空间和策略的选择.

2.2.1 点映射

点映射或者是基准点映射技术是在不知道两幅图像的映射方式时最常采用的配准方法.例如,如果图像是在同一个场景中从不同的角度按照平滑的景深变化拍摄到的,则这两幅图像会由于透视变形而有所区别.我们不能确定正确的透视变换,因为通常并不知道在场景中真实的景深.但我们能在两幅图像中找到基准点,并利用一个普通的变换来进行配准.然而,如果场景并不是由光滑的表面组成,而是由很大的景深变化,这样两幅图像之间就会产生变形以及遮挡等问题,物体将出现在图像的不同位置,而且一些变形也会是局部的.当更多的变形是局部的,这就给全局的点映射方法图像配准带来了很大的困难.在这个情况下,利用局部的变换,例如局部点映射方法将会比较合适.

点映射方法通常有3个步骤组成:

第一步:计算图像中的特征.

第二步:在参考图像上找到特征点,也就是经常说的控制点,并在待配准图像中找到相对应的特征点.

第三步:利用这些配准的特征点计算出空间映射参数,这个空间通常是2D的多项式函数.通常,还需要在一幅图像中进行重采样,对另一幅图像应用空间映射和插值.

点映射方法经常不能稳定的得到配准,因此,点映射方法还经常利用各个阶段之间的反馈来找到最优的变换.

前面提到的控制点在图像配准中起到了重要的作用.在点配准后,点映射的方法就只剩下插值或者逼近了.这样,点配准的精度就确定了最后配准的精度.

很多特征都可以用来作为控制点,我们可以将它们分为内在的和外部的特征点.内在的控制点指的是图像中不依赖于图像数据本身的一些点,它们通常是为了配准的目的放入场景中的标记点,并且很容易进行识别.例如在医学图像中,就经常往患者的皮肤或者其他不会产生变形和移位的位置上放置一些特征点,以便进行配准.外在的控制点指的是那些从数据中得到点.这些点可以是手工得到的,也可以是自动获取的.手工的控制点也就是利用人的交互得到的点,例如一些可鉴别的基准点或者解剖结构.这些点一般都是选取为刚性、稳定并且在数据中很容易点击得到等.当然,这需要由在其领域的专门知识.还有许多应用自动定位控制点.用来自动定位的控制点典型的有角点、直线的交点、曲线中的局部最大曲率点、具有局部最大曲率的窗口的中心、闭合区域的重心等等.这些特征通常都是在配准的两幅图像中唯一的,并且对于局部的变形表现更鲁棒一些.

得到控制点后,就可以对这些控制点进行配准了.另一幅图像中配准的控制点可以用手工点击得到,也可以利用互相关等方法进行自动获取.

2.2.2 基于弹性模型的配准

在很多图像配准中,没有直接应用插值来计算控制点之间的映射,而是采用了基于弹性模型的方法来进行.这些方法对图像中的变形利用了一个弹性的变形来模型化.从另一个角度来说,配准变换就是一个弹性的材料经过最小的弯曲和拉伸变换的结果.弯曲和拉伸的量由弹性材料的能量状态来表示.然而,插值的方法也和此类似,因为能量的最小化需要满足弹性模型的限制,而这可以用样条来解决.

通常,这些方法是逼近图像之间的配准,尽管它们有时也利用特征,但是它们没有包括点配准这个步骤.图像或者物体是模型化为一个弹性的整体,并且两幅图像之间点或者特征点的相似性是用整体的“拉伸”的外部的力来表示的.这些方法通常用硬度或者是光滑度的约束上给了用户很多的灵活性.最后确定的最小能量的状态将决定定义配准的变形变换.但其问题在于最小能量状态的求取上通常包括迭代的计算过程.

2.2.3 特征空间的选择

配准的过程中,第一步就是特征空间的选择.有许多的特征可供选择,这可能就是图像本身的亮度,同时也有许多其他类似的选择,这包括边沿、曲线、表面.显著的特征也可以用来配准,例如角点、直线交点,高曲率的点.也可以是统计特征,例如不变矩、重心等.高层的结果和语义描述也可以用来配准.

显著的特征通常是指在图像中可以容易辨别处理的有意义特征的一些特殊的像素.统计特征指的是一个区域(这个区域通常是通过一个分割的预处理得到)的测度,它表示了这个区域的估计.特征空间是图像配准,同时也是几乎所有的高层图像处理或者计算机视觉的基础.

对于图像配准,特征空间的选择将影响:

·传感器和场景中的数据什么特征的敏感的(通常,特征是选择那些减少传感器噪声和其他变形,例如亮度的变换等).

·图像是什么特征将会配准(例如在配准结构比纹理特征更有利).

·计算代价,通过减少计算的相似性,或者从另一个角度来说,增加预计算的必要性的代价.

2.2.4 相似性测度的选择

图像配准的第二步就是设计或者选择相似性测度.这个阶段和配准特征的选择有很大关系.对于内部结构,也就是说图像的不变特征,通常是通过特征空间和通过相似性测度提取得到的.典型的相似性测度有:经过或者不经过预先滤波的互相关(例如,配准滤波或者统计相关)、差别的绝对值(这是很高效的方法)、傅立叶不变特征(例如相位相关).利用曲线和表面作为特征空间的方法则需要取在最近邻域差别的平方和.结构或者语义的方法则需要高度依赖于其特征的测度.例如,“自由”图形之间的熵的最小变化就是用来作为一个结构模式识别的相似性测度.

相似性测度的选择是一个图像配准中最重要的步骤之一,它将决定如何确定配准变换.而且,其配准的程度最后应转化为配准或者不配准.

2.2.5 搜索空间和策略的选择

由于很多的配准特征和相似度测量方法都需要大量的计算量,因此图像配准中最后一步设计就是一个选择搜索策略的问题.搜索空间通常是将要找到的配准最优变换的变换集.我们可以在特征空间上利用相似性测度计算每一个变换.然而,在很多情况下,例如利用相关作为相似性测度的方法.减少测量计算的数量是很重要的.误配准位置越多,计算量越大,这个问题就越严重.在许多情况下,搜索空间就是所有变换的空间.通常,可以将这个集合从影响的大小和搜索空间的复杂度分为全局或者局部的变换.在有些情况下,可以利用一些可以得到的信息去掉不可能配准的搜索子空间,从而达到减少计算量的目的.

通常的搜索策略包括分层或多分辨技术、判决序列、松弛、广义Hough变换、线性规划、树和图像配准、动态规划以及启发式的搜索等等.

3.图像配准及其主要VC++代码

上面我们介绍了图像配准的理论,下面我们利用VC++来实现图像的配准.我们给出一个半自动的基于特征的图像配准MFC,在程序中,需要手工选取特征点,程序将自动寻找到相匹配的特征点,然后自动计算 仿射变换参数,并将两幅图像拼接,显示匹配图像.

配准后:

下面我们介绍一个在图像配准中用到的一个主要函数TemplateMatch()的VC++源代码:

BOOL CDlgRecMatch::TemplateMatch(CDib* pDibSrc, CDib* pDibTemplate)

{   

      // 指向源图像的指针

      LPBYTE       lpSrc,lpTemplateSrc;

     

// 指向缓存图像的指针

      LPBYTE       lpDst;

 

      //循环变量

      long i;

      long j;

      long m;

      long n;

 

      //中间结果

      double dSigmaST;

      double dSigmaS;

      double dSigmaT;

 

      //相似性测度

      double R;

 

      //最大相似性测度

      double  dbMaxR;

 

      //最大相似性出现位置

      int nMaxWidth;

      int nMaxHeight;

 

      //像素值

      unsigned char unchPixel;

      unsigned char unchTemplatePixel;

 

      // 获得图象数据存储的高度和宽度

      CSize sizeSaveImage;

      sizeSaveImage = pDibSrc->GetDibSaveDim();

 

      // 获得模板图象数据存储的高度和宽度

      CSize sizeSaveTemplate;

      sizeSaveTemplate = pDibTemplate->GetDibSaveDim();

 

 

      // 暂时分配内存,以保存新图像

      CDib* pDibNew;

      pDibNew = new CDib;

 

      // 如果分配内存失败,则推出

      if(!CopyDIB(pDibSrc,pDibNew)){

             // 释放已分配内存

             pDibNew->Empty();

 

             // 返回

             return FALSE;

      }

     

 

      // 初始化新分配的内存

      lpDst = (LPBYTE)pDibNew->m_lpImage;

     

      // 图象的高度

      int nImageHeight ;

      nImageHeight = pDibSrc->m_lpBMIH->biHeight;

 

      // 图象的宽度

      int nImageWidth;

      nImageWidth = pDibSrc->m_lpBMIH->biWidth;

 

      // 模板图象的高度

      int nTemplateHeight;

      nTemplateHeight = pDibTemplate->m_lpBMIH->biHeight;

 

      // 模板图象的宽度

      int nTemplateWidth;

      nTemplateWidth = pDibTemplate->m_lpBMIH->biWidth;

 

      //计算dSigmaT

      dSigmaT = 0;

      for (n = 0;n < nTemplateHeight ;n++)

      {

             for(m = 0;m < nTemplateWidth ;m++)

             {

                    // 指向模板图像倒数第j行,第i个象素的指针                   

                    lpTemplateSrc = (LPBYTE)pDibTemplate->m_lpImage + sizeSaveTemplate.cx * n + m;

                    unchTemplatePixel = (unsigned char)*lpTemplateSrc;

                    dSigmaT += (double)unchTemplatePixel*unchTemplatePixel;

             }

      }

 

      //找到图像中最大相似性的出现位置

       dbMaxR = 0.0;

      for (j = 0;j < nImageHeight - nTemplateHeight +1 ;j++)

      {

             for(i = 0;i < nImageWidth - nTemplateWidth + 1;i++)

             {

                    dSigmaST = 0;

                    dSigmaS = 0;

     

                    for (n = 0;n < nTemplateHeight ;n++)

                    {

                           for(m = 0;m < nTemplateWidth ;m++)

                           {

                                  // 指向源图像倒数第j+n行,第i+m个象素的指针              

                                  lpSrc  = (LPBYTE)pDibSrc->m_lpImage + sizeSaveImage.cx * (j+n) + (i+m);

                   

                                  // 指向模板图像倒数第n行,第m个象素的指针                 

                                  lpTemplateSrc  = (LPBYTE)pDibTemplate->m_lpImage + sizeSaveTemplate.cx * n + m;

 

                                  unchPixel = (unsigned char)*lpSrc;

                                  unchTemplatePixel = (unsigned char)*lpTemplateSrc;

 

                                  dSigmaS += (double)unchPixel*unchPixel;

                                  dSigmaST += (double)unchPixel*unchTemplatePixel;

                           }

                    }

                    //计算相似性

                    R = dSigmaST / ( sqrt(dSigmaS)*sqrt(dSigmaT));

                    //与最大相似性比较

                    if (R >  dbMaxR)

                    {

                            dbMaxR = R;

                           nMaxWidth = i;

                           nMaxHeight = j;

                    }

             }

      }

 

      // 对目标图象的象素进行赋值

      for(i=0; i<nImageHeight; i++)

             for( j=0; j<nImageWidth; j++){

                    lpDst[i*sizeSaveImage.cx +j] /=2;                  

             }

 

      //将最大相似性出现区域部分复制到目标图像

      for (n = 0;n < nTemplateHeight ;n++)

      {

             for(m = 0;m < nTemplateWidth ;m++)

             {

                    lpTemplateSrc = (LPBYTE)pDibTemplate->m_lpImage + sizeSaveTemplate.cx * n + m;

                    lpDst = (LPBYTE)pDibNew->m_lpImage + sizeSaveImage.cx * (n+nMaxHeight) + (m+nMaxWidth);

                    *lpDst = *lpTemplateSrc;

             }

      }

     

      // 复制图像

      memcpy(pDibSrc->m_lpImage, pDibNew->m_lpImage, nImageWidth * nImageHeight);

 

      // 释放内存

      pDibNew->Empty();

     

      // 返回

      return TRUE;

}

 其中CDib*pDibSrc指向CDib类的指针,含有待匹配图象信息,CDib*pDibTemplate指向CDib类的指针,含有模板图象信息 该函数将对图象进行模板匹配操作.需要注意的是,此程序只处理256灰度级的图象. 

你可能感兴趣的:(图像的配准及在VC++中实现)