我想在主图像中查找/检查子图像/模板图像,并想知道其坐标,
我使用了以下链接中提供的代码来实现它,
如果模板图像的大小与更大图像中匹配部分的大小完全相同,它工作得很好。
但如果子图像相对于更大图像的匹配部分被缩小或放大,它就不能正确给出结果。
回答:
使用OpenCV特征检测。它比模板匹配更准确..
请尝试使用以下代码..
-(void)featureDetection:(UIImage*)largerImage withImage:(UIImage*)subImage{ cv::Mat tempMat1 = [largerImage CVMat]; cv::Mat tempMat2 = [subImage CVMat]; cv::cvtColor(tempMat1, tempMat1, CV_RGB2GRAY); cv::cvtColor(tempMat2, tempMat2, CV_RGB2GRAY); if( !tempMat1.data || !tempMat2.data ) { return; } //-- 步骤1:使用SURF检测器检测关键点 int minHessian = 25; cv::SurfFeatureDetector detector( minHessian ); // 更准确但耗时更长.. //cv::FastFeatureDetector detector( minHessian ); // 准确性较低但耗时较短.. std::vector<cv::KeyPoint> keypoints_1, keypoints_2; detector.detect( tempMat1, keypoints_1 ); detector.detect( tempMat2, keypoints_2 ); //-- 步骤2:计算描述符(特征向量) cv::SurfDescriptorExtractor extractor; cv::Mat descriptors_1, descriptors_2; extractor.compute( tempMat1, keypoints_1, descriptors_1 ); extractor.compute( tempMat2, keypoints_2, descriptors_2 ); std::vector<cv::Point2f> obj_corners(4); //从对象中获取角点 obj_corners[0] = (cvPoint(0,0)); obj_corners[1] = (cvPoint(tempMat2.cols,0)); obj_corners[2] = (cvPoint(tempMat2.cols,tempMat2.rows)); obj_corners[3] = (cvPoint(0, tempMat2.rows)); //-- 步骤3:使用暴力匹配器匹配描述符向量 //cv::BruteForceMatcher < cv::L2<float> > matcher; cv::FlannBasedMatcher matcher; //std::vector< cv::DMatch > matches; std::vector<cv::vector<cv::DMatch > > matches; std::vector<cv::DMatch> good_matches; std::vector<cv::Point2f> obj; std::vector<cv::Point2f> scene; std::vector<cv::Point2f> scene_corners(4); cv::Mat H; matcher.knnMatch( descriptors_2, descriptors_1, matches,2); for(int i = 0; i < cv::min(tempMat1.rows-1,(int) matches.size()); i++) { if((matches[i][0].distance < 0.6*(matches[i][1].distance)) && ((int) matches[i].size()<=2 && (int) matches[i].size()>0)) { good_matches.push_back(matches[i][0]); } } cv::Mat img_matches; drawMatches( tempMat2, keypoints_2, tempMat1, keypoints_1, good_matches, img_matches ); NSLog(@"good matches %lu",good_matches.size()); if (good_matches.size() >= 4) { for( int i = 0; i < good_matches.size(); i++ ) { //从良好匹配中获取关键点 obj.push_back( keypoints_2[ good_matches[i].queryIdx ].pt ); scene.push_back( keypoints_1[ good_matches[i].trainIdx ].pt ); } H = findHomography( obj, scene, CV_RANSAC ); perspectiveTransform( obj_corners, scene_corners, H); NSLog(@"%f %f",scene_corners[0].x,scene_corners[0].y); NSLog(@"%f %f",scene_corners[1].x,scene_corners[1].y); NSLog(@"%f %f",scene_corners[2].x,scene_corners[2].y); NSLog(@"%f %f",scene_corners[3].x,scene_corners[3].y); //在场景图像中绘制角点之间的线(映射的对象) line( tempMat1, scene_corners[0], scene_corners[1], cvScalar(0, 255, 0), 4 ); line( tempMat1, scene_corners[1], scene_corners[2], cvScalar( 0, 255, 0), 4 ); line( tempMat1, scene_corners[2], scene_corners[3], cvScalar( 0, 255, 0), 4 ); line( tempMat1, scene_corners[3], scene_corners[0], cvScalar( 0, 255, 0), 4 ); } // 查看匹配.. UIImage *resultimage = [UIImage imageWithCVMat:img_matches]; UIImageView *imageview = [[UIImageView alloc] initWithImage:resultimage]; imageview.frame = CGRectMake(0, 0, 320, 240); [self.view addSubview:imageview]; // 查看结果 UIImage *resultimage2 = [UIImage imageWithCVMat:tempMat1]; UIImageView *imageview2 = [[UIImageView alloc] initWithImage:resultimage2]; imageview2.frame = CGRectMake(0, 240, 320, 240); [self.view addSubview:imageview2];}