目标跟踪(3)MultiTracker基于OpenCV(CP
在这篇文章中,我们将介绍如何使用通过MultiTracker类实现的OpenCV的多对象跟踪API。我们将共享C和Python代码。
1。为什么我们需要多目标跟踪
大多数计算机视觉和机器学习的初学者都学习对象检测。如果您是初学者,您可能会想为什么我们需要对象跟踪。我们不能只检测每一帧中的对象吗?
让我们来探究一下跟踪是有用的几个原因。
首先,当在视频帧中检测到多个对象(例如人)时,跟踪有助于跨帧建立对象的身份。
其次,在某些情况下,对象检测可能会失败,但仍可能跟踪对象,因为跟踪考虑了对象在前一帧中的位置和外观。
第三,一些跟踪算法非常快,因为它们做的是局部搜索,而不是全局搜索。因此,我们可以通过每n帧进行目标检测,并在中间帧中跟踪目标,从而为我们的系统获得很高的帧率。
那么,为什么不在第一次检测后无限期地跟踪对象呢?跟踪算法有时可能会丢失它正在跟踪的对象。例如,当对象的运动太大时,跟踪算法可能跟不上。许多现实世界的应用程序同时使用检测和跟踪。
在本教程中,我们只关注跟踪部分。我们想要跟踪的对象将通过拖动它们周围的包围框来指定。2。MultiTracker:OpenCV的多对象跟踪器
OpenCV中的MultiTracker类提供了多目标跟踪的实现。它是一个简单的实现,因为它独立处理跟踪对象,而不对跟踪对象进行任何优化。
让我们逐步查看代码,了解如何使用OpenCV的多目标跟踪API。
2。1第1步:创建单一对象跟踪器
多目标跟踪器只是单目标跟踪器的集合。我们首先定义一个函数,该函数接受一个跟踪器类型作为输入,并创建一个跟踪器对象。OpenCV有8种不同的跟踪器类型:BOOSTING,MIL,KCF,TLD,MEDIANFLOW,GOTURN,MOSSE,CSRT。
如果您想使用GOTURN跟踪器,请务必阅读这篇文章并下载caffe模型。
在下面的代码中,给定跟踪器类的名称,我们返回跟踪器对象。这将在稍后用于多目标跟踪器。
Pythonfromfutureimportprintfunctionimportsysimportcv2fromrandomimportrandinttrackerTypes〔BOOSTING,MIL,KCF,TLD,MEDIANFLOW,GOTURN,MOSSE,CSRT〕defcreateTrackerByName(trackerType):CreateatrackerbasedontrackernameiftrackerTypetrackerTypes〔0〕:trackercv2。TrackerBoostingcreate()eliftrackerTypetrackerTypes〔1〕:trackercv2。TrackerMILcreate()eliftrackerTypetrackerTypes〔2〕:trackercv2。TrackerKCFcreate()eliftrackerTypetrackerTypes〔3〕:trackercv2。TrackerTLDcreate()eliftrackerTypetrackerTypes〔4〕:trackercv2。TrackerMedianFlowcreate()eliftrackerTypetrackerTypes〔5〕:trackercv2。TrackerGOTURNcreate()eliftrackerTypetrackerTypes〔6〕:trackercv2。TrackerMOSSEcreate()eliftrackerTypetrackerTypes〔7〕:trackercv2。TrackerCSRTcreate()else:trackerNoneprint(Incorrecttrackername)print(Availabletrackersare:)fortintrackerTypes:print(t)returntracker
C注意:除了包含opencv2opencv。hpp,还需要包含opencv2tracking。hpp。includeopencv2opencv。hppincludeopencv2tracking。hppusingnamespacecv;usingnamespacestd;vectorstringtrackerTypes{BOOSTING,MIL,KCF,TLD,MEDIANFLOW,GOTURN,MOSSE,CSRT};createtrackerbynamePtrTrackercreateTrackerByName(stringtrackerType){PtrTrackertracker;if(trackerTypetrackerTypes〔0〕)trackerTrackerBoosting::create();elseif(trackerTypetrackerTypes〔1〕)trackerTrackerMIL::create();elseif(trackerTypetrackerTypes〔2〕)trackerTrackerKCF::create();elseif(trackerTypetrackerTypes〔3〕)trackerTrackerTLD::create();elseif(trackerTypetrackerTypes〔4〕)trackerTrackerMedianFlow::create();elseif(trackerTypetrackerTypes〔5〕)trackerTrackerGOTURN::create();elseif(trackerTypetrackerTypes〔6〕)trackerTrackerMOSSE::create();elseif(trackerTypetrackerTypes〔7〕)trackerTrackerCSRT::create();else{coutIncorrecttrackernameendl;coutAvailabletrackersare:endl;for(vectorstring::iteratorittrackerTypes。begin();it!trackerTypes。end();it)std::coutitendl;}returntracker;}
2。2第2步:读取视频的第一帧
多目标跟踪器需要两个输入一个视频帧我们要跟踪的所有对象的位置(边界框)。
给定这些信息,跟踪器在所有后续帧中跟踪这些指定对象的位置。在下面的代码中,我们首先使用VideoCapture类加载视频并读取第一帧。这将在稍后用于初始化MultiTracker。
PythonSetvideotoloadvideoPathvideosrun。mp4Createavideocaptureobjecttoreadvideoscapcv2。VideoCapture(videoPath)Readfirstframesuccess,framecap。read()quitifunabletoreadthevideofileifnotsuccess:print(Failedtoreadvideo)sys。exit(1)
CsetdefaultvaluesfortrackingalgorithmandvideostringvideoPathvideosrun。mp4;InitializeMultiTrackerwithtrackingalgovectorRectbboxes;createavideocaptureobjecttoreadvideoscv::VideoCapturecap(videoPath);Matframe;quitifunabketoreadvideofileif(!cap。isOpened()){coutErroropeningvideofilevideoPathendl;return1;}readfirstframecapframe;
2。3第3步:在第一帧中定位对象
接下来,我们需要在第一帧中定位我们想要跟踪的对象。该位置只是一个边界框。OpenCV提供了一个名为selectROI的函数,该函数会弹出一个GUI来选择边界框(也称为感兴趣区域(ROI))。在C版本中,selectROI允许您获取多个边界框,但在Python版本中,它只返回一个边界框。所以,在Python版本中,我们需要一个循环来获取多个边界框。对于每个对象,我们还选择一种随机颜色来显示边界框。代码如下所示。
PythonSelectboxesbboxes〔〕colors〔〕OpenCV的selectROI函数不适用于在Python中选择多个对象所以我们将循环调用这个函数,直到我们完成选择所有对象whileTrue:在对象上绘制边界框selectROI的默认行为是从中心开始绘制框当fromCenter设置为false时,可以从左上角开始画框bboxcv2。selectROI(MultiTracker,frame)bboxes。append(bbox)colors。append((randint(0,255),randint(0,255),randint(0,255)))print(Pressqtoquitselectingboxesandstarttracking)print(Pressanyotherkeytoselectnextobject)kcv2。waitKey(0)0xFFif(k113):qispressedbreakprint(Selectedboundingboxes{}。format(bboxes))
CGetboundingboxesforfirstframeselectROIsdefaultbehaviouristodrawboxstartingfromthecenterwhenfromCenterissettofalse,youcandrawboxstartingfromtopleftcornerboolshowCrosshairtrue;boolfromCenterfalse;cout;coutOpenCVsayspressctocancelobjectsselectionprocessendl;coutItdoesntwork。PressEscapetoexitselectionprocessendl;cout;cv::selectROIs(MultiTracker,frame,bboxes,showCrosshair,fromCenter);quitiftherearenoobjectstotrackif(bboxes。size()1)return0;vectorScalarcolors;getRandomColors(colors,bboxes。size());
getRandomColors函数相当简单FillthevectorwithrandomcolorsvoidgetRandomColors(vectorScalarcolors,intnumColors){RNGrng(0);for(inti0;inumColors;i)colors。pushback(Scalar(rng。uniform(0,255),rng。uniform(0,255),rng。uniform(0,255)));}
2。4第3步:初始化MultiTracker
到目前为止,我们已经读取了第一帧并获得了对象周围的边界框。这就是我们初始化多目标跟踪器所需的所有信息。
我们首先创建一个MultiTracker对象,并向其中添加与边界框一样多的单个对象跟踪器。在此示例中,我们使用CSRT单对象跟踪器,但您可以通过将下面的trackerType变量更改为本文开头提到的8个跟踪器之一来尝试其他跟踪器类型。CSRT跟踪器不是最快的,但在我们尝试的许多情况下它产生了最好的结果。
您还可以使用包裹在同一个MultiTracker中的不同跟踪器,但当然,这没什么意义。
MultiTracker类只是这些单个对象跟踪器的包装器。正如我们从上一篇文章中知道的那样,单个对象跟踪器是使用第一帧初始化的,并且边界框指示我们想要跟踪的对象的位置。MultiTracker将此信息传递给它在内部包装的单个对象跟踪器。
PythonSpecifythetrackertypetrackerTypeCSRTCreateMultiTrackerobjectmultiTrackercv2。MultiTrackercreate()InitializeMultiTrackerforbboxinbboxes:multiTracker。add(createTrackerByName(trackerType),frame,bbox)
CSpecifythetrackertypestringtrackerTypeCSRT;CreatemultitrackerPtrMultiTrackermultiTrackercv::MultiTracker::create();Initializemultitrackerfor(inti0;ibboxes。size();i)multiTrackeradd(createTrackerByName(trackerType),frame,Rect2d(bboxes〔i〕));
2。5第4步:更新MultiTracker并显示结果
最后,我们的MultiTracker已准备就绪,我们可以在新帧中跟踪多个对象。我们使用MultiTracker类的update方法来定位新框架中的对象。每个跟踪对象的每个边界框都使用不同的颜色绘制。
PythonProcessvideoandtrackobjectswhilecap。isOpened():success,framecap。read()ifnotsuccess:breakgetupdatedlocationofobjectsinsubsequentframessuccess,boxesmultiTracker。update(frame)drawtrackedobjectsfori,newboxinenumerate(boxes):p1(int(newbox〔0〕),int(newbox〔1〕))p2(int(newbox〔0〕newbox〔2〕),int(newbox〔1〕newbox〔3〕))cv2。rectangle(frame,p1,p2,colors〔i〕,2,1)showframecv2。imshow(MultiTracker,frame)quitonESCbuttonifcv2。waitKey(1)0xFF27:Escpressedbreak
Cwhile(cap。isOpened()){getframefromthevideocapframe;Stoptheprogramifreachedendofvideoif(frame。empty())break;UpdatethetrackingresultwithnewframemultiTrackerupdate(frame);Drawtrackedobjectsfor(unsignedi0;imultiTrackergetObjects()。size();i){rectangle(frame,multiTrackergetObjects()〔i〕,colors〔i〕,2,1);}Showframeimshow(MultiTracker,frame);quitonxbuttonif(waitKey(1)27)break;}
3。完整代码
Cincludeopencv2opencv。hppincludeopencv2tracking。hppusingnamespacecv;usingnamespacestd;vectorstringtrackerTypes{BOOSTING,MIL,KCF,TLD,MEDIANFLOW,GOTURN,MOSSE,CSRT};按名称创建跟踪器PtrTrackercreateTrackerByName(stringtrackerType){PtrTrackertracker;if(trackerTypetrackerTypes〔0〕)trackerTrackerBoosting::create();elseif(trackerTypetrackerTypes〔1〕)trackerTrackerMIL::create();elseif(trackerTypetrackerTypes〔2〕)trackerTrackerKCF::create();elseif(trackerTypetrackerTypes〔3〕)trackerTrackerTLD::create();elseif(trackerTypetrackerTypes〔4〕)trackerTrackerMedianFlow::create();elseif(trackerTypetrackerTypes〔5〕)trackerTrackerGOTURN::create();elseif(trackerTypetrackerTypes〔6〕)trackerTrackerMOSSE::create();elseif(trackerTypetrackerTypes〔7〕)trackerTrackerCSRT::create();else{coutIncorrecttrackernameendl;coutAvailabletrackersare:endl;for(vectorstring::iteratorittrackerTypes。begin();it!trackerTypes。end();it)std::coutitendl;}returntracker;}用随机颜色填充vectorvoidgetRandomColors(vectorScalarcolors,intnumColors){RNGrng(0);for(inti0;inumColors;i)colors。pushback(Scalar(rng。uniform(0,255),rng。uniform(0,255),rng。uniform(0,255)));}intmain(intargc,charargv〔〕){coutDefaulttrackingalgoritmisCSRTendl;coutAvailabletrackingalgorithmsare:endl;for(vectorstring::iteratorittrackerTypes。begin();it!trackerTypes。end();it)std::coutitendl;设置跟踪器类型。更改此项以尝试不同的跟踪器。stringtrackerTypeCSRT;设置跟踪算法和视频的默认值stringvideoPathvideosrun。mp4;使用跟踪算法初始化MultiTrackervectorRectbboxes;创建一个视频捕获对象来读取视频cv::VideoCapturecap(videoPath);Matframe;如果无法读取视频文件则退出if(!cap。isOpened()){coutErroropeningvideofilevideoPathendl;return1;}读取第一帧capframe;在对象上绘制边界框selectROI的默认行为是从中心开始绘制框当fromCenter设置为false时,可以从左上角开始画框boolshowCrosshairtrue;boolfromCenterfalse;cout;coutOpenCVsayspressctocancelobjectsselectionprocessendl;coutItdoesntwork。PressEscapetoexitselectionprocessendl;cout;cv::selectROIs(MultiTracker,frame,bboxes,showCrosshair,fromCenter);如果没有要跟踪的对象,则退出if(bboxes。size()1)return0;vectorScalarcolors;getRandomColors(colors,bboxes。size());创建multitrackerPtrMultiTrackermultiTrackercv::MultiTracker::create();初始化multitrackerfor(inti0;ibboxes。size();i)multiTrackeradd(createTrackerByName(trackerType),frame,Rect2d(bboxes〔i〕));处理视频和跟踪对象cout;coutStartedtracking,pressESCtoquit。endl;while(cap。isOpened()){从视频中获取帧capframe;如果到达视频结尾,则停止程序if(frame。empty())break;用新帧更新跟踪结果multiTrackerupdate(frame);绘制跟踪对象for(unsignedi0;imultiTrackergetObjects()。size();i){rectangle(frame,multiTrackergetObjects()〔i〕,colors〔i〕,2,1);}显示frameimshow(MultiTracker,frame);按ESC退出if(waitKey(1)27)break;}}
Python!usrbinpythonfromfutureimportprintfunctionimportsysimportcv2fromrandomimportrandinttrackerTypes〔BOOSTING,MIL,KCF,TLD,MEDIANFLOW,GOTURN,MOSSE,CSRT〕defcreateTrackerByName(trackerType):CreateatrackerbasedontrackernameiftrackerTypetrackerTypes〔0〕:trackercv2。TrackerBoostingcreate()eliftrackerTypetrackerTypes〔1〕:trackercv2。TrackerMILcreate()eliftrackerTypetrackerTypes〔2〕:trackercv2。TrackerKCFcreate()eliftrackerTypetrackerTypes〔3〕:trackercv2。TrackerTLDcreate()eliftrackerTypetrackerTypes〔4〕:trackercv2。TrackerMedianFlowcreate()eliftrackerTypetrackerTypes〔5〕:trackercv2。TrackerGOTURNcreate()eliftrackerTypetrackerTypes〔6〕:trackercv2。TrackerMOSSEcreate()eliftrackerTypetrackerTypes〔7〕:trackercv2。TrackerCSRTcreate()else:trackerNoneprint(Incorrecttrackername)print(Availabletrackersare:)fortintrackerTypes:print(t)returntrackerifnamemain:print(DefaulttrackingalgoritmisCSRTAvailabletrackingalgorithmsare:)fortintrackerTypes:print(t)trackerTypeCSRTSetvideotoloadvideoPathvideosrun。mp4Createavideocaptureobjecttoreadvideoscapcv2。VideoCapture(videoPath)Readfirstframesuccess,framecap。read()quitifunabletoreadthevideofileifnotsuccess:print(Failedtoreadvideo)sys。exit(1)Selectboxesbboxes〔〕colors〔〕OpenCVsselectROIfunctiondoesntworkforselectingmultipleobjectsinPythonSowewillcallthisfunctioninalooptillwearedoneselectingallobjectswhileTrue:drawboundingboxesoverobjectsselectROIsdefaultbehaviouristodrawboxstartingfromthecenterwhenfromCenterissettofalse,youcandrawboxstartingfromtopleftcornerbboxcv2。selectROI(MultiTracker,frame)bboxes。append(bbox)colors。append((randint(64,255),randint(64,255),randint(64,255)))print(Pressqtoquitselectingboxesandstarttracking)print(Pressanyotherkeytoselectnextobject)kcv2。waitKey(0)0xFFif(k113):qispressedbreakprint(Selectedboundingboxes{}。format(bboxes))InitializeMultiTrackerTherearetwowaysyoucaninitializemultitracker1。trackercv2。MultiTracker(CSRT)AllthetrackersaddedtothismultitrackerwilluseCSRTalgorithmasdefault2。trackercv2。MultiTracker()NodefaultalgorithmspecifiedInitializeMultiTrackerwithtrackingalgoSpecifytrackertypeCreateMultiTrackerobjectmultiTrackercv2。MultiTrackercreate()InitializeMultiTrackerforbboxinbboxes:multiTracker。add(createTrackerByName(trackerType),frame,bbox)Processvideoandtrackobjectswhilecap。isOpened():success,framecap。read()ifnotsuccess:breakgetupdatedlocationofobjectsinsubsequentframessuccess,boxesmultiTracker。update(frame)drawtrackedobjectsfori,newboxinenumerate(boxes):p1(int(newbox〔0〕),int(newbox〔1〕))p2(int(newbox〔0〕newbox〔2〕),int(newbox〔1〕newbox〔3〕))cv2。rectangle(frame,p1,p2,colors〔i〕,2,1)showframecv2。imshow(MultiTracker,frame)quitonESCbuttonifcv2。waitKey(1)0xFF27:Escpressedbreak
参考目录
https:learnopencv。commultitrackermultipleobjecttrackingusingopencvcpython