Opencv目标跟踪—CamShift算法

CamShift算法全称是“Continuously Adaptive Mean-Shift”(连续的自适应MeanShift算法),是对MeanShift算法的改进算法,可以在跟踪的过程中随着目标大小的变化实时调整搜索窗口大小,对于视频序列中的每一帧还是采用MeanShift来寻找最优迭代结果,至于如何实现自动调整窗口大小的,可以查到的论述较少,我的理解是通过对MeanShift算法中零阶矩的判断实现的。

在MeanShift算法中寻找搜索窗口的质心用到窗口的零阶矩M00和一阶矩M10,M01:



零阶矩是搜索窗口内所有像素的积分,即所有像素值之和,物理上的意义是计算搜索窗口的尺寸。经过目标的H分量直方图反向投影后,目标区域的搜索窗口大部分像素值归一化后应该是最大值255,如果计算出来零阶矩大于某一阈值,可以认为此时目标铺满了整个搜索窗口,有理由认为在搜索窗口之外的区域还存在目标区域,需要增大搜索窗口的尺寸;相应的,如果零阶矩小于某一阈值,则需要缩小搜索窗口的尺寸,如此一来,当目标的大小发生变化的时候,CamShift算法就可以自适应的调整目标区域进行跟踪。

以上过程中涉及到一个关键的概念——反向投影,CamShift和MeanShift的运算都是在反向投影图像上进行的,反向投影的实现过程如下:计算并生成目标区域的H分量的直方图,反向投影其实就是把目标图像上每一个像素点的像素值替换为当前像素值所在bin对应的直方图bin的数值。

Opencv中CamShfit在使用上跟MeanShift一致:


CamShift( InputArray probImage, CV_OUT CV_IN_OUT Rect& window,
                                   TermCriteria criteria );

第一个参数probImage是反向投影图像

第二个参数window是输入和输出的搜索窗口/目标窗口,window的尺寸会自动调整

第三个参数criteria是迭代收敛终止条件


#include "core/core.hpp"      
#include "highgui/highgui.hpp"      
#include "imgproc/imgproc.hpp"  
#include "video/tracking.hpp"  
#include<iostream>      

using namespace cv;      
using namespace std;      

Mat image;    
Mat rectImage;  
Mat imageCopy; //绘制矩形框时用来拷贝原图的图像    
bool leftButtonDownFlag=false; //左键单击后视频暂停播放的标志位    
Point originalPoint; //矩形框起点    
Point processPoint; //矩形框终点    

Mat targetImageHSV;  
int histSize=200;    
float histR[]={0,255};    
const float *histRange=histR;    
int channels[]={0,1};   
Mat dstHist;  
Rect rect;  
vector<Point> pt; //保存目标轨迹  
void onMouse(int event,int x,int y,int flags ,void* ustc); //鼠标回调函数    

int main(int argc,char*argv[])      
{      
	VideoCapture video(argv[1]);    
	double fps=video.get(CV_CAP_PROP_FPS); //获取视频帧率    
	double pauseTime=1000/fps; //两幅画面中间间隔    
	namedWindow("跟踪木头人",0);      
	setMouseCallback("跟踪木头人",onMouse);    
	while(true)    
	{    
		if(!leftButtonDownFlag) //判定鼠标左键没有按下,采取播放视频,否则暂停    
		{    
			video>>image;    
		}    
		if(!image.data||waitKey(pauseTime)==27)  //图像为空或Esc键按下退出播放    
		{    
			break;    
		}   
		if(originalPoint!=processPoint&&!leftButtonDownFlag)    
		{   
			Mat imageHSV;  
			Mat calcBackImage;  
			cvtColor(image,imageHSV,CV_RGB2HSV);  
			calcBackProject(&imageHSV,2,channels,dstHist,calcBackImage,&histRange);  //反向投影  
			TermCriteria criteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.001);    
			CamShift(calcBackImage, rect, criteria);     
			Mat imageROI=imageHSV(rect);   //更新模板             
			targetImageHSV=imageHSV(rect);  
			calcHist(&imageROI, 2, channels, Mat(), dstHist, 1, &histSize, &histRange);    
			normalize(dstHist, dstHist, 0.0, 1.0, NORM_MINMAX);   //归一化  
			rectangle(image, rect, Scalar(255, 0, 0),3);    //目标绘制    
			pt.push_back(Point(rect.x+rect.width/2,rect.y+rect.height/2));  
			for(int i=0;i<pt.size()-1;i++)  
			{  
				line(image,pt[i],pt[i+1],Scalar(0,255,0),2.5);  
			}  
		}    
		imshow("跟踪木头人",image);   
		waitKey(100);  
	}  
	return 0;    
}      

//*******************************************************************//      
//鼠标回调函数      
void onMouse(int event,int x,int y,int flags,void *ustc)      
{     
	if(event==CV_EVENT_LBUTTONDOWN)      
	{      
		leftButtonDownFlag=true; //标志位    
		originalPoint=Point(x,y);  //设置左键按下点的矩形起点    
		processPoint=originalPoint;    
	}      
	if(event==CV_EVENT_MOUSEMOVE&&leftButtonDownFlag)      
	{      
		imageCopy=image.clone();    
		processPoint=Point(x,y);    
		if(originalPoint!=processPoint)    
		{    
			//在复制的图像上绘制矩形    
			rectangle(imageCopy,originalPoint,processPoint,Scalar(255,0,0),2);    
		}    
		imshow("跟踪木头人",imageCopy);    
	}      
	if(event==CV_EVENT_LBUTTONUP)      
	{      
		leftButtonDownFlag=false;    
		rect=Rect(originalPoint,processPoint);        
		rectImage=image(rect); //子图像显示    
		imshow("Sub Image",rectImage);        
		cvtColor(rectImage,targetImageHSV,CV_RGB2HSV);  
		imshow("targetImageHSV",targetImageHSV);  
		calcHist(&targetImageHSV,2,channels,Mat(),dstHist,1,&histSize,&histRange,true,false);         
		normalize(dstHist,dstHist,0,255,CV_MINMAX);  
		imshow("dstHist",dstHist);  
	}        
}     








蓝色窗口是跟踪的目标,绿色线条是目标走过的轨迹。


  • 12
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
CamShift(Continuously Adaptive Meanshift)算法是基于Meanshift算法的一种算法,常用于目标跟踪。在OpenCV中,可以使用CamShift函数来实现该算法。 以下是实现CamShift算法的基本步骤: 1. 读取视频或打开摄像头,并读取第一帧图像。 2. 在第一帧图像中选择一个感兴趣区域(ROI)作为跟踪目标。 3. 将ROI的直方图计算出来,并使用Meanshift算法来跟踪该区域。 4. 在后续每一帧图像中,使用CamShift算法来跟踪该区域。 5. 如果目标区域发生变化,重新计算直方图。 以下是一个简单的Python代码示例,用于使用CamShift算法跟踪视频中的目标: ```python import cv2 # 读取视频并获取第一帧图像 cap = cv2.VideoCapture('test.avi') ret, frame = cap.read() # 选择ROI,并计算直方图 r, h, c, w = 250, 90, 400, 125 track_window = (c, r, w, h) roi = frame[r:r+h, c:c+w] hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv_roi, np.array((0., 60., 32.)), np.array((180., 255., 255.))) roi_hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0, 180]) cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX) # 设置迭代停止条件 term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1) while True: ret, frame = cap.read() if ret == True: # 将当前帧图像转换为HSV空间 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # 计算反向投影图像 dst = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1) # 使用CamShift算法跟踪目标 ret, track_window = cv2.CamShift(dst, track_window, term_crit) # 绘制跟踪结果 pts = cv2.boxPoints(ret) pts = np.int0(pts) img = cv2.polylines(frame, [pts], True, (0, 255, 0), 2) cv2.imshow('img', img) # 按下ESC键退出 k = cv2.waitKey(60) & 0xff if k == 27: break else: break # 释放所有资源 cap.release() cv2.destroyAllWindows() ``` 在上述代码中,我们首先选择了一个ROI,并计算了其直方图。然后,在后续每一帧图像中,使用CamShift算法来跟踪该区域,并在图像上绘制出跟踪结果。最后,按下ESC键退出程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值