[学习笔记]BCB下实现彩色目标跟踪

实现彩色目标跟踪,就调用opencv中的camshift算法。
个人对camshift算法理解是:搜索目标的直方图 与 被搜索目标的直方图,通过某种迭代运算。
使得圈出的范围越来越逼近想要搜寻的目标对象。详细请看camshift算法的具体说明。
程序来自:opencv教程 例题 5 -22 (加上自己的注释)
书中的在VC6下控制台实现,我把它改到C++ builder 6下实现。
运行后效果图:

 

 程序代码:

//---------------------------------------------------------------------------
//--------------头文件---------------
#ifndef camshiftH
#define camshiftH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include 
<Controls.hpp>
#include 
<StdCtrls.hpp>
#include 
<Forms.hpp>
#include 
"cv.h"
#include 
"highgui.h"
//---------------------------------------------------------------------------
//==================全局变量=====================
IplImage *image = 0,*hsv = 0,* hue = 0;
IplImage 
*mask = 0*backproject = 0*histimg = 0;
CvHistogram
* hist = 0;                  //直方
       CvCapture* capture = 0;
int backproject_mode = 0;               //表示反向投影窗体是否打开
int select_object = 0;                  //表示是否已开始选
int track_object = 0;                   //表示是否已选好区域
int show_hist = 0;                      //表示是否显示直方图窗体
CvPoint origin;                         //选中区域的原始点
CvRect selection;                       //选中的矩形区域
CvRect track_window;                    //
CvBox2D track_box;                      //tracking 返回的区域box,带角度
CvConnectedComp track_comp;
int hdims = 48;                         //划分HIST的个数,越高越精确
float hranges_arr[] = {0,180};          //定义直方图内方块的范围,第i维上下界
float* hranges = hranges_arr;
int vmin = 10, vmax = 256, smin = 30;   //三个滚动条的初始值
bool closeCAM = false;

//------------全局函数--------------
//定义鼠标回调函数,此处设为全局函数,便于回调
//若想设为类成员函数,参考回调函数说明
//后面加了个指针参数,不加出错,vc中确不会错,不知道为什么。
//查看opencv中Callback函数定义,确实要5个参数
void on_mouse(int event,int x,int y,int flags,void* t = NULL)
{
    
if(!image)return;
    
if(image->origin)                   //windows的bitmap标准
        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;        //选中区域有效,则表示范围已选好
    }
}
//---------------------------------------------------------------------------
CvScalar hsv2rgb(float hue)     //直立方H值转为RGB,为什么是这样算的,不清楚
{
    
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.033333333333333333333f;
    sector 
= cvFloor(hue);              //cvFloor 返回不大于参数的最大整数值
    p = cvRound(255 * (hue - sector));  //cvRound 返回和参数最接近的整数值
    p ^= sector & 1 ? 255 : 0;
    rgb[sector_data[sector][
0]] = 255;
    rgb[sector_data[sector][
1]] = 0;
    rgb[sector_data[sector][
2]] = p;
    
return cvScalar(rgb[2],rgb[1],rgb[0],0);
}
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    
// IDE-managed Components
    TButton *Button1;
    TButton 
*Button2;
    TButton 
*Button3;
    TButton 
*Button4;
    TButton 
*Button5;
    
void __fastcall Button1Click(TObject *Sender);
    
void __fastcall Button3Click(TObject *Sender);
    
void __fastcall Button4Click(TObject *Sender);
    
void __fastcall Button5Click(TObject *Sender);
    
void __fastcall Button2Click(TObject *Sender);
private:    // User declarations
public:        // User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------


 

//---------------------------------------------------------------------------
//----------------实现文件-----------------------
#include <vcl.h>
#pragma hdrstop

#include 
"camshift.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 
*Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    
    IplImage
* frame = 0;

    capture 
= cvCaptureFromCAM(0);
    
if(!capture)
    {
        ShowMessage(
"启动摄像头失败!");
        
return;
    }

    cvNamedWindow(
"目标捕获",1);
    
//设定鼠标回调事件
    cvSetMouseCallback("目标捕获",on_mouse,NULL);
    
//创建滚动条
    cvCreateTrackbar("掩码范围A","目标捕获",&vmin,256,0);
    cvCreateTrackbar(
"掩码范围B","目标捕获",&vmax,256,0);
    cvCreateTrackbar(
"Smin","目标捕获",&smin,256,0);

    
while(frame = cvQueryFrame(capture))
    {
        
int i,bin_w,c;
        
if(!image)
        {
            
//分配内存
            image = cvCreateImage(cvSize(frame->width,frame->height),8,3);
            image
->origin = frame->origin;
            hsv 
= cvCreateImage(cvSize(frame->width,frame->height),8,3);
            hue 
= cvCreateImage(cvSize(frame->width,frame->height),8,1);
            mask 
= cvCreateImage(cvSize(frame->width,frame->height),8,1);
            backproject 
= cvCreateImage(cvSize(frame->width,frame->height),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到HSV

        
if(track_object)
        {
            
int _vmin = vmin, _vmax = vmax;
            
//对色彩空间在一定范围内二值化,得出掩码mask
            cvInRangeS(hsv,cvScalar(0,smin,MIN(_vmin,_vmax),0),
                    cvScalar(
180,256,MAX(_vmin,_vmax),0),mask);
            cvSplit(hsv,hue,
0,0,0);             //只提取HUE分量
            if(track_object < 0)                //区域已选择完成
            {
                
float max_val = 0.f;
                cvSetImageROI(hue,selection);   
//设置感兴趣区域
                cvSetImageROI(mask,selection);
                cvCalcHist(
&hue,hist,0,mask);   //用掩码计算出直方图
                cvGetMinMaxHistValue(hist,0,&max_val,0,0);  //找最大值
                
//线性变换数组,缩放bin到[0,255]区间
                cvConvertScale(hist->bins,hist->bins,
                                max_val 
? 255./max_val : 0.,0);
                cvResetImageROI(hue);           
//取消感兴趣区域
                cvResetImageROI(mask);
                track_window 
= selection;
                track_object 
= 1;

                cvZero(histimg);
                bin_w 
= histimg->width /hdims;  //直方图中每条柱子的宽度

                
//画直方图
                for(i = 0;i < hdims;i++)
                {
                    
//GetReal*D  返回单通道数组的指定元素
                    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);
                }
            }
            
//计算直方图的反向投影,backproject是想要的结果
            cvCalcBackProject(&hue,backproject,hist);
            
//逻辑相与,用掩码选出相应区域
            cvAnd(backproject,mask,backproject,0);

            
//调用Camshift算法模块
            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);  
//使用backproject灰度图像
            if(image->origin)
                track_box.angle 
= -track_box.angle;
            cvEllipseBox(image,track_box,CV_RGB(
255,0,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(
"目标捕获",image);
        cvShowImage(
"直方图",histimg);
        
if(cvWaitKey(10== 27 || closeCAM)break;
    }
    cvReleaseCapture(
&capture);
    cvDestroyWindow(
"目标捕获");
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button3Click(TObject *Sender)
{
    
if(capture)
        backproject_mode 
^= 1;
    
else
        ShowMessage(
"您还未启动摄像头");
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button4Click(TObject *Sender)
{
    
if(!capture)
    {
        ShowMessage(
"您还未启动摄像头");
        
return;
    }
    track_object 
= 0;
    cvZero(histimg);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button5Click(TObject *Sender)
{

    
if(!capture)
    {
        ShowMessage(
"您还未启动摄像头");
        
return;
    }
    show_hist 
^= 1;
    
if(!show_hist)
    {
        cvDestroyWindow(
"直方图");
        
this->Button5->Caption = "打开直方图窗体";
    }
    
else
    {
        cvNamedWindow(
"直方图",1);
        
this->Button5->Caption = "关闭直方图窗体";
    }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
    
if(!capture)
    {
        ShowMessage(
"您还未启动摄像头");
        
return;
    }
    closeCAM 
= true;
}
//---------------------------------------------------------------------------


 




posted @ 2009-07-22 14:16  mxm  阅读(1552)  评论(0)    收藏  举报