使用Qt实现图片拼接功能

                             使用Qt实现图片拼接功能

   Qt可以在自带的界面编辑器Qt Creator下编写,也可以在VS下配置Qt 环境编写,本文将介绍在Creator下编写一个简单的界面用以实现图片拼接的功能。

图片拼接需要使用到opencv库,所以需要在Qt Creator 下配置一下opencv,此步骤可百度教程即可,本文就不再赘述,现给出pro文件内的环境配置代码(本文以2.4.13版本为例)。

INCLUDEPATH+=D:\opencv2413\opencv\build\include\

D:\opencv2413\opencv\build\include\opencv\

D:\opencv2413\opencv\build\include\opencv2

LIBS +=-LD:\opencv2413\opencv\build\x86\vc11\lib \

-lopencv_ml2413d\

-lopencv_calib3d2413d\

-lopencv_contrib2413d\

-lopencv_core2413d\

-lopencv_features2d2413d\

-lopencv_flann2413d\

-lopencv_gpu2413d\

-lopencv_highgui2413d\

-lopencv_imgproc2413d\

-lopencv_legacy2413d\

-lopencv_objdetect2413d\

-lopencv_ts2413d\

-lopencv_video2413d\

-lopencv_nonfree2413d\

-lopencv_ocl2413d\

-lopencv_photo2413d\

-lopencv_stitching2413d\

-lopencv_superres2413d\

-lopencv_videostab2413d

在环境配置完成后,开始ui设计,本次设计界面如下,在File下拉框内添加Open打开动作用以打开图片。

 

在Creator下的控件关联比较方便,可以不需要使用connect函数,直接“转到槽”即可。

先打开两张图片,并显示在label1、label2控件上,然后实现点击按钮进行拼接,并将拼接结果图片显示在label3控件上。

代码实现如下:

//头文件

#ifndef MAINWINDOW_H

#define MAINWINDOW_H

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

using namespace cv;

using namespace std;

namespace Ui {

class MainWindow;

}

class MainWindow : public QMainWindow

{

    Q_OBJECT

public:

    explicit MainWindow(QWidget *parent = 0);

    ~MainWindow();

    Mat image01,image02;

    QImage img01,img02,imgpano;

    typedef struct

    {

        Point2f left_top;

        Point2f left_bottom;

        Point2f right_top;

        Point2f right_bottom;

    }four_corners_t;

    four_corners_t corners;

    void paintEvent(QPaintEvent *);

    void MainWindow::OptimizeSeam(Mat& img1, Mat& trans, Mat& dst);

    void MainWindow::CalcCorners(const Mat& H, const Mat& src);

private slots:

    void on_actionOpen_triggered();

    void on_pushButton_stitch_clicked();

private:

    Ui::MainWindow *ui;

};

#endif // MAINWINDOW_H
  //源文件

#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::paintEvent(QPaintEvent *)

{

    QPainter p(this);

    //画背景图

    p.drawPixmap(0,0,width(),height(),QPixmap("D:/lena.jpg"));

}



void MainWindow::on_actionOpen_triggered()

{

    //从路径中导入第一张图片

    QString fileName = QFileDialog::getOpenFileName(this,"Open Image",

    "../","Image Files (*.png *.jpg *.bmp)");

    QTextCodec *code = QTextCodec::codecForName("GB2312");

    string name = code->fromUnicode(fileName).data();

    image01=imread(name,1);

    cvtColor(image01,image01,CV_BGR2RGB);

    //将Mat转为QImage

    img01 = QImage((const unsigned char*)(image01.data),

                   image01.cols,image01.rows,image01.cols*image01.channels(),

                   QImage::Format_RGB888);

    ui->label->clear();

    //将图片以Label控件大小显示

    img01= img01.scaled(ui->label->width(),ui->label->height());

    ui->label->setPixmap(QPixmap::fromImage(img01));



    //自定义路径中导入第二张图片

    QString fileName2 = QFileDialog::getOpenFileName(this,"Open Image",

    "../","Image Files (*.png *.jpg *.bmp)");

    QTextCodec *code2 = QTextCodec::codecForName("GB2312");

    string name2 = code2->fromUnicode(fileName2).data();

    image02=imread(name2,1);

    //下面的操作主要为格式的转换

    cvtColor(image02,image02,CV_BGR2RGB);//保证颜色通道

    img02 = QImage((const unsigned char*)(image02.data),

                   image02.cols,image02.rows,image02.cols*image02.channels(),

                   QImage::Format_RGB888);

    ui->label_right->clear();

    img02= img02.scaled(ui->label_right->width(),ui->label_right->height());

    ui->label_right->setPixmap(QPixmap::fromImage(img02));

}

void MainWindow::on_pushButton_stitch_clicked()

{

    Mat image1, image2;

            cvtColor(image01, image1, CV_RGB2GRAY);

            cvtColor(image02, image2, CV_RGB2GRAY);

            //提取特征点

            SurfFeatureDetector Detector(10000);

            vector keyPoint1, keyPoint2;

            Detector.detect(image1, keyPoint1);

            Detector.detect(image2, keyPoint2);



        /*特征点描述,为下边的特征点匹配做准备   */

            cv::SurfDescriptorExtractor Descriptor;

            Mat imageDesc1, imageDesc2;

            Descriptor.compute(image1, keyPoint1, imageDesc1);

            Descriptor.compute(image2, keyPoint2, imageDesc2);



            cv::FlannBasedMatcher matcher;

            cv::vector > matchePoints;

            cv::vector GoodMatchePoints;



            cv::vector train_desc(1, imageDesc1);

            matcher.add(train_desc);

            matcher.train();



            matcher.knnMatch(imageDesc2, matchePoints, 2);



            Mat first_match;

            drawMatches(image02, keyPoint2, image01, keyPoint1, matchePoints, first_match);

            // Lowe's algorithm,获取优秀匹配点

            for (int i = 0; i < matchePoints.size(); i++)

            {

                if (matchePoints[i][0].distance < 0.8* matchePoints[i][1].distance)

                {

                    GoodMatchePoints.push_back(matchePoints[i][0]);

                }

            }

            Mat good_match;

            drawMatches(image02, keyPoint2, image01, keyPoint1, GoodMatchePoints, good_match);



//            imshow("goodmatch",good_match);

           cv::vector imagePoints1, imagePoints2;



            for (int i = 0; ilabel_pano->clear();

        imgpano= imgpano.scaled(ui->label_pano->width(),ui->label_pano->height());

        ui->label_pano->setPixmap(QPixmap::fromImage(imgpano));





}

void MainWindow::CalcCorners(const Mat& H, const Mat& src)

{



    double v2[] = { 0, 0, 1 };//左上角

    double v1[3];//变换后的坐标值

    Mat V2 = Mat(3, 1, CV_64FC1, v2);  //列向量

    Mat V1 = Mat(3, 1, CV_64FC1, v1);  //列向量



    V1 = H * V2;

    //左上角(0,0,1)

    /* cout << "V2: " << V2 << endl;

    cout << "V1: " << V1 << endl;*/

    corners.left_top.x = v1[0] / v1[2];

    corners.left_top.y = v1[1] / v1[2];



    //左下角(0,src.rows,1)

    v2[0] = 0;

    v2[1] = src.rows;

    v2[2] = 1;

    V2 = Mat(3, 1, CV_64FC1, v2);  //列向量

    V1 = Mat(3, 1, CV_64FC1, v1);  //列向量

    V1 = H * V2;

    corners.left_bottom.x = v1[0] / v1[2];

    corners.left_bottom.y = v1[1] / v1[2];



    //右上角(src.cols,0,1)

    v2[0] = src.cols;

    v2[1] = 0;

    v2[2] = 1;

    V2 = Mat(3, 1, CV_64FC1, v2);  //列向量

    V1 = Mat(3, 1, CV_64FC1, v1);  //列向量

    V1 = H * V2;

    corners.right_top.x = v1[0] / v1[2];

    corners.right_top.y = v1[1] / v1[2];



    //右下角(src.cols,src.rows,1)

    v2[0] = src.cols;

    v2[1] = src.rows;

    v2[2] = 1;

    V2 = Mat(3, 1, CV_64FC1, v2);  //列向量

    V1 = Mat(3, 1, CV_64FC1, v1);  //列向量

    V1 = H * V2;

    corners.right_bottom.x = v1[0] / v1[2];

    corners.right_bottom.y = v1[1] / v1[2];



}

void MainWindow::OptimizeSeam(Mat& img1, Mat& trans, Mat& dst)

{

    int start = MIN(corners.left_top.x, corners.left_bottom.x);//开始位置,即重叠区域的左边界



    double processWidth = img1.cols - start;//重叠区域的宽度

    int rows = dst.rows;

    int cols = img1.cols; //注意,是列数*通道数

    double alpha = 1;//img1中像素的权重,初始化权重值

    for (int i = 0; i < rows; i++)

    {

        uchar* p = img1.ptr(i);  //获取第i行的首地址

        uchar* t = trans.ptr(i);

        uchar* d = dst.ptr(i);

        for (int j = start; j < cols; j++)

        {

            //如果遇到图像trans中无像素的黑点,则完全拷贝img1中的数据

            if (t[j * 3] == 0 && t[j * 3 + 1] == 0 && t[j * 3 + 2] == 0)

            {

                alpha = 1;

            }

            else

            {

                //img1中像素的权重,与当前处理点距重叠区域左边界的距离成正比,实验证明,这种方法确实好

                alpha = (processWidth - (j - start)) / processWidth;

                if (alpha>=0.5)

                {

                    alpha = 1;

                 }

                else

                {

                    alpha = 0;

                }

            }



            d[j * 3] = p[j * 3] * alpha + t[j * 3] * (1 - alpha);

            d[j * 3 + 1] = p[j * 3 + 1] * alpha + t[j * 3 + 1] * (1 - alpha);

            d[j * 3 + 2] = p[j * 3 + 2] * alpha + t[j * 3 + 2] * (1 - alpha);



        }

    }



}

结果如下:

 

 

 

 

 

 

 

 

你可能感兴趣的:(opencv,QT)