#include "highgui.h"#include "cv.h" #include <iostream>#include <stdlib.h>#include <stdio.h> // 求最大值max,最小值min,絕對值abs,正負標志sign#define max(a, b) ((a) > (b) ? (a) : (b))#define min(a, b) ((a) < (b) ? (a) : (b)) #define abs(x) ((x) > 0 ? (x) : -(x))#define sign(x) ((x) > 0 ? 1 : -1) //物體位移動的最小值和最大值#define STEP_MIN 5#define STEP_MAX 100 iplImage *image; // 物體放置地點CvPoint objectPos = cvPoint(-1, -1);// 被跟蹤的顏色和允許范圍---------------可調--------------------int h = 0, s = 0, v = 0, tolerance =5;int H_slider_pos=173,S_slider_pos=150,V_slider_pos=255; /* * 功能:將原圖轉換為二值圖 * 輸入:image圖片,被檢測的像素值nbPixels * 輸出:被檢測物體的重心 */CvPoint binarisation(IplImage* image, int *nbPixels) { int x, y; CvScalar pixel; IplImage *hsv, *mask; IplConvKernel *kernel; int sommeX = 0, sommeY = 0; *nbPixels = 0; // 創建一個mask圖像 mask = cvCreateImage(cvGetSize(image), image->depth, 1); //得到hsv格式圖像 hsv = cvCloneImage(image); cvCvtColor(image, hsv, CV_BGR2HSV); //按照顏色范圍給mask圖像賦值(像素值在范圍內則被置為0xff) cvInRangeS(hsv, cvScalar(h - tolerance -1, s - 5*tolerance, 0), cvScalar(h + tolerance -1, s + 5*tolerance, 255), mask); //創建結構元素----一個5X5的橢圓,錨點在(2,2) kernel = cvCreateStructuringElementEx(5, 5, 2, 2, CV_SHAPE_ELLIPSE); //膨脹 cvDilate(mask, mask, kernel, 1); //腐蝕 cvErode(mask, mask, kernel, 1); //計算出查找的重心 for(x = 0; x < mask->width; x++) { for(y = 0; y < mask->height; y++) { //計算符合的像素點的個數 和X,Y值的和 if(((uchar *)(mask->imageData + y*mask->widthStep))[x] == 255) { sommeX += x; sommeY += y; (*nbPixels)++; } } } //顯示mask圖像 cvShowImage("視頻二值化", mask); //釋放結構元素 cvReleaseStructuringElement(&kernel); //釋放mask圖像內存 cvReleaseImage(&mask); //釋放hsv圖像內存 cvReleaseImage(&hsv); //如果找到了符合的點,將所有的點的X,Y坐標求均值并返回 if(*nbPixels > 0) return cvPoint((int)(sommeX / (*nbPixels)), (int)(sommeY / (*nbPixels))); else return cvPoint(-1, -1);} /* * 功能:在被跟蹤的物體重心上畫圓 * 輸入:image圖片,物體重心objectNextPos,像素點個數nbPixels * 輸出:無 */void addObjectToVideo(IplImage* image, CvPoint objectNextPos, int nbPixels) { int objectNextStepX, objectNextStepY; // 計算下一個紅點位置 if (nbPixels > 10) { if (objectPos.x == -1 || objectPos.y == -1) { objectPos.x = objectNextPos.x; objectPos.y = objectNextPos.y; } if (abs(objectPos.x - objectNextPos.x) > STEP_MIN) { objectNextStepX = max(STEP_MIN, min(STEP_MAX, abs(objectPos.x - objectNextPos.x) / 2)); objectPos.x += (-1) * sign(objectPos.x - objectNextPos.x) * objectNextStepX; } if (abs(objectPos.y - objectNextPos.y) > STEP_MIN) { objectNextStepY = max(STEP_MIN, min(STEP_MAX, abs(objectPos.y - objectNextPos.y) / 2)); objectPos.y += (-1) * sign(objectPos.y - objectNextPos.y) * objectNextStepY; } } else { objectPos.x = -1; objectPos.y = -1; } // 在image圖像上畫一個半徑為15的紅色圓點 if (nbPixels > 10) cvDrawCircle(image, objectPos, 10, CV_RGB(255, 0, 0), -1); /* CvFont* font; char string[]="i am happy"; cvInitFont(font,CV_FONT_HERSHEY_SIMPLEX,1.0f,1.0f,0,1,8); cvPutText(image,string,objectPos,font,CV_RGB(0,0,255));*/ cvShowImage("動態追蹤", image); } /* * 功能:得到鼠標點擊處的像素值(被跟蹤的像素值) * 輸入:event事件,坐標x,y ,標志flags,屬性指針param * 輸出:無 */void getObjectColor(int event, int x, int y, int flags, void *param = NULL) { // 定義一個var[4]數組變量pixel CvScalar pixel; //定義hsv圖像 IplImage *hsv; //鼠標按下 if(event == CV_EVENT_LBUTTONUP) { // 獲取hsv圖像 hsv = cvCloneImage(image); cvCvtColor(image, hsv, CV_BGR2HSV); // 獲取像素值 pixel = cvGet2D(hsv, y, x); h = (int)pixel.val[0]; s = (int)pixel.val[1]; v = (int)pixel.val[2]; PRintf("%d/n",hsv->depth); printf("%d,%d,%d/n",h,s,v); // 釋放image內存 cvReleaseImage(&hsv); } }//修改HSV值void H_changed(int pos){ h=H_slider_pos;}void S_changed(int pos){ s=S_slider_pos;}void V_changed(int pos){ v=V_slider_pos;}/***************************************** 主程序******************************************/ int main() { IplImage *hsv; CvCapture *capture; char key=NULL; int nbPixels; CvPoint objectNextPos; // 讀取攝像頭 capture = cvCreateCameraCapture(1); // 檢測攝像頭捕獲是否成功 if (!capture) { printf("Can't initialize the video capture./n"); return -1; } // 創建兩個視頻窗口 cvNamedWindow("動態追蹤", CV_WINDOW_AUTOSIZE); cvNamedWindow("視頻二值化", CV_WINDOW_AUTOSIZE); cvMoveWindow("動態追蹤", 0, 100); cvMoveWindow("視頻二值化", 650, 100); //創建顏色控制的滾動條 //cvCreateTrackbar("H:","GeckoGeek Mask",&H_slider_pos,255,H_changed); //cvCreateTrackbar("S:","GeckoGeek Mask",&S_slider_pos,255,S_changed); //cvCreateTrackbar("V:","GeckoGeek Mask",&V_slider_pos,255,V_changed);/* // 點擊鼠標選擇被跟蹤的顏色 cvSetMouseCallback("GeckoGeek Color Tracking", getObjectColor);*//* //紅瓶蓋 h=174; s=146; v=160;*//* //紅瓶蓋 h=171; s=151; v=84;*//* //皮膚 h=11; s=51; v=124;*//* //激光1 h=173; s=150;//s最大值190,最小值130 v=255;*//* //激光2 h=173; s=150; v=255;*/ // 按Q退出 while(key != 'Q' && key != 'q') { // 得到當前圖像 image = cvQueryFrame(capture); // 若無圖像,退出當前循環繼續獲取圖像 if(!image) continue; //得到被檢測的顏色重心 objectNextPos = binarisation(image, &nbPixels); //添加紅色圓點到被檢測顏色的重心 addObjectToVideo(image, objectNextPos, nbPixels); //等待10ms key = cvWaitKey(10); } // 銷毀窗口 cvDestroyWindow("動態追蹤"); cvDestroyWindow("視頻二值化"); // 釋放capture資源 cvReleaseCapture(&capture); return 0; }感謝wg_chn大神提供的指導!
新聞熱點
疑難解答