目录
1.基于ORB自动化图像透视变换方法
2.图像对齐的历史知识
3.应用ECC进行图像对齐
4.参考资料
研究该专题是因为在后续使用随机森林做样本训练的过程中我需要提前制作样本的数据集,但是这就面临一个问题:图像的对齐问题 为了解决图像的对齐问题,我查到了一篇论文:Parametric Image Alignment Using Enhanced Correlation Coefficient Maximization 但是发现ECC算法已经被实现了,所以整理下如何应用。
在整理的过程中发现了一名大佬,我的内容是从他的github:https://github.com/spmallick/learnopencv整理而来。
简历:
有兴趣的小伙伴可以关注!!!
在之前识别答题卡的博客中,为了提取答题卡的区域特征我应用了OTSU方法;为了进行计算透视变化的矩阵我应用了DP算法来计算矩形的四个对应的点,但是今天却看到了更有价值的方法,在此进行分析:
问题:寻找一种鲁棒的算法让左右两幅图像进行对齐。
思路:
计算图像的ORB特征点(当然也可以选择其他特征点,但是计算量会更大)-->筛选最佳的匹配点-->基于这些匹配点应用Levenberg–Marquardt方法迭代求解非线性方程组(在OpenCV中已经实现了)-->计算单应性矩阵-->图像变换
代码实现(注意:要实现这段代码需要对opencv的xfeatures2d自行编译):
#include
#include
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/features2d.hpp"
using namespace cv;
using namespace std;
using namespace xfeatures2d;
void alignImages1(Mat img1, Mat img2, Mat &result, Mat &M)
{
//rgb-gray转化
cvtColor(img1,img1,CV_BGR2GRAY);
cvtColor(img2, img2, CV_BGR2GRAY);
//计算orb
Ptr orb = ORB::create();
vector keypoints1, keypoints2;
Mat descriptors1, descriptors2;
orb->detectAndCompute(img1, Mat(), keypoints1, descriptors1);
orb->detectAndCompute(img2, Mat(), keypoints2, descriptors2);
//匹配
vector matches;
Ptr matcher = DescriptorMatcher::create("BruteForce-Hamming");
matcher->match(descriptors1, descriptors2, matches, Mat());
//筛选好的匹配
sort(matches.begin(), matches.end());
const int numGoodMatches = matches.size() * 0.15;
matches.erase(matches.begin() + numGoodMatches, matches.end());
//绘图确认下匹配关系
Mat drawMat;
drawMatches(img1, keypoints1, img2, keypoints2, matches, drawMat);
//提取好的匹配点
vector points1, points2;
for (size_t i = 0; i < matches.size(); i++)
{
points1.push_back(keypoints1[matches[i].queryIdx].pt);
points2.push_back(keypoints2[matches[i].trainIdx].pt);
}
//随机取样一致性计算单应性矩阵
M = findHomography(points2, points1, RANSAC);
//进行单应性变换
warpPerspective(img2, result, M, img1.size());
}
int main()
{
Mat templateImg = imread("form.jpg");
Mat testImg = imread("scanned-form.jpg");
//存储对齐结果
Mat result;
//存储变换矩阵
Mat M;
//计算
alignImages1(templateImg, testImg,result,M);
return 0;
}
所筛选出来的ORB特征点(对应的特征点用彩色线段连接)如下图:
应用单应性矩阵进行透视变换最终的结果:
和模板的结果对比:
图像对齐的历史可以追溯到上个世纪人们对彩色照片拍摄的探索,总所周知,从可视化的角度来说一张彩色图像可以看成是RGB三原色以不同的分量叠加而成。那么是不是说有了这三色通道的底片就能成功合成完美的彩色图像了呢?
在1855年,James Clerk Maxwell提出了一个合成彩色图像的想法:
使用三个主要滤色镜(红色,绿色,蓝色)拍摄三张不同照片并将它们组合以获得彩色图像
在1861年,英国摄影师托马斯萨顿将马克斯韦尔的理论付诸实践,制作了第一张彩色照片:
图 Maxwell Sutton叠加3张灰度图像生成的第一张彩色照片
他在一张彩带上拍摄了三张灰度图像(见上图),使用三种不同的彩色滤镜,然后使用三台配有相同滤色镜的投影仪叠加图像。当时可用的照相材料对蓝光敏感,但对绿光不敏感,对红光几乎不敏感。虽然它的时代是革命性的,但这种方法并不实用。
到20世纪初,照相材料的灵敏度已经大大提高,并且在本世纪的前十年,一些实用相机可用于彩色摄影。这些相机中最受欢迎的是 Lumière兄弟发明的 Autochrome。
当时被广泛使用的相机系统是由Adolf Miethe设计的,最后由Wilhelm Bermpohl打造,因此称之为"Professor Dr. Miethe’s Dreifarben-Camera. "
在德国,单词"Dreifarben"也称之为“三原色”,这款相机也被称之为"Miethe-Bermpohl",它是由一张长的玻璃板和三个不同的滤镜构成的,因此它能同时捕获三张照片。
图 Professor Dr. Miethe's Dreifarben-Camera (01)
图 Professor Dr. Miethe's Dreifarben-Camera (02)
图 Professor Dr. Miethe's Dreifarben-Camera (03)
在1909年,Sergey Prokudin-Gorskii使用Miethe-Bermpohl camera 为沙皇尼古拉斯二世拍摄了第一张彩色照片,随后在沙皇尼古拉斯二世的资助下 ,Sergey Prokudin-Gorskii开始了长达十年的俄罗斯征途,沿途拍摄了将近10,000张照片,他最著名的照片便是列夫 托尔斯泰的肖像画。
图 Miethe-Bermpohl相机在垂直玻璃板上拍摄的三张图像
事实上,从这些黑白图像中生成彩色图像并非易事。由于Miethe-Bermpohl相机是在2-6秒的时间内拍摄这三张照片,因此,三个通道经常不对齐,如果我们直接对三色通道直接堆叠往往会导致令人非常失望的结果:
图 三色通道直接叠加
那么该如何解决图像对齐的问题呢?
下面将会以下面的图像作为demo来实现图像的对齐:
图 图像对齐demo
“Parametric Image Alignment Using Enhanced Correlation Coefficient Maximization”一文中提出增强相关系数(ECC)的新相似性度量来估计运动模型的参数,使用ECC进行图像对齐有两个优点:
1.ECC对比度和亮度的光度失真不变;
2.虽然目标函数是参数的非线性函数,但它们为解决优化问题而开发的迭代方案是线性的。换句话说,他们在表面上遇到了计算成本昂贵的问题,却找到了一种迭代求解的简单方法。
在OpenCV中的实现方法是应用findTransformECC(),具体请参考官方文档:
https://docs.opencv.org/3.4.1/dc/d6b/group__video__track.html#ga7ded46f9a55c0364c92ccd2019d43e3a
值得注意的是运动模型的选择:
对齐实验1:
code:
#include
#include
using namespace cv;
using namespace std;
int main()
{
//加载
Mat img_01 = imread("image1.jpg",0);
Mat img_02 = imread("image2.jpg", 0);
//定义运动模型
const int warp_mode = MOTION_EUCLIDEAN;
//建立变化矩阵
Mat warp_matrix;
if (warp_mode == MOTION_HOMOGRAPHY)
warp_matrix = Mat::eye(3, 3, CV_32F);
else
warp_matrix = Mat::eye(2, 3, CV_32F);
//最大迭代数
int number_of_iterations = 5000;
//迭代精度
double termination_eps = 1e-10;
//迭代标准
TermCriteria criteria(TermCriteria::COUNT + TermCriteria::EPS,
number_of_iterations, termination_eps);
//计算变换矩阵
findTransformECC(img_01,img_02,warp_matrix,warp_mode,criteria);
//计算对齐后的图像
Mat result;
if (warp_mode != MOTION_HOMOGRAPHY)
warpAffine(img_02, result, warp_matrix, img_01.size(),
INTER_LINEAR + WARP_INVERSE_MAP);
else
warpPerspective(img_02, result, warp_matrix, img_01.size(),
INTER_LINEAR + WARP_INVERSE_MAP);
return 0;
}
实现实现的结果:
对齐实验2:三通道图像进行对齐,它们的像素尺寸是一样的
正如Satya Mallick所言,从上图的BGR三色的通道图像中可以看出,就像素强度来看,三色通道的相关性并没有我们想象的那样强。就好比emir所穿的衣服来说,三色通道的相关性显然是不足的。
事实证明,三色通道在梯度阈内的相似度是最高的:
code:
#include
#include
using namespace cv;
using namespace std;
//计算梯度信息
Mat GetGradient1(Mat src_gray)
{
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
int scale = 1;
int delta = 0;
int ddepth = CV_32FC1; ;
//利用sobel算子计算x、y轴的梯度信息
Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x );
Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y );
//梯度加权
Mat grad;
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
return grad;
}
int main()
{
//读取emir的肖像
Mat img_emir = imread("emir.jpg", 0);
//分割3通道图像
vector img_tri_emir(3);
img_tri_emir[0] = img_emir(Rect(0, 0, img_emir.cols, img_emir.rows / 3));
img_tri_emir[1] = img_emir(Rect(0, img_emir.rows / 3, img_emir.cols, img_emir.rows / 3));
img_tri_emir[2] = img_emir(Rect(0, img_emir.rows * 2 / 3, img_emir.cols, img_emir.rows / 3));
//1.不对齐图像直接进行叠加
Mat emir_color_01;
merge(img_tri_emir, emir_color_01);
//2.应用ECC对齐后进行叠加
//2.1 计算梯度信息
vector emir_grad(3);
for (int i = 0; i < 3;i++)
emir_grad[i] = GetGradient1(img_tri_emir[i]);
//2.2 ECC参数设置
const int warp_mode = MOTION_AFFINE;
Mat warp_matrix;
if (warp_mode == MOTION_HOMOGRAPHY)
warp_matrix = Mat::eye(3, 3, CV_32F);
else
warp_matrix = Mat::eye(2, 3, CV_32F);
int number_of_iterations = 5000;
double termination_eps = 1e-10;
TermCriteria criteria(TermCriteria::COUNT + TermCriteria::EPS,
number_of_iterations, termination_eps);
//2.3 图像对齐
vector emir_aligned(3);
emir_aligned[2] = img_tri_emir[2];
for (int i = 0; i < 2; i++)
{
double cc = findTransformECC(emir_grad[2], emir_grad[i],warp_matrix,warp_mode,criteria);
if (cc == -1)
{
cerr << "The execution was interrupted.
The correlation value is going to be minimized." << endl;
cerr << "Check the warp initialization and/or the size of
images." << endl << flush;
}
if (warp_mode == MOTION_HOMOGRAPHY)
warpPerspective(img_tri_emir[i], emir_aligned[i],
warp_matrix, emir_aligned[2].size(),
INTER_LINEAR + WARP_INVERSE_MAP);
else
warpAffine(img_tri_emir[i], emir_aligned[i],
warp_matrix, emir_aligned[2].size(),
INTER_LINEAR + WARP_INVERSE_MAP);
}
//2.4 叠加
Mat emir_color_02;
merge(emir_aligned, emir_color_02);
return 0;
}
最终结果:左图为直接叠加,右图为应用ECC对齐后进行叠加
https://download.csdn.net/download/qiao_lili/10790432
1.Evangelidis G D , Psarakis E Z . Parametric Image Alignment Using Enhanced Correlation Coefficient Maximization[J]. IEEE Transactions on Pattern Analysis & Machine Intelligence, 2008, 30(10):1858-1865.
2.相关资料:https://github.com/spmallick/learnopencv
3.Professor Dr. Miethe's Dreifarben-Camera:http://www.vintagephoto.tv/mb.shtml