导读
本文主要介绍OpenCV基于相位相关的图像拼接方法与演示。
OpenCV图像拼接相关文章
了解OpenCV图像拼接常用方法可以点击下面标题进入对应往期文章介绍:
- OpenCV常用图像拼接方法(一):直接拼接(硬拼)
- OpenCV常用图像拼接方法(二):基于模板匹配拼接
- OpenCV常用图像拼接方法(三):基于特征匹配拼接
- OpenCV常用图像拼接方法(四):基于Stitcher类拼接
- OpenCV图像拼接终章--Stitching detailed使用与参数介绍
相位相关简介
相位相关(phase correlate)可以用于检测两幅内容相同的图像之间的相对位移量。可用于对齐图像,不具备光照不变性。它是基于傅立叶变换的位移定理:一个平移过的函数的傅立叶变换仅仅是未平移函数的傅立叶变换与一个具有线性相位的指数因子的乘积,即空间域中的平移会造成频域中频谱的相移。它的公式定义为:设二维函数(图像)f(x,y)的傅立叶变换为F(u,v),即DFT[f(x,y)]=F(u,v),如果f(x,y)平移(a,b),则平移后的傅立叶变换为:
因此,当两幅函数f1(x,y)和f2(x,y)仅仅有位移的差异,即f2(x,y)= f1(x-a,y-b),则它们的傅立叶变换F1(u,v)和F2(u,v)有如下关系:
由上式很容易得到f1(x,y)和f2(x,y)的互功率谱为(这里还用到了f1(x,y)和f2(x,y)的频谱的模相等):
式中F*表示F的共轭,上式表示平移定理保证了互功率谱的相位等于两幅图像之间的相移。
参考链接:https://blog.csdn.net/zhaocj/article/details/50157801
Opencv的文档给出了详细的用相位相关法求解位移量的过程:
[1] 对待处理的两幅图像src1和src2应用窗函数去除图像的边界效应,文档中推荐使用汉宁窗,它可用createHanningWindow函数生成;
[2] 求傅立叶变换:Ga=DFT[scr1]和Ga=DFT[scr1];
[3] 计算互功率谱;
[4] 对互功率谱求傅立叶逆变换:r=DFT-1[R];
[5] 对r计算最大值的位置,并在以该位置为中心的5×5的窗体内应用下列公式获得亚像素级的精度位置:
最终(a,b)为两个图像之间的位移量。
OpenCV相位相关函数
OpenCV相位相关函数phaseCorrelate:
参数:
src1 | 输入浮点图像1 CV_32FC1 或 CV_64FC1 |
---|---|
src2 | 输入浮点图像2 CV_32FC1 或 CV_64FC1,与src1相同宽高 |
window | 带加窗系数的浮点数组以减少边缘效应(可选) |
response=0 | 峰值周围5x5质心内的信号功率,介于0和1之间(可选) |
返回值 | 检测到两个阵列之间的相移(亚像素级别) |
基于相位相关图像拼接
本文使用的拼接图像从下图中截取两部分,分别保存为01.jpg(待拼接左图)和02.jpg(待拼接右图)
01.jpg(待拼接左图)
02.jpg(待拼接右图)
相位相关函数返回结果:
代码语言:javascript复制Point2d shiftPt = phaseCorrelate(grayL64F, grayR64F);
cout << shiftPt << endl;
代码语言:javascript复制Point shiftPt = phaseCorrelate(grayL64F, grayR64F);
cout << shiftPt << endl;
待拼接左图向左平移205pixel,向下平移60pixel与待拼接右图左上角重合,[-205, 60]即为水平和竖直方向的平移量。
完整代码与拼接结果:
代码语言:javascript复制// 06_Image_Stitch_PhaseCorrelate.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// 公众号:OpenCV与AI深度学习
// 环境 VS2017 OpenCV4.4.0
// 功能介绍:基于相位相关的图像拼接
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat imgL = imread("./imgs/01.jpg");
Mat imgR = imread("./imgs/02.jpg");
double start = getTickCount();
Mat grayL, grayR;
cvtColor(imgL, grayL, COLOR_BGR2GRAY);
cvtColor(imgR, grayR, COLOR_BGR2GRAY);
Mat grayL64F, grayR64F;
grayL.convertTo(grayL64F, CV_64F);
grayR.convertTo(grayR64F, CV_64F);
Point shiftPt = phaseCorrelate(grayL64F, grayR64F);
cout << shiftPt << endl;
Mat dstImg(imgL.rows, imgR.cols abs(shiftPt.x), CV_8UC3, Scalar::all(0));
Mat roiLeft = dstImg(Rect(0, 0, imgL.cols, imgL.rows));
imgL.copyTo(roiLeft);
Mat roiRight = dstImg(Rect(-shiftPt.x, 0, imgR.cols, imgR.rows - shiftPt.y));
Mat cutImg = imgR(Rect(0, shiftPt.y, imgR.cols, imgR.rows - shiftPt.y));
cutImg.copyTo(roiRight);
Mat debugImg = dstImg.clone();
rectangle(debugImg, Point(-shiftPt.x, -shiftPt.y), Point(dstImg.cols-1, imgR.rows - shiftPt.y), Scalar(0, 255, 0), 2, 8);
imwrite("match.jpg", debugImg);
double end = getTickCount();
double useTime = (end - start) / getTickFrequency();
cout << "use-time : " << useTime << "s" << endl;
imwrite("dst.jpg", dstImg);
cout << "Done!" << endl;
return 0;
}
拼接结果图:
匹配区域:
结尾语
[1] 相位相关法相比模板匹配方法可以自动计算偏移量,省去设定模板的步骤;
[2] 在特征点较少的图像拼接情况下,特征匹配如SIFT/SURF可能会失败,此时可尝试相位相关法:
[3] 相位相关法不适用图像有周期性重复区域的图像,如棋盘格图像。
[4] 上面代码只给出了一种左右拼接情形,实际应用需根据水平和竖直方向平移量正负判断拼接方向和位置。
[5] 一些畸变明显的图像不能单纯靠此方法得到好的效果。