开发环境:Windows7, VS2010, OpenCV2.4.10
1.图像特征匹配
1 // AxFeatureExtract.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include "opencv2/opencv.hpp" 6 #include <opencv2/features2d/features2d.hpp> 7 #include <opencv2/nonfree/nonfree.hpp> 8 #include <opencv2/calib3d/calib3d.hpp> 9 #include "vector" 10 11 using namespace std; 12 13 int _tmain(int argc, _TCHAR* argv[]) 14 { 15 cv::Mat rgb1 = cv::imread( "G:\SLAMDatasets\一起做RGB-DSLAM数据\rgb_png\1.png"); 16 cv::Mat rgb2 = cv::imread( "G:\SLAMDatasets\一起做RGB-DSLAM数据\rgb_png\2.png"); 17 cv::Mat depth1 = cv::imread( "G:\SLAMDatasets\一起做RGB-DSLAM数据\depth_png\1.png", -1); 18 cv::Mat depth2 = cv::imread( "G:\SLAMDatasets\一起做RGB-DSLAM数据\depth_png\2.png", -1); 19 20 // 声明特征提取器与描述子提取器 21 cv::Ptr<cv::FeatureDetector> _detector; 22 cv::Ptr<cv::DescriptorExtractor> _descriptor; 23 24 // 构建提取器,默认两者都为sift 25 // 构建sift, surf之前要初始化nonfree模块 26 cv::initModule_nonfree(); 27 _detector = cv::FeatureDetector::create( "GridSIFT" ); 28 _descriptor = cv::DescriptorExtractor::create( "SIFT" ); 29 30 vector< cv::KeyPoint > kp1, kp2; //关键点 31 _detector->detect( rgb1, kp1 ); //提取关键点 32 _detector->detect( rgb2, kp2 ); 33 34 cout<<"Key points of two images: "<<kp1.size()<<", "<<kp2.size()<<endl; 35 36 // 可视化, 显示关键点 37 cv::Mat imgShow; 38 cv::drawKeypoints( rgb1, kp1, imgShow, cv::Scalar::all(-1), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS ); 39 cv::imshow( "keypoints", imgShow ); 40 cv::imwrite( "data\keypoints.png", imgShow ); 41 cv::waitKey(0); //暂停等待一个按键 42 43 // 计算描述子 44 cv::Mat desp1, desp2; 45 _descriptor->compute( rgb1, kp1, desp1 ); 46 _descriptor->compute( rgb2, kp2, desp2 ); 47 48 // 匹配描述子 49 vector< cv::DMatch > matches; 50 cv::FlannBasedMatcher matcher; 51 matcher.match( desp1, desp2, matches ); 52 cout<<"Find total "<<matches.size()<<" matches."<<endl; 53 54 // 可视化:显示匹配的特征 55 cv::Mat imgMatches; 56 cv::drawMatches( rgb1, kp1, rgb2, kp2, matches, imgMatches ); 57 cv::imshow( "matches", imgMatches ); 58 cv::imwrite( "data\matches.png", imgMatches ); 59 cv::waitKey( 0 ); 60 61 // 筛选匹配,把距离太大的去掉 62 // 这里使用的准则是去掉大于四倍最小距离的匹配 63 vector< cv::DMatch > goodMatches; 64 double minDis = 9999; 65 for ( size_t i=0; i<matches.size(); i++ ) 66 { 67 if ( matches[i].distance < minDis ) 68 minDis = matches[i].distance; 69 } 70 71 for ( size_t i=0; i<matches.size(); i++ ) 72 { 73 if (matches[i].distance < 4*minDis) 74 goodMatches.push_back( matches[i] ); 75 } 76 77 // 显示 good matches 78 cout<<"good matches="<<goodMatches.size()<<endl; 79 cv::drawMatches( rgb1, kp1, rgb2, kp2, goodMatches, imgMatches ); 80 cv::imshow( "good matches", imgMatches ); 81 cv::imwrite( "data\good_matches.png", imgMatches ); 82 system("pause"); 83 return 0; 84 }
2.膨胀和侵蚀
形态学方法:读取图像,实现图像的膨胀和侵蚀操作。
1 // AxFeatureExtract.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include "opencv2/opencv.hpp" 6 #include <opencv2/core/core.hpp> 7 #include <opencv2/features2d/features2d.hpp> 8 #include <opencv2/nonfree/nonfree.hpp> 9 #include <opencv2/calib3d/calib3d.hpp> 10 #include <opencv2/imgproc/imgproc.hpp> 11 #include "vector" 12 13 using namespace std; 14 using namespace cv; 15 16 int _tmain(int argc, _TCHAR* argv[]) 17 { 18 cv::Mat rgb1 = cv::imread( "G:\SLAMDatasets\一起做RGB-DSLAM数据\rgb_png\1.png"); 19 cv::Mat depth1 = cv::imread( "G:\SLAMDatasets\一起做RGB-DSLAM数据\depth_png\1.png", -1); 20 21 cv::imshow( "matches", rgb1 ); 22 cv::Mat elementdilate = getStructuringElement(MORPH_RECT, Size(15, 15)); 23 cv::Mat outdilate; 24 //进行膨胀操作 25 dilate(rgb1, outdilate, elementdilate); 26 cv::imshow( "dilate", outdilate ); 27 cv::imwrite( "data\dilate.png", outdilate ); 28 cv::waitKey( 0 ); 29 30 cv::Mat elementerode = getStructuringElement(MORPH_RECT, Size(15, 15)); 31 cv::Mat outerode; 32 33 //进行腐蚀操作 34 erode(depth1,outerode, elementerode); 35 cv::imshow( "erode", outerode ); 36 cv::imwrite( "data\outerode.png", outerode ); 37 system("pause"); 38 return 0; 39 }
3.图像二值化
4.图像边缘提取
1 // AxFeatureExtract.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include "opencv2/opencv.hpp" 6 #include <opencv2/core/core.hpp> 7 #include <opencv2/features2d/features2d.hpp> 8 #include <opencv2/nonfree/nonfree.hpp> 9 #include <opencv2/calib3d/calib3d.hpp> 10 #include <opencv2/imgproc/imgproc.hpp> 11 #include "vector" 12 13 using namespace std; 14 using namespace cv; 15 void RemoveSmallRegion(Mat& Src, Mat& Dst, int AreaLimit=50, int CheckMode=1, int NeihborMode=0); 16 17 int _tmain(int argc, _TCHAR* argv[]) 18 { 19 cv::Mat rgb1 = cv::imread( "data\dump-00050.png"); 20 cv::imshow( "dump", rgb1 ); 21 22 23 24 cv::waitKey( 0 ); 25 //提取边缘 26 cv::Mat src=rgb1.clone(); 27 cv::Mat dstSobel; 28 Sobel(src,dstSobel,src.depth(),1,1); 29 cv::imshow( "Sobel", dstSobel ); 30 imwrite("sobel.jpg",dstSobel); 31 32 cv::Mat dstLaplacian; 33 Laplacian(src,dstLaplacian,src.depth()); 34 cv::imshow("Laplacian", dstLaplacian ); 35 imwrite("laplacian.jpg",dstLaplacian); 36 37 cv::Mat g_grayImage; 38 cv::Mat dstCanny; 39 cvtColor(src,g_grayImage,CV_BGR2GRAY); //canny只处理灰度图 40 Canny(g_grayImage,dstCanny,50,150,3); 41 cv::imshow("Canny", dstCanny ); 42 imwrite("canny.jpg",dstCanny); 43 44 45 cv::Mat g_dstImage; 46 threshold(g_grayImage,g_dstImage,125,255,CV_THRESH_BINARY_INV); //大津阈值 47 imshow("threshold",g_dstImage); 48 imwrite("threshold.jpg",g_dstImage); 49 50 cv::Mat elementdilate = getStructuringElement(MORPH_RECT, Size(5, 5)); 51 cv::Mat outdilate; 52 //进行膨胀操作 53 dilate(g_dstImage, outdilate, elementdilate); 54 cv::imshow( "dilate", outdilate ); 55 //cv::imwrite( "data\dilate.png", outdilate ); 56 57 cv::Mat outresult; 58 cv::Mat image=dstLaplacian.clone(); 59 cv::subtract(dstCanny, outdilate, outresult);//注意保证两个图像的格式一致 60 cv::imshow( "frontier", outresult ); 61 62 Mat rgb2 = Mat::zeros(outresult.size(), CV_8UC1); 63 /*blur(outresult,rgb2,Size(3,3),Point(-1,-1)); 64 cv::imshow( "blur", rgb2 );*/ 65 RemoveSmallRegion(outresult,rgb2,10,1, 1); 66 cv::imshow( "blur", rgb2 ); 67 cv::waitKey( 0 ); 68 system("pause"); 69 return 0; 70 } 71 72 void RemoveSmallRegion(Mat& Src, Mat& Dst, int AreaLimit, int CheckMode, int NeihborMode) 73 { 74 int RemoveCount=0; //记录除去的个数 75 //记录每个像素点检验状态的标签,0代表未检查,1代表正在检查,2代表检查不合格(需要反转颜色),3代表检查合格或不需检查 76 Mat Pointlabel = Mat::zeros( Src.size(), CV_8UC1 ); 77 78 if(CheckMode==1) 79 { 80 cout<<"Mode: 去除小区域. "; 81 for(int i = 0; i < Src.rows; ++i) 82 { 83 uchar* iData = Src.ptr<uchar>(i); 84 uchar* iLabel = Pointlabel.ptr<uchar>(i); 85 for(int j = 0; j < Src.cols; ++j) 86 { 87 if (iData[j] < 10) 88 { 89 iLabel[j] = 3; 90 } 91 } 92 } 93 } 94 else 95 { 96 cout<<"Mode: 去除孔洞. "; 97 for(int i = 0; i < Src.rows; ++i) 98 { 99 uchar* iData = Src.ptr<uchar>(i); 100 uchar* iLabel = Pointlabel.ptr<uchar>(i); 101 for(int j = 0; j < Src.cols; ++j) 102 { 103 if (iData[j] > 10) 104 { 105 iLabel[j] = 3; 106 } 107 } 108 } 109 } 110 111 vector<Point2i> NeihborPos; //记录邻域点位置 112 NeihborPos.push_back(Point2i(-1, 0)); 113 NeihborPos.push_back(Point2i(1, 0)); 114 NeihborPos.push_back(Point2i(0, -1)); 115 NeihborPos.push_back(Point2i(0, 1)); 116 if (NeihborMode==1) 117 { 118 cout<<"Neighbor mode: 8邻域."<<endl; 119 NeihborPos.push_back(Point2i(-1, -1)); 120 NeihborPos.push_back(Point2i(-1, 1)); 121 NeihborPos.push_back(Point2i(1, -1)); 122 NeihborPos.push_back(Point2i(1, 1)); 123 } 124 else cout<<"Neighbor mode: 4邻域."<<endl; 125 int NeihborCount=4+4*NeihborMode; 126 int CurrX=0, CurrY=0; 127 //开始检测 128 for(int i = 0; i < Src.rows; ++i) 129 { 130 uchar* iLabel = Pointlabel.ptr<uchar>(i); 131 for(int j = 0; j < Src.cols; ++j) 132 { 133 if (iLabel[j] == 0) 134 { 135 //********开始该点处的检查********** 136 vector<Point2i> GrowBuffer; //堆栈,用于存储生长点 137 GrowBuffer.push_back( Point2i(j, i) ); 138 Pointlabel.at<uchar>(i, j)=1; 139 int CheckResult=0; //用于判断结果(是否超出大小),0为未超出,1为超出 140 141 for ( int z=0; z<GrowBuffer.size(); z++ ) 142 { 143 144 for (int q=0; q<NeihborCount; q++) //检查四个邻域点 145 { 146 CurrX=GrowBuffer.at(z).x+NeihborPos.at(q).x; 147 CurrY=GrowBuffer.at(z).y+NeihborPos.at(q).y; 148 if (CurrX>=0&&CurrX<Src.cols&&CurrY>=0&&CurrY<Src.rows) //防止越界 149 { 150 if ( Pointlabel.at<uchar>(CurrY, CurrX)==0 ) 151 { 152 GrowBuffer.push_back( Point2i(CurrX, CurrY) ); //邻域点加入buffer 153 Pointlabel.at<uchar>(CurrY, CurrX)=1; //更新邻域点的检查标签,避免重复检查 154 } 155 } 156 } 157 158 } 159 if (GrowBuffer.size()>AreaLimit) CheckResult=2; //判断结果(是否超出限定的大小),1为未超出,2为超出 160 else {CheckResult=1; RemoveCount++;} 161 for (int z=0; z<GrowBuffer.size(); z++) //更新Label记录 162 { 163 CurrX=GrowBuffer.at(z).x; 164 CurrY=GrowBuffer.at(z).y; 165 Pointlabel.at<uchar>(CurrY, CurrX) += CheckResult; 166 } 167 //********结束该点处的检查********** 168 169 170 } 171 } 172 } 173 174 CheckMode=255*(1-CheckMode); 175 //开始反转面积过小的区域 176 for(int i = 0; i < Src.rows; ++i) 177 { 178 uchar* iData = Src.ptr<uchar>(i); 179 uchar* iDstData = Dst.ptr<uchar>(i); 180 uchar* iLabel = Pointlabel.ptr<uchar>(i); 181 for(int j = 0; j < Src.cols; ++j) 182 { 183 if (iLabel[j] == 2) 184 { 185 iDstData[j] = CheckMode; 186 } 187 else if(iLabel[j] == 3) 188 { 189 iDstData[j] = iData[j]; 190 } 191 } 192 } 193 194 cout<<RemoveCount<<" objects removed."<<endl; 195 }