采用 CAMSHIFT 算法快速跟踪和检测运动目标的 C/C++ 源代码,OPENCV
BETA 4.0 版本在其 SAMPLE
中给出了这个例子。算法的简单描述如下(英文):
This application demonstrates a fast, simple color tracking
algorithm that can be used to track faces, hands . The CAMSHIFT
algorithm is a modification of the Meanshift algorithm which is a
robust statistical method of finding the mode (top) of a
probability distribution. Both CAMSHIFT and Meanshift algorithms
exist in the library. While it is a very fast and simple method of
tracking, because CAMSHIFT tracks the center and size of the
probability distribution of an object, it is only as good as the
probability distribution that you produce for the object. Typically
the probability distribution is derived from color via a histogram,
although it could be produced from correlation, recognition scores
or bolstered by frame differencing or motion detection schemes, or
joint probabilities of different colors/motions etc.
In this application, we use only the most simplistic approach: A
1-D Hue histogram is sampled from the object in an HSV color space
version of the image. To produce the probability image to track,
histogram "back projection" (we replace image pixels by their
histogram hue value) is used.
算法的详细情况,请看论文:
http://www.assuredigit.com/incoming/camshift.pdf
关于OPENCV B4.0
库的使用方法以及相关问题,请查阅下面的相关文章:
http://forum.assuredigit.com/display_topic_threads.asp?ForumID=11&TopicID=3471
运行文件下载:
http://www.assuredigit.com/product_tech/Demo_Download_files/camshiftdemo.exe
该运行文件在VC6.0环境下编译通过,是一个 stand-alone
运行程序,不需要OPENCV的DLL库支持。在运行之前,请先连接好USB接口的摄像头。然后可以用鼠标选定欲跟踪目标。
=====
#ifdef _CH_
#pragma package <opencv>
#endif
#ifndef _EiC
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <ctype.h>
#endif
IplImage *image = 0, *hsv = 0, *hue = 0, *mask = 0, *backproject
= 0, *histimg = 0;
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;
CvBox2D track_box; // tracking 返回的区域
box,带角度
CvConnectedComp track_comp;
int hdims =
48;
// 划分HIST的个数,越高越精确
float hranges_arr[] = {0,180};
float* hranges = hranges_arr;
int vmin = 10, vmax = 256, smin = 30;
void on_mouse( int event, int x, int y, int flags )
{
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 )
{
CvCapture*
capture = 0;
IplImage*
frame = 0;
if( argc ==
1 || (argc == 2 && strlen(argv[1]) == 1 &&
isdigit(argv[1][0])))
capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0
);
else if(
argc == 2 )
capture = cvCaptureFromAVI( argv[1] );
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 ); // on_mouse
自定义事件
cvCreateTrackbar( "Vmin", "CamShiftDemo", &vmin, 256, 0
);
cvCreateTrackbar( "Vmax", "CamShiftDemo", &vmax, 256, 0
);
cvCreateTrackbar( "Smin", "CamShiftDemo", &smin, 256, 0 );
for(;;)
{
int i, bin_w, c;
frame = cvQueryFrame( capture );
if( !frame )
break;
if( !image )
{
image = cvCreateImage( cvGetSize(frame), 8, 3 );
image->origin = frame->origin;
hsv = cvCreateImage( cvGetSize(frame), 8, 3 );
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
); // 计算直方图
histimg = cvCreateImage( cvSize(320,200), 8, 3 );
cvZero( histimg );
}
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(180,256,MAX(_vmin,_vmax),0), mask ); //
得到二值的MASK
cvSplit( hsv, hue, 0, 0, 0 ); // 只提取 HUE
分量
if( track_object < 0 )
{
float max_val = 0.f;
cvSetImageROI( hue, selection ); // 得到选择区域
for ROI
cvSetImageROI( mask, selection ); // 得到选择区域 for mask
cvCalcHist( &hue, hist, 0, mask ); // 计算直方图
cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0
); // 只找最大值
cvConvertScale( hist->bins, hist->bins, max_val ? 255. /
max_val : 0., 0 ); // 缩放 bin 到区间 [0,255]
cvResetImageROI( hue ); // remove 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 方法
cvAnd( backproject, mask, backproject, 0 );
...
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 字符编码:从基础到乱码解决