相机镜头所呈现出的景物要比人类的视觉系统所看到的景物要狭小得多,因此一幅图像不可能捕获到我们所看到的整个景物。全景图像拼接给出了这个问题的解决办法,它是把图像间重叠部分拿出来拼接起来,从而得到一幅更大的图像。这种算法也可以用于把一幅图像插入到另一幅图像中。
图1 图像拼接执行过程及方法
要想完成图像拼接,所要用到的算法较多,Opencv把这些算法用一张图呈现了处理,如图1所示。下面我们就详细图像拼接算法。
1、计算特征点
1.1 原理
图像拼接的第一步是计算图像的特征,并得到它们的描述符。好的特征检测的算法有SIFT和SURF,但它们都受到专利的保护,使用上有一定的限制。而ORB算法是一种很好的替代方法,它是利用FAST检测特征,并生成BRIEF描述符。
关于局部特征检测方面的内容,我前面的文章中有一些算法的介绍,在这里就不再做过多的讲解。
1.2 源码
Opencv中应用的是SURF算法和ORB算法,详细的内容为:
class detail::FeaturesFinder表示寻找图像特征的类:
class CV_EXPORTS FeaturesFinder
{
public:
virtual ~FeaturesFinder() {}
//寻找给定图像的特征
void operator ()(const Mat &image, ImageFeatures &features);
void operator ()(const Mat &image, ImageFeatures &features, const std::vector<cv::Rect> &rois);
virtual void collectGarbage() {} //释放已被分配、但还没有被使用的内存
protected:
//虚函数,根据用户所选取的特征类别,调用不同子类的find函数,目前只实现了SURF特征和ORB特征
virtual void find(const Mat &image, ImageFeatures &features) = 0;
};
在FeaturesFinder类中,重载( )运算符主要的任务是调用find函数来检测图像特征。而find是虚函数,具体是执行FeaturesFinder类的两个子类——SurfFeaturesFinder和OrbFeaturesFinder中的find函数。下面我们就来介绍这两个子类,它们分别表示SURF特征和ORB特征。
SurfFeaturesFinder类的构造函数:
SurfFeaturesFinder::SurfFeaturesFinder(double hess_thresh, int num_octaves, int num_layers,
int num_octaves_descr, int num_layers_descr)
//hess_thress表示Hessian矩阵行列式响应值的阈值,默认值为300
//num_octaves表示特征点所用到的图像堆的组数,默认值为3
//num_layers表示特征点所用到的图像堆中每组中的中间层数,默认值为4
//num_octaves_descr表示描述符所用到的图像堆的组数,默认值为3
//num_layers_descr表示描述符所用到的图像堆中每组中的中间层数,默认值为4
{
//如果特征点和描述符所用到的组数和层数都相同,则只需一个Feature2D数据类型来表示特征点和描述符即可,默认就是这种情况
if (num_octaves_descr == num_octaves && num_layers_descr == num_layers)
{
//surf为Feature2D数据类型的指针变量,它被创建为SURF特征点
surf = Algorithm::create<Feature2D>("Feature2D.SURF"