首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Surf进行目标检测

使用Surf进行目标检测
EN

Stack Overflow用户
提问于 2013-07-10 20:16:04
回答 4查看 10.3K关注 0票数 11

我正在尝试从视频中检测车辆,我将在实时应用程序中进行检测,但目前和为了更好地理解,我在视频中进行检测,代码如下:

代码语言:javascript
复制
void surf_detection(Mat img_1,Mat img_2); /** @function main */

int main( int argc, char** argv )
{

 int i;
 int key;

 CvCapture* capture = cvCaptureFromAVI("try2.avi");// Read the video file

 if (!capture){

     std::cout <<" Error in capture video file";
     return -1;
 }

 Mat img_template = imread("images.jpg"); // read template image

int numFrames = (int) cvGetCaptureProperty(capture,  CV_CAP_PROP_FRAME_COUNT);



IplImage* img = 0; 

for(i=0;i<numFrames;i++){
  cvGrabFrame(capture);          // capture a frame
  img=cvRetrieveFrame(capture);  // retrieve the captured frame


  surf_detection (img_template,img);

  cvShowImage("mainWin", img); 
  key=cvWaitKey(20);           

}

 return 0;
 }

void surf_detection(Mat img_1,Mat img_2)
{ 

if( !img_1.data || !img_2.data )
{ 
    std::cout<< " --(!) Error reading images " << std::endl; 

}




//-- Step 1: Detect the keypoints using SURF Detector
int minHessian = 400;
SurfFeatureDetector detector( minHessian );
std::vector<KeyPoint> keypoints_1, keypoints_2;

std::vector< DMatch > good_matches;

do{ 

detector.detect( img_1, keypoints_1 );
detector.detect( img_2, keypoints_2 );

//-- Draw keypoints

Mat img_keypoints_1; Mat img_keypoints_2;
drawKeypoints( img_1, keypoints_1, img_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
drawKeypoints( img_2, keypoints_2, img_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DEFAULT );

//-- Step 2: Calculate descriptors (feature vectors)
SurfDescriptorExtractor extractor;
Mat descriptors_1, descriptors_2;
extractor.compute( img_1, keypoints_1, descriptors_1 );
extractor.compute( img_2, keypoints_2, descriptors_2 );


//-- Step 3: Matching descriptor vectors using FLANN matcher
FlannBasedMatcher matcher;
std::vector< DMatch > matches;
matcher.match( descriptors_1, descriptors_2, matches );
double max_dist = 0; 
double min_dist = 100;

//-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors_1.rows; i++ )
{ 
    double dist = matches[i].distance;
if( dist < min_dist )
    min_dist = dist;
if( dist > max_dist ) 
    max_dist = dist;
}


//-- Draw only "good" matches (i.e. whose distance is less than 2*min_dist )


for( int i = 0; i < descriptors_1.rows; i++ )
{ 
    if( matches[i].distance < 2*min_dist )
        { 
                good_matches.push_back( matches[i]);
        }
}

}while(good_matches.size()<100);

//-- Draw only "good" matches
Mat img_matches;
drawMatches( img_1, keypoints_1, img_2, keypoints_2,good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );

//-- Localize the object
std::vector<Point2f> obj;
std::vector<Point2f> scene;
for( int i = 0; i < good_matches.size(); i++ )
{
//-- Get the keypoints from the good matches
obj.push_back( keypoints_1[ good_matches[i].queryIdx ].pt );
scene.push_back( keypoints_2[ good_matches[i].trainIdx ].pt );
}


Mat H = findHomography( obj, scene, CV_RANSAC );


//-- Get the corners from the image_1 ( the object to be "detected" )
std::vector<Point2f> obj_corners(4);
obj_corners[0] = Point2f(0,0); 
obj_corners[1] = Point2f( img_1.cols, 0 );
obj_corners[2] = Point2f( img_1.cols, img_1.rows ); 
obj_corners[3] = Point2f( 0, img_1.rows );
std::vector<Point2f> scene_corners(4);

perspectiveTransform( obj_corners, scene_corners, H);

//-- Draw lines between the corners (the mapped object in the scene - image_2 )
line( img_matches, scene_corners[0] , scene_corners[1] , Scalar(0, 255, 0), 4 );
line( img_matches, scene_corners[1], scene_corners[2], Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[2] , scene_corners[3], Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[3] , scene_corners[0], Scalar( 0, 255, 0), 4 );
imshow( "Good Matches & Object detection", img_matches );

}

我得到了以下输出

和std::cout << scene_cornersi

H的值:

但我的问题是,为什么不在检测到的对象上绘制矩形,如下所示:

我是在简单的视频和图像上做这件事,但当我在静态相机上做这件事时,如果没有那个矩形可能会很困难

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-07-17 14:10:18

首先,在您显示的图像中,根本没有绘制任何矩形。你能画一个矩形吗,比方说,画在你的图像中间?

然后,查看以下代码:

代码语言:javascript
复制
int x1 , x2 , y1 , y2 ;
x1 = scene_corners[0].x + Point2f( img_1.cols, 0).x ; 
y1 = scene_corners[0].y + Point2f( img_1.cols, 0).y ; 
x2 = scene_corners[0].x + Point2f( img_1.cols, 0).x + in_box.width ; 
y2 = scene_corners[0].y + Point2f( img_1.cols, 0).y + in_box.height ;

我不明白为什么要在每个角落添加in_box.widthin_box.height (它们是在哪里定义的?)。您应该改用scene_corners[2]。但是注释行应该在某处打印一个矩形。

既然您要求了解更多详细信息,那么让我们看看代码中发生了什么。

首先,如何访问perspectiveTransform()

您可以使用detector.detect检测feature points。它为你提供了两张图片中的兴趣点。

  • you extractor.compute这些特征。它为您提供了一种比较兴趣点的方法。比较两个特征的描述符回答了一个问题:这些点有多相似?*

  • 你实际上将第一个图像上的每个特征与第二个图像中的所有特征(某种程度上)进行比较,并保持每个特征的最佳匹配。在这一点上,您知道了看起来最相似的特征对。

  • 您只保留good_matches。因为对于一个特征,另一个图像中最相似的特征实际上是完全不同的(它仍然是最相似的,因为你没有更好的选择)。这是第一个过滤掉错误匹配的过滤器。

  • 你会找到一个与你找到的匹配相对应的单应性变换。这意味着您试图找出第一个图像中的点应该如何投影到第二个图像中。然后,您获得的单应矩阵允许您将第一个图像的任意点投影到第二个图像中的对应关系上。

第二,你用这个做了什么?

现在它变得有趣了。你有一个单应矩阵,它允许你将第一个图像的任何点投影到第二个图像中的对应关系上。因此,您可以决定在对象(即obj_corners)周围绘制一个矩形,并将其投影到第二张图像(perspectiveTransform( obj_corners, scene_corners, H);)上。结果在scene_corners中。

现在,您希望使用scene_corners绘制一个矩形。但还有一点:drawMatches()显然会在img_matches中将你的两张图片放在一起。但是投影(单应矩阵)是在图像上单独计算的!这意味着每个scene_corner都必须相应地进行翻译。由于场景图像是在对象图像的右侧绘制的,因此必须将对象图像的宽度添加到每个scene_corner,以便将其向右平移。

这就是为什么要将0添加到y1y2中,因为您不必垂直转换它们。但对于x1x2,您必须添加img_1.cols

代码语言:javascript
复制
//-- Draw lines between the corners (the mapped object in the scene - image_2 )
line( img_matches, scene_corners[0] + Point2f( img_1.cols, 0), scene_corners[1] + Point2f( img_1.cols, 0), Scalar(0, 255, 0), 4 );
line( img_matches, scene_corners[1] + Point2f( img_1.cols, 0), scene_corners[2] + Point2f( img_1.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[2] + Point2f( img_1.cols, 0), scene_corners[3] + Point2f( img_1.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[3] + Point2f( img_1.cols, 0), scene_corners[0] + Point2f( img_1.cols, 0), Scalar( 0, 255, 0), 4 );

因此,我建议您取消注释这些线,并查看是否绘制了一个矩形。如果没有,请尝试硬编码值(例如Point2f(0, 0)Point2f(100, 100)),直到成功绘制矩形。也许您的问题来自于同时使用cvPointPoint2f。也试着使用Scalar(0, 255, 0, 255)...

希望能有所帮助。

*必须理解的是,两个点可能看起来完全相同,但实际上并不对应于同一点。想一想一个真正重复的图案,比如建筑物的窗户边角。所有的窗口看起来都一样,所以两个不同窗口的角可能看起来真的很相似,即使这显然是错误的匹配。

票数 8
EN

Stack Overflow用户

发布于 2013-07-23 14:19:20

您执行了以下步骤:

2 images.

  • Assuming中的
  1. 匹配关键点匹配正确,计算单应性(投影矩阵)。
  2. 使用单应性投影原始图像的角点以绘制一个四边形形状(在透视图中称为矩形)。

你遇到的问题是,当步骤1失败时,你在步骤2中得到了错误的单应性(错误的矩阵),当你在步骤3中投影角点时,它们可能会从图像中掉出来,你看不到线条。

你真正想要的是一种知道你计算的单应性是否为正确形式的方法。要做到这一点,请看这里的答案:How to check if obtained homography matrix is good?使用它来测试您的单应性是否正确。如果不是,您就知道匹配失败了。如果它是正确的,你可以画一个矩形,你会看到它,但如果关键点之间的匹配不准确,它可能不那么准确。

最后,我认为你的算法方法是错误的。通过将车辆与正面视图中的车辆图像进行匹配来从俯视图识别/检测车辆是一个死胡同。你根本不应该使用关键点匹配。只需手动标记图像上的所有车辆,并将其发送到支持向量机。如果这是太多的工作,使用机械土耳其平台自动标记车辆。总之,关键点匹配是一种不适合您的需求的方法,因为它有一个强有力的假设,即两个图像中的汽车外观是相似的。在你的例子中,这些图像太不同了(由于汽车的3D结构和不同的视角)

票数 2
EN

Stack Overflow用户

发布于 2013-07-10 20:49:34

您实际要做的是在图像中找到参考点(关键点),并将它们相互比较,以找到它们在另一个图像中重新出现(基于SURF特征向量)。这是对象检测和识别中的重要步骤,但不要与图像分割(http://en.wikipedia.org/wiki/Image_segmentation)或对象定位相混淆,在图像分割或对象定位中,您可以找到所需对象的确切轮廓(或一组像素或超像素)。

获取对象的边界矩形,特别是像您的示例中那样透视的对象,并不是一项简单的任务。您可以从已找到的关键点的边界框开始。但是,这将只覆盖对象的一部分。特别是在你的例子中,如果没有图像的3D配准,可能很难找到透视中的边界框,即知道图像中每个像素的第三维值(z值,深度)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17570421

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档