现在的位置: 首页 > 综合 > 正文

基于OpenCV的图像拼接

2018年04月25日 ⁄ 综合 ⁄ 共 5956字 ⁄ 字号 评论关闭

这个程序是本人用于OpenCV项目学习而写的,其中很多代码都是从网上或cook book 中借鉴而来的。由于本人还是菜鸟,程序中难免会出现很多不合理的地方,希望各位高手能赐教或交流。
    这个程序在linux 的ubuntu 中能运行,没试过其他平台,但应该是大同小异的。其中代码都是C++风格,用了surf算法寻找特征点,用flann算法匹配特征点,有简单拼接模式和加权平均匹配模式(加权匹配模式还有优化的空间,其中的遍历图像还可以用其他方法来提升速度,但由于代码还没调好,先发一下初始版)。
    最后感谢你看了我的代码,希望如果你对算法或图像处理甚至对电子有研究或有兴趣的话,可以加我QQ交流。

QQ:448680688

//#include <stdio.h>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include "opencv2/calib3d/calib3d.hpp"
//#include "opencv2/legacy/legacy.hpp"
#include <QDebug>
#include <iostream>
#include <fstream>
#include <QApplication>
#include <QTextStream>
#include <ImageMosaic.h>
//#include <harrisDetector.h>

using namespace cv;

void ImageMosaic::computeSIFT(){

    cv::Mat g1(img1,cv::Rect(0,0,img1.cols,img1.rows));
    cv::Mat g2(img2,cv::Rect(0,0,img2.cols,img2.rows));
    cv::cvtColor(g1,g1,CV_BGR2GRAY);
    cv::cvtColor(g2,g2,CV_BGR2GRAY);
    cv::SURF sift;
    sift(g1, cv::Mat(), keypoints_roi, descriptor_roi);      /* get keypoints of ROI image */
    sift(g2, cv::Mat(), keypoints_img, descriptor_img);         /* get keypoints of the image */
}

void ImageMosaic::matchKeypoint(){
    cv::FlannBasedMatcher matcher;  /* FLANN based matcher to match keypoints */
    int i;
    double max_dist = 0; double min_dist = 1000;
    //int  dist=80;
    std::vector<cv::DMatch> matches;
    matcher.match(descriptor_roi, descriptor_img, matches);
    //try to understand what it is! ! !
    //-- Quick calculation of max and min distances between keypoints ;it's said that the distance must
    //less than 3*min,but i can't find the resource
    for( int i = 0; i < descriptor_roi.rows; i++ )
        {
        double dist = matches[i].distance;
        if( dist < min_dist ) min_dist = dist;
        if( dist > max_dist ) max_dist = dist;
            }

    for (i=0; i < descriptor_roi.rows; i++)
        {
        if (matches[i].distance < 3*min_dist)
            {
               good_matches.push_back(matches[i]);
                 }
             }
    //Mat img_matches;
 cv:: drawMatches(img1, keypoints_roi, img2, keypoints_img,
                   good_matches, img_matches, cv::Scalar(200,200,200));
                  // , vector<char>(),DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
 cv::namedWindow("Matches");
 cv::imshow("Matches",img_matches);
}

void ImageMosaic::findH(){
    std::vector<cv::Point2f> keypoints1, keypoints2;
    for (int i=0; i<good_matches.size(); i++)
    {
        keypoints1.push_back(keypoints_img[good_matches[i].trainIdx].pt);
        keypoints2.push_back(keypoints_roi[good_matches[i].queryIdx].pt);
    }
    H = cv::findHomography( keypoints1, keypoints2, CV_RANSAC );
//    CalcFourCorner(H,img2);
}

void ImageMosaic::CalcFourCorner()
{
    //计算图2的四个角经矩阵H变换后的坐标
    double v2[]={0,0,1};//左上角
    double v1[3];//变换后的坐标值

    cv::Mat V2 = cv::Mat(3,1,CV_64FC1,v2);
    cv::Mat V1 = cv::Mat(3,1,CV_64FC1,v1);qDebug("p1");
    cv::gemm(H,V2,1,1,0,V1);//矩阵乘法////the src3 can't be 0,so if you want to ignore the src3,
                            //you should set the beater as 0

    leftTop.x = cvRound(v1[0]/v1[2]);
    leftTop.y = cvRound(v1[1]/v1[2]);
    //cvCircle(xformed,leftTop,7,CV_RGB(255,0,0),2);

    //将v2中数据设为左下角坐标
    v2[0] = 0;
    v2[1] = img2.rows;
    V2 = cv::Mat(3,1,CV_64FC1,v2);
    V1 = cv::Mat(3,1,CV_64FC1,v1);
    cv::gemm(H,V2,1,1,0,V1);
    leftBottom.x = cvRound(v1[0]/v1[2]);
    leftBottom.y = cvRound(v1[1]/v1[2]);
    //cvCircle(xformed,leftBottom,7,CV_RGB(255,0,0),2);

    //将v2中数据设为右上角坐标
    v2[0] = img2.cols;
    v2[1] = 0;
    V2 = cv::Mat(3,1,CV_64FC1,v2);
    V1 = cv::Mat(3,1,CV_64FC1,v1);
    cv::gemm(H,V2,1,1,0,V1);
    rightTop.x = cvRound(v1[0]/v1[2]);
    rightTop.y = cvRound(v1[1]/v1[2]);
    //cvCircle(xformed,rightTop,7,CV_RGB(255,0,0),2);

    //将v2中数据设为右下角坐标
    v2[0] = img2.cols;
    v2[1] = img2.rows;
    V2 = cv::Mat(3,1,CV_64FC1,v2);
    V1 = cv::Mat(3,1,CV_64FC1,v1);
    cv::gemm(H,V2,1,1,0,V1);
    rightBottom.x = cvRound(v1[0]/v1[2]);
    rightBottom.y = cvRound(v1[1]/v1[2]);
    //cvCircle(xformed,rightBottom,7,CV_RGB(255,0,0),2);

}

void ImageMosaic::showSimpleImg(){
    // show stitchImage
     cv::Mat stitchedImage;
     int mRows = img2.rows;
     if (img1.rows> img2.rows)
     {
       mRows = img1.rows;
          }
     stitchedImage = cv::Mat::zeros(cv::min(rightTop.x,rightBottom.x), mRows, CV_8UC3);
     cv::warpPerspective(img2,stitchedImage,H,cv::Size(cv::min(rightTop.x,rightBottom.x),mRows));
     cv::Mat half(stitchedImage,cv::Rect(0,0,img1.cols,img1.rows));
//    cv::namedWindow("IMG1");
//    cv::imshow("IMG1",stitchedImage);
//    cv::namedWindow("Test");
//    cv::imshow("Test",half);
     img1.copyTo(half);
//    cv::Mat stitchedImage_simple=stitchedImage.clone();
     cv::imshow("stitchedImage",stitchedImage);//(cv::Rect(0,0,img1.cols+stitchedImage.cols,img1.rows)));

}

void ImageMosaic::showAVImage(){
    cv::Mat stitchedImage;
    int mRows = img2.rows;
    if (img1.rows> img2.rows)
    {
      mRows = img1.rows;
         }
    stitchedImage = cv::Mat::zeros(cv::min(rightTop.x,rightBottom.x), mRows, CV_8UC3);
    cv::warpPerspective(img2,stitchedImage,H,cv::Size(cv::min(rightTop.x,rightBottom.x),mRows));
    cv::Mat xformed_proc=stitchedImage.clone();
    cv::Mat xformed=stitchedImage.clone();
    cv::Mat img1_ROI=img1(cv::Rect(0,0,cv::min(leftTop.x,leftBottom.x),xformed_proc.rows));
    cv::Mat xformed_ROI=xformed_proc(cv::Rect(0,0,cv::min(leftTop.x,leftBottom.x),xformed_proc.rows));
    cv::addWeighted(img1_ROI,1,xformed_ROI,0,0,
                    xformed_proc(cv::Rect(0,0,cv::min(leftTop.x,leftBottom.x),xformed_proc.rows)));
    cv::namedWindow("Temp");
    cv::imshow("Temp",xformed_proc);

    int nl=xformed_proc.rows;
//    int nc=xformed_proc.cols*xformed_proc.channels();
    int nc1=img1.cols;
    int start=cv::min(leftTop.x,leftBottom.x);
//    double processWidth=img1.cols*img1.channels()-start;
    double processWidth=img1.cols-start;
    double alpha=1;
//    if(xformed_proc.isContinuous()){
//        nc*=nl;
//        nl=1;
//    }
    for(int j=0;j<nl;j++){
        uchar *data=xformed_proc.ptr<uchar>(j);
        uchar *data_img1=img1.ptr<uchar>(j);
        uchar *data_xformed=xformed_proc.ptr<uchar>(j);
        for(int i=start;i<nc1;i++){
            if(data_xformed[i]<50 &&data_xformed[i+1]<50 &&data_xformed[i+2]<50){
                alpha=1;
            }
            else{
                alpha = (processWidth-(i-start)) / processWidth ;
            }
            data[i*3]=data_img1[i*3]*alpha+data_xformed[i*3]*(1-alpha);
            data[i*3+1]=data_img1[i*3+1]*alpha+data_xformed[i*3+1]*(1-alpha);
            data[i*3+2]=data_img1[i*3+2]*alpha+data_xformed[i*3+2]*(1-alpha);
//            data[i]=0;
//            data[i+1]=0;
//            data[i+2]=0;
        }
    }
    cv::namedWindow("Final");
    cv::imshow("Final",xformed_proc);
//    cv::Mat xformedROI=stitchedImage(cv::Rect(0,0,cv::min(leftTop.x,leftBottom.x),xformed_proc.cols));
//    cv::Mat xformed_procROI=img1(cv::Rect(0,0,cv::min(leftTop.x,leftBottom.x),xformed_proc.cols));
//    cv::addWeighted(img1,1,stitchedImage,0,0,xformed_proc)     ;
//    cv::imshow("xformed_proc",xformed_proc);
}

另外,完整版在这里:点击打开链接 

抱歉!评论已关闭.