OpenCV SURF SIFT特征提取及RANSAC算法
2015-08-12 08:41
357 查看
看到OpenCV2.4.6里面ORB特征提取算法也在里面了,套用给的SURF特征例子程序改为ORB特征一直提示错误,类型不匹配神马的,由于没有找到示例程序,只能自己找答案。
(ORB特征论文:ORB: an efficient alternative to SIFT or SURF.点击下载论文)
经过查找发现:
描述符数据类型有是float的,比如说SIFT,SURF描述符,还有是uchar的,比如说有ORB,BRIEF
对于float 匹配方式有:
FlannBased
BruteForce<L2<float> >
BruteForce<SL2<float> >
BruteForce<L1<float> >
对于uchar有:
BruteForce<Hammin>
BruteForce<HammingLUT>
BruteForceMatcher< L2<float> > matcher;//改动的地方
BruteForceMatcher< L2<float> > matcher;//改动的地方
完整代码如下:
(ORB特征论文:ORB: an efficient alternative to SIFT or SURF.点击下载论文)
经过查找发现:
描述符数据类型有是float的,比如说SIFT,SURF描述符,还有是uchar的,比如说有ORB,BRIEF
对于float 匹配方式有:
FlannBased
BruteForce<L2<float> >
BruteForce<SL2<float> >
BruteForce<L1<float> >
对于uchar有:
BruteForce<Hammin>
BruteForce<HammingLUT>
BruteForceMatcher< L2<float> > matcher;//改动的地方
BruteForceMatcher< L2<float> > matcher;//改动的地方
完整代码如下:
int main(int argc, char** argv) { initModule_nonfree();//初始化模块,使用SIFT或SURF时用到 Ptr<FeatureDetector> detector = FeatureDetector::create( "SURF" );//创建SIFT特征检测器,可改成SURF/ORB Ptr<DescriptorExtractor> descriptor_extractor = DescriptorExtractor::create( "SURF" );//创建特征向量生成器,可改成SURF/ORB Ptr<DescriptorMatcher> descriptor_matcher = DescriptorMatcher::create( "BruteForce" );//创建特征匹配器 if( detector.empty() || descriptor_extractor.empty() ) cout<<"fail to create detector!"; //读入图像 Mat img1 = imread("E:/Book/3.jpg"); Mat img2 = imread("E:/Book/4.jpg"); Size imgSize(320,240); resize(img1, img1, imgSize); resize(img2, img2, imgSize); //特征点检测 double t = getTickCount();//当前滴答数 vector<KeyPoint> m_LeftKey,m_RightKey; detector->detect( img1, m_LeftKey );//检测img1中的SIFT特征点,存储到m_LeftKey中 detector->detect( img2, m_RightKey ); cout<<"图像1特征点个数:"<<m_LeftKey.size()<<endl; cout<<"图像2特征点个数:"<<m_RightKey.size()<<endl; //根据特征点计算特征描述子矩阵,即特征向量矩阵 Mat descriptors1,descriptors2; descriptor_extractor->compute( img1, m_LeftKey, descriptors1 ); descriptor_extractor->compute( img2, m_RightKey, descriptors2 ); t = ((double)getTickCount() - t)/getTickFrequency(); cout<<"SIFT算法用时:"<<t<<"秒"<<endl; cout<<"图像1特征描述矩阵大小:"<<descriptors1.size() <<",特征向量个数:"<<descriptors1.rows<<",维数:"<<descriptors1.cols<<endl; cout<<"图像2特征描述矩阵大小:"<<descriptors2.size() <<",特征向量个数:"<<descriptors2.rows<<",维数:"<<descriptors2.cols<<endl; //画出特征点 Mat img_m_LeftKey,img_m_RightKey; drawKeypoints(img1,m_LeftKey,img_m_LeftKey,Scalar::all(-1),0); drawKeypoints(img2,m_RightKey,img_m_RightKey,Scalar::all(-1),0); //imshow("Src1",img_m_LeftKey); //imshow("Src2",img_m_RightKey); //特征匹配 vector<DMatch> matches;//匹配结果 descriptor_matcher->match( descriptors1, descriptors2, matches );//匹配两个图像的特征矩阵 cout<<"Match个数:"<<matches.size()<<endl; //计算匹配结果中距离的最大和最小值 //距离是指两个特征向量间的欧式距离,表明两个特征的差异,值越小表明两个特征点越接近 double max_dist = 0; double min_dist = 100; for(int i=0; i<matches.size(); i++) { double dist = matches[i].distance; if(dist < min_dist) min_dist = dist; if(dist > max_dist) max_dist = dist; } cout<<"最大距离:"<<max_dist<<endl; cout<<"最小距离:"<<min_dist<<endl; //筛选出较好的匹配点 vector<DMatch> goodMatches; for(int i=0; i<matches.size(); i++) { if(matches[i].distance < 0.6 * max_dist) { goodMatches.push_back(matches[i]); } } cout<<"goodMatch个数:"<<goodMatches.size()<<endl; //画出匹配结果 Mat img_matches; //红色连接的是匹配的特征点对,绿色是未匹配的特征点 drawMatches(img1,m_LeftKey,img2,m_RightKey,goodMatches,img_matches, Scalar::all(-1)/*CV_RGB(255,0,0)*/,CV_RGB(0,255,0),Mat(),2); imshow("MatchSIFT",img_matches); IplImage result=img_matches; waitKey(10); //RANSAC匹配过程 vector<DMatch> m_Matches=goodMatches; // 分配空间 int ptCount = (int)m_Matches.size(); if ( ptCount<100) { cout<<"没有找到足够的匹配点"<<endl; waitKey(0); return 0; } Mat p1(ptCount, 2, CV_32F); Mat p2(ptCount, 2, CV_32F); // 把Keypoint转换为Mat Point2f pt; for (int i=0; i<ptCount; i++) { pt = m_LeftKey[m_Matches[i].queryIdx].pt; p1.at<float>(i, 0) = pt.x; p1.at<float>(i, 1) = pt.y; pt = m_RightKey[m_Matches[i].trainIdx].pt; p2.at<float>(i, 0) = pt.x; p2.at<float>(i, 1) = pt.y; } // 用RANSAC方法计算F Mat m_Fundamental; vector<uchar> m_RANSACStatus; // 这个变量用于存储RANSAC后每个点的状态 findFundamentalMat(p1, p2, m_RANSACStatus, FM_RANSAC); // 计算野点个数 int OutlinerCount = 0; for (int i=0; i<ptCount; i++) { if (m_RANSACStatus[i] == 0) // 状态为0表示野点 { OutlinerCount++; } } int InlinerCount = ptCount - OutlinerCount; // 计算内点 cout<<"内点数为:"<<InlinerCount<<endl; // 这三个变量用于保存内点和匹配关系 vector<Point2f> m_LeftInlier; vector<Point2f> m_RightInlier; vector<DMatch> m_InlierMatches; m_InlierMatches.resize(InlinerCount); m_LeftInlier.resize(InlinerCount); m_RightInlier.resize(InlinerCount); InlinerCount=0; float inlier_minRx=img1.cols; //用于存储内点中右图最小横坐标,以便后续融合 for (int i=0; i<ptCount; i++) { if (m_RANSACStatus[i] != 0) { m_LeftInlier[InlinerCount].x = p1.at<float>(i, 0); m_LeftInlier[InlinerCount].y = p1.at<float>(i, 1); m_RightInlier[InlinerCount].x = p2.at<float>(i, 0); m_RightInlier[InlinerCount].y = p2.at<float>(i, 1); m_InlierMatches[InlinerCount].queryIdx = InlinerCount; m_InlierMatches[InlinerCount].trainIdx = InlinerCount; if(m_RightInlier[InlinerCount].x<inlier_minRx) inlier_minRx=m_RightInlier[InlinerCount].x; //存储内点中右图最小横坐标 InlinerCount++; } } // 把内点转换为drawMatches可以使用的格式 vector<KeyPoint> key1(InlinerCount); vector<KeyPoint> key2(InlinerCount); KeyPoint::convert(m_LeftInlier, key1); KeyPoint::convert(m_RightInlier, key2); // 显示计算F过后的内点匹配 Mat OutImage; drawMatches(img1, key1, img2, key2, m_InlierMatches, OutImage); cvNamedWindow( "Match features", 1); cvShowImage("Match features", &IplImage(OutImage)); waitKey(10); cvDestroyAllWindows(); //矩阵H用以存储RANSAC得到的单应矩阵 Mat H = findHomography( m_LeftInlier, m_RightInlier, RANSAC ); //存储左图四角,及其变换到右图位置 std::vector<Point2f> obj_corners(4); obj_corners[0] = Point(0,0); obj_corners[1] = Point( img1.cols, 0 ); obj_corners[2] = Point( img1.cols, img1.rows ); obj_corners[3] = Point( 0, img1.rows ); std::vector<Point2f> scene_corners(4); perspectiveTransform( obj_corners, scene_corners, H); //画出变换后图像位置 Point2f offset( (float)img1.cols, 0); line( OutImage, scene_corners[0]+offset, scene_corners[1]+offset, Scalar( 0, 255, 0), 4 ); line( OutImage, scene_corners[1]+offset, scene_corners[2]+offset, Scalar( 0, 255, 0), 4 ); line( OutImage, scene_corners[2]+offset, scene_corners[3]+offset, Scalar( 0, 255, 0), 4 ); line( OutImage, scene_corners[3]+offset, scene_corners[0]+offset, Scalar( 0, 255, 0), 4 ); imshow( "Good Matches & Object detection", OutImage ); waitKey(10); imwrite("warp_position.jpg",OutImage); int drift = scene_corners[1].x; //储存偏移量 //新建一个矩阵存储配准后四角的位置 int width = int(max(abs(scene_corners[1].x), abs(scene_corners[2].x))); int height= img1.rows; //或者:int height = int(max(abs(scene_corners[2].y), abs(scene_corners[3].y))); float origin_x=0,origin_y=0; if(scene_corners[0].x<0) { if (scene_corners[3].x<0) origin_x+=min(scene_corners[0].x,scene_corners[3].x); else origin_x+=scene_corners[0].x;} width-=int(origin_x); if(scene_corners[0].y<0) { if (scene_corners[1].y) origin_y+=min(scene_corners[0].y,scene_corners[1].y); else origin_y+=scene_corners[0].y;} //可选:height-=int(origin_y); Mat imageturn=Mat::zeros(width,height,img1.type()); //获取新的变换矩阵,使图像完整显示 for (int i=0;i<4;i++) {scene_corners[i].x -= origin_x; } //可选:scene_corners[i].y -= (float)origin_y; } Mat H1=getPerspectiveTransform(obj_corners, scene_corners); //进行图像变换,显示效果 warpPerspective(img1,imageturn,H1,Size(width,height)); imshow("image_Perspective", imageturn); waitKey(10); //图像融合 int width_ol=width-int(inlier_minRx-origin_x); int start_x=int(inlier_minRx-origin_x); cout<<"width: "<<width<<endl; cout<<"img1.width: "<<img1.cols<<endl; cout<<"start_x: "<<start_x<<endl; cout<<"width_ol: "<<width_ol<<endl; uchar* ptr=imageturn.data; double alpha=0, beta=1; for (int row=0;row<height;row++) { ptr=imageturn.data+row*imageturn.step+(start_x)*imageturn.elemSize(); for(int col=0;col<width_ol;col++) { uchar* ptr_c1=ptr+imageturn.elemSize1(); uchar* ptr_c2=ptr_c1+imageturn.elemSize1(); uchar* ptr2=img2.data+row*img2.step+(col+int(inlier_minRx))*img2.elemSize(); uchar* ptr2_c1=ptr2+img2.elemSize1(); uchar* ptr2_c2=ptr2_c1+img2.elemSize1(); alpha=double(col)/double(width_ol); beta=1-alpha; if (*ptr==0&&*ptr_c1==0&&*ptr_c2==0) { *ptr=(*ptr2); *ptr_c1=(*ptr2_c1); *ptr_c2=(*ptr2_c2); } *ptr=(*ptr)*beta+(*ptr2)*alpha; *ptr_c1=(*ptr_c1)*beta+(*ptr2_c1)*alpha; *ptr_c2=(*ptr_c2)*beta+(*ptr2_c2)*alpha; ptr+=imageturn.elemSize(); } } //imshow("image_overlap", imageturn); //waitKey(0); Mat img_result=Mat::zeros(height,width+img2.cols-drift,img1.type()); uchar* ptr_r=imageturn.data; for (int row=0;row<height;row++) { ptr_r=img_result.data+row*img_result.step; for(int col=0;col<img_result.cols;col++) { uchar* ptr_rc1=ptr_r+imageturn.elemSize1(); uchar* ptr_rc2=ptr_rc1+imageturn.elemSize1(); uchar* ptr=imageturn.data+row*imageturn.step+col*imageturn.elemSize(); uchar* ptr_c1=ptr+imageturn.elemSize1(); uchar* ptr_c2=ptr_c1+imageturn.elemSize1(); *ptr_r=*ptr; *ptr_rc1=*ptr_c1; *ptr_rc2=*ptr_c2; ptr_r+=img_result.elemSize(); } ptr_r=img_result.data+row*img_result.step+imageturn.cols*img_result.elemSize(); for(int col=imageturn.cols;col<img_result.cols;col++) { uchar* ptr_rc1=ptr_r+imageturn.elemSize1(); uchar* ptr_rc2=ptr_rc1+imageturn.elemSize1(); uchar* ptr2=img2.data+row*img2.step+(col-imageturn.cols+drift)*img2.elemSize(); uchar* ptr2_c1=ptr2+img2.elemSize1(); uchar* ptr2_c2=ptr2_c1+img2.elemSize1(); *ptr_r=*ptr2; *ptr_rc1=*ptr2_c1; *ptr_rc2=*ptr2_c2; ptr_r+=img_result.elemSize(); } } //imshow("image_result", img_result); //imwrite("final_result.jpg",img_result); waitKey(0); return 0; }
相关文章推荐
- hadoop学习笔记 YARN
- hadoop学习笔记 MapReduce + HDFS
- 架构师速成-如何高效编程 for java
- 修改Tomcat内存大小
- 有了 Linux,你就可以搭建自己的超级计算机
- linux redhat-6.5系统配置nfs服务器的方法
- Linux系统下快速删除某个目录下大量文件
- Linux下进程间通信概述
- nginx服务器去掉url中的index.php 和 配置path_info
- 搜狗输入法 for linux 安装后未出现
- hadoop之家族
- 在Linux下编译安装Apache2(2)
- 【Powershell】【CPU使用率】脚本实时获取所有cpu使用时间非0的进程
- linux 下安装 composer
- globalCompositeOperation 学习
- 【OPENGL】第三篇 着色器基础(一)
- 在Linux下编译安装Apache2(1)
- JavaScript实现网站访问次数统计代码
- 牢记这七点 让你的Linux服务器变得更安全
- linux系统读磁盘文件过程发生的事。