********** Features2d ********** .. highlight:: cpp 关键点检测 =========== 关键点描述 =========== 关键点匹配 ================== 代码 -------- 来自 ``opencv/samples/cpp/matcher_simple.cpp`` 的一个简短的例子: :: Mat img1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE); Mat img2 = imread(argv[2], CV_LOAD_IMAGE_GRAYSCALE); if(img1.empty() || img2.empty()) { printf("Can't read one of the images\n"); return -1; } // detecting keypoints SurfFeatureDetector detector(400); vector keypoints1, keypoints2; detector.detect(img1, keypoints1); detector.detect(img2, keypoints2); // computing descriptors SurfDescriptorExtractor extractor; Mat descriptors1, descriptors2; extractor.compute(img1, keypoints1, descriptors1); extractor.compute(img2, keypoints2, descriptors2); // matching descriptors BruteForceMatcher > matcher; vector matches; matcher.match(descriptors1, descriptors2, matches); // drawing the results namedWindow("matches", 1); Mat img_matches; drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches); imshow("matches", img_matches); waitKey(0); 代码分析 ------------------ 将代码分段分析 :: Mat img1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE); Mat img2 = imread(argv[2], CV_LOAD_IMAGE_GRAYSCALE); if(img1.empty() || img2.empty()) { printf("Can't read one of the images\n"); return -1; } 读入两张图像,并检查读入是否正确。 :: // detecting keypoints FastFeatureDetector detector(15); vector keypoints1, keypoints2; detector.detect(img1, keypoints1); detector.detect(img2, keypoints2); 首先,创建关键点检测器的实例。所有的检测器都继承自抽象类 ``FeatureDetector`` ,但是构造函数是与算法相关的。每个检测器的第一个参数一般用于控制关键点的数量和它们的稳定性。对不同的检测器,这个参数的取值范围是不同的(例如 *FAST* 的阈值为像素的亮度值之差,取值范围一般位于 *[0,40]* 之间。 *SURF* 的阈值应用到图像的Hessian,取值通常大于 *100* )。所以在不确定的情况下,请使用默认值。 :: // computing descriptors SurfDescriptorExtractor extractor; Mat descriptors1, descriptors2; extractor.compute(img1, keypoints1, descriptors1); extractor.compute(img2, keypoints2, descriptors2); 这儿创建了一个描述子提取器的实例。大部分OpenCV描述子继承自抽象类 ``DescriptorExtractor`` 。然后给每个关键点计算描述子。函数 ``DescriptorExtractor::compute`` 的输出 ``Mat`` 包含描述子,第 *i* 行是 第 *i* 个关键点的描述特征。注意,这个函数会修改关键点向量,一些无描述子定义的关键点(一般为在图像边界上的关键点)将被移除。这个函数会使输出的关键点和描述子保持一致(也就是关键点的数目等于描述子的数目)。 :: // matching descriptors BruteForceMatcher > matcher; vector matches; matcher.match(descriptors1, descriptors2, matches); 现在我们获取了两副图像的关键点的描述子,所以可以匹配它们了。首先创建一个匹配器,它可以从图像1中采用穷举法搜索图像2中最相似的关键点,采用的相似度量为欧氏度量。马氏距离和哈明(Hamming)距离也已被实现,可用于Brief描述子匹配。输出向量 ``matches`` 包含匹配好的点的索引对。 :: // drawing the results namedWindow("matches", 1); Mat img_matches; drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches); imshow("matches", img_matches); waitKey(0); 例子的最后一部分是将匹配结果可视化。 翻译 ====================== 于仕琪 http://www.opencv.org.cn