Object Tracking using OpenCV (C++/Python)(使用OpenCV进行目标跟踪)
本博客翻譯搬運自https://www.learnopencv.com/object-tracking-using-opencv-cpp-python,用于初入目標跟蹤的新手學習,轉貼請注明!
使用OpenCV進行目標跟蹤(C++/Python)
在本教程里,我們將學習OpenCV3.0中引入的OpenCV跟蹤API。我們將學習如何以及何時使用OpenCV3.4.1中提供的7中不同的跟蹤器——BOOSTING,MIL,KCF,TLD,MEDIANFLOW,GOTURN和MOSSE。我們還將學習現代跟蹤算法背后的一般理論。
我的朋友Boris Babenko完美的解決了這個問題,正如下面的這個完美的實時人臉跟蹤器所示!開玩笑的說,下面的這個GIF描述了我們想要的理想物體跟蹤器——速度,準確性和面對遮擋的魯棒性。
OpenCV目標跟蹤樣例:
如果你沒有時間閱讀整個教程,那就看看下面這個視頻并了解一下用法。但是如果你想系統學習一下目標跟蹤,那就完整讀下去。
視頻地址(需FQ):https://www.youtube.com/watch?reload=9&v=61QjSz-oLr8&feature=youtu.be
什么是目標跟蹤?
簡單的說,在一個視頻的連續幀中定位目標就稱之為跟蹤。
這個定義聽起來很直接但是在計算機視覺和機器學習領域,跟蹤是一個非常廣泛的術語,涵蓋概念上相似但技術上不同的想法。舉個例子,下面所有不同的但卻相關的方法均是可用在目標跟蹤的研究領域的。
1.密集光流法:這類算法有助于估計視頻幀中每個像素的運動矢量。
2.稀疏光流法:這類算法,如Kanade-Lucas-Tomashi(KLT)特征跟蹤器,跟蹤圖像中幾個特征點的位置。
3.卡爾曼濾波:這是一個非常流行的信號處理算法,用于根據先前的運動信息預測運動物體的位置。這種算法的早期應用之一是導彈制導!
4.Meanshift和Camshift:這些是用于定位密度函數的最大值的算法。它們也用于跟蹤領域。
5.單目標跟蹤器:在此類跟蹤器中,第一幀使用矩形標記來指示我們要跟蹤的對象的位置。然后使用跟蹤算法在后續幀中跟蹤對象。在大多數實際應用中,這些跟蹤器與物體檢測器結合使用。
6.多目標跟蹤器:在我們有快速物體探測器的情況下,檢測每個幀中的多個物體然后運行軌跡查找算法來識別一幀中的哪個矩形對應于下一幀中的矩形是有意義的。
跟蹤VS檢測
如果你曾經使用OpenCV做過面部檢測,你就明白它可以實時工作,你可以輕松地檢測每一幀中的臉部。那么,你為什么需要首先進行跟蹤?讓我們探討一下你可能想要跟蹤視頻中對象的不同原因,而不僅僅是重復檢測。
1.跟蹤比檢測快:通常跟蹤算法比檢測算法快。理由很簡單。當你跟蹤在前一幀中檢測到的對象時,你對該目標的外觀了解很多。你還知道前一幀的位置以及運動的方向和速度。因此在下一幀中,您可以使用所有這些信息來預測下一幀中目標的位置,并圍繞目標的預期位置進行小搜索,以準確定位目標。 一個好的跟蹤算法將使用它所擁有的關于該目標的所有信息,而檢測算法總是從頭開始。因此,在設計有效系統時,通常在每第n幀上運行目標檢測,而在其間的n-1幀中采用跟蹤算法。為什么我們不直接檢測第一幀中的目標并隨后跟蹤?確實,跟蹤可以從它擁有的額外信息中獲益,但是當它們長時間在障礙物后面或者如果它們移動速度太快以至于跟蹤算法無法趕上時,你也可能失去對目標的跟蹤。跟蹤算法累積錯誤也很常見,跟蹤目標的邊界框會慢慢偏離其正在跟蹤的目標。為了通過跟蹤算法解決這些問題,每隔一段時間運行一次檢測算法。檢測算法在目標的大量示例上進行訓練。因此,他們對目標的一般類有更多的了解。另一方面,跟蹤算法更多地了解他們正在跟蹤的類的特定實例。
2.檢測失敗時跟蹤可以提供幫助:如果你在視頻上運行人臉檢測器并且人臉被物體遮擋,那么人臉檢測大概率會失敗。另一方面,優秀的跟蹤算法可以解決某種程度的遮擋。在下面的視頻中,你可以看到MIL跟蹤器的作者Boris Bakenko博士演示MIL跟蹤器如何在遮擋下工作
視頻地址(需FQ):https://www.youtube.com/watch?v=n4QA3shA8Yw
3.跟蹤保留身份:目標檢測的輸出是包含目標的矩形數組。但是,目標沒有附加標識。例如,在下面的視頻中,檢測紅點的檢測器將輸出對應于它在幀中檢測到的所有點的矩形。在下一幀中,它將輸出另一個矩形數組。在第一幀中,特定點可以由陣列中位置10處的舉行表示,并且在第二幀中,它可以在位置17處。當在幀上使用檢測時,我們不知道哪個矩形對應于哪個目標。另一方面,跟蹤提供了一種字面連接點的方法。
視頻地址(需FQ):https://www.youtube.com/watch?v=SsiHH_wrwDg
OpenCV 跟蹤API
OpenCV3附帶了新的跟蹤API,其中包括許多單目標跟蹤算法的實現。OpenCV 3.4.1中有7種不同的跟蹤器——BOOSTING,MIL,KCF,TLD,MEDIANFLOW,GOTURN和MOSSE。
注意:OpenCV 3.2包括6種跟蹤器——BOOSTING,MIL,TLD,MEDIANFLOW和MOSSE。OpenCV 3.1有5種跟蹤器——BOOSTING,MIL,KCF,TLD,MEDIANFLOW。OpenCV 3.0包括4種跟蹤器——BOOSTING,MIL,TLD,MEDIANFLOW。
更新:在OpenCV 3.3種,跟蹤API已更改。請檢查代碼版本然后使用相應的API。
在我們提供算法的簡單描述之前,讓我們看看設置和用法。在下面的注釋代碼中,我們首先通過選擇跟蹤器類型來設置跟蹤器——BOOSTING,MIL,KCF,TLD,MEDIANFLOW,GOTURN或MOSSE。然后我們打開一個視頻并讀取一幀。我們定義一個包含第一幀目標的邊界框,并用第一幀和邊界框初始化跟蹤器。最后,我們從視頻中讀取幀并僅在循環中更新跟蹤器以獲得當前幀的新邊界框。隨后顯示結果。
C++
#include <opencv2/opencv.hpp> #include <opencv2/tracking.hpp> #include <opencv2/core/ocl.hpp>using namespace cv; using namespace std;// Convert to string #define SSTR( x ) static_cast< std::ostringstream & >( \ ( std::ostringstream() << std::dec << x ) ).str()int main(int argc, char **argv) {// List of tracker types in OpenCV 3.4.1string trackerTypes[7] = {"BOOSTING", "MIL", "KCF", "TLD","MEDIANFLOW", "GOTURN", "MOSSE"};// vector <string> trackerTypes(types, std::end(types));// Create a trackerstring trackerType = trackerTypes[2];Ptr<Tracker> tracker;#if (CV_MINOR_VERSION < 3){tracker = Tracker::create(trackerType);}#else{if (trackerType == "BOOSTING")tracker = TrackerBoosting::create();if (trackerType == "MIL")tracker = TrackerMIL::create();if (trackerType == "KCF")tracker = TrackerKCF::create();if (trackerType == "TLD")tracker = TrackerTLD::create();if (trackerType == "MEDIANFLOW")tracker = TrackerMedianFlow::create();if (trackerType == "GOTURN")tracker = TrackerGOTURN::create();if (trackerType == "MOSSE")tracker = TrackerMOSSE::create();}#endif// Read videoVideoCapture video("videos/chaplin.mp4");// Exit if video is not openedif(!video.isOpened()){cout << "Could not read video file" << endl; return 1; } // Read first frame Mat frame; bool ok = video.read(frame); // Define initial boundibg box Rect2d bbox(287, 23, 86, 320); // Uncomment the line below to select a different bounding box bbox = selectROI(frame, false); // Display bounding box. rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 ); imshow("Tracking", frame); tracker->init(frame, bbox);while(video.read(frame)){ // Start timerdouble timer = (double)getTickCount();// Update the tracking resultbool ok = tracker->update(frame, bbox);// Calculate Frames per second (FPS)float fps = getTickFrequency() / ((double)getTickCount() - timer);if (ok){// Tracking success : Draw the tracked objectrectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );}else{// Tracking failure detected.putText(frame, "Tracking failure detected", Point(100,80), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0,0,255),2);}// Display tracker type on frameputText(frame, trackerType + " Tracker", Point(100,20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50),2);// Display FPS on frameputText(frame, "FPS : " + SSTR(int(fps)), Point(100,50), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50), 2);// Display frame.imshow("Tracking", frame);// Exit if ESC pressed.int k = waitKey(1);if(k == 27){break;}} }Python
import cv2 import sys(major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')if __name__ == '__main__' :# Set up tracker.# Instead of MIL, you can also usetracker_types = ['BOOSTING', 'MIL','KCF', 'TLD', 'MEDIANFLOW', 'GOTURN', 'MOSSE']tracker_type = tracker_types[2]if int(minor_ver) < 3:tracker = cv2.Tracker_create(tracker_type)else:if tracker_type == 'BOOSTING':tracker = cv2.TrackerBoosting_create()if tracker_type == 'MIL':tracker = cv2.TrackerMIL_create()if tracker_type == 'KCF':tracker = cv2.TrackerKCF_create()if tracker_type == 'TLD':tracker = cv2.TrackerTLD_create()if tracker_type == 'MEDIANFLOW':tracker = cv2.TrackerMedianFlow_create()if tracker_type == 'GOTURN':tracker = cv2.TrackerGOTURN_create()if tracker_type == 'MOSSE':tracker = cv2.TrackerMOSSE_create()# Read videovideo = cv2.VideoCapture("videos/chaplin.mp4")# Exit if video not opened.if not video.isOpened():print "Could not open video"sys.exit()# Read first frame.ok, frame = video.read()if not ok:print 'Cannot read video file'sys.exit()# Define an initial bounding boxbbox = (287, 23, 86, 320)# Uncomment the line below to select a different bounding boxbbox = cv2.selectROI(frame, False)# Initialize tracker with first frame and bounding boxok = tracker.init(frame, bbox)while True:# Read a new frameok, frame = video.read()if not ok:break# Start timertimer = cv2.getTickCount()# Update trackerok, bbox = tracker.update(frame)# Calculate Frames per second (FPS)fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);# Draw bounding boxif ok:# Tracking successp1 = (int(bbox[0]), int(bbox[1]))p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1)else :# Tracking failurecv2.putText(frame, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2)# Display tracker type on framecv2.putText(frame, tracker_type + " Tracker", (100,20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50),2);# Display FPS on framecv2.putText(frame, "FPS : " + str(int(fps)), (100,50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50), 2);# Display resultcv2.imshow("Tracking", frame)# Exit if ESC pressedk = cv2.waitKey(1) & 0xffif k == 27 : break目標跟蹤算法
在本節中,我們將深入研究不同的跟蹤算法。目標并不是要對每個跟蹤器都有深入的理論理解,而是從實際的角度理解它們。
首先讓我解釋一下跟蹤背后的一些一般原則。 在跟蹤中,我們的目標是在當前幀中找到一個對象,因為我們已經在所有(或幾乎所有)前一幀中成功跟蹤了對象。
由于我們已經跟蹤了當前幀的目標,因此我們知道它是如何移動的。 換句話說,我們知道運動模型的參數。 運動模型只是一種奇特的方式,表示你知道前一幀中物體的位置和速度(速度+運動方向)。如果你對該目標一無所知,則可以根據當前運動模型預測新位置,并且你將非常接近目標的新位置。
我們有更多的信息,但是它們僅僅是關于目標的運動的。我們知道目標在每個先前幀中的外觀。換句話說,我們可以構建一個外觀模型來編碼目標的外觀。該外觀模型可用于在運動模型預測的位置的小領域中搜索,以更準確地預測目標的位置。
運動模型預測目標的大致位置,外觀模型精細調整該估計以基于外觀提供更準確的估計。
如果目標非常簡單并且沒有更改它的外觀,我們可以使用一個簡單的模板作為外觀模型并查找該模板。然而,顯示并非那么簡單。目標的外觀可能會發生巨大的變化,為了解決這個問題,在許多現代跟蹤器中,外觀模型是以在線方式訓練的分類器。別怕,讓我用簡單的術語解釋一下。分類器的工作是將圖像的矩形區域分類為目標或背景。分類器將圖像作為輸入,并返回0和1之間的分數,以指示圖像塊包含目標的概率。當絕對確定圖像塊是背景時得分為0,當絕對確定圖像塊是目標時得分為1。在機器學習中,我們使用“在線”一詞來指代在運行時即時訓練的算法。 離線分類器可能需要數千個示例來訓練分類器,但是在線分類器通常在運行時使用極少數示例進行訓練。通過將其分為正(目標)和負(目標)示例來訓練分類器。 如果你想建立一個用于檢測貓的分類器,你可以使用包含貓的數千個圖像和數千個不包含貓的圖像來訓練它。 通過這種方式,分類器學會區分什么是貓而什么不是。 你可以在此處詳細了解圖像分類。 在構建在線分類器的過程中,我們沒有數千個正面和負面類的例子。
讓我們看看不同的跟蹤算法如何解決在線訓練的這個問題。
BOOSTING跟蹤器
這個跟蹤器基于AdaBoost的在線版本——基于HAAR面部檢測器在內部使用的算法。需要在運行時使用目標的正面和負面示例訓練此分類器。由用戶(或另一個目標檢測算法)提供的初始邊界框被視為對象的正例,并且邊界框外的許多圖像塊被視為背景。 給定新幀,分類器在先前位置的鄰域中的每個像素上運行,并且記錄分類器的分數。 目標的新位置是得分最大的位置。 所以現在我們又有了一個分類器的正面例子。 隨著更多幀進入,分類器將使用此附加數據進行更新
優點:沒有。 這個算法已有十年歷史了,雖然工作正常,但我找不到使用它的好理由,特別是當其他基于類似原理的高級跟蹤器(MIL,KCF)可用時。
缺點:跟蹤性能平庸。且它無法可靠地知道跟蹤失敗的時間。
MIL跟蹤器
該跟蹤器在概念上類似于上述的BOOSTING跟蹤器。 最大的區別在于,不是僅考慮目標的當前位置作為正例,而是在當前位置周圍的小鄰域中查找以產生若干潛在的正例。 你可能認為這是一個壞主意,因為在大多數這些“積極”的例子中,目標不是居中的。這正是MIL拯救的地方。在MIL中,你沒有指定正面和負面的例子,而是正面和負面的“包”。 正面“包”中的圖像集合并非都是正面的例子。 相反,只有正面包中的一個圖像需要是一個正面的例子! 在我們的示例中,正面包包含以目標當前位置為中心的補丁,以及在其周圍的小鄰域中的補丁。 即使被跟蹤目標的當前位置不準確,當來自當前位置附近的樣本被放入正面包中時,該包很可能包含至少一個圖像,其中目標很好地居中。 MIL項目主頁為喜歡深入了解MIL跟蹤器內部工作原理的人提供了更多信息。
MIL項目主頁:http://vision.ucsd.edu/~bbabenko/new/project_miltrack.shtml
優點:表現非常好,它不會像BOOSTING跟蹤器那樣漂移,并且在部分遮擋下可以完成合理的工作,如果你使用的是OpenCV3.0,這可能是你可以使用的最佳跟蹤器。但是如果你是用的是更高版本,請考慮使用KCF。
缺點:不能可靠的報告跟蹤失敗,以及無法從完全遮擋中恢復。
KCF跟蹤器
KCF表示核相關濾波器,該跟蹤器基于前兩個跟蹤器中提出的想法,利用MIL跟蹤器中使用的多個正樣本具有大的重疊區域的事實,這種重疊的數據導致一些很好的數學屬性,這個跟蹤器利用這些屬性可以使跟蹤更快更準確。
優點:精度和速度都優于MIL,它報告跟蹤失敗比BOOSTING和MIL更好。 如果你使用的是OpenCV 3.1及更高版本,我建議你在大多數應用程序中使用它。
缺點:無法從完全遮擋中恢復。 未在OpenCV 3.0中實現。
BUG警告:OpenCV 3.1(僅限Python)中存在一個錯誤,因為返回了錯誤的邊界框。 查看錯誤報告。 感謝Andrei Cheremskoy指出這一點。
錯誤報告:https://github.com/opencv/opencv_contrib/issues/640
TLD跟蹤器
TLD代表tracking,learning和detection。顧名思義,該跟蹤器將長期跟蹤任務分解為三個部分——(短期)跟蹤,學習和檢測。作者的論文中指出,“跟蹤器在幀與幀之間跟蹤對象。檢測器定位到目前為止觀察到的所有外觀,并在必要時糾正跟蹤器。 學習估計檢測器的錯誤并更新它以避免將來出現這些錯誤?!斑@個跟蹤器的輸出往往會跳躍一下。 例如,如果你正在跟蹤行人并且場景中還有其他行人,則此跟蹤器有時可以臨時跟蹤與你要跟蹤的行人不同的行人。 從積極的方面來看,這個跟蹤器似乎可以在更大的大小,運動和遮擋上跟蹤物體。 如果你有一個視頻序列,其中目標隱藏在另一個目標后面,則此跟蹤器可能是一個不錯的選擇。
優點:在多個幀的遮擋下工作效果最佳。 此外,在目標大小變化時跟蹤效果最佳。
缺點:很多誤報使它幾乎無法使用。
MEDIANFLOW跟蹤器
在內部,該跟蹤器及時向前和向后跟蹤目標,并測量這兩個軌跡之間的差異。 最小化此前向后向錯誤使他們能夠可靠地檢測跟蹤失敗并選擇視頻序列中的可靠軌跡。
在我的測試中,我發現當動作可預測且很小時,這個跟蹤器效果最好。 與其他即使在跟蹤明顯失敗時繼續運行的跟蹤器不同,此跟蹤器也知道跟蹤失敗的時間。
優點:出色的跟蹤失敗報告。當運動可預測且沒有遮擋時,效果很好。
缺點:目標動作大時跟蹤失敗。
GOTURN跟蹤器
在跟蹤器類的所有跟蹤算法中,這是唯一基于卷積神經網絡(CNN)的跟蹤算法。 從OpenCV文檔中,我們知道它“對視點變化,光照變化和變形具有魯棒性”。 但它不能很好地處理遮擋。
注意:GOTURN是基于CNN的跟蹤器,使用caffe模型進行跟蹤。 Caffe模型和原始文本文件必須存在于代碼所在的目錄中。 這些文件也可以從opencv_extra存儲庫下載,在使用前連接并解壓縮。
MOSSE跟蹤器
誤差最小平方和濾波器(MOSSE)使用自適應相關進行目標跟蹤,當使用單個幀初始化時產生穩定的相關濾波器。 MOSSE跟蹤器對照明,比例,姿勢和非剛性變形的變化非常穩健。 它還根據峰值與旁瓣比率檢測遮擋,這使得跟蹤器能夠暫停并在對象重新出現時從中斷處繼續。 MOSSE跟蹤器也以更高的fps(450 fps甚至更高)運行。 為了增加積極性,它也很容易實現,與其他復雜的跟蹤器一樣準確,速度更快。 但是,在性能方面,它落后于基于深度學習的跟蹤器。
訂閱&下載代碼
如果你喜歡這篇文章并想下載此文章中使用的代碼(C++和Python)和示例圖片,請訂閱我的欄目。你還將收到免費的計算機視覺資源指南。在我們的欄目里,我們還分享了用C++/Python編寫的OpenCV教程和示例,以及計算機視覺和機器學習的算法和新聞。
訂閱欄目:https://bigvisionllc.leadpages.net/leadbox/143948b73f72a2%3A173c9390c346dc/5649050225344512/
?
?
?
?
?
?
?
?
?
?
?
?
?
轉載于:https://www.cnblogs.com/annie22wang/p/9366610.html
總結
以上是生活随笔為你收集整理的Object Tracking using OpenCV (C++/Python)(使用OpenCV进行目标跟踪)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tomcat和servlet的关系
- 下一篇: java 认证 种类_java认证:Ja