利用OpenCV進(jìn)行對(duì)象跟蹤的示例代碼
OpenCV 對(duì)象跟蹤
這篇文章使用 OpenCV 中內(nèi)置的八種不同的對(duì)象跟蹤算法,實(shí)現(xiàn)對(duì)物體的跟蹤。
首先,介紹一下8種跟蹤算法。
然后,演示如何使用OpenCV實(shí)現(xiàn)這些跟蹤算法。
最后,對(duì)本文做總結(jié)。
OpenCV 對(duì)象跟蹤器
OpenCV 八種對(duì)象跟蹤器:
BOOSTING Tracker:基于用于驅(qū)動(dòng) Haar 級(jí)聯(lián) (AdaBoost) 背后的機(jī)器學(xué)習(xí)的相同算法,但與 Haar 級(jí)聯(lián)一樣,已有十多年的歷史。這個(gè)跟蹤器很慢,而且效果不太好。僅出于遺留原因和比較其他算法而感興趣。 (最低 OpenCV 3.0.0)
MIL Tracker:比 BOOSTING 跟蹤器更準(zhǔn)確,但在報(bào)告失敗方面做得很差。 (最低 OpenCV 3.0.0)
KCF 跟蹤器:內(nèi)核化相關(guān)過濾器。比 BOOSTING 和 MIL 更快。與 MIL 和 KCF 類似,不能很好地處理完全遮擋。 (最低 OpenCV 3.1.0)
CSRT Tracker:判別相關(guān)濾波器(具有通道和空間可靠性)。往往比 KCF 更準(zhǔn)確,但速度稍慢。 (最低 OpenCV 3.4.2)
MedianFlow Tracker:很好地報(bào)告失?。坏?,如果運(yùn)動(dòng)中的跳躍太大,例如快速移動(dòng)的物體,或者外觀快速變化的物體,模型就會(huì)失敗。 (最低 OpenCV 3.0.0)
TLD 跟蹤器:我不確定 TLD 跟蹤器的 OpenCV 實(shí)現(xiàn)或?qū)嶋H算法本身是否存在問題,但 TLD 跟蹤器極易出現(xiàn)誤報(bào)。我不推薦使用這個(gè) OpenCV 對(duì)象跟蹤器。 (最低 OpenCV 3.0.0)
MOSSE Tracker:非常非???。不如 CSRT 或 KCF 準(zhǔn)確,但如果您需要純粹的速度,這是一個(gè)不錯(cuò)的選擇。 (最低 OpenCV 3.4.1)
GOTURN Tracker:OpenCV 中唯一基于深度學(xué)習(xí)的目標(biāo)檢測(cè)器。它需要額外的模型文件才能運(yùn)行(本文不會(huì)涉及)。我最初的實(shí)驗(yàn)表明,盡管據(jù)說它可以很好地處理查看變化,但使用起來還是有點(diǎn)痛苦(盡管我最初的實(shí)驗(yàn)并沒有證實(shí)這一點(diǎn))。我將嘗試在以后的帖子中介紹它,但與此同時(shí),請(qǐng)看一下 Satya 的文章。 (最低 OpenCV 3.2.0)
個(gè)人建議:
- 當(dāng)需要更高的對(duì)象跟蹤精度并且可以容忍較慢的 FPS 吞吐量時(shí),請(qǐng)使用 CSRT
- 當(dāng)需要更快的 FPS 吞吐量但可以處理稍低的對(duì)象跟蹤精度時(shí)使用 KCF
- 當(dāng)需要純粹的速度時(shí)使用 MOSSE
物體跟蹤
在開始算法之前,先寫輔助方法和類。
fps類:
import datetime class FPS: ?? ?def __init__(self): ?? ??? ?# 定義開始時(shí)間、結(jié)束時(shí)間和總幀數(shù) ?? ??? ?self._start = None ?? ??? ?self._end = None ?? ??? ?self._numFrames = 0 ?? ?def start(self): ?? ??? ?# 開始計(jì)時(shí) ?? ??? ?self._start = datetime.datetime.now() ?? ??? ?return self ?? ?def stop(self): ?? ??? ?# 停止計(jì)時(shí) ?? ??? ?self._end = datetime.datetime.now() ?? ?def update(self): ?? ??? ?# 增加在開始和結(jié)束間隔期間檢查的總幀數(shù) ?? ??? ?self._numFrames += 1 ?? ?def elapsed(self): ?? ??? ?# 返回開始和結(jié)束間隔之間的總秒數(shù) ?? ??? ?return (self._end - self._start).total_seconds() ?? ?def fps(self): ?? ??? ?# 計(jì)算每秒幀數(shù) ?? ??? ?return self._numFrames / self.elapsed()
請(qǐng)打開一個(gè)新文件,將其命名為 object_tracker.py ,定義resize方法,等比例縮放圖片。
import cv2 from fps import FPS def resize(image, width=None, height=None, inter=cv2.INTER_AREA): # 初始化要調(diào)整大小的圖像的尺寸并抓取圖像大小 dim = None (h, w) = image.shape[:2] # 如果寬高都為None,則返回原圖 if width is None and height is None: return image # 檢查寬度是否為None if width is None: # 計(jì)算高度的比例并構(gòu)造尺寸 r = height / float(h) dim = (int(w * r), height) # 否則,高度為 None else: # 計(jì)算寬度的比例并構(gòu)造尺寸 r = width / float(w) dim = (width, int(h * r)) resized = cv2.resize(image, dim, interpolation=inter) return resized
定義全局變量:
videos = 0 tracker_type = 'kcf'
我們的命令行參數(shù)包括:
videos:輸入視頻文件或者攝像頭的ID。
tracker_type:跟蹤器的類型,接下來的代碼定義了跟蹤器列表。
接下來定義不同類型的跟蹤器:
# 提取 OpenCV 版本信息 (major, minor) = cv2.__version__.split(".")[:2] # 如果我們使用 OpenCV 3.2 或之前版本,我們可以使用特殊的工廠函數(shù)來創(chuàng)建我們的對(duì)象跟蹤器 if int(major) == 3 and int(minor) < 3: tracker = cv2.Tracker_create(tracker_type) # 否則,對(duì)于 OpenCV 3.3 或更新版本,我們需要顯式調(diào)用對(duì)應(yīng)的對(duì)象跟蹤器構(gòu)造函數(shù): else: # 初始化一個(gè)字典,將字符串映射到其對(duì)應(yīng)的 OpenCV 對(duì)象跟蹤器實(shí)現(xiàn) OPENCV_OBJECT_TRACKERS = { "csrt": cv2.TrackerCSRT_create, "kcf": cv2.TrackerKCF_create, "boosting": cv2.legacy.TrackerBoosting_create, "mil": cv2.TrackerMIL_create, "tld": cv2.legacy.TrackerTLD_create, "medianflow": cv2.legacy.TrackerMedianFlow_create, "mosse": cv2.legacy.TrackerMOSSE_create } # 使用我們的 OpenCV 對(duì)象跟蹤器對(duì)象字典獲取適當(dāng)?shù)膶?duì)象跟蹤器 tracker = OPENCV_OBJECT_TRACKERS[tracker_type]()
在OpenCV 3.3之前,必須使用cv2.Tracker_create創(chuàng)建跟蹤器對(duì)象,并傳遞跟蹤器名稱的大寫字符串。
對(duì)于OpenCV 3.3+,可以使用各自的函數(shù)調(diào)用創(chuàng)建每個(gè)跟蹤器,例如cv2.TrackerCSRT_create。字典OPENCV_OBJECT_TRACKERS包含8個(gè)內(nèi)置OpenCV對(duì)象跟蹤器中的七個(gè)。它將對(duì)象跟蹤器命令行參數(shù)字符串(鍵)與實(shí)際的OpenCV對(duì)象跟蹤器函數(shù)(值)進(jìn)行映射。
# 初始化我們要追蹤的物體的邊界框坐標(biāo) initBB = None vs = cv2.VideoCapture(videos) fps = None
initBB初始化為None,此變量將保存我們使用鼠標(biāo)選擇的對(duì)象的邊界框坐標(biāo)。
接下來,初始化VideoCapture對(duì)象和FPS計(jì)數(shù)器。
讓我們開始循環(huán)來自視頻流的幀:
# 循環(huán)播放視頻流中的幀 while True: # 抓取當(dāng)前幀。 (grabbed, frame) = vs.read() if not grabbed: break # 調(diào)整框架大小并獲取框架尺寸。 frame = resize(frame, width=500) (H, W) = frame.shape[:2] # 檢查是否正在跟蹤一個(gè)對(duì)象 if initBB is not None: # 抓取物體的新邊界框坐標(biāo) (success, box) = tracker.update(frame) # 檢查跟蹤是否成功 if success: (x, y, w, h) = [int(v) for v in box] cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) # 更新 FPS 計(jì)數(shù)器 fps.update() fps.stop() # 初始化在框架上顯示的信息集 info = [ ("Tracker", tracker_type), ("Success", "Yes" if success else "No"), ("FPS", "{:.2f}".format(fps.fps())), ] # 遍歷信息元組并將它們繪制在框架上 for (i, (k, v)) in enumerate(info): text = "{}: {}".format(k, v) cv2.putText(frame, text, (10, H - ((i * 20) + 20)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) # 顯示輸出幀 cv2.imshow("Frame", frame) key = cv2.waitKey(1) & 0xFF
抓住一個(gè)幀,如果獲取不到幀,則退出。
為了使對(duì)象跟蹤算法能夠更快地處理幀,我們將輸入幀的大小調(diào)整為500像素。
然后輸出框架的高和寬。
如果已選擇對(duì)象,則需要更新對(duì)象的位置。 update方法將定位對(duì)象的新位置并返回成功布爾值和對(duì)象的邊界框。
如果成功,我們?cè)诳蚣苌侠L制新的,更新的邊界框位置。
更新FPS。
初始化顯示的文本信息列表。隨后,繪制到frame上。
顯示輸出幀。
# 使用's'鍵選擇一個(gè)邊界框來跟蹤 if key == ord("s"): # 選擇跟蹤的對(duì)象的邊界框(選擇 ROI 后按 ENTER 或 SPACE) initBB = cv2.selectROI("Frame", frame, fromCenter=False, showCrosshair=True) # 使用提供的邊界框坐標(biāo)啟動(dòng) OpenCV 對(duì)象跟蹤器,然后也啟動(dòng) FPS 吞吐量估計(jì)器 tracker.init(frame, initBB) fps = FPS().start() # 如果 `q` 鍵被按下,則退出循環(huán) elif key == ord("q"): break vs.release() cv2.destroyAllWindows()
按下“s”鍵時(shí),使用cv2.selectROI“選擇”對(duì)象ROI。此時(shí),視頻幀凍結(jié),用鼠標(biāo)繪制跟蹤對(duì)象的邊界框。
繪制完邊界框,然后按“ENTER”或“SPACE”確認(rèn)選擇。如果需要重新選擇區(qū)域,只需按“ESCAPE”即可。
然后,啟動(dòng)OpenCV 對(duì)象跟蹤器,再啟動(dòng) FPS 吞吐量估計(jì)器。
最后一個(gè)段代碼只是處理我們已經(jīng)脫離循環(huán)的情況。釋放所有指針并關(guān)閉窗口。
總結(jié)
在今天的博客文章中,您學(xué)習(xí)了如何利用OpenCV進(jìn)行對(duì)象跟蹤。具體來說,我們回顧了OpenCV庫(kù)中包含的8個(gè)對(duì)象跟蹤算法(從OpenCV 3.4開始):
CSRT、KCF、Boosting、MIL、TLD、MedianFlow、MOSSE、GOTURN。
建議對(duì)大多數(shù)對(duì)象跟蹤應(yīng)用程序使用CSRT,KCF或MOSSE:
當(dāng)需要更高的對(duì)象跟蹤精度并且可以容忍更慢的FPS吞吐量時(shí),請(qǐng)使用CSRT
當(dāng)需要更快的FPS吞吐量時(shí)使用KCF,但可以處理稍低的對(duì)象跟蹤精度
當(dāng)需要純粹的速度時(shí)使用MOSSE
到此這篇關(guān)于利用OpenCV進(jìn)行對(duì)象跟蹤的示例代碼的文章就介紹到這了,更多相關(guān)OpenCV對(duì)象跟蹤內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python工程師面試題 與Python基礎(chǔ)語(yǔ)法相關(guān)
這篇文章主要為大家分享了Python工程師面試題,面試題的內(nèi)容主要與Python基礎(chǔ)語(yǔ)法相關(guān),感興趣的小伙伴們可以參考一下2016-01-01只需要100行Python代碼就可以實(shí)現(xiàn)的貪吃蛇小游戲
貪吃蛇小游戲相信80、90后小時(shí)候肯定都玩過,那么你知道如果通過Python來實(shí)現(xiàn)嗎?今天就來教大家,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)python的小伙伴們很有幫助,需要的朋友可以參考下2021-05-05Python二叉搜索樹與雙向鏈表轉(zhuǎn)換實(shí)現(xiàn)方法
這篇文章主要介紹了Python二叉搜索樹與雙向鏈表轉(zhuǎn)換實(shí)現(xiàn)方法,涉及Python二叉搜索樹的定義、實(shí)現(xiàn)以及雙向鏈表的轉(zhuǎn)換技巧,需要的朋友可以參考下2016-04-04python如何解析配置文件并應(yīng)用到項(xiàng)目中
這篇文章主要介紹了python如何解析配置文件并應(yīng)用到項(xiàng)目中,如果我們更換了電腦也可以繼續(xù)使用原來的文件,只要把里面的數(shù)據(jù)拷貝到游戲執(zhí)行的配置文件里面就可以了,我們重新再進(jìn)入就不用重新設(shè)置內(nèi)掛的配置了,需要的朋友可以參考下2019-06-06OpenCV圖像識(shí)別之相機(jī)校準(zhǔn)Camera?Calibration學(xué)習(xí)
這篇文章主要為大家介紹了OpenCV圖像識(shí)別之相機(jī)校準(zhǔn)Camera?Calibration學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05