C/C ++ source code for fast tracking and detection of moving targets using the camshift algorithm. This example is provided in opencv beta 4.0 in its sample. The algorithm is described as follows ):
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 bability 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 cocould 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.
For details about the algorithm, see the following:
Http://www.assuredigit.com/incoming/camshift.pdf
For usage of opencv b4.0 library and related questions, refer to the following articles:
Http://forum.assuredigit.com/display_topic_threads.asp? Forumid = 11 & topic id = 3471
Download running files:
Http://www.assuredigit.com/product_tech/Demo_Download_files/camshiftdemo.exe
The running file is compiled in the vc6.0 environment. It is a stand-alone running program and does not require support from the dll library of opencv. Before running, connect the USB camera. You can then select the target to be tracked with the mouse.
=====
# 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; // The Box returned by tracking, with an angle
Cvconnectedcomp track_comp;
Int hdims = 48; // Number of Hist partitions, the higher the accuracy
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 # select area of the mouse :");
Printf ("/N x = % d, y = % d, width = % d, Height = % d ",
Selection. X, selection. Y, selection. Width, selection. Height );
# Endif
Break;
}
}
Cvscalar HSV 2rgb (float Hue)
{
Int RGB [3], p, sector;
Static const int sector_data [] [3] =
{, 1}, {, 0}, {, 2}, {, 1}, {, 0}, {, 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, "cocould 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 Custom Event
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)
{
/* Allocate all the buffers */
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); // calculates the Histogram
Histimg = cvcreateimage (cvsize (320,200), 8, 3 );
Cvzero (histimg );
}
Cvcopy (frame, image, 0 );
Cvcvtcolor (image, HSV, cv_bgr2hsv); // color space conversion 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); // obtain the binary mask.
Cvsplit (HSV, hue, 0, 0, 0); // extract only the hue component
If (track_object <0)
{
Float max_val = 0.f;
Cvsetimageroi (hue, selection); // obtain the selected region for ROI
Cvsetimageroi (mask, selection); // obtain the selected region for mask
Cvcalchist (& hue, Hist, 0, mask); // calculates the histogram.
Cvgetminmaxhistvalue (Hist, 0, & max_val, 0, 0); // you can specify the maximum value only.
Cvconvertscale (hist-> bins, hist-> bins, max_val? 255./max_val: 0., 0); // scale the bin to the interval [0,255]
Cvresetimageroi (Hue); // remove ROI
Cvresetimageroi (mask );
Track_window = selection;
Track_object = 1;
Cvzero (histimg );
Bin_w = histimg-> width/hdims; // hdims: number of entries, then bin_w is the width
// Draw a Histogram
For (I = 0; I {
Int val = cvround (cvgetreal1d (hist-> bins, I) * histimg-> height/255 );
Cvscalar color = HSV 2rgb (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); // use the back Project Method
Cvand (backproject, mask, backproject, 0 );
// Calling camshift Algorithm Module
Cvcamshift (backproject, track_window,
Cvtermcriteria (cv_termcrit_eps | cv_termcrit_iter, 10, 1 ),
& Track_comp, & track_box );
Track_window = track_comp.rect;
If (backproject_mode)
Cvcvtcolor (backproject, image, cv_gray2bgr); // use the backproject grayscale image
If (image-> origin)
Track_box.angle =-track_box.angle;
Cvellipsebox (image, track_box, cv_rgb (255, 0), 3, cv_aa, 0 );
}
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;
}
# Ifdef _ EIC
Main (1, "camshiftdemo. c ");
# Endif