Camshift算法的C++实现

描述

Camshift算法可以用来在视频或者摄像头开启时,跟踪某个固定的物体。

  • 原理:
    求待跟踪目标的颜色直方图模型,将图像转换为颜色概率分布图,初始化一个搜索窗的大小和位置,并根据上一帧得到的结果自适应调整搜索窗口的位置和大小,从而定位出当前图像中目标的中心位置。

  • 不足:受光照影响大,精度不足

代码

摄像头+鼠标框出物体

下面这段代码,会打开摄像头,需要用鼠标框出要跟踪的物体,源代码地址在 https://github.com/prateekvjoshi/Object-Tracker-CAMShift,我进行了少部分修改

main.cpp

// Tracks the selected object using CAMShift algorithm

#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <ctype.h>

#define CV_TERMCRIT_EPS 2
#define CV_TERMCRIT_ITER 1  
#define CV_AA 16

cv::Mat image;

bool selectObject = false;
int trackObject = 0;
cv::Point origin;
cv::Rect selection;
int vmin = 10, vmax = 256, smin = 30;

static void onMouse( int event, int x, int y, int, void* )
{
    if( selectObject )
    {
        selection.x = MIN(x, origin.x);
        selection.y = MIN(y, origin.y);
        selection.width = std::abs(x - origin.x);
        selection.height = std::abs(y - origin.y);
        
        selection &= cv::Rect(0, 0, image.cols, image.rows);
    }
    
    switch( event )
    {
        case cv::EVENT_LBUTTONDOWN:
            origin = cv::Point(x,y);
            selection = cv::Rect(x,y,0,0);
            selectObject = true;
            break;
        case cv::EVENT_LBUTTONUP:
            selectObject = false;
            if( selection.width > 0 && selection.height > 0 )
                trackObject = -1;
            break;
    }
}

static void help()
{
    std::cout << "\nCAMShift based object tracking\n"
    "You select a colored object and the algorithm tracks it.\n"
    "This takes the input from the webcam\n"
    "Usage: \n"
    "$ ./main [camera number]\n";
    
    std::cout << "\n\nKeyboard input options: \n"
    "\tESC - quit the program\n"
    "\ts - stop the tracking\n"
    "\tp - pause video\n"
    "\nTo start tracking an object, select the rectangular region around it with the mouse\n\n";
}

int main( int argc, const char** argv )
{
    help();
    
    cv::VideoCapture cap;
    cv::Rect trackWindow;
    int hsize = 16;
    float hranges[] = {0,180};
    const float* phranges = hranges;
    
    int camNum = 0;
    if(argc == 2)
        camNum = atoi(argv[1]);
    
    cap.open(camNum);
    
    if( !cap.isOpened() )
    {
        help();
        std::cout << "***Could not initialize capturing...***\n";
        std::cout << "Current parameter's value: " << camNum << std::endl;
        return -1;
    }
    
    cv::namedWindow( "CamShift Object Tracker", 0 );
    cv::setMouseCallback( "CamShift Object Tracker", onMouse, 0 );
    
    cv::Mat frame, hsv, hue, mask, hist, histimg = cv::Mat::zeros(200, 320, CV_8UC3), backproj;
    bool paused = false;
    
    for(;;)
    {
        if( !paused )
        {
            cap >> frame;
            if( frame.empty() )
                break;
        }
        
        frame.copyTo(image);
        
        if( !paused )
        {
            cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
            
            if( trackObject )
            {
                int _vmin = vmin, _vmax = vmax;
                
                inRange(hsv, cv::Scalar(0, smin, MIN(_vmin,_vmax)),
                        cv::Scalar(180, 256, MAX(_vmin, _vmax)), mask);
                int ch[] = {0, 0};
                hue.create(hsv.size(), hsv.depth());
                mixChannels(&hsv, 1, &hue, 1, ch, 1);
                
                if( trackObject < 0 )
                {
                    cv::Mat roi(hue, selection), maskroi(mask, selection);
                    calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
                    normalize(hist, hist, 0, 255, cv::NORM_MINMAX);
                    
                    trackWindow = selection;
                    trackObject = 1;
                    
                    histimg = cv::Scalar::all(0);
                    int binW = histimg.cols / hsize;
                    cv::Mat buf(1, hsize, CV_8UC3);
                    for( int i = 0; i < hsize; i++ )
                        buf.at<cv::Vec3b>(i) = cv::Vec3b(cv::saturate_cast<uchar>(i*180./hsize), 255, 255);
                    cvtColor(buf, buf, cv::COLOR_HSV2BGR);
                    
                    for( int i = 0; i < hsize; i++ )
                    {
                        int val = cv::saturate_cast<int>(hist.at<float>(i)*histimg.rows/255);
                        rectangle( histimg, cv::Point(i*binW,histimg.rows),
                                  cv::Point((i+1)*binW,histimg.rows - val),
                                  cv::Scalar(buf.at<cv::Vec3b>(i)), -1, 8 );
                    }
                }
                
                calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
                backproj &= mask;
                cv::RotatedRect trackBox = cv::CamShift(backproj, trackWindow,
                                                cv::TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
                if( trackWindow.area() <= 1 )
                {
                    int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;
                    trackWindow = cv::Rect(trackWindow.x - r, trackWindow.y - r,
                                       trackWindow.x + r, trackWindow.y + r) &
                    cv::Rect(0, 0, cols, rows);
                }
                
                ellipse( image, trackBox, cv::Scalar(0,0,255), 3, CV_AA );
            }
        }
        else if( trackObject < 0 )
            paused = false;
        
        if( selectObject && selection.width > 0 && selection.height > 0 )
        {
            cv::Mat roi(image, selection);
            bitwise_not(roi, roi);
        }
        
        imshow( "CamShift Object Tracker", image );
        
        char c = (char)cv::waitKey(10);
        if( c == 27 )
            break;
        switch(c)
        {
            case 's':
                trackObject = 0;
                histimg = cv::Scalar::all(0);
                break;

            case 'p':
                paused = !paused;
                break;
                
            default:
                ;
        }
    }   
    return 0;
}

附赠一个它的CMakeLists.txt吧

project(test)
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)

find_package(OpenCV REQUIRED)

add_executable (main main.cpp )
target_link_libraries(main ${OpenCV_LIBS})

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值