参考论文中的文字:图像配准是图像处理的基本任务之一,用于将不同时间、不同传感器、不同视角及不同拍摄条件下获取的关于同一目标或场景的两幅或多幅图像进行主要是几何意义上的匹配套和的过程。在对图像配准的研究过程中,大量技术被应用于针对不同数据和问题的图像配准工作,产生了多种不同形式的图像配准技术。

图像配准的基本问题是找出一种图像转换方法,用以纠正图像的形变。造成图像形变的原因多种多样,例如对于遥感图像而言,传感器噪声、由传感器视点变化或平台不稳定造成的透视变化、被拍摄物体的移动、变形或生长等变化、闪电和大气变化,以及阴影和云层遮盖都使图像产生不同形式的形变。正是图像形变原因和形式的不同决定了多种多样的图像配准技术。

迄今已报道了多种图像配准方法,主要有互相关法、傅立叶变换法、点映射法口脚外和弹性模型法。其中傅立叶变换法基于傅立叶变换的相位匹配是利用傅立叶变换的性质而出现的一种图像配准方法。图像经过傅立叶变换,由空域变换到频率缘则两组数据在空何上的相关运算可以变为频谱的复数乘法运算,同时图像在变换域中还能获得在空域中很难获得的特征。

一,基于相位相关的图像配准方法

在时域中信号的平移运动可以通过在频域中相位的变化表现出来(这是傅里叶变换的特性,见下图)。

平移不影响傅氏变换的幅值(谱),对应的幅值谱和原图像是一样的。旋转在傅氏变换中是小变量。根据傅氏变换的旋转特性,旋转一幅图,在频域相当于对这幅图的傅氏变换做相同的旋转。使用频域方法的好处是计算简单,速度快(可使用MIT的fftw库),同时傅立叶变换可以采用方法提高执行的速度。因此,傅氏变换是图像配准中常用的方法之一。下面我们就具体分析当图像发生平移、旋转和缩放时,图像信号在频域中的表现。

1,解决刚性平移问题的原理阐述

通过求取互功率谱的傅立叶反变换,得到一个狄拉克函数(脉冲函数),再寻找函数峰值点对应的坐标,即可得到我们所要求得的配准点。实际上,在计算机处理中,连续域要用离散域代替,这使得狄拉克函数转化为离散时间单位冲击函数序列的形式。在实际运算中,两幅图像互功率谱相位的反变换,总是含有一个相关峰值代表两幅图像的配准点,和一些非相关峰值,相关峰值直接反映两幅图像间的一致程度。更精确的讲,相关峰的能量对应重叠区域的所占百分比,非相关峰对应非重叠区域所占百分比。由此我们可以看出,当两幅图像重叠区域较小时,采用本方法就不能检测出两幅图像的平移量。

2,合理的配准情况

当图像间仅存在平移时,正确的配准图像如图a所示(中心平移化了),最大峰的位置就是两图像的相对平移量,反之若不存在单纯的平移,则会出现如b所示的情况(多脉冲林立)

3,算法流程

4,配准模拟结果:

1,对绝对理想的图像进行配准模拟
(代码见后面)
绝对理想的图像:图中整体的图像都没有因为平移而带来像素的损失,即再往下移动越界后像素偏移到了上面,往右移动越界后像素偏移到左边,所以图片中模拟的图像没有任何像素损失。

2,对带有指定偏移量的图像偏移估计

(matlab实现,代码见参考1)

本实验图像大小为600*450(其中600是宽度),可以看见成功找到了偏移量。

但是后来我想了想,这个实验中的图像平移是不严谨的,平移后图像左上方的像素变成了黑色,不过从结果来看,影响并不大,接下来换了一张更严谨的偏移实验图像:

3,与OpenCV实现的库函数相比较

代码见参考2

从结果可以看出,两者基本一致,对于制定偏移量为13,17的图像,估计结果opencv还是有一点偏差,但是还是可以接受的。

但是OpenCV自己实现的phaseCorrelate()明显快很多很多很多,666666666666666666666

参考代码1:

%读取
Image1 = (imread('image_gray.jpg')); %
Image2 = (imread('img_result_8_15.jpg')); % 带有偏移量的图像,高度向下偏移8,宽度向右偏移15%显示
subplot(1,2,1);imshow(Image1);  title('原参考图像');
subplot(1,2,2);imshow(Image2);  title('带有偏移量的图像');FFT1 = fft2(Image1); % 二维 FFT
FFT2 = conj(fft2(Image2)); %共轭复数  %求复功率谱
FFTR = FFT1.*FFT2; % 复共轭(复功率谱的分子)
magFFTR = abs(FFTR); %sqrt(real^2 + imag^2)取模 (复功率谱的分母)
FFTRN = (FFTR./magFFTR);  %复功率谱的反变换
result = ifft2(double(FFTRN));   M = max(max(result));
[i,j] = find(result == M)figure;  colormap('gray');imagesc(result);
figure;  colormap(jet);  mesh(result);  

参考代码2:

int main(int argc, char** argv)
{Mat srcImage11 = imread("Brain13x17y.bmp");Mat srcImage21 = imread("BrainP.bmp");Mat dst1, dst2;Mat srcImage1, srcImage2;cvtColor(srcImage11, srcImage1, CV_BGR2GRAY);cvtColor(srcImage21, srcImage2, CV_BGR2GRAY);srcImage1.convertTo(dst1, CV_32FC1);srcImage2.convertTo(dst2, CV_32FC1);QueryPerformanceFrequency(&freq);QueryPerformanceCounter(&startTime);//开始计时Point2d phase_shift;phase_shift = phaseCorrelate(dst1, dst2);cout << "OpneCV库函数实现 :" << endl << "\tX方向的偏移 : " << phase_shift.x << ",\tY方向的偏移 : " << phase_shift.y << endl;QueryPerformanceCounter(&stopTime);time = 1e3*(stopTime.QuadPart - startTime.QuadPart) / freq.QuadPart;cout << "你电脑的频率为:" << freq.QuadPart << endl;cout << "opencv库函数消耗时间为:" << time << "毫秒" << endl;QueryPerformanceCounter(&startTime);//开始计时int height_offset = 0;int width_offset = 0;PhaseCorrelation2D(srcImage1, srcImage2, height_offset, width_offset);//宽的偏移量  cout << "Phase Correlation自实现 :" << endl << "高度偏移量" << -height_offset << ",   宽度偏移量" << -width_offset << endl;QueryPerformanceCounter(&stopTime);//结束计时time = 1e3*(stopTime.QuadPart - startTime.QuadPart) / freq.QuadPart;cout << "自实现相位相关函数消耗时间为:" << time << "毫秒" << endl;waitKey(0);getchar();return 0;
}
参考代码3(需要配置opencv库和MIT的fftw库):
#include <stdio.h>
#include <iostream>
#include "fftw3.h"
#include "vector"#include <opencv2/legacy/legacy.hpp>
#include <opencv2/nonfree/nonfree.hpp>//opencv_nonfree模块:包含一些拥有专利的算法,如SIFT、SURF函数源码。
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/nonfree/features2d.hpp>using namespace cv;
using namespace std;void PhaseCorrelation2D(const Mat &signal,//原图像信号const  Mat &pattern,//带配准图像信号int &height_offset,//用来获取估计的高度偏移量int &width_offset);//获取宽的偏移量//本程序做了一个很简单的测试:计算“配准样图”中那些样图的偏移量
//(这些图都是通过matlab理想化的平移图)
int main()
{Mat srcImage11 = imread("image_gray.jpg");Mat srcImage21 = imread("img_result_-8_-25.jpg");Mat srcImage1, srcImage2;cvtColor(srcImage11, srcImage1, CV_BGR2GRAY);cvtColor(srcImage21, srcImage2, CV_BGR2GRAY);int height_offset = 0;int width_offset = 0;PhaseCorrelation2D(srcImage1,srcImage2,height_offset,width_offset);//宽的偏移量cout <<"Phase Correlation法 :  高度偏移量"<< -height_offset<<"   宽度偏移量" << -width_offset << endl;getchar();return 0;
}//该函数返回图像的刚性平移量
void PhaseCorrelation2D(const Mat &signal,//原信号const  Mat &pattern,//带配准信号int &height_offset,//高的偏移量int &width_offset)//宽的偏移量
{int nRow = signal.rows;int nCol = signal.cols;fftw_complex *signal_img = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*nRow*nCol);fftw_complex *pattern_img = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*nRow*nCol);for (int i = 0; i < nRow; i++){for (int j = 0; j < nCol; j++){signal_img[i*nCol + j][0] = signal.at<uchar>(i, j);signal_img[i*nCol + j][1] = 0;pattern_img[i*nCol + j][0] = pattern.at<uchar>(i, j);pattern_img[i*nCol + j][1] = 0;}}// 对两幅图像进行傅里叶变换fftw_plan signal_forward_plan = fftw_plan_dft_2d(nRow, nCol, signal_img, signal_img,FFTW_FORWARD, FFTW_ESTIMATE);fftw_plan pattern_forward_plan = fftw_plan_dft_2d(nRow, nCol, pattern_img, pattern_img,FFTW_FORWARD, FFTW_ESTIMATE);fftw_execute(signal_forward_plan);fftw_execute(pattern_forward_plan);// 求互功率谱fftw_complex *cross_img = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*nRow*nCol);double temp;for (int i = 0; i < nRow*nCol; i++){cross_img[i][0] = (signal_img[i][0] * pattern_img[i][0]) -(signal_img[i][1] * (-1.0*pattern_img[i][1]));cross_img[i][1] = (signal_img[i][0] * (-1.0*pattern_img[i][1])) +(signal_img[i][1] * pattern_img[i][0]);temp = sqrt(cross_img[i][0] * cross_img[i][0] + cross_img[i][1] * cross_img[i][1]) + 0.001;cross_img[i][0] /= temp;cross_img[i][1] /= temp;}// backward fft,对互功率谱求反变换// FFTW computes an unnormalized transform,// in that there is no coefficient in front of// the summation in the DFT.// In other words, applying the forward and then// the backward transform will multiply the input by n.// BUT, we only care about the maximum of the inverse DFT,// so we don't need to normalize the inverse result.// the storage order in FFTW is row-orderfftw_plan cross_backward_plan = fftw_plan_dft_2d(nRow, nCol, cross_img, cross_img,FFTW_BACKWARD, FFTW_ESTIMATE);fftw_execute(cross_backward_plan);// free memoryfftw_destroy_plan(signal_forward_plan);fftw_destroy_plan(pattern_forward_plan);fftw_destroy_plan(cross_backward_plan);fftw_free(signal_img);fftw_free(pattern_img);double *cross_real = new double[nRow*nCol];for (int i = 0; i < nRow*nCol; i++)cross_real[i] = cross_img[i][0];//根据反变换求出平移量int max_loc = 0;//准备存放最大值的位置坐标(注意,只有一个值)double max_vlaue = 0.0;for (int i = 0; i < nRow*nCol; i++){if (max_vlaue<cross_real[i]){max_vlaue = cross_real[i];max_loc = i;}}height_offset = (int)floor(((int)max_loc) / nCol);width_offset = (int)max_loc - nCol*height_offset;if (height_offset > 0.5*nRow)height_offset = height_offset - nRow;if (width_offset > 0.5*nCol)width_offset = width_offset - nCol;delete[] cross_real;cross_real = NULL;
}
文章收录:
这俩天一直在做关于物体匹配的方面的工作,前几天朋友推荐我看西安电子科技大学张瑞娟的一篇硕士论文“图像配准理论及算法研究”,我收获很大,所以我也总结一些对我有用的算法,将来便于查找应用。
我做的目标追踪这一块,虽然和图像配准不是一个方向,但是前期工作都是一样的,首先都需要物体检测,特征检测和匹配。这里我总结一些对我有用的,也希望对和我一样研究方向的人有帮助。这里图像配准可以换成物体匹配的。
1, 图像配准要素结合:特征空间,搜索空间,搜索策略,近似性度量
2, 图像配准方法:
2.1基于灰度信息的方法,
交叉相关(互相关)方法,相关系数度量,序贯相似检测算法,信息理论的交换信息相似性准则
2.2基于变换域的方法
相位相关法,Walsh Transform变换
2.3基于特征的方法
常用的图像特征有:特征点(包括角点、高曲率点等)、直线段、边缘(Robert、高斯-拉普拉斯LoG、Canny、Gabor滤波等边缘检测算子)或轮廓、闭合区域、特征结构以及统计特征如矩不变量等
注:像素灰度信息的互相关算法相比,特征提取包含了高层信号信息,所以该类算法对光照、噪声等的抗干扰能力强。
3,常用的空间变换模型
刚体变换(平移、旋转与缩放的组合)、仿射变换、透射变换、投影变换、非线性变换
4, 常用的相似性测度
4.1距离测度
均方根误差,差绝对值和误差,兰氏距离,Mahalanobis距离,绝对差,Hausdorff距离等
4.2角度度量法(概率测度)。
4.3 相关度量法
5,配准算法的评价标准
配准时间、配准率、算法复杂度、算法的可移植性、算法的适用性、图像数据对算法的影响等(这里虽然不是目标追踪的评价标准,但是我们可以借鉴这些评价算法的标准)
收录文章2:
cv::Point2d cv::phaseCorrelateRes(InputArray _src1, InputArray _src2, InputArray _window, double* response)
{  //分别得到两幅输入图像和窗函数的矩阵形式  Mat src1 = _src1.getMat();  Mat src2 = _src2.getMat();  Mat window = _window.getMat();  //输入图像的类型和大小的判断,必须一致,而且类型必须是32位或64位浮点灰度图像  CV_Assert( src1.type() == src2.type());  CV_Assert( src1.type() == CV_32FC1 || src1.type() == CV_64FC1 );  CV_Assert( src1.size == src2.size);  //如果使用窗函数,则窗函数的大小和类型必须与输入图像的一致  if(!window.empty())  {  CV_Assert( src1.type() == window.type());  CV_Assert( src1.size == window.size);  }  //因为要进行离散傅立叶变换,所以为了提高效率,就要得到最佳的图像尺寸  int M = getOptimalDFTSize(src1.rows);  int N = getOptimalDFTSize(src1.cols);  Mat padded1, padded2, paddedWin;  //生成尺寸修改以后的矩阵  if(M != src1.rows || N != src1.cols)   //最佳尺寸不是原图像的尺寸  {  //通过补零的方式填充多出来的像素  copyMakeBorder(src1, padded1, 0, M - src1.rows, 0, N - src1.cols, BORDER_CONSTANT, Scalar::all(0));  copyMakeBorder(src2, padded2, 0, M - src2.rows, 0, N - src2.cols, BORDER_CONSTANT, Scalar::all(0));  if(!window.empty())  {  copyMakeBorder(window, paddedWin, 0, M - window.rows, 0, N - window.cols, BORDER_CONSTANT, Scalar::all(0));  }  }  else    //最佳尺寸与原图像的尺寸一致  {  padded1 = src1;  padded2 = src2;  paddedWin = window;  }  Mat FFT1, FFT2, P, Pm, C;  // perform window multiplication if available  //执行步骤1,两幅输入图像分别与窗函数逐点相乘  if(!paddedWin.empty())  {  // apply window to both images before proceeding...  multiply(paddedWin, padded1, padded1);  multiply(paddedWin, padded2, padded2);  }  // execute phase correlation equation  // Reference: http://en.wikipedia.org/wiki/Phase_correlation  //执行步骤2,分别对两幅图像取傅立叶变换  dft(padded1, FFT1, DFT_REAL_OUTPUT);  dft(padded2, FFT2, DFT_REAL_OUTPUT);  //执行步骤3  //计算互功率谱的分子部分,即公式3中的分子,其中P为输出结果,true表示的是对FF2取共轭,所以得到的结果为:P=FFT1×FFT2*,mulSpectrums函数为通用函数  mulSpectrums(FFT1, FFT2, P, 0, true);  //计算互功率谱的分母部分,即公式3中的分母,结果为:Pm=|P|,magSpectrums函数就是在phasecorr.cpp文件内给出的,它的作用是对复数取模。  magSpectrums(P, Pm);  //计算互功率谱,即公式3,结果为:C=P / Pm,divSpectrums函数也是在phasecorr.cpp文件内给出的,它仿照mulSpectrums函数的写法,其中参数false表示不取共轭  divSpectrums(P, Pm, C, 0, false); // FF* / |FF*| (phase correlation equation completed here...)  //执行步骤4,傅立叶逆变换  idft(C, C); // gives us the nice peak shift location...  /*平移处理,fftShift函数也是在phasecorr.cpp文件内给出的,它的作用是把图像平均分割成——左上、左下、右上、右下,把左上和右下对调,把右上和左下对调。它的目的是把能量调整到图像的中心,也就是图像的中心对应于两幅图像相频差为零的地方,即没有发生位移的地方。*/  fftShift(C); // shift the energy to the center of the frame.  //执行步骤5  // locate the highest peak  //找到最大点处的像素位置,minMaxLoc为通用函数  Point peakLoc;  minMaxLoc(C, NULL, NULL, NULL, &peakLoc);  // get the phase shift with sub-pixel accuracy, 5x5 window seems about right here...  //在5×5的窗体内确定亚像素精度的坐标位置  Point2d t;  // weightedCentroid也是在phasecorr.cpp文件内给出的,它是利用公式4来计算更精确的坐标位置  t = weightedCentroid(C, peakLoc, Size(5, 5), response);  // max response is M*N (not exactly, might be slightly larger due to rounding errors)  //求最大响应值  if(response)  *response /= M*N;  // adjust shift relative to image center...  //最终确定位移量  //先找到图像中点,然后用中点减去由步骤5得到的坐标位置  Point2d center((double)padded1.cols / 2.0, (double)padded1.rows / 2.0);  return (center - t);
}  

参考资源:

【1】西北工业大学,吕海霞,硕士论文,《自动图像配准技术研究》,2007.3

【2】MIT,FFTW库

【3】Joseph L. Horner and Peter D. Gianino. Phase-only matched ltering. Applied Optics, 23(6):812-816, 1984.

【4】复旦大学,宋智礼,博士论文,《图像配准技术及其应用的研究》,2010,4

【5】中国科学技术大学信号统计处理研究院,郑志彬,叶中付,《基于相位相关的图像配准算法》,2006,12

【6】(美)冈萨雷斯著; 阮秋琦译. 数字图像处理(MATLAB 版) [M]. 北京:电子工业出版社, 2005.

【7】(美)冈萨雷斯著; 阮秋琦等译. 数字图像处理(第二版) [M]. 北京:电子工业出版社, 2003.

【8】感谢该博主对OpneCV相位相关库函数的解析,http://blog.csdn.net/zhaocj/article/details/50157801

数字图像处理,相位相关算法解决图像的刚性平移问题相关推荐

  1. 相位相关算法的详细介绍(一)

    相位相关算法: 1.相位相关简介:相位相关算法的理论基础是傅里叶变换,目前在傅里叶变换领域有了快速算法fft,比较成熟的库有fftw开源库,因此相位相关法有极大的速度优势,相位相关在图像融合.模式识别 ...

  2. 数字图像处理笔记(一)——图像存储空间,分辨率,图像内插

    数字图像处理笔记(一)--图像存储空间,分辨率,图像内插 本系列笔记是笔者在学习冈萨雷斯<数字图像处理>第三版时做的总结,日后看的时候方便点,如果有幸得到大家的讨论,喜上眉梢. 本节参考书 ...

  3. 图像处理边缘增强matlab,数字图像处理实验 matlab 图像增强 边缘检测 图像操作.doc...

    数字图像处理实验 matlab 图像增强 边缘检测 图像操作 实验1 点运算和直方图处理 实验目的 1. 掌握利用Matlab图像工具箱显示直方图的方法 2. 掌握运用点操作进行图像处理的基本原理. ...

  4. 【数字图像处理】三.MFC实现图像灰度、采样和量化功能详解

    本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行讲解,主要通过MFC单文档视图实现显示BMP格式图片,并通过Bitmap进行灰度 ...

  5. 【数字图像处理之(一)】数字图像处理与相关领域概述

    数字图像(Digital Image) 一副图像可以定义为一个 二维函数f(x, y),这里的x和y是空间坐标,而在任意坐标(x, y)处的幅度f被称为这一坐标位置图像的亮度或灰度.当x.y和f的幅值 ...

  6. 《数字图像处理》实验之对图像进行双线性(bilinear)插值缩放

    最近数字图像处理的实验课,老师让我们实现对图像进行双线性(bilinear)插值缩放,以下是原理和代码. 一.双线性插值缩放 1.图像几何变换的一般流程: ①确定变换后新图像的大小 ②对新图像的每一个 ...

  7. Win8 Metro(C#)数字图像处理--2.66FloodFill算法

    原文:Win8 Metro(C#)数字图像处理--2.66FloodFill算法  [函数名称] 洪水填充算法函数 WriteableBitmap FloodfillProcess(Writeab ...

  8. 数字图像处理与python实现_数字图像处理学习(2)—— 图像直方图均衡与图像匹配(python实现)...

    数字图像处理学习(2)-- 直方图均衡与图像匹配 1. 直方图均衡(Histogram Equalization) 1.1 直方图均衡化概念 1.2 直方图均衡实现简单思路 1.3 直方图均衡实现代码 ...

  9. 数字图像处理实验--实验项目一 图像的基本操作和基本运算

    目录 前言 实验项目一 图像的基本操作和基本运算 1.[图像的读取操作] 2 [图像的基本运算] 3[ 图像的几何变换] 4[图像的灰度变换] 前言 数字图像处理(Digital Image Proc ...

  10. 数字图像处理实验(一)|图像的基本操作和基本统计指标计算{图像读取imread、图像写入imwrite、图像显示imshow、图像的相关统计量|均值、方差、大小尺寸裁减旋转|}(附实验代码和实验截图)

    文章目录 一.实验目的 二.实验主要仪器设备 三.实验原理 (1)将一幅图像视为一个二维矩阵. (2)利用MATLAB图像处理工具箱读.写和显示图像文件. (3)计算图像的有关统计参数. (4)改变图 ...

最新文章

  1. 在Ubuntu 16.04.3 TLS上玩转tls协议的简单demo
  2. maven 主工程 java_Maven创建Java Application工程(既jar包)
  3. 协程、asyncio、异步编程
  4. 机器学习之数学基础(二)~数组、向量、矩阵、向量空间、二维矩阵
  5. HBase 数据库检索性能优化策略--转
  6. 超负荷写代码 = 慢性自杀
  7. angularjs入门学习【应用剖析中篇】
  8. ubuntu12.04的NFS配置
  9. ERROR - ORA-12560: TNS:protocol adapter error
  10. 游戏关卡设计理论普及
  11. vue项目运行后自动打开浏览器
  12. 手机连上电脑热点发现网络不可用,怎么办?
  13. V831——识别指定的人脸
  14. 我做实施交付那些年——说点废话(1)
  15. 联想thinkcentre微型计算机,联想ThinkCentre一体机_ThinkCentre台式机-ThinkPad官网
  16. NLP系列(4)_朴素贝叶斯实战与进阶
  17. 【SeMask】Semantically Masked Transformers for Semantic Segmentation
  18. 禾川科技通过注册:拟募资8亿 达晨与国弘投资是股东
  19. linux环境下编译部署php生产环境
  20. 【无私分享】修订版干货!!!一个炫酷的自定义日历控件,摆脱日历时间选择烦恼,纯福利~...

热门文章

  1. 我的车辆过户办理经历分享(深圳市内过户)
  2. Google账号找回通用方法(尤其是知道账号密码仍无法登录和找回的)
  3. 付呗聚合支付快速教程 基础篇②——FubeiUtils付呗工具类(封装参数和签名规则)
  4. 主数据项目交付最佳实践
  5. ubuntu命令行模式与图形桌面切换方法
  6. ReactNative 导航栏Navigator的使用及参数navigator的传递
  7. java-php-python-ssm南京新东方学校家校通系统计算机毕业设计
  8. EOF到底是什么意思?
  9. readonly属性
  10. java 加权平均_使用Java 8流计算加权平均值