天天看点

opencv在Android上实现物体跟踪(7)

简介

  本章继续在opencv和android平台上,利用opencv的算法来实现对物体的跟踪。
      

实现步骤

原理介绍

  实现物体跟踪,需要一个用来匹配的模板图像,以及被分析跟踪的原图像或者原视频流。如果被分析的是视频流,也是将它拆分成一帧一帧的图像进行分析。
因此,我们只讨论对一张图像上找到模板图像的做法。
      
  计算模板匹配方法是,从原图像的左上角开始,从左往右,接着从上往下,每个像素点的位置作为模板图像的做上角位置,接着计算出这个位置,原图像对目标图像的
匹配度,接着新建一张和原图像一样大小的空白图像。将每个点的匹配度存在空白图像对应的像素位置。
      
  整个计算完了之后,新建的空白图像每个像素点位置,都存好了原图像对应像素点位置对于模板图像的匹配度,匹配度越高的,表示在该点位置,是模板图像的可能性
越高。
      

opencv匹配度计算

  OpenCV通过函数 matchTemplate 实现了模板匹配算法. 可用的方法有6个:
      
opencv在Android上实现物体跟踪(7)

matchTemplate介绍

  重点api为matchTemplate:      
void cvMatchTemplate(const CvArr* image, const CvArr* templ, CvArr* result, int method)
    image :原图像
    temp1 :模板图像
    result:保存匹配度的结果图像
    method:方式选择(0-5,对应前面几种匹配度的计算方法)
           

代码实现

  这里是在android设备上用jni实现的,利用该模板匹配实现的,预览界面物体跟踪代码(注意:代码没有优化,非常卡,而且跟踪成功性不高,只能作为演示参考)      
JNIEXPORT void Java_com_example_camera_1opencv_1android_PreviceGray_grayProc(JNIEnv* env, jclass obj, jlong imageGray,jint touch_x,jint touch_y){
	int width,height;
    int k = 0,n = 0,i,j;
    CvScalar s;
 
    int result_cols;
    int result_rows;
 
    Mat result;
	Mat mat = Mat(*((Mat*)imageGray));
	width = mat.rows;
	height = mat.cols;
 
    result_cols = height - Template + 1;
    result_rows = width - Template + 1;
 
    double minVal;
    double maxVal;
    Point minLoc;
    Point maxLoc;
    Point matchLoc;
    int match_method = CV_TM_SQDIFF;
 
    cv::Mat img = cv::Mat(Template,Template,CV_8UC3,cv::Scalar(0,0,0));
    IplImage pI = mat;
    IplImage pI_2 = img;
 
    Mat img_display = cv::Mat(width,height,CV_8UC3,cv::Scalar(0,0,0));
    IplImage pI_3 = img_display;
    for(i=0;i<width;i++){
        for(j=0;j<height;j++){
            s = cvGet2D(&pI,i,j);
            cvSet2D(&pI_3,i,j,s);
        }
    }
 
    for(i=(touch_x-(Template/2));i<(touch_x+(Template/2));i++){
        for(j=(touch_y-(Template/2));j<(touch_y+(Template/2));j++){
            s = cvGet2D(&pI,j,i);
            cvSet2D(&pI_2,k,n,s);
            n++;
        }   
        k++;
        n=0;
    }
 
    result.create(result_cols, result_rows, CV_32FC1 );
    /// Do the Matching and Normalize
    matchTemplate( img_display, img, result, match_method);
    normalize(result, result, 0, 1, NORM_MINMAX, -1, Mat() );
    /// Localizing the best match with minMaxLoc
 
    minMaxLoc( result, &minVal, &maxVal, &minLoc, &maxLoc, Mat() );
    /// For SQDIFF and SQDIFF_NORMED, the best matches are lower values. For all the other methods, the higher the better
    if(match_method == CV_TM_SQDIFF || match_method == CV_TM_SQDIFF_NORMED ){
        matchLoc = minLoc;
    }else{
        matchLoc = maxLoc;
    }
    rectangle(mat, matchLoc, Point(matchLoc.x + img.cols , matchLoc.y + img.rows ), Scalar::all(0), 2, 8, 0);
}
           
  上层传入了三个主要参数,分别表示预览的一帧画面,手指触屏点击的x,y轴坐标。
    代码中首先将预览的图像复制了一份到img_display中,img_display作为原图像。
接着用手指点击的触屏坐标x,y为矩阵中心,Template为矩阵宽、高的矩形作为目标模板图像。
新建了和原图像大小的result图像作为保存匹配度的结果图像。

    调用matchTemplate函数来取到匹配度保存到result图像中,minMaxLoc函数在result图像中,找到它的最大、最小值对应的像素点位置分别保存到minLoc、maxLoc中。
根据matchTemplate的匹配度计算方法不同,则result中匹配度最大值为最适合的匹配坐标,还是匹配度最小值为匹配坐标,从minLoc、maxLoc中选出最适合匹配坐标后,
存入到matchLoc中。
      
最后在预览图像上,matchLoc坐标位置画方框,表示皮匹配跟踪到了该模板图像。      
参考代码如下:http://download.csdn.net/detail/u011630458/8405791