#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大神提供的指导!
新闻热点
疑难解答