基于OpenCV的图像拼接
这个程序是本人用于OpenCV项目学习而写的,其中很多代码都是从网上或cook book 中借鉴而来的。由于本人还是菜鸟,程序中难免会出现很多不合理的地方,希望各位高手能赐教或交流。 这个程序在linux 的ubuntu 中能运行,没试过其他平台,但应该是大同小异的。其中代码都是C++风格,用了surf算法寻找特征点,用flann算法匹配特征点,有简单拼接模式和加权平均匹配模式(加权匹配
·
这个程序是本人用于OpenCV项目学习而写的,其中很多代码都是从网上或cook book 中借鉴而来的。由于本人还是菜鸟,程序中难免会出现很多不合理的地方,希望各位高手能赐教或交流。
这个程序在linux 的ubuntu 中能运行,没试过其他平台,但应该是大同小异的。其中代码都是C++风格,用了surf算法寻找特征点,用flann算法匹配特征点,有简单拼接模式和加权平均匹配模式(加权匹配模式还有优化的空间,其中的遍历图像还可以用其他方法来提升速度,但由于代码还没调好,先发一下初始版)。
最后感谢你看了我的代码,希望如果你对算法或图像处理甚至对电子有研究或有兴趣的话,可以加我QQ交流。
这个程序在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);
}
另外,完整版在这里:
点击打开链接
更多推荐
已为社区贡献1条内容
所有评论(0)