opencv跟踪手掌 代码

xiaoxiao2021-02-28  112

#include "cv.h" #include "highgui.h" #include <stdio.h> #include <ctype.h> #include <iostream> #include <windows.h> CvPoint2D32f pt[4];//自己定义的点作为椭圆方框图的基准点的数组 CvHistogram *hist = 0; int backproject_mode = 0; int select_object = 0; int track_object = 0; int show_hist = 1; CvPoint origin; CvRect selection; CvRect track_window; /*CvRect矩形框的偏移和大小 typedef struct CvRect { int x; /* 方形的最左角的x-坐标 int y; /* 方形的最上或者最下角的y-坐标 int width; /* 宽 int height; /* 高 *}*/ CvBox2D track_box; // tracking 返回的区域 box带角度 .CvBox2D旋转的二维盒子 CvConnectedComp track_comp; int hdims = 48; // 划分HIST的个数越高越精确 float hranges_arr[] = {0,180}; float* hranges = hranges_arr; int vmin = 10, vmax = 256, smin = 30; IplImage *image=NULL; static void on_mouse( int event, int x, int y, int flags,void *param) { if( !image ) return ; if( image->origin ) y = image->height - y; if( select_object ) { selection.x = MIN(x,origin.x); selection.y = MIN(y,origin.y); selection.width = selection.x + CV_IABS(x - origin.x); selection.height = selection.y + CV_IABS(y - origin.y); selection.x = MAX( selection.x, 0 ); selection.y = MAX( selection.y, 0 ); selection.width = MIN( selection.width, image->width ); selection.height = MIN( selection.height, image->height ); selection.width -= selection.x; selection.height -= selection.y; } switch( event ) { case CV_EVENT_LBUTTONDOWN: origin = cvPoint(x,y); selection = cvRect(x,y,0,0); select_object = 1; break; case CV_EVENT_LBUTTONUP: select_object = 0; if( selection.width > 0 && selection.height > 0 ) track_object = -1; #ifdef _DEBUG printf("\n # 鼠标的选择区域"); printf("\n X = %d, Y = %d, Width = %d, Height = %d", selection.x, selection.y, selection.width, selection.height); #endif break; } } CvScalar hsv2rgb( float hue ) { int rgb[3], p, sector; static const int sector_data[][3]= {{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}}; hue *= 0.033333333333333333333333333333333f; sector = cvFloor(hue); p = cvRound(255*(hue - sector)); p ^= sector & 1 ? 255 : 0; rgb[sector_data[sector][0]] = 255; rgb[sector_data[sector][1]] = 0; rgb[sector_data[sector][2]] = p; #ifdef _DEBUG printf("\n # Convert HSV to RGB"); printf("\n?? HUE = %f", hue); printf("\n?? R = %d, G = %d, B = %d", rgb[0],rgb[1],rgb[2]); #endif return cvScalar(rgb[2], rgb[1], rgb[0],0); } int main( int argc, char** argv ) { char chishu=0; int yzhi,yyzhi,jishu; IplImage* hsv,*backproject,*mask,*hue,*histimg; CvCapture* capture = 0;//CvCapture 视频获取结构 IplImage* frame = 0; capture = cvCaptureFromCAM( 0 );//cvCaptureFromCAM 初始化从摄像头中获取视频 if( !capture ) { fprintf(stderr,"Could not initialize capturing...\n"); return -1; } printf( "Hot keys: \n" "\tESC - quit the program\n" "\tc - stop the tracking\n" "\tb - switch to/from backprojection view\n" "\th - show/hide object histogram\n" "To initialize tracking, select the object with mouse\n"); //cvNamedWindow( "Histogram", 1 ); cvNamedWindow( "CamShiftDemo", 1 ); cvSetMouseCallback( "CamShiftDemo", on_mouse, NULL ); // on_mouse 自定义事件 cvCreateTrackbar( "Vmin", "CamShiftDemo", &vmin, 256, 0 );//cvCreateTrackbar 创建横拉条 cvCreateTrackbar( "Vmax", "CamShiftDemo", &vmax, 256, 0 ); cvCreateTrackbar( "Smin", "CamShiftDemo", &smin, 256, 0 ); for(;;) { int i, bin_w, c; frame = cvQueryFrame( capture );//vQueryFrame 从摄像头或者文件中抓取并返回一帧 if( !frame ) break; if( !image ) { /* allocate all the buffers */ image = cvCreateImage( cvGetSize(frame), 8, 3 ); image->origin = frame->origin; hsv = cvCreateImage( cvGetSize(frame), 8, 3 );//CreateImage创建头并分配数据 //IplImage* cvCreateImage( CvSize size, int depth, int channels ); hue = cvCreateImage( cvGetSize(frame), 8, 1 ); mask = cvCreateImage( cvGetSize(frame), 8, 1 ); backproject = cvCreateImage( cvGetSize(frame), 8, 1 ); hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 ); /*CreateHist创建直方图 CvHistogram* cvCreateHist( int dims, int* sizes, int type, float** ranges=NULL, int uniform=1 );dims直方图维数的数目*/ // 计算直方图 histimg = cvCreateImage( cvSize(320,200), 8, 3 ); /*CvSize 矩形框大小以像素为精度 typedef struct CvSize {int width; / 矩形宽 /int height; / 矩形高 /}*/ cvZero( histimg ); /*对于密集型号数组(CvMat, CvMatND or IplImage)cvZero(array) 就相当于 cvSet(array,cvScalarAll(0),0), 对于稀疏数组所有的元 素都将被删除.*/ } cvCopy( frame, image, 0 ); cvCvtColor( image, hsv, CV_BGR2HSV ); // 彩色空间转换 BGR to HSV if( track_object ) { int _vmin = vmin, _vmax = vmax; cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0), /*CvScalar可存放在1-2-3-4-TUPLE类型的捆绑数据的容 器 typedef struct CvScalar { double val[4] } CvScalar; /* 构造函数用val0初始化val[0]用val1初始化val[1]等等*/ cvScalar(180,256,MAX(_vmin,_vmax),0), mask ); /*InRangeS检查数组元素是否在两个数量之间 void cvInRangeS( const CvArr* src, CvScalar lower, CvScalar upper, CvArr* dst ); src第一个原数组 lower包括进的下边界. upper 不包括进的上边界 dst 输出数组必须是 8u 或 8s 类型.*/ // 得到二值的MASK cvSplit( hsv, hue, 0, 0, 0 ); // 只提取 HUE 分量 /*Split分割多通道数组成几个单通道数组或者从数组中提取一 个通道 void cvSplit( const CvArr* src, CvArr* dst0, CvArr* dst1,CvArr* dst2, CvArr* dst3 ); #define cvCvtPixToPlane cvSplit src 原数组. dst0...dst3目标通道*/ if( track_object < 0 ) { float max_val = 0.f; cvSetImageROI( hue, selection ); // 得到选择区域 for ROI /*SetImageROI基于给定的矩形设置感兴趣区域 void cvSetImageROI( IplImage* image, CvRect rect ); image 图像头.rect ROI矩形. */ cvSetImageROI( mask, selection ); // 得到选择区域 for mask cvCalcHist( &hue, hist, 0, mask ); // 计算直方图 /*CalcHist计算图像image(s) 的直方图 void cvCalcHist( IplImage** image, CvHistogram* hist,int accumulate=0, const CvArr* mask=NULL ); image输入图像s (虽然也可以使用 CvMat** ). hist直方图指针 accumulate累计标识。如果设置则直方图在开始时不被清零。 这个特征保证可以为多个图像计算一个单独的直方图或者在线更新 直方图。 mask 操作 mask, 确定输入图像的哪个象素被计数*/ cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 ); // 只找最大值 /*void cvGetMinMaxHistValue( const CvHistogram* hist,float* min_value, float* max_value,int* min_idx=NULL, int* max_idx=NULL ); hist直方图 min_value直方图最小值的指针 max_value直方图最大值的指针 min_idx数组中最小坐标的指针 max_idx数组中最大坐标的指针 函数 cvGetMinMaxHistValue 发现最大和最小直方块以及它们 的位置。任何输出变量都是可选的。 在具有同样值几个极值中返回具有最小下标索引以字母排 列顺序定的那一个。*/ cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 ); // 缩放 bin 到区间 [0,255] /*ConvertScale使用线性变换转换数组 void cvConvertScale( const CvArr* src, CvArr* dst, double scale=1, doubleshift=0 ); #define cvCvtScale cvConvertScale #define cvScale cvConvertScale #define cvConvert( src, dst ) cvConvertScale( (src), (dst), 1, 0 ) src原数组. dst输出数组 scale比例因子. shift原数组元素按比例缩放后添加的值。*/ cvResetImageROI( hue ); // remove ROI /*ResetImageROI释放图偈的ROI void cvResetImageROI( IplImage* image ); image图像头.函数 cvResetImageROI 释放图像 ROI. 释放之后 整个图像被认为是全部被选中的*/ cvResetImageROI( mask ); track_window = selection; track_object = 1; cvZero( histimg ); bin_w = histimg->width / hdims; // hdims: 条的个数则 bin_w 为条的宽度 // 画直方图 for( i = 0; i < hdims; i++ ) { int val = cvRound( cvGetReal1D(hist->bins,i)*histimg->height/255 ); CvScalar color = hsv2rgb(i*180.f/hdims); cvRectangle( histimg, cvPoint(i*bin_w,histimg->height),cvPoint((i+1)*bin_w,histimg->height - val),color, -1, 8, 0 ); } } cvCalcBackProject( &hue, backproject, hist ); // 使用 back project 方法 /*CalcBackProject计算反向投影 void cvCalcBackProject( IplImage** image, CvArr* back_project, constCvHistogram* hist ); image输入图像 (也可以传递 CvMat** ). back_project反向投影图像与输入图像具有同样类型. hist直方图*/ cvAnd( backproject, mask, backproject, 0 ); /*And计算两个数组的每个元素的按位与 void cvAnd( const CvArr* src1, const CvArr* src2, CvArr* dst, const CvArr*mask=NULL ); src1第一个原数组 src2第二个原数组. dst输出数组 mask操作覆盖面 8-bit 单通道数组; 只有覆盖面指定的输出 数组被修改*/ // calling CAMSHIFT 算法模块 cvCamShift( backproject, track_window, cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ), &track_comp, &track_box ); /*CamShift发现目标中心尺寸和方向 int cvCamShift( const CvArr* prob_image, CvRect window, CvTermCriteriacriteria, CvConnectedComp* comp, CvBox2D* box=NULL ); prob_image目标直方图的反向投影 (见 cvCalcBackProject). window初始搜索窗口 criteria确定窗口搜索停止的准则 comp生成的结构包含收敛的搜索窗口坐标 (comp->rect 字段) 与窗口内部所有象素点的和(comp->area 字段). box目标的带边界盒子。如果非 NULL, 则包含目标的尺寸和方 向。 */ track_window = track_comp.rect; if( backproject_mode ) cvCvtColor( backproject, image, CV_GRAY2BGR ); // 使用backproject灰度图像 /*CvtColor色彩空间转换 void cvCvtColor( const CvArr* src, CvArr* dst, int code ); src输入的 8-比特 或浮点图像. dst输出的 8-比特 或浮点图像. code色彩空间转换*/ if( image->origin ) track_box.angle = -track_box.angle; cvEllipseBox( image, track_box, CV_RGB(255,0,0), 3, CV_AA, 0 );//绘制椭圆圆弧和椭圆扇形 /*void cvEllipseBox( CvArr* img, CvBox2D box, CvScalar color,int thickness=1, int line_type=8, int shift=0 ); img 图像。 box 绘制椭圆圆弧所需要的外界矩形. thickness 分界线线条的粗细程度。 line_type 分界线线条的类型,见CVLINE的描述。 shift 椭圆框顶点坐标的精度。 */ //图形处理 cvBoxPoints( track_box, &pt[0] ); if(chishu==10)///处理图像每十副图检测一次椭圆方框的基准坐标左下角是基准点0,0 { printf(" x= %d,y= %d ",(int)pt[0].x,(int)pt[0].y);//强制转换变成整形数值 chishu=0; } chishu++; } if( select_object && selection.width > 0 && selection.height > 0 ) { cvSetImageROI( image, selection ); cvXorS( image, cvScalarAll(255), image, 0 ); cvResetImageROI( image ); } cvShowImage( "CamShiftDemo", image ); cvShowImage( "Histogram", histimg ); c = cvWaitKey(10); if( c == 27 ) break; // exit from for-loop switch( c ) { case 'b': backproject_mode ^= 1; break; case 'c': track_object = 0; cvZero( histimg ); break; case 'h': show_hist ^= 1; if( !show_hist ) cvDestroyWindow( "Histogram" ); else cvNamedWindow( "Histogram", 1 ); break ; default: ; } } cvReleaseCapture( &capture ); cvDestroyWindow("CamShiftDemo"); return 0; }
转载请注明原文地址: https://www.6miu.com/read-48685.html

最新回复(0)