影象處理之其他雜項(一)之MeanShift的目標跟蹤演算法opencv c++程式碼 VS2015+opencv3.2
阿新 • • 發佈:2019-01-03
//#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"); }