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