OpenCV:基于特征的图像校准

**OpenCV: 基于特征的图像校准**

  • 什么是图像配准或图像对齐
  • 图像配准的应用
  • 图像配准的基本理论
  • 如何得到单应矩阵
  • 寻找匹配点
  • OpenCV图像配准代码(C++)
  • 结果:

本文将会介绍一种基于特征的图像校准方式,在这种方式中,大量的特征将在第一张源图中被提取出来,这些特征将在目标图像中寻找匹配的特征信息。通过两幅图片中相匹配的特征信息,源图和目标图像之间的像素坐标转换关系将会被提取出来。借助这种转换关系可以实现将一幅图片与另一幅校准对齐。

什么是图像配准或图像对齐

在许多应用中,我们有两幅包含相同物体的图片或者文件图片,但两幅图片中的相同物体是没有对齐的。比如说你在第一幅图中选择一个角点,在另一幅图片中相同角点的坐标位置是不一样的。
图像配准可以将其中一幅图片进行变形处理,使得两幅图片中相同的特征完美对齐。
OpenCV:基于特征的图像校准_第1张图片
上图显示了在文件分析中的应用,我们用原始表格作为原始图像,手机拍摄的填写完成的表格图像作为目标图像,经过图像配准,目标图像已经与原始表格对齐,便于后期分析与信息提取等操作。

图像配准的应用

图像配准的应用领域广泛。
在许多文件处理的应用中,第一步一般都是将扫描的文件或拍摄的文件与模板对齐。如果你像编写一个自动的表格数据读取系统,第一步就需要将表格与模板对齐,然后对模板中特定位置的信息进行提取。
在医学处理上,在不同的时间对同一组织进行扫描的结果往往有轻微的偏差,利用配准技术可以将两幅图片进行对齐,便于病灶的对比分析。
另一个有意思的应用是在全景照片的生成,若两幅相邻图片是围绕光轴旋转摄像机所拍摄得来的,我们可以通过本文所说的技术对两幅图片进行配准。

图像配准的基本理论

在计算机视觉中,平面的单应性被定义为一个平面到另外一个平面的投影映射。图像配准的核心是一个3*3的单应矩阵。在满足以下两个条件下,两幅图片是单应相关的:

  1. 两幅图片是平面的。(比如纸业,信用卡等)
  2. 这两幅图像是通过将摄像机绕其光轴旋转来获取的。我们在生成全景图的同时拍摄这些图像。

单应性简单来说就是一个3*3矩阵:
在这里插入图片描述
若(x1,y1)是第一幅图中的一个点的坐标,(x2,y2)是第二幅图片中相同物理点的坐标,单应矩阵可以通过以下方式将这两幅图片联系起来:
在这里插入图片描述
这样看来,如果我们能获取这个单应矩阵,那么应用这个单应矩阵对一幅图片所有像素的坐标进行变换,变换结果就能和第二图图片配准。

如何得到单应矩阵

OpenCV:基于特征的图像校准_第2张图片
如果两幅图像中我们知道4对以上的对应点,那么我们就可以用OpenCV函数 findHomography 来找到这种单应关系,如上图所示红黄蓝橙四对点。在内部函数 findHomography 将会通过解决一个线性方程组来找到单应矩阵,数学解析细节在此不表。

看函数用法是怎么样的:

findHomography(point1, point2, h);

point1point2是存储对应点的向量,h是计算出的单应矩阵。那我们该如何找到对应的点对呢?

寻找匹配点

在许多计算机视觉应用中,我们通常需要识别图像中感兴趣的稳定点。这些点被称为关键点特征点,几种关键点检测技术已在OpenCV中实现。在此我们将会用ORB特征算子,因为SIFTSURF已经被申请专利,如果要实际应用的话,必须要付一定的专利费,ORB免费,除此以外,ORB速度快,也比较精确。下图显示了ORB关键点的检测结果:
OpenCV:基于特征的图像校准_第3张图片
一个特征点检测器包含两部分:

  1. 定位器:图像中被检测到的点在图像尺度变化,图像旋转等条件下要保持稳定。定位器就是用来找到这些稳定的点。ORB中所用的定位器是FSAT
  2. 描述子:定位器告诉我们兴趣点的位置,描述子则可以使我们区分不同的兴趣点。描述器可以把每个特征点描述成一个由数字构成的矩阵,理想情况下,在两幅图像中,相同物理点的描述子结果是相同的。ORB所用的是一个被改进的特征描述子BRISK.

两幅图片的单应性在我们知道两幅图片的对应特征的情况下可以被计算出来。所以匹配算法用于寻找在两幅图片中的那些对应特征点。为此,将一个图像中每个特征的描述符与第二个图像中每个特征的描述符进行比较,以找到良好的匹配。

OpenCV图像配准代码(C++)

//特征匹配的函数需要包含contirbe
#include 
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/features2d.hpp"

using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;

const int MAX_FEATURES = 500; 	//控制最多可以检测到的特征点对数
const float GOOD_MATCH_PERCENT = 0.15f;


void alignImages(Mat &im1, Mat &im2, Mat &im1Reg, Mat &h)

{

	// Convert images to grayscale
	Mat im1Gray, im2Gray;
	cvtColor(im1, im1Gray, CV_BGR2GRAY);
	cvtColor(im2, im2Gray, CV_BGR2GRAY);

	// Variables to store keypoints and descriptors
	std::vector keypoints1, keypoints2;
	Mat descriptors1, descriptors2;

	// Detect ORB features and compute descriptors.
	Ptr orb = ORB::create(MAX_FEATURES);
	orb->detectAndCompute(im1Gray, Mat(), keypoints1, descriptors1);
	orb->detectAndCompute(im2Gray, Mat(), keypoints2, descriptors2);

	// Match features.
	std::vector matches;
	Ptr matcher = DescriptorMatcher::create("BruteForce-Hamming");
	matcher->match(descriptors1, descriptors2, matches, Mat());

	// Sort matches by score
	std::sort(matches.begin(), matches.end());

	// Remove not so good matches
	const int numGoodMatches = matches.size() * GOOD_MATCH_PERCENT;
	matches.erase(matches.begin() + numGoodMatches, matches.end());


	// Draw top matches
	Mat imMatches;
	drawMatches(im1, keypoints1, im2, keypoints2, matches, imMatches);
	imwrite("matches.jpg", imMatches);


	// Extract location of good matches
	std::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);
	}

	// Find homography
	h = findHomography(points1, points2, RANSAC);

	// Use homography to warp image
	warpPerspective(im1, im1Reg, h, im2.size());

}


int main(int argc, char **argv)
{
	// Read reference image
	string refFilename("src.jpg");
	cout << "Reading reference image : " << refFilename << endl;
	Mat imReference = imread(refFilename);


	// Read image to be aligned
	string imFilename("dst.jpg");
	cout << "Reading image to align : " << imFilename << endl;
	Mat im = imread(imFilename);


	// Registered image will be resotred in imReg. 
	// The estimated homography will be stored in h. 
	Mat imReg, h;

	// Align images
	cout << "Aligning images ..." << endl;
	alignImages(im, imReference, imReg, h);

	// Write aligned image to disk. 
	string outFilename("aligned.jpg"
	cout << "Saving aligned image : " << outFilename << endl;
	imwrite(outFilename, imReg);

	// Print estimated homography
	cout << "Estimated homography : \n" << h << endl;

}

OpenCV内对特征点提取,描述子生成,特征匹配,计算单应矩阵,根据单应矩阵转换图像等都有对应函数,我们可以很方便的看算法效果。唯一需要注意的是头文件“xfeatures2d.hpp”和“features2d.hpp”并不在官方发行的opencv版本中包含,需要另外编译一个OpenCV_contrib库,该库包含一些匹配,深度神经网络,人脸识别等内容。OpenCV_contrib库的编译网上有许多详细的帖子介绍,在此给一个推荐https://blog.csdn.net/u012905422/article/details/74926256

结果:

源图像如下:
OpenCV:基于特征的图像校准_第4张图片

目标图像如下:
OpenCV:基于特征的图像校准_第5张图片

匹配结果如下:
OpenCV:基于特征的图像校准_第6张图片
配准后目标图像变形结果如下:
OpenCV:基于特征的图像校准_第7张图片

你可能感兴趣的:(OpenCV)