基于python的移动物体检测_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)...
感興趣區(qū)域、特定區(qū)域、框出移動物體的輪廓、越界檢測、入侵物體檢測、使用 opencv-python庫的函數(shù)cv2.findContours、cv2.approxPolyDP、cv2.arcLength,利用固定攝像頭拍攝的實時視頻,框出移動物體的輪廓(即FrogEyes蛙眼移動物體偵測)
對移動目標的輪廓的框選,將使用下面這篇文章提及的方法:曾伊言:邊緣檢測,框出物體的輪廓(使用opencv-python的函數(shù)cv2.findContours() )?zhuanlan.zhihu.com
移動物體框選結(jié)果預(yù)覽(即便鏡頭被移動了,它也能夠自己調(diào)整回來,方法后面會講):https://www.zhihu.com/video/997056905654755328
核心代碼預(yù)覽(可以先看看我用到了哪些函數(shù),完整版代碼(點擊查看)已上傳到github):
...
# 差值提取的核心代碼
dif = np.abs(dif - img_back)
gray = cv2.cvtColor(dif, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, self.min_thresh, 255, 0) # 對差值取閾值,和激活函數(shù)Relu有點像
thresh = cv2.blur(thresh, (self.thresh_blur, self.thresh_blur)) # 模糊的這個操作是很重要的
...
...
# 計算得出輪廓的核心代碼
thresh, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
...
approxs = [cv2.approxPolyDP(cnt, self.min_side_len, True) for cnt in contours]
approxs = [approx for approx in approxs
if len(approx) > self.min_side_num and cv2.arcLength(approx, True) > self.min_poly_len]
contours = approxs
...2018-06-30 初版 Yonv1943
2018-07-02 對RrawROI的注釋方案,即對region_of_interest_pts 的賦值
傳言青蛙蹲在地上不動的時候,將死掉不動的小昆蟲擺放在它的眼前,青蛙也無動于衷。而當(dāng)某些小昆蟲在青蛙眼前飛來飛去的時候,青蛙會注意到它們,然后將它們吃了。我這個程序也可“注意到”鏡頭拍攝到的移動物體,因此我也將它稱為 FrogEyes。
這是傳統(tǒng)的圖像處理(不涉及深度學(xué)習(xí)),所以算法的本質(zhì)是:對固定攝像頭前后兩幀圖片做差值,得到并框出不同的區(qū)域(使用opencv-python 的 cv2.findContours()函數(shù))
因此,該方法只適用于固定鏡頭的移動物體識別,如果拍攝實時圖像的時候鏡頭是移動的,那么此時移動物體的識別就只能交由深度學(xué)習(xí)去解決了。
不能簡單地對比前后兩幀的圖片如果簡單地對比前后兩幀圖片,那么對圖片做差值,將會得到前后幀圖片中不同的區(qū)域,這個區(qū)域并不是目標的輪廓
如果目標是純色的,那么對圖片做差值得到的結(jié)果,將不能得到目標的完整輪廓左邊是背景圖片,右邊是實時圖片
若將實時圖片與背景圖片做差值,那么將會得到紅色區(qū)域
若將實時圖片與先前圖片做差值,那么將會得到黃色區(qū)域
實際情況中,當(dāng)圖片幀率比較高,目標移動速度慢(甚至不移動),由前后兩幀圖片做對比的算法的黃色區(qū)域會非常小。當(dāng)然可以通過對比更久前的圖片(兩幀差別更大)來得到更大的不同區(qū)域,不過,這樣一來,黃色的區(qū)域就不是目標的輪廓了,而是目標在兩個時段區(qū)域的并集。所以,如果事先保存好背景圖片,那么就可以將實時圖片與背景圖片對比,并得到準確的目標輪廓。代碼的流程圖
簡單地設(shè)置背景圖片會來兩個新的問題:若相機視角被移動(比如路過的人不小心碰了一下),那么實時圖片和背景圖片做差值,將會得到整個畫面,目標檢測失效
若背景發(fā)生變化,比如鏡頭中的桌子被移動了,或者環(huán)境光突然發(fā)生變化,或者有目標進入鏡頭后,賴著不走,etc. 那么鏡頭如實將會一直把這變化為框出來,這不智能
這些都是不更新背景圖片導(dǎo)致的,所以要設(shè)置更新背景圖片的策略
下面講流程圖中【對比并有策略地更新背景圖片】的策略:背景圖片更新策略
相關(guān)代碼
由邊緣檢測改寫而來的函數(shù),它根據(jù)輸入的兩張圖片,返回被檢測出的目標輪廓,如果兩張圖片相似,那么就返回一個空列表 [] ,空列表在Python的邏輯判斷中,是False,方便背景圖片更改的邏輯判斷:
def get_polygon_contours(self, img, img_back):
img = np.copy(img)
dif = np.array(img, dtype=np.int16)
dif = np.abs(dif - img_back)
dif = np.array(dif, dtype=np.uint8) # get different
gray = cv2.cvtColor(dif, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, self.min_thresh, 255, 0)
thresh = cv2.blur(thresh, (self.thresh_blur, self.thresh_blur))
if np.max(thresh) == 0: # have not different
contours = [] # 空列表在Python的邏輯判斷中,是False
else:
thresh, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# hulls = [cv2.convexHull(cnt) for cnt, hie in zip(contours, hierarchy[0]) if hie[2] == -1]
# hulls = [hull for hull in hulls if cv2.arcLength(hull, True) > self.min_hull_len]
# contours = hulls
approxs = [cv2.approxPolyDP(cnt, self.min_side_len, True) for cnt in contours]
approxs = [approx for approx in approxs
if len(approx) > self.min_side_num and cv2.arcLength(approx, True) > self.min_poly_len]
contours = approxs
return contours
位于類EdgeDetection 中的 函數(shù)main_get_img_show(),執(zhí)行更換背景的邏輯判斷:
...
contours = self.get_polygon_contours(img, self.img_back) # 這個函數(shù)框出并返回目標輪廓
self.img_list.append(img) # 將實時圖片加入歷史圖片隊列
img_prev = self.img_list.pop(0) # 取出最在的歷史圖片
# 兩個邏輯判斷,決定是否更換背景圖片
# 一個是背景圖片微調(diào),即背景與實時相似的時候,更新背景圖片
# 另一個是背景圖片更換,當(dāng)歷史圖片與實時圖片相似的時候,證明背景已經(jīng)更改一段時間了,因此更新背景
self.img_back = img \
if not contours or not self.get_polygon_contours(img, img_prev) \
else self.img_back
...
需要明白的Python小技巧——空列表在Python的邏輯判斷中,是False
print("[] is %s" % bool([]))
if []:
print("[] is True")
else:
print("[] is False")
如下,被視為背景的卡片移動了,出現(xiàn)兩個框,一段時間后紅框消失,證明背景圖片被更換,伸入手進行測試,其他功能正常:https://www.zhihu.com/video/997434329294729216
還有一個對目標輪廓的篩選過程——根據(jù)輪廓多邊形的邊數(shù)、周長進行篩選:
...
# 在 類的初始化中 def __init__(self, img, roi_pts):
self.min_side_len = int(self.img_len0 / 24) # min side len of polygon
self.min_poly_len = int(self.img_len0 / 12)
self.thresh_blur = int(self.img_len0 / 8)
...
# 在 類的函數(shù) get_polygon_contours() 中
approxs = [cv2.approxPolyDP(cnt, self.min_side_len, True) for cnt in contours]
approxs = [approx for approx in approxs
if len(approx) > self.min_side_num and cv2.arcLength(approx, True) > self.min_poly_len]
contours = approxs
...
視頻的前面幾秒,手指在灰色部分,即ROI(Regin of Interest)以外,沒有觸發(fā)輪廓框選,進入?yún)^(qū)域后,出現(xiàn)了一個四邊形將目標框出,而且周長足夠:https://www.zhihu.com/video/997459527129841664
(從這個視頻中還可以看出,我的移動目標輪廓框選算法還是有疏漏的,比如影子也框進去了、手指退出后,還留有錯誤的紅框)
感興趣區(qū)域的設(shè)定
感興趣區(qū)域的設(shè)定視頻 ↓https://www.zhihu.com/video/997462804596600832
↑ 視頻中的操作:按退格鍵重新劃定ROI ,鼠標點擊定義多邊形,按enter 確認ROI
應(yīng)用討論
移動物體識別的這個特性,在固定攝像頭實時視頻偵測的時候比較有用,比如:監(jiān)控攝像頭,檢測到鏡頭畫面有變化(移動物體出現(xiàn))的時候,才開啟記錄功能,錄下視頻,避免記錄重復(fù)視頻,節(jié)省磁盤空間。(即電子蛙眼)
保留前景,過濾掉無關(guān)的背景。
比較前后幀像素差異算法的缺點 @朱琦
這種方法受光線變化影響非常大。如果我們只想要檢測闖入感興趣區(qū)域的物體,那么這種方法會不可避免地把影子認為是闖入物體。
而深度學(xué)習(xí)目標檢測可以排除這種影響。因此這種算法最好是和深度學(xué)習(xí)相結(jié)合:使用這種像素差異算法進行低準確率的檢測,然后使用深度學(xué)習(xí)進行最終的判斷。如:對于畫面長時間持續(xù)不動的多個攝像頭,我們使用像素差異算法進行檢測,當(dāng)檢測到有物體闖入時,程序?qū)惓蠼o給深度學(xué)習(xí)卷積網(wǎng)絡(luò),由它進行把關(guān)。(這樣子可以減少計算,同時維持判斷精度。例如:車庫車輛檢測,異常闖入檢測)。
用在自動生成訓(xùn)練集上:(自從2018年數(shù)據(jù)集逐漸完善、以及半監(jiān)督算法的發(fā)展,以下方法已經(jīng)過時)
將要識別的物體放在鏡頭前,不斷地移動物體(最好是換不同高度環(huán)繞拍攝),識別出物體輪廓,處理成邊緣羽化的png圖片,然后和其他背景合成大量訓(xùn)練集(此時可以通過輪廓輸出框選完畢的box,再批量創(chuàng)建label,自動導(dǎo)出成為xml格式,就可以為所欲為了)(可以看我的另外一篇:利用初步訓(xùn)練的深度學(xué)習(xí)模型自動生成訓(xùn)練圖片,包括csv文件、Python字典、TensorFlow目標檢測訓(xùn)練圖片xml注釋 相互轉(zhuǎn)換(還沒寫完))
用傳統(tǒng)圖像識別將目標準確框出,并過濾掉背景,傳給目標檢測模型,甚至可以取代目標檢測提取候選框的那一步,將目標檢測的工作,從:生成候選框 → 分類器處理多個候選框,得到類別匹配度信息 →
計算匹配度,篩選出得分高的目標 → 調(diào)整對應(yīng)候選框的位置 →
輸出目標及對應(yīng)的候選框
簡化為:傳統(tǒng)圖形識別框出待分類的目標移動目標 →
分類器計算目標匹配度,判斷目標類別 →
輸出目標輪廓,以及目標的類別
簡化的內(nèi)容如下:簡化目標檢測的任務(wù):從“判斷目標位置,確定目標類型”簡化為“判斷目標類型”
處理的圖片變小了:從原來的全圖檢測 縮減為對移動目標對應(yīng)圖片的檢測
減小背景的影響:框出移動目標輪廓,并刪去背景,減少了影響分類判斷的干擾因素
在縮小了目標檢測應(yīng)用范圍的情況下(只能用來檢測固定鏡頭的移動物體/入侵物體,用在安防攝像頭上面最好了),預(yù)計這樣子處理可以減少計算量,提高檢測準確率。
用在固定攝像頭實時目標檢測上:(自2018年Mask-RCNN發(fā)展成熟后,以下方法已過時)
移動物體框選結(jié)果預(yù)覽(深度學(xué)習(xí)結(jié)合目標檢測結(jié)合(這里用的是Yolo目標檢測),假裝把segmentation 做出來了)
參考資料:
在評論區(qū)指出的問題,我會修改到正文中,并注明貢獻者的名字。
在評論區(qū)提出的問題,我可能會嘗試解答,并添加到正文中。
交流可以促進社區(qū)與自身成長,歡迎評論,謝謝大家。
總結(jié)
以上是生活随笔為你收集整理的基于python的移动物体检测_感兴趣区域的移动物体检测,框出移动物体的轮廓 (固定摄像头, opencv-python)...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python给用户打标签_python用
- 下一篇: python求解方程组_python如何