MeanShift的目标跟踪算法opencv c++接口代码 VS2015+opencv3.2

来源:互联网 发布:用intent传递数据 编辑:程序博客网 时间:2024/06/17 22:52

MeanShift的目标跟踪算法



  这几天在学meanshift跟踪的原理和实现,虽然还不是特别明白,但总想先找个程序跑一下试一下效果,网上的程序多是基于c接口的老的opencv程序,在借鉴大神思路的基础上,对其代码进行了一些小的改动升级,变成了c++接口。大神‘taotao1233’的原meanshift讲解与源代码网址:http://blog.csdn.net/jinshengtao/article/details/30258833。

  ps:虽然代码可用,但对于代码算法具体原理及实现还未掌握透彻,有待进一步学习
  1.这是根据原有作者的c接口opencv升级的c++接口程序,适用于opencv 接口2.0版本,开发环境为VS2015+opencv3.2。
  2.程序视频的默认路径为”E\\dd4.mp4“。”
  3.视频启动后按 s 键进行暂停,然后用鼠标选取需要跟踪的矩形框,再次按 s 视频启动进行跟踪。
  4.程序有个bug,视频播放完毕会报错。
  5.程序中有imwrite函数,opencv本身bug存在,建议编译时选择release选项。
//#include "stdafx.h"  //#include "cv.h"  //#include "highgui.h"  #include<opencv.hpp>#define  u_char unsigned char  #define  DIST 0.5  #define  NUM 20  using namespace std;using namespace cv;//全局变量  bool pause = false;bool is_tracking = false;Rect drawing_box;Mat current;double *hist1, *hist2;double *m_wei;double C = 0.0;bool xx = false;bool g_bDrawingBox = false;Mat tempImage;void ShowHelpText();void init_target(double *hist1, double *m_wei, Mat current){int t_h, t_w, t_x, t_y;double h, dist;int i, j;int q_r, q_g, q_b, q_temp;t_h = drawing_box.height;t_w = drawing_box.width;t_x = drawing_box.x;t_y = drawing_box.y;h = pow(((double)t_w) / 2, 2) + pow(((double)t_h) / 2, 2);            //带宽  Mat pic_hist = Mat(300, 200, CV_8UC3);     //生成直方图图像  for (i = 0; i < t_w*t_h; i++){m_wei[i] = 0.0;}for (i = 0; i < 4096; i++){hist1[i] = 0.0;}for (i = 0; i < t_h; i++){for (j = 0; j < t_w; j++){dist = pow(i - (double)t_h / 2, 2) + pow(j - (double)t_w / 2, 2);m_wei[i * t_w + j] = 1 - dist / h;//printf("%f\n",m_wei[i * t_w + j]);  C += m_wei[i * t_w + j];}}//计算目标权值直方  for (i = t_y; i < t_y + t_h; i++){for (j = t_x; j < t_x + t_w; j++){//rgb颜色空间量化为16*16*16 bins  /*q_r = ((u_char)current.at(i + j * 3 + 2) / 16;q_g = ((u_char)current->imageData[i * current->widthStep + j * 3 + 1]) / 16;q_b = ((u_char)current->imageData[i * current->widthStep + j * 3 + 0]) / 16;*/q_r = current.at<Vec3b>(i, j)[2] / 16;q_g = current.at<Vec3b>(i, j)[1] / 16;q_b = current.at<Vec3b>(i, j)[0] / 16;q_temp = q_r * 256 + q_g * 16 + q_b;hist1[q_temp] = hist1[q_temp] + m_wei[(i - t_y) * t_w + (j - t_x)];}}//归一化直方图  for (i = 0; i < 4096; i++){hist1[i] = hist1[i] / C;//printf("%f\n",hist1[i]);  }//生成目标直方图  double temp_max = 0.0;for (i = 0; i < 4096; i++)         //求直方图最大值,为了归一化  {//printf("%f\n",val_hist[i]);  if (temp_max < hist1[i]){temp_max = hist1[i];}}//画直方图  Point p1, p2;double bin_width = pic_hist.cols / 4096;double bin_unith = pic_hist.rows / temp_max;for (i = 0; i < 4096; i++){p1.x = i * bin_width;p1.y = pic_hist.rows;p2.x = (i + 1)*bin_width;p2.y = pic_hist.rows - hist1[i] * bin_unith;//printf("%d,%d,%d,%d\n",p1.x,p1.y,p2.x,p2.y);  rectangle(pic_hist, p1, p2, Scalar(0, 255, 0), -1, 8, 0);}imwrite("hist1.jpg", pic_hist);//cvReleaseImage(&pic_hist);}void MeanShift_Tracking(Mat current){int num = 0, i = 0, j = 0;int t_w = 0, t_h = 0, t_x = 0, t_y = 0;double *w = 0, *hist2 = 0;double sum_w = 0, x1 = 0, x2 = 0, y1 = 2.0, y2 = 2.0;int q_r, q_g, q_b;int *q_temp;//Mat pic_hist;t_w = drawing_box.width;t_h = drawing_box.height;Mat pic_hist = Mat(300, 200, CV_8UC3);     //生成直方图图像  hist2 = (double *)malloc(sizeof(double) * 4096);w = (double *)malloc(sizeof(double) * 4096);q_temp = (int *)malloc(sizeof(int)*t_w*t_h);while ((pow(y2, 2) + pow(y1, 2) > 0.5) && (num < NUM)){num++;t_x = drawing_box.x;t_y = drawing_box.y;memset(q_temp, 0, sizeof(int)*t_w*t_h);for (i = 0; i < 4096; i++){w[i] = 0.0;hist2[i] = 0.0;}for (i = t_y; i < t_h + t_y; i++){for (j = t_x; j < t_w + t_x; j++){//rgb颜色空间量化为16*16*16 bins  /*q_r = ((u_char)current->imageData[i * current->widthStep + j * 3 + 2]) / 16;q_g = ((u_char)current->imageData[i * current->widthStep + j * 3 + 1]) / 16;q_b = ((u_char)current->imageData[i * current->widthStep + j * 3 + 0]) / 16;*/q_r = current.at<Vec3b>(i, j)[2] / 16;q_g = current.at<Vec3b>(i, j)[1] / 16;q_b = current.at<Vec3b>(i, j)[0] / 16;q_temp[(i - t_y) *t_w + j - t_x] = q_r * 256 + q_g * 16 + q_b;hist2[q_temp[(i - t_y) *t_w + j - t_x]] = hist2[q_temp[(i - t_y) *t_w + j - t_x]] + m_wei[(i - t_y) * t_w + j - t_x];}}//归一化直方图  for (i = 0; i < 4096; i++){hist2[i] = hist2[i] / C;//printf("%f\n",hist2[i]);  }//生成目标直方图  double temp_max = 0.0;for (i = 0; i < 4096; i++)         //求直方图最大值,为了归一化  {if (temp_max < hist2[i]){temp_max = hist2[i];}}//画直方图  Point p1, p2;double bin_width = pic_hist.cols / (4368);double bin_unith = pic_hist.rows / temp_max;for (i = 0; i < 4096; i++){p1.x = i * bin_width;p1.y = pic_hist.cols;p2.x = (i + 1)*bin_width;p2.y = pic_hist.rows - hist2[i] * bin_unith;rectangle(pic_hist, p1, p2, Scalar(0, 255, 0), -1, 8, 0);}imwrite("hist2.jpg", pic_hist);for (i = 0; i < 4096; i++){if (hist2[i] != 0){w[i] = sqrt(hist1[i] / hist2[i]);}else{w[i] = 0;}}sum_w = 0.0;x1 = 0.0;x2 = 0.0;for (i = 0; i < t_h; i++){for (j = 0; j < t_w; j++){//printf("%d\n",q_temp[i * t_w + j]);  sum_w = sum_w + w[q_temp[i * t_w + j]];x1 = x1 + w[q_temp[i * t_w + j]] * (i - t_h / 2);x2 = x2 + w[q_temp[i * t_w + j]] * (j - t_w / 2);}}y1 = x1 / sum_w;y2 = x2 / sum_w;//中心点位置更新  drawing_box.x += y2;drawing_box.y += y1;}rectangle(current, Point(drawing_box.x, drawing_box.y), Point(drawing_box.x + drawing_box.width, drawing_box.y + drawing_box.height), Scalar(255, 0, 0), 2);imshow("Meanshift", current);}void onMouse(int event, int x, int y, int flags, void *param){if (pause){switch (event){case EVENT_MOUSEMOVE:if (g_bDrawingBox){drawing_box.width = x - drawing_box.x;drawing_box.height = y - drawing_box.y;}break;case CV_EVENT_LBUTTONDOWN:g_bDrawingBox = true;drawing_box = Rect(x, y, 0, 0);//记录起始点//the left up point of the rect  //drawing_box.x = x;//drawing_box.y = y;break;case CV_EVENT_LBUTTONUP://finish drawing the rect (use color green for finish)  g_bDrawingBox = false;xx = true;drawing_box.width = x - drawing_box.x;drawing_box.height = y - drawing_box.y;rectangle(current, drawing_box.tl(), drawing_box.br(), Scalar(255, 0, 0), 2);//目标初始化  hist1 = (double *)malloc(sizeof(double) * 16 * 16 * 16);m_wei = (double *)malloc(sizeof(double)*drawing_box.height*drawing_box.width);init_target(hist1, m_wei, current);is_tracking = true;//imshow("Meanshift", current);break;}imshow("Meanshift", current);return;}}int main(){ShowHelpText();VideoCapture capture("E://dd4.mp4");capture.grab(); //从视频文件或捕获设备获取下一帧  capture.retrieve(current);//解码并返回抓取了的视频帧  while (1){if (is_tracking){MeanShift_Tracking(current);}int c = waitKey(1);//暂停  if (c == 's'){while (1){pause = true;setMouseCallback("Meanshift", onMouse, 0);current.copyTo(tempImage);if (g_bDrawingBox)rectangle(tempImage, drawing_box.tl(), drawing_box.br(), Scalar(255, 0, 0), 2);if (xx == true)break;waitKey(2);imshow("Meanshift", tempImage);}}while (pause){if (waitKey(0) == 's')pause = false;}//if (current.size != 0)try { imshow("Meanshift", current); }catch (exception& e) { cout << "视频播放完毕"; return 0; }//else//break;capture.grab(); //从视频文件或捕获设备获取下一帧  capture.retrieve(current);//解码并返回抓取了的视频帧    }namedWindow("Meanshift", 1);return 0;}void ShowHelpText(){//输出欢迎信息和OpenCV版本printf("\n1.这是根据原有作者的c接口opencv升级的c++接口程序,适用于opencv2.0版本,开发环境为VS2015+opencv3.2\n");printf("\n2.程序视频的默认路径为(E\\dd4.mp4)\n");printf("\n3.视频启动后按 s 键进行暂停,然后用鼠标选取需要跟踪的矩形框,再次按 s 视频启动进行跟踪\n");printf("\n4.程序有个bug,视频播放完毕会报错");//printf("\n\n  ----------------------------------------------------------------------------\n");//输出一些帮助信息//printf("\n\n\n\t欢迎来到【鼠标交互演示】示例程序\n");//printf("\n\n\t请在窗口中点击鼠标左键并拖动以绘制矩形\n");}


原创粉丝点击