文章目錄
- 1.序言
- 2.設計思路以及遇到的問題
- 3.實現過程
- 4.總結&吐槽
- 5.更新源碼
- 6.聯系方式
1.序言
這里主要說一下遇到的問題以及想法,如有問題歡迎大家指正。
2.設計思路以及遇到的問題
第一步是完成物體(也就是車輛)的檢測,這里有兩種解決辦法,第一種辦法是使用opencv的形態學處理,比如背景消除、做幀差、膨脹腐蝕等等,這個辦法比較基礎,但是要處理好需要調整諸多細節,我的細節調整的不夠好,因此實現時會遇到許多小問題。第二個辦法是直接實現物體的識別,需要用到一定的訓練模型,我測試過googlenet和SSD,最終選擇了SSD,如果大家有能力也能自己訓練,可能效果更好。第二步是追蹤,這里我看到很多博文都提到了opencv自帶的追蹤器,比如kcf等,但是我對于追蹤器沒有成功使用,放棄了這個選擇,并選擇了最簡單粗暴的方法:逐幀讀取視頻并尋找車輛,一幀一幀畫出來。第三步是計數,這里我卡了一個星期,遇到了各種問題,為此我幾乎翻遍了CSDN關于這塊的文章,有些文章確實給到了一些思路,但大部分都沒給出具體過程。第一個問題是怎么判斷是否計數的問題,我最開始的想法是:當車輛輪廓的y坐標碰到檢測線(這里假定為700)時加1,但接下里的測試卻非常失敗,很多車輛在愛檢測線附近會掉幀或者檢測不到或者其他原因,總之僅僅靠一個y軸直接判斷肯定是不夠的,后來我改成往下大于檢測線1(700),往上大于檢測線2(400),發現問題更大了,你會一直檢測(這里我劃分ROI區域沒有解決,可能是我方法不對)。之后在CSDN 中找到一篇博文,提到的做法是建立一個類,每次出現新的目標就創建一個類,舊的目標就替換坐標,這個做法后來證實的確有效。但問題是如何判斷這一幀的車輛是否新的目標,我給出的解決辦法是創建一個列表,將第一幀的所有目標(也就是每一個對象)存入,第二幀的時候遍歷每一個目標與列表的每一輛車,判斷x,y的距離,如果變化不超過車的長度和寬度,就認為這是同一輛車(也有學長告訴為特征值匹配的辦法,也許更可行,但我能力不夠沒有學到這里,所以沒有采用)。第三個問題 是來去方向問題,最開始的想法是讀取質心,將每一輛車變成點,然后讀取幀,當這一幀的這一輛車的y坐標相較于上一輛車增加時,就認為這輛車方向向下,否者認為方向向上,后來的測試證明我大錯特錯,有些車的輪廓會來回浮動,質點也會來回浮動,因此有時候下一幀中方向向下的車輛的y坐標甚至低于上一幀,所以我沒有采取這種方式。最終只能考慮最簡單粗暴的辦法:根據x坐標給定方向,視頻中x軸1000往左為下,1000往右為上,我承認這種辦法確實很笨,但我確實沒有想出好的辦法來,如有同學有辦法解決,懇請您大膽指出。第四個問題回到了計數判斷環節,這里由于上面問題的解決,所以我給出的判斷條件是y坐標+方向+是否已經計數。最后有個非常重要的步驟是車輛跨越一定限度后刪除對象,節約計算時間。
3.實現過程
1.物體檢測識別和追中請看我的上幾篇博文,鏈接1 opencv檢測 鏈接2SSD車輛識別
結果如下:
2.定義類:(其實id沒啥用,方便測試)
class Car:def __init__(self
,c_id
,c_x
,c_y
,direction
,c_count
): self
.c_id
= c_id self
.c_x
=c_x self
.c_y
=c_yself
.direction
= direction self
.c_count
= c_count
def updateCoords(self
,x
,y
): self
.c_x
= xself
.c_y
=y
3.計數
for i
in cars
:if abs(cx
- i
.c_x
) < width
and abs(cy
- i
.c_y
) < height
: new
= Falsei
.updateCoords
(cx
, cy
)if i
.c_y
>= 700 and i
.direction
== 'down' and i
.c_count
== False:count_down
+= 1i
.c_count
= Trueif i
.c_y
< 400 and i
.direction
== 'up' and i
.c_count
== False:count_up
+= 1i
.c_count
= Trueif i
.c_y
>= 790 or i
.c_y
<= 290:cars
.remove
(i
)if new
== True:p
= Car
(pid
, cx
, cy
, 'unknow', False)if p
.c_x
> 1000:p
.direction
= 'up'else:p
.direction
= 'down'cars
.append
(p
)pid
+= 1print(len(cars
))cv
.circle
(image
, (cx
, cy
), 5, (0, 0, 255), -1)cv
.rectangle
(image
, (int(left
), int(top
)), (int(right
), int(bottom
)), (255, 0, 0), thickness
=2)
4.結果(由于視頻畫質原因,遇到一些車輛比較模糊時會出現很多框,因此還需改進)
4.總結&吐槽
由于代碼還不夠完善,這里就不給大家一一貼出來了,主要是跟大家說一下我的思路,要是有小伙伴想參考的話,我就放一個下載鏈接吧,其實這個東西只要想明白了應該不是什么難事(雖然我現在也有點暈),作為計算機視覺還在入門的新人,歡迎大家指出我的錯誤以便改進,也歡迎同樣是計算機視覺新手的小伙伴們一起學習,本博客將一直更新相關內容,我會把計算機視覺入門過程中所遇到的重要問題和自己的想法分享給大家,同時也希望能收到大家的點贊或者指點迷津。
我在學習過程同遇到很多有經驗的同學,他們有的使用了yolo v3算法,有的使用tensorflow訓練模型,深感自己能力的不足,現在我會繼續學習這方面的內容,希望能有更多思路和內容分享給大家。
吐槽:算法確實挺難的,但更難的是找測試素材,這十字路口的監控錄像上哪找去(各大視頻網站愣是沒找到幾個能用的,給跪了orz)
5.更新源碼
有許多小伙伴詢問,現在將源碼分享給大家,希望大家指正
2022.3.29更新:
這篇博客是20年寫的,現在22年了,兩年過去了,沒想到這么多人評論留言和郵件聯系我,在這里謝謝大家了,作為cv新人(可能一直都會是新人)受寵若驚。
需要說明的是,其實這個代碼有很大的局限性,因為像素點什么的都寫死了,換個視頻就不行了。而且純圖像處理的方法確實有很大的問題,一點點調參數確實能把一些大的物體運動軌跡給抓住,但是一旦有的視頻會有光線啊、遮擋物啊什么的,僅僅用圖像處理就解決不掉了,因為這個代碼是我剛學圖像處理的時候做的,所以沒想太多。主要是記錄一下我遇到的問題吧,現在我現在已經很久沒有用opencv了,有一些問題我也不知道在哪,這篇博客主要是提供一個思路,其實我回看一下思路確實沒啥問題,只是水平有限當時沒有做好,如果是現在來做的話,yolo模型確實是比較優秀的選擇,但是你用了yolo后,可以把我過線檢測以及定義類的思路用上。最后,無論是做畢設的、工作的還是在學習的兄弟,如果這篇博客幫到了大家,哪怕是一點點思路,那就是我開源的意義所在了,祝大家一帆風順~
此外,有問題還是可以繼續留言或者郵件,所有留言和郵件我都會看,并且會一一回復的!**
import numpy
as np
import cv2
as cv
import time
class Car:def __init__(self
,c_id
,c_x
,c_y
,direction
,c_count
,c_start_time
,c_over_time
,c_v
):self
.c_id
= c_idself
.c_x
=c_xself
.c_y
=c_yself
.direction
= directionself
.c_count
= c_countself
.c_start_time
= c_start_timeself
.c_over_time
= c_over_timeself
.c_v
= c_v
def updateCoords(self
,x
,y
):self
.c_x
= xself
.c_y
=ycount_up
= 0
count_down
= 0
cars
= []
pid
= 1
max_v
= 0
distance
= 10
vc
= cv
.VideoCapture
(r"C:\Users\zn\Desktop\監控錄像_1.mp4")fourcc
= cv
.VideoWriter_fourcc
(*'XVID')
out
= cv
.VideoWriter
('output.avi',fourcc
,15, (1920,1080))BS
= cv
.createBackgroundSubtractorMOG2
(detectShadows
=True)
while (vc
.isOpened
()):ret
, frame
= vc
.read
()gray
= cv
.cvtColor
(frame
,cv
.COLOR_BGR2GRAY
)fgmask
= BS
.apply(gray
)image
= cv
.medianBlur
(fgmask
,5)element
= cv
.getStructuringElement
(cv
.MORPH_RECT
,(5, 5));image2
= cv
.morphologyEx
(image
, cv
.MORPH_CLOSE
,element
,iterations
=5);image3
= cv
.morphologyEx
(image2
, cv
.MORPH_OPEN
, element
, iterations
=5)contours
, hierarchy
= cv
.findContours
(image3
, cv
.RETR_TREE
, cv
.CHAIN_APPROX_NONE
)cv
.line
(frame
, (0, 700), (1920, 700), (0, 255, 0), 3)cv
.line
(frame
, (0, 400), (1920, 400), (0, 255, 0), 3)cv
.line
(frame
, (0, 800), (1920, 800), (255, 255, 255), 2)cv
.line
(frame
, (0, 300), (1920, 300), (255, 255, 255), 2)cv
.putText
(frame
,"Up:"+str(count_up
),(1100,100),cv
.FONT_HERSHEY_COMPLEX
,2,(255,0,0),3)cv
.putText
(frame
, "Down:" + str(count_down
),(700, 100), cv
.FONT_HERSHEY_COMPLEX
, 2, (255, 0, 0), 3)cv
.putText
(frame
, "max_v:" + str('%.2f' %(max_v
*3.6))+'km/h', (50, 100), cv
.FONT_HERSHEY_COMPLEX
, 1.5, (255, 0, 0), 2)null
= True for cnt
in contours
:x
, y
, w
, h
= cv
.boundingRect
(cnt
)cx
= int(x
+ w
/ 2)cy
= int(y
+ h
/ 2)if 300<int(y
+(h
/2))<800 and 400<int(x
+(w
/2))<1800:if cv
.contourArea
(cnt
) < 13000 or w
< 100 or h
< 100:continuenull
= False new
= True for i
in cars
:if abs(cx
-i
.c_x
) <100 and abs(cy
- i
.c_y
)<100:new
= Falsei
.updateCoords
(cx
,cy
)if 700<=i
.c_y
<=720 and i
.direction
=='down' and i
.c_count
==False:i
.c_over_time
= time
.time
()i
.c_v
= distance
/(i
.c_over_time
- i
.c_start_time
)if i
.c_v
>max_v
:max_v
= i
.c_vcount_down
+=1i
.c_count
=Trueif 380<=i
.c_y
<=400 and i
.direction
=='up' and (i
.c_count
== False):i
.c_over_time
= time
.time
()i
.c_v
= distance
/ (i
.c_over_time
- i
.c_start_time
)if i
.c_v
> max_v
:max_v
= i
.c_vcount_up
+=1i
.c_count
=Trueif i
.c_y
>720 or i
.c_y
<380:cars
.remove
(i
) if new
== True and 340<cy
<760: start_time
= time
.time
()p
= Car
(pid
, cx
, cy
, 'unknow', False, start_time
,0,0)if p
.c_x
<1000:p
.direction
= 'down'else:p
.direction
= 'up'cars
.append
(p
)pid
+= 1cv
.circle
(frame
, (cx
, cy
), 5, (0, 0, 255), -1)cv
.rectangle
(frame
, (x
, y
), (x
+ w
, y
+ h
), (0, 0, 255), 3)if null
== True: cars
= []cv
.imshow
("frame",frame
)out
.write
(frame
)k
= cv
.waitKey
(30) & 0xffif k
== 27:break
vc
.release
()
cv
.destroyAllWindows
()
6.聯系方式
有問題歡迎聯系我:
視頻刪掉了,好像是從優酷還是騰訊視頻找的吧。
1759412770@qq.com
zn1759412770@163.com
總結
以上是生活随笔為你收集整理的Python + OpenCv实现视频中的车辆检测计数(车流量统计) (2020.7.15已更新源码)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。