本文由@星沉阁冰不语出品,转载请注明作者和出处。
文章链接:http://blog.csdn.net/xingchenbingbuyu/article/details/50695399
微博:http://weibo.com/xingchenbing
SIFT是我本科毕业设计就开始研究的一个算法,也是视觉领域极为经典的一个算法。SIFT算法的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出,不会因光照,仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。
Lowe将SIFT算法分解为如下四步:1. 尺度空间极值检测:搜索所有尺度上的图像位置。通过高斯微分函数来识别潜在的对于尺度和旋转不变的兴趣点。
2. 关键点定位:在每个候选的位置上,通过一个拟合精细的模型来确定位置和尺度。关键点的选择依据于它们的稳定程度。
3. 方向确定:基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向。所有后面的对图像数据的操作都相对于关键点的方向、尺度和位置进行变换,从而提供对于这些变换的不变性。
4. 关键点描述:在每个关键点周围的邻域内,在选定的尺度上测量图像局部的梯度。这些梯度被变换成一种表示,这种表示允许比较大的局部形状的变形和光照变化。
下面就来在Qt中调用Opencv来简单实现一下吧。
mainwindow.cpp如下:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{ //打开一张图片
QString fileName = QFileDialog::getOpenFileName(this,tr("Open Image"),".",tr("Image File(*.png *.jpg *.jpeg *.bmp)"));
image1 = cv::imread(fileName.toLatin1().data());
if(image1.empty())
{
cout<<"Please open an image!" <<endl;
}
else
{
//把Mat转换成QImage
cv::cvtColor(image1,image1,CV_BGR2RGB);
QImage img = QImage((const unsigned char*)(image1.data),image1.cols,image1.rows,QImage::Format_RGB888);
//在QLabel中显示图片
ui->label->setPixmap(QPixmap::fromImage(img));
ui->label->resize(ui->label->pixmap()->size());
}
}
void MainWindow::on_pushButton_2_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this,tr("Open Image"),".",tr("Image File(*.png *.jpg *.jpeg *.bmp)"));
image2 = cv::imread(fileName.toLatin1().data());
if(image1.empty())
{
cout<<"Please open an image!" <<endl;
}
else
{
cv::cvtColor(image2,image2,CV_BGR2RGB);
QImage img2 = QImage((const unsigned char*)(image2.data),image2.cols,image2.rows,QImage::Format_RGB888);
ui->label_2->setPixmap(QPixmap::fromImage(img2));
ui->label_2->resize(ui->label_2->pixmap()->size());
}
}
void MainWindow::on_pushButton_3_clicked()
{
if(image1.empty())
{
cout<<"Please open an image!" <<endl;
}
else
{ //特征点检测
SiftFeatureDetector featureDetector;
featureDetector.detect(image1, image1_kp);
//画出特征点
drawKeypoints(image1,image1_kp,image1,Scalar(0,255,0),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
QImage img1 = QImage((const unsigned char*)(image1.data),image1.cols,image1.rows,QImage::Format_RGB888);
ui->label->setPixmap(QPixmap::fromImage(img1));
ui->label->resize(QSize(img1.width(),img1.height()));
}
if(image2.empty())
{
cout<<"Please open an image!" <<endl;
}
else
{
SiftFeatureDetector featureDetector;
featureDetector.detect(image2, image2_kp);
drawKeypoints(image2,image2_kp,image2,Scalar(0,255,0),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
QImage img2 = QImage((const unsigned char*)(image2.data),image2.cols,image2.rows,QImage::Format_RGB888);
ui->label_2->setPixmap(QPixmap::fromImage(img2));
ui->label_2->resize(QSize(img2.width(),img2.height()));
}
}
void MainWindow::on_pushButton_4_clicked()
{
Mat image1_desc,image2_desc;
//特征点提取
SiftDescriptorExtractor featureExtractor;
featureExtractor.compute(image1, image1_kp, image1_desc);
featureExtractor.compute(image2, image2_kp, image2_desc);
//FLANN based descriptor matcher object
FlannBasedMatcher matcher;
vector<Mat> image1_desc_collection(1, image1_desc);
matcher.add(image1_desc_collection);
matcher.train();
//match image1 and image2 descriptor,getting 2 nearest neighbors for all test descriptor
vector<vector<DMatch> > matches;
matcher.knnMatch(image2_desc, matches, 2);
//filter for good matches according to Lowe's algorithm
vector<DMatch> good_matches;
for (unsigned int i = 0; i < matches.size(); i++)
{
if (matches[i][0].distance < 0.6*matches[i][1].distance)
good_matches.push_back(matches[i][0]);
}
Mat img_show;
drawMatches(image2, image2_kp, image1, image1_kp, good_matches, img_show);
QImage img3 = QImage((const unsigned char*)(img_show.data),img_show.cols,img_show.rows,QImage::Format_RGB888);
ui->label->setPixmap(QPixmap::fromImage(img3));
ui->label->resize(QSize(img3.width(),img3.height()));
ui->label_2->hide();
}
最后效果如下:
这里两边选择了同一张照片,所以所有特征点都匹配了。可以换成相似的或者完全不同的照片看看结果。
值得一提的是
SiftFeatureDetector featureDetector;
可以换成
SurfFeatureDetector featureDetector;
<pre name="code" class="cpp">OrbFeatureDetector featureDetector;
而
FlannBasedMatcher matcher;
可以换成
BFMatcher matcher;//Brute Force based descriptor matcher object
更多细节还得自己亲自去探索。
本文由@星沉阁冰不语出品,转载请注明作者和出处。
文章链接:http://blog.csdn.net/xingchenbingbuyu/article/details/51375078
微博:http://weibo.com/xingchenbing