「计算机视觉C++」Camshift的自适应彩色目标跟踪

1.camshift算法介绍

camshift算法就是将meanshift算法扩展到连续图像序列。camshift将视频的所有帧做meanshift运算,并将上一帧的结果(搜索窗的大小和中心),作为下一帧meanshift算法搜索窗的初始值。然后一直迭代下去,实现对目标的跟踪。

2.CamShift函数说明

<code>//查找对象中心,大小和方向。
RotatedRect CamShift(
InputArray probImage,//对象直方图的反向投影
CV_IN_OUT Rect& window,//初始搜索窗口
TermCriteria criteria//底层meanShift的停止标准
);/<code>

3.OpenCV3 camshift跟踪实现

<code>//--------------------------------------【程序说明】-------------------------------------------
//\t\t程序描述:来自OpenCV安装目录下Samples文件夹中的官方示例程序-彩色目标跟踪操作
//\t\t开发测试所用操作系统: Windows 10 64bit
//\t\t开发测试所用IDE版本:Visual Studio 2017
//\t\t开发测试所用OpenCV版本:\t3.4
//\t\t2020年3月 Revised by @DL小宝
//------------------------------------------------------------------------------------------------

//---------------------------------【头文件、命名空间包含部分】----------------------------
//\t\t描述:包含程序所使用的头文件和命名空间
//-------------------------------------------------------------------------------------------------
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <ctype.h>

using namespace cv;
using namespace std;

//-----------------------------------【全局变量声明】-----------------------------------------
//\t\t描述:声明全局变量
//-------------------------------------------------------------------------------------------------

Mat image;
bool backprojMode = false;
bool selectObject = false;
int trackObject = 0;
bool showHist = true;
Point origin;
Rect selection;
int vmin = 10, vmax = 256, smin = 30;

//--------------------------------【onMouse( )回调函数】------------------------------------
//\t\t描述:鼠标操作回调
//-------------------------------------------------------------------------------------------------
static void onMouse( int event, int x, int y, int, void* )
{
\tif( selectObject )
\t{
\t\tselection.x = MIN(x, origin.x);
\t\tselection.y = MIN(y, origin.y);
\t\tselection.width = std::abs(x - origin.x);
\t\tselection.height = std::abs(y - origin.y);
\t\tselection &= Rect(0, 0, image.cols, image.rows);
\t}

\tswitch( event )
\t{
\t//此句代码的OpenCV2版为:
\t//case CV_EVENT_LBUTTONDOWN:
\t//此句代码的OpenCV3版为:
\tcase EVENT_LBUTTONDOWN:
\t\torigin = Point(x,y);
\t\tselection = Rect(x,y,0,0);
\t\tselectObject = true;
\t\tbreak;
\t//此句代码的OpenCV2版为:
\t//case CV_EVENT_LBUTTONUP:
\t//此句代码的OpenCV3版为:
\tcase EVENT_LBUTTONUP:
\t\tselectObject = false;
\t\tif( selection.width > 0 && selection.height > 0 )
\t\t\ttrackObject = -1;
\t\tbreak;
\t}
}

//--------------------------------【help( )函数】----------------------------------------------
//\t\t描述:输出帮助信息

//-------------------------------------------------------------------------------------------------
static void ShowHelpText()
{
\tcout <\t\t<
\tcout << "\\n\\n\\t此Demo显示了基于均值漂移的追踪(tracking)技术\\n"
\t\t"\\t请用鼠标框选一个有颜色的物体,对它进行追踪操作\\n";

\tcout << "\\n\\n\\t操作说明: \\n"
\t\t"\\t\\t用鼠标框选对象来初始化跟踪\\n"
\t\t"\\t\\tESC - 退出程序\\n"
\t\t"\\t\\tc - 停止追踪\\n"
\t\t"\\t\\tb - 开/关-投影视图\\n"
\t\t"\\t\\th - 显示/隐藏-对象直方图\\n"
\t\t"\\t\\tp - 暂停视频\\n";
}
const char* keys = {"{1| | 0 | camera number}"};

//-----------------------------------【main( )函数】--------------------------------------------
//\t\t描述:控制台应用程序的入口函数,我们的程序从这里开始
//-------------------------------------------------------------------------------------------------
int main( int argc, const char** argv )
{
\tShowHelpText();
\tVideoCapture cap;
\tRect trackWindow;
\tint hsize = 16;
\tfloat hranges[] = {0,180};
\tconst float* phranges = hranges;
\tcap.open(0);

\tif( !cap.isOpened() )
\t{
\t\tcout << "不能初始化摄像头\\n";
\t}

\tnamedWindow( "Histogram", 0 );
\tnamedWindow( "CamShift Demo", 0 );
\tsetMouseCallback( "CamShift Demo", onMouse, 0 );

\tcreateTrackbar( "Vmin", "CamShift Demo", &vmin, 256, 0 );
\tcreateTrackbar( "Vmax", "CamShift Demo", &vmax, 256, 0 );
\tcreateTrackbar( "Smin", "CamShift Demo", &smin, 256, 0 );

\tMat frame, hsv, hue, mask, hist, histimg = Mat::zeros(200, 320, CV_8UC3), backproj;
\tbool paused = false;

\tfor(;;)
\t{
\t\tif( !paused )
\t\t{
\t\t\tcap >> frame;
\t\t\tif( frame.empty() )
\t\t\t\tbreak;
\t\t}
\t\tframe.copyTo(image);
\t\tif( !paused )
\t\t{
\t\t\tcvtColor(image, hsv, COLOR_BGR2HSV);

\t\t\tif( trackObject )
\t\t\t{
\t\t\t\tint _vmin = vmin, _vmax = vmax;

\t\t\t\tinRange(hsv, Scalar(0, smin, MIN(_vmin,_vmax)),
\t\t\t\t\tScalar(180, 256, MAX(_vmin, _vmax)), mask);
\t\t\t\tint ch[] = {0, 0};
\t\t\t\thue.create(hsv.size(), hsv.depth());
\t\t\t\tmixChannels(&hsv, 1, &hue, 1, ch, 1);

\t\t\t\tif( trackObject < 0 )
\t\t\t\t{
\t\t\t\t\tMat roi(hue, selection), maskroi(mask, selection);
\t\t\t\t\tcalcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
\t\t\t\t\t//此句代码的OpenCV3版为:
\t\t\t\t\tnormalize(hist, hist, 0, 255, NORM_MINMAX);
\t\t\t\t\ttrackWindow = selection;
\t\t\t\t\ttrackObject = 1;
\t\t\t\t\thistimg = Scalar::all(0);
\t\t\t\t\tint binW = histimg.cols / hsize;
\t\t\t\t\tMat buf(1, hsize, CV_8UC3);
\t\t\t\t\tfor( int i = 0; i < hsize; i++ )
\t\t\t\t\t\tbuf.at<vec3b>(i) = Vec3b(saturate_cast<uchar>(i*180./hsize), 255, 255);

\t\t\t\t\t//此句代码的OpenCV3版为:
\t\t\t\t\tcvtColor(buf, buf, COLOR_HSV2BGR);

\t\t\t\t\tfor( int i = 0; i < hsize; i++ )
\t\t\t\t\t{

\t\t\t\t\t\tint val = saturate_cast(hist.at<float>(i)*histimg.rows/255);
\t\t\t\t\t\trectangle( histimg, Point(i*binW,histimg.rows),
\t\t\t\t\t\t\tPoint((i+1)*binW,histimg.rows - val),
\t\t\t\t\t\t\tScalar(buf.at<vec3b>(i)), -1, 8 );
\t\t\t\t\t}
\t\t\t\t}

\t\t\t\tcalcBackProject(&hue, 1, 0, hist, backproj, &phranges);
\t\t\t\tbackproj &= mask;
\t\t\t\tRotatedRect trackBox = CamShift(backproj, trackWindow,

\t\t\t\t//此句代码的OpenCV3版为:
\t\t\t\tTermCriteria( TermCriteria::EPS | TermCriteria::COUNT, 10, 1 ));

\t\t\t\tif( trackWindow.area() <= 1 )
\t\t\t\t{
\t\t\t\t\tint cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;
\t\t\t\t\ttrackWindow = Rect(trackWindow.x - r, trackWindow.y - r,
\t\t\t\t\t\ttrackWindow.x + r, trackWindow.y + r) &
\t\t\t\t\t\tRect(0, 0, cols, rows);
\t\t\t\t}

\t\t\t\tif( backprojMode )
\t\t\t\t\tcvtColor( backproj, image, COLOR_GRAY2BGR );

\t\t\t\t//此句代码的OpenCV3版为:
\t\t\t\tellipse( image, trackBox, Scalar(0,0,255), 3, LINE_AA );
\t\t\t}
\t\t}
\t\telse if( trackObject < 0 )
\t\t\tpaused = false;

\t\tif( selectObject && selection.width > 0 && selection.height > 0 )
\t\t{
\t\t\tMat roi(image, selection);
\t\t\tbitwise_not(roi, roi);
\t\t}

\t\timshow( "CamShift Demo", image );
\t\timshow( "Histogram", histimg );

\t\tchar c = (char)waitKey(10);
\t\tif( c == 27 )
\t\t\tbreak;
\t\tswitch(c)
\t\t{
\t\tcase 'b':
\t\t\tbackprojMode = !backprojMode;

\t\t\tbreak;
\t\tcase 'c':
\t\t\ttrackObject = 0;
\t\t\thistimg = Scalar::all(0);
\t\t\tbreak;
\t\tcase 'h':
\t\t\tshowHist = !showHist;
\t\t\tif( !showHist )
\t\t\t\tdestroyWindow( "Histogram" );
\t\t\telse
\t\t\t\tnamedWindow( "Histogram", 1 );
\t\t\tbreak;
\t\tcase 'p':
\t\t\tpaused = !paused;
\t\t\tbreak;
\t\tdefault:
\t\t\t;
\t\t}
\t}
\treturn 0;
}/<vec3b>/<float>
/<uchar>/<vec3b>/<ctype.h>/<iostream>/<code>
「计算机视觉C++」Camshift的自适应彩色目标跟踪


分享到:


相關文章: