基于OpenCV4.2實現(xiàn)單目標跟蹤
在本教程中,我們將學(xué)習使用OpenCV跟蹤對象。OpenCV 3.0開始引入跟蹤API。我們將學(xué)習如何和何時使用OpenCV 4.2中可用的8種不同的跟蹤器- BOOSTING, MIL, KCF, TLD, MEDIANFLOW, GOTURN, MOSSE和CSRT。我們還將學(xué)習現(xiàn)代跟蹤算法背后的一般理論。
1.什么是目標跟蹤
簡單地說,在視頻的連續(xù)幀中定位一個對象稱為跟蹤。
這個定義聽起來很簡單,但在計算機視覺和機器學(xué)習中,跟蹤是一個非常廣泛的術(shù)語,它包含了概念相似但技術(shù)不同的想法。例如,以下所有不同但相關(guān)的思想通常都是在對象跟蹤中研究的
1.Dense Optical flow(稠密光流):這些算法有助于估計視頻幀中每個像素的運動矢量。
2.Sparse optical flow(稀疏光流):這些算法,如Kanade-Lucas-Tomashi (KLT)特征跟蹤器,跟蹤圖像中幾個特征點的位置。
3.Kalman Filtering(卡爾曼濾波):一種非常流行的信號處理算法,用于基于先驗運動信息預(yù)測運動目標的位置。該算法的早期應(yīng)用之一是導(dǎo)彈制導(dǎo)!
4.Meanshift and Camshift:這些是定位密度函數(shù)最大值的算法。它們也被用于跟蹤。
5.Single object trackers(單一對象追蹤器):在這類跟蹤器中,第一幀使用一個矩形來標記我們想要跟蹤的對象的位置。然后使用跟蹤算法在隨后的幀中跟蹤目標。在大多數(shù)現(xiàn)實生活中的應(yīng)用程序中,這些跟蹤器是與對象檢測器結(jié)合使用的。
6.Multiple object track finding algorithms(多目標追蹤算法):在我們有快速目標檢測器的情況下,在每幀中檢測多個目標,然后運行軌跡查找算法來識別一幀中的哪個矩形對應(yīng)于下一幀中的矩形是有意義的。
2.跟蹤與檢測
如果你曾經(jīng)玩過OpenCV人臉檢測,你知道它是實時工作的,你可以很容易地在每一幀中檢測人臉。那么,為什么一開始就需要跟蹤呢?讓我們來探討一下你可能想要在視頻中跟蹤對象而不僅僅是重復(fù)檢測的不同原因。
1.跟蹤比檢測快:通常跟蹤算法要比檢測算法快。原因很簡單。當您在跟蹤前一幀中檢測到的對象時,您會對該對象的外觀有很多了解。你也知道在前一個坐標系中的位置以及它運動的方向和速度。所以在下一幀中,你可以利用所有這些信息來預(yù)測下一幀中物體的位置,并對物體的預(yù)期位置做一個小搜索來精確地定位物體。一個好的跟蹤算法會使用它所擁有的關(guān)于目標的所有信息,而檢測算法總是從頭開始。因此,在設(shè)計一個高效的系統(tǒng)時,通常在每n幀上進行目標檢測,在n-1幀之間使用跟蹤算法。為什么我們不直接在第一幀檢測目標,然后跟蹤它呢?跟蹤確實可以從它所擁有的額外信息中獲益,但如果一個物體在障礙物后面停留了很長一段時間,或者它移動得太快,以至于跟蹤算法無法跟上,你也會失去對它的跟蹤。跟蹤算法也經(jīng)常會累積誤差,跟蹤對象的包圍框會慢慢地偏離跟蹤對象。我們會經(jīng)常使用檢測算法解決跟蹤算法的這些問題。檢測算法基于大數(shù)據(jù)訓(xùn)練,因此,他們對對象的一般類別有更多的了解。另一方面,跟蹤算法更了解它們所跟蹤的類的具體實例。
2.當檢測失敗時,跟蹤可以提供幫助:如果你在視頻中運行人臉檢測器,而這個人的臉被物體遮擋,人臉檢測器很可能會失敗。一個好的跟蹤算法將解決某種程度的遮擋。
3.跟蹤保護身份ID:對象檢測的輸出是一個包含對象的矩形數(shù)組。但是,該對象沒有附加身份。例如,在下面的視頻中,一個檢測紅點的探測器將輸出與它在一幀中檢測到的所有點相對應(yīng)的矩形。在下一幀中,它將輸出另一個矩形數(shù)組。在第一幀中,一個特定的點可能由數(shù)組中位置10的矩形表示,而在第二幀中,它可能位于位置17。當在幀上使用檢測時,我們不知道哪個矩形對應(yīng)哪個對象。另一方面,追蹤提供了一種將這些點連接起來的方法!
3.使用OpenCV 4實現(xiàn)對象跟蹤
OpenCV 4附帶了一個跟蹤API,它包含了許多單對象跟蹤算法的實現(xiàn)。在OpenCV 4.2中有8種不同的跟蹤器可用- BOOSTING, MIL, KCF, TLD, MEDIANFLOW, GOTURN, MOSSE,和CSRT。
注意: OpenCV 3.2實現(xiàn)了這6個跟蹤器- BOOSTING, MIL, TLD, MEDIANFLOW, MOSSE和GOTURN。OpenCV 3.1實現(xiàn)了這5個跟蹤器- BOOSTING, MIL, KCF, TLD, MEDIANFLOW。OpenCV 3.0實現(xiàn)了以下4個跟蹤器- BOOSTING, MIL, TLD, MEDIANFLOW。
在OpenCV 3.3中,跟蹤API已經(jīng)改變。代碼檢查版本,然后使用相應(yīng)的API。
在簡要描述這些算法之前,讓我們先看看它們的設(shè)置和使用方法。在下面的注釋代碼中,我們首先通過選擇跟蹤器類型來設(shè)置跟蹤器——BOOSTING、MIL、KCF、TLD、MEDIANFLOW、GOTURN、MOSSE或CSRT。然后我們打開一段視頻,抓取一幀。我們定義了一個包含第一幀對象的邊界框,并用第一幀和邊界框初始化跟蹤器。最后,我們從視頻中讀取幀,并在循環(huán)中更新跟蹤器,以獲得當前幀的新包圍框。隨后顯示結(jié)果。
3.1使用OpenCV 4實現(xiàn)對象跟蹤 C++代碼
#include <opencv2/opencv.hpp>
#include <opencv2/tracking.hpp>
#include <opencv2/core/ocl.hpp>
using namespace cv;
using namespace std;
// 轉(zhuǎn)換為字符串
#define SSTR( x ) static_cast< std::ostringstream & >( ( std::ostringstream() << std::dec << x ) ).str()
int main(int argc, char **argv)
{
// OpenCV 3.4.1中的跟蹤器類型列表
string trackerTypes[8] = {"BOOSTING", "MIL", "KCF", "TLD","MEDIANFLOW", "GOTURN", "MOSSE", "CSRT"};
// vector <string> trackerTypes(types, std::end(types));
// 創(chuàng)建一個跟蹤器
string 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();
if (trackerType == "CSRT")
tracker = TrackerCSRT::create();
}
#endif
// 讀取視頻
VideoCapture video("videos/chaplin.mp4");
// 如果視頻沒有打開,退出
if(!video.isOpened())
{
cout << "Could not read video file" << endl;
return 1;
}
// 讀第一幀
Mat frame;
bool ok = video.read(frame);
// 定義初始邊界框
Rect2d bbox(287, 23, 86, 320);
// 取消注釋下面的行以選擇一個不同的邊界框
// bbox = selectROI(frame, false);
// 顯示邊界框
rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );
imshow("Tracking", frame);
tracker->init(frame, bbox);
while(video.read(frame))
{
// 啟動定時器
double timer = (double)getTickCount();
// 更新跟蹤結(jié)果
bool ok = tracker->update(frame, bbox);
// 計算每秒幀數(shù)(FPS)
float fps = getTickFrequency() / ((double)getTickCount() - timer);
if (ok)
{
// 跟蹤成功:繪制被跟蹤對象
rectangle(frame, bbox, Scalar( 255, 0, 0 ), 2, 1 );
}
else
{
// 跟蹤失敗
putText(frame, "Tracking failure detected", Point(100,80), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0,0,255),2);
}
// 在幀上顯示跟蹤器類型
putText(frame, trackerType + " Tracker", Point(100,20), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50),2);
// 幀顯示FPS
putText(frame, "FPS : " + SSTR(int(fps)), Point(100,50), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(50,170,50), 2);
// 顯示幀
imshow("Tracking", frame);
// 按ESC鍵退出。
int k = waitKey(1);
if(k == 27)
{
break;
}
}
}
3.2使用OpenCV 4實現(xiàn)對象跟蹤 Python代碼
import cv2
import sys
(major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')?
if __name__ == '__main__' :
# 建立追蹤器
# 除了MIL之外,您還可以使用
tracker_types = ['BOOSTING', 'MIL','KCF', 'TLD', 'MEDIANFLOW', 'GOTURN', 'MOSSE', 'CSRT']
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()
if tracker_type == "CSRT":
tracker = cv2.TrackerCSRT_create()
# 讀取視頻
video = cv2.VideoCapture("videos/chaplin.mp4")
# 如果視頻沒有打開,退出。
if not video.isOpened():
print "Could not open video"
sys.exit()
# 讀第一幀。
ok, frame = video.read()
if not ok:
print('Cannot read video file')
sys.exit()
# 定義一個初始邊界框
bbox = (287, 23, 86, 320)
# 取消注釋下面的行以選擇一個不同的邊界框
# bbox = cv2.selectROI(frame, False)
# 用第一幀和包圍框初始化跟蹤器
ok = tracker.init(frame, bbox)
while True:
# 讀取一個新的幀
ok, frame = video.read()
if not ok:
break
# 啟動計時器
timer = cv2.getTickCount()
# 更新跟蹤器
ok, bbox = tracker.update(frame)
# 計算幀率(FPS)
fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);
# 繪制包圍框
if ok:
# 跟蹤成功
p1 = (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 :
# 跟蹤失敗
cv2.putText(frame, "Tracking failure detected", (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2)
# 在幀上顯示跟蹤器類型名字
cv2.putText(frame, tracker_type + " Tracker", (100,20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50),2);
# 在幀上顯示幀率FPS
cv2.putText(frame, "FPS : " + str(int(fps)), (100,50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50,170,50), 2);
# 顯示結(jié)果
cv2.imshow("Tracking", frame)
# 按ESC鍵退出
k = cv2.waitKey(1) & 0xff
if k == 27 : break
4.跟蹤算法解析
在本節(jié)中,我們將深入研究不同的跟蹤算法。我們的目標不是對每一個跟蹤器都有一個深刻的理論理解,而是從實際的角度來理解它們。
讓我首先解釋一些跟蹤的一般原則。在跟蹤中,我們的目標是在當前幀中找到一個對象,因為我們已經(jīng)成功地在所有(或幾乎所有)之前的幀中跟蹤了這個對象。
因為我們一直跟蹤對象直到當前幀,所以我們知道它是如何移動的。換句話說,我們知道運動模型的參數(shù)。運動模型只是一種花哨的說法,表示你知道物體在前幾幀中的位置和速度(速度+運動方向)。如果你對物體一無所知,你可以根據(jù)當前的運動模型預(yù)測新的位置,你會非常接近物體的新位置。
但我們有比物體運動更多的信息。我們知道物體在之前的每一幀中的樣子。換句話說,我們可以構(gòu)建一個對對象的外觀進行編碼的外觀模型。該外觀模型可用于在運動模型預(yù)測的小鄰域內(nèi)搜索位置,從而更準確地預(yù)測物體的位置。
運動模型預(yù)測了物體的大致位置。外觀模型對這個估計進行微調(diào),以提供基于外觀的更準確的估計。
如果對象非常簡單,并且沒有太多改變它的外觀,我們可以使用一個簡單的模板作為外觀模型,并尋找該模板。然而,現(xiàn)實生活并沒有那么簡單。物體的外觀會發(fā)生巨大的變化。為了解決這個問題,在許多現(xiàn)代跟蹤器中,這個外觀模型是一個以在線方式訓(xùn)練的分類器。別慌!讓我用更簡單的術(shù)語解釋一下。
分類器的工作是將圖像中的矩形區(qū)域分類為物體或背景。分類器接收圖像patch作為輸入,并返回0到1之間的分數(shù),表示圖像patch包含該對象的概率。當完全確定圖像patch是背景時,分數(shù)為0;當完全確定patch是對象時,分數(shù)為1。
在機器學(xué)習中,我們用“在線”這個詞來指在運行時進行動態(tài)訓(xùn)練的算法。離線分類器可能需要數(shù)千個示例來訓(xùn)練一個分類器,但在線分類器通常在運行時使用很少的示例進行訓(xùn)練。
通過向分類器輸入正(對象)和負(背景)的例子來訓(xùn)練分類器。如果您想要構(gòu)建一個用于檢測貓的分類器,您可以使用數(shù)千張包含貓的圖像和數(shù)千張不包含貓的圖像來訓(xùn)練它。這樣分類器學(xué)會區(qū)分什么是貓,什么不是。在構(gòu)建一個在線分類器時,我們沒有機會擁有數(shù)千個正面和負面類的例子。
讓我們看看不同的跟蹤算法是如何處理在線訓(xùn)練的這個問題的。
4.1 BOOSTING Tracker
該跟蹤器基于AdaBoost的在線版本——基于HAAR級聯(lián)的人臉檢測器內(nèi)部使用的算法。這個分類器需要在運行時用對象的正面和反面例子進行訓(xùn)練。將用戶提供的初始包圍盒(或其他目標檢測算法提供的初始包圍盒)作為目標的正例,將包圍盒外的許多圖像patch作為背景。
給定一個新的幀,分類器在前一個位置附近的每個像素上運行,并記錄分類器的得分。對象的新位置是分數(shù)最高的位置。現(xiàn)在分類器又多了一個正樣本。當更多的幀進來時,分類器就會用這些額外的數(shù)據(jù)更新。
優(yōu)點:沒有。 這個算法已經(jīng)有10年的歷史了,而且運行良好,但我找不到使用它的好理由,特別是當基于類似原則的其他高級跟蹤器(MIL, KCF)可用時。
缺點:跟蹤性能平庸。 它不能可靠地知道何時跟蹤失敗了。
4.2 MIL Tracker
這個跟蹤器在思想上與上述的BOOSTING跟蹤器相似。最大的區(qū)別是,它不是只考慮對象的當前位置作為一個正樣本,而是在當前位置周圍的一個小領(lǐng)域中尋找?guī)讉€潛在的正樣本。你可能會認為這不是一個好主意,因為在大多數(shù)這些“正樣本”的例子中,物體不是居中的。
這就是多實例學(xué)習 (MIL) 的用武之地。在 MIL 中,您不指定正面和負面示例,而是指定正面和負面“袋子”。正面“袋子”中的圖像集合并不都是正例。取而代之的是,正面袋子中只有一張圖像需要是正面的例子!
在我們的示例中,一個正面袋子包含以對象當前位置為中心的patch,以及它周圍的一個小鄰域中的patch。即使被跟蹤對象的當前位置不準確,當來自當前位置附近的樣本被放入正面袋子中時,這個正面袋子很有可能包含至少一個對象很好地居中的圖像。
優(yōu)點:性能很好。 它不像BOOSTING跟蹤器那樣漂移,并且在部分遮擋下做了合理的工作。如果你正在使用OpenCV 3.0,這可能是你可用的最好的跟蹤器。但是,如果您使用的是更高的版本,請考慮KCF。
缺點: 無法可靠地報告跟蹤失敗。不能從完全遮擋中恢復(fù)。
4.3 KCF Tracker
KFC 代表Kernelized Correlation Filters(Kernelized相關(guān)性過濾器)。該跟蹤器建立在前兩個跟蹤器中提出的想法之上。該跟蹤器利用了 MIL 跟蹤器中使用的多個正樣本具有較大重疊區(qū)域的事實。這種重疊數(shù)據(jù)導(dǎo)致了一些很好的數(shù)學(xué)特性,該跟蹤器利用這些特性使跟蹤更快、更準確。
優(yōu)點:準確性和速度都優(yōu)于 MIL,它報告的跟蹤失敗比 BOOSTING 和 MIL 更好。 如果您使用的是 OpenCV 3.1 及更高版本,我建議將其用于大多數(shù)應(yīng)用程序。
缺點: 不能從完全遮擋中恢復(fù)。
4.4 TLD Tracker
TLD 代表跟蹤、學(xué)習和檢測。顧名思義,這個跟蹤器將長期跟蹤任務(wù)分解為三個部分——(短期)跟蹤、學(xué)習和檢測。從作者的論文中,“跟蹤器逐幀跟蹤對象。檢測器定位到目前為止已觀察到的所有外觀,并在必要時糾正跟蹤器。
學(xué)習估計檢測器的錯誤并對其進行更新以避免將來出現(xiàn)這些錯誤。”這個跟蹤器的輸出往往會有點跳躍。例如,如果您正在跟蹤行人并且場景中有其他行人,則此跟蹤器有時可以臨時跟蹤與您打算跟蹤的行人不同的行人。從積極的方面來說,這條軌跡似乎可以在更大的范圍、運動和遮擋范圍內(nèi)跟蹤對象。如果您有一個對象隱藏在另一個對象后面的視頻序列,則此跟蹤器可能是一個不錯的選擇。
優(yōu)點:在多個幀的遮擋下效果最佳。此外,跟蹤最好的規(guī)模變化。
缺點:大量的誤報使得它幾乎無法使用。
4.5 MEDIANFLOW Tracker
在內(nèi)部,該跟蹤器在時間上向前和向后跟蹤對象,并測量這兩個軌跡之間的差異。最小化這種 ForwardBackward 誤差使他們能夠可靠地檢測跟蹤失敗并在視頻序列中選擇可靠的軌跡。
在我的測試中,我發(fā)現(xiàn)該跟蹤器在運動可預(yù)測且較小時效果最佳。與其他跟蹤器即使在跟蹤明顯失敗時仍繼續(xù)運行不同,該跟蹤器知道跟蹤何時失敗。
優(yōu)點:出色的跟蹤失敗報告。當運動是可預(yù)測的并且沒有遮擋時效果很好。
缺點:在大運動下失敗。
4.6 GOTURN tracker
在跟蹤器類的所有跟蹤算法中,這是唯一一種基于卷積神經(jīng)網(wǎng)絡(luò) (CNN) 的算法。從 OpenCV 文檔中,我們知道它“對視點變化、光照變化和變形具有魯棒性”。但它不能很好地處理遮擋。
注意:GOTURN 是基于 CNN 的跟蹤器,使用 Caffe 模型進行跟蹤。 Caffe 模型和 proto 文本文件必須存在于代碼所在的目錄中。這些文件也可以從 opencv_extra 存儲庫下載、連接并在使用前提取。
4.7 MOSSE tracker
最小輸出平方誤差和 (MOSSE) 使用自適應(yīng)相關(guān)性進行對象跟蹤,在使用單幀初始化時會產(chǎn)生穩(wěn)定的相關(guān)性濾波器。 MOSSE 跟蹤器對光照、比例、姿勢和非剛性變形的變化具有魯棒性。它還根據(jù)峰值旁瓣(peak-to-sidelobe)比檢測遮擋,這使跟蹤器能夠在對象重新出現(xiàn)時暫停并從中斷的地方恢復(fù)。 MOSSE 跟蹤器還以更高的 fps(450 fps 甚至更高)運行。除此之外,它還非常容易執(zhí)行,與其他復(fù)雜追蹤器一樣準確,而且速度更快。但是,在性能尺度上,它落后于基于深度學(xué)習的跟蹤器。
4.8 CSRT tracker
在DCF-CSR (Discriminative Correlation Filter with Channel and Spatial Reliability, DCF-CSR)中,我們使用空間可靠性映射來調(diào)整濾波器的支持度,使其適應(yīng)幀中被選擇區(qū)域的跟蹤部分。這確保了所選區(qū)域的放大和定位,并改進了對非矩形區(qū)域或?qū)ο蟮母?。它只使?個標準特性(hog和Colornames)。它也運行在一個相對較低的fps (25 fps),但提供了較高的目標跟蹤精度。
到此這篇關(guān)于基于OpenCV4.2實現(xiàn)單目標跟蹤的文章就介紹到這了,更多相關(guān)OpenCV單目標跟蹤內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python+selenium+chrome實現(xiàn)淘寶購物車秒殺自動結(jié)算
這篇文章主要介紹了python+selenium+chrome實現(xiàn)淘寶購物車秒殺自動結(jié)算,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2021-01-01
Python實現(xiàn)列表轉(zhuǎn)換成字典數(shù)據(jù)結(jié)構(gòu)的方法
這篇文章主要介紹了Python實現(xiàn)列表轉(zhuǎn)換成字典數(shù)據(jù)結(jié)構(gòu)的方法,結(jié)合實例形式分析了Python數(shù)值類型轉(zhuǎn)換的相關(guān)技巧,需要的朋友可以參考下2016-03-03

