OpenCV实践之路——Qt中用opencv提取和匹配SIFT特征点

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();
}


这里需要注意的一点是由于图片在打开的时候已经从BGR转换到RGB了,最后提取和匹配特征点之后就不需要再转换了,不然图片发蓝。

最后效果如下:

OpenCV实践之路——Qt中用opencv提取和匹配SIFT特征点_第1张图片

OpenCV实践之路——Qt中用opencv提取和匹配SIFT特征点_第2张图片

OpenCV实践之路——Qt中用opencv提取和匹配SIFT特征点_第3张图片

这里两边选择了同一张照片,所以所有特征点都匹配了。可以换成相似的或者完全不同的照片看看结果。

值得一提的是

SiftFeatureDetector featureDetector;

可以换成

SurfFeatureDetector featureDetector;
<pre name="code" class="cpp">OrbFeatureDetector featureDetector;

FlannBasedMatcher matcher;
可以换成

BFMatcher matcher;//Brute Force based descriptor matcher object
更多细节还得自己亲自去探索。


你可能感兴趣的:(C++,qt,opencv,机器视觉,sift)