日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【OpenCV学习】(九)目标识别之车辆检测与计数

發布時間:2024/3/24 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【OpenCV学习】(九)目标识别之车辆检测与计数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【OpenCV學習】(九)目標識別之車輛檢測及計數

背景

本篇將具體介紹一個實際應用項目——車輛檢測及計數,在交通安全中是很重要的一項計數;當然,本次完全采用OpenCV進行實現,和目前落地的采用深度學習的算法并不相同,但原理是一致的;本篇將從基礎開始介紹,一步步完成車輛檢測計數的項目;

一、圖像輪廓

本質:具有相同顏色強度連續點的曲線;

作用:

1、可用于圖形分析;

2、應用于物體的識別與檢測;

注意點:

1、為了檢測的準確性,需要先對圖像進行二值化或Canny操作;

2、畫輪廓的時候回修改輸入的圖像,需要先深拷貝原圖;

輪廓查找的函數原型:

findContours(img,mode,ApproximationMode…)

  • mode

    RETR_EXTERNAL=0,表示只檢測外輪廓;

    RETR_LIST=1,檢測的輪廓不建立等級關系;(常用)

    RETR_CCOMP=2,每層最多兩級;

    RETR_TREE=3,按樹形結構存儲輪廓,從右到左,從大到小;(常用)

  • ApproximationMode

    CHAIN_APPROX_BOBE:保存輪廓上所有的點;

    CHAIN_APPROX_SIMPLE:只保存輪廓的角點;

代碼實戰:

img = cv2.imread('./contours1.jpeg') # 轉變成單通道 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY) # 輪廓查找 contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

contours輸出結果:

(array([[[ 0, 0]],[[ 0, 435]],[[345, 435]],[[345, 0]]], dtype=int32),)

可以看出,我們找最外層輪廓,找出了一個矩形輪廓的四個點;

當然,我們不需要通過畫形狀來繪制輪廓,可以通過一個內置函數來繪制輪廓;

繪制輪廓函數原型

drawContours(img,contours,contoursIdx,color,thickness,…)

  • contours:表示保存輪廓的數組;
  • contoursIdx:表示繪制第幾個輪廓,-1表示所有輪廓;

代碼案例:

img = cv2.imread('./contours1.jpeg') img2 = img.copy() # 轉變成單通道 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY) # 輪廓查找 contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)cv2.drawContours(img, contours, -1, (0, 0, 255), 1) cv2.drawContours(img2, contours, -1, (0, 0, 255), -1)cv2.imshow('org', img) cv2.imshow('org2', img2) cv2.waitKey(0)

如上圖所示,左圖是線寬設置為1,右圖為線寬設置為-1,也就是填充的效果;

當然,OpenCV還提供了計算輪廓周長和面積的方法;

輪廓面積函數原型:

contourArea(contour)

輪廓周長函數原型:

arcLength(curve,closed)

  • curve:表示輪廓;
  • closed:是否是閉合的輪廓;

上述兩個函數比較簡單,在這就不做代碼演示了;

二、多邊形逼近與凸包

多邊形逼近函數原型:

approxPolyDP(curve,epsilon,closed)

  • epslion:精度;

凸包的函數原型:

convexHull(points,clockwise,…)

  • points:輪廓;
  • clockwise:繪制方向,順時針或逆時針;(不重要)

首先我們看一下基于輪廓查找輸出的輪廓形狀:

可以看出輪廓點十分密集,接下來看一下基于多變形逼近和凸包的效果:

代碼案例:

img = cv2.imread('./hand.png') img2 = img.copy() # 轉變成單通道 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY) # 輪廓查找 contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# cv2.drawContours(img, contours, -1, (0, 0, 255), 1) e = 20 approx = cv2.approxPolyDP(contours[0], e, True) # 多邊形逼近 approx = (approx, ) cv2.drawContours(img, approx, 0, (0, 0, 255), 3)hull = cv2.convexHull(contours[0]) hull = (hull, ) cv2.drawContours(img2, hull, 0, (0, 0, 255), 3) # 凸包cv2.imshow('org', img) cv2.imshow('org2', img2) cv2.waitKey(0)

這里需要注意一點,繪制輪廓的函數對于輪廓的傳入需要為元組,需要將得到的數組放到一個元組中!

當然,多邊形逼近這里設置的精度為20,所以比較粗糙,設置小一些可以達到更好的效果;

三、外接矩形

外接矩陣分為最大外接矩陣和最小外接矩陣,如下圖所示:

最小外接矩陣還有一個功能,就是計算旋轉角度,從上圖的綠框應該可以很明顯看出;

最小外接矩陣函數原型:

minAreaRect(points)

返回值:起始點(x,y)、寬高(w,h)、角度(angle)

最大外接矩形函數原型:

boundingRect(array)

返回值:起始點(x,y)、寬高(w,h)

代碼案例:

img = cv2.imread('./hello.jpeg') img2 = img.copy() # 轉變成單通道 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY) # 輪廓查找 contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# 獲取最小外接矩形 r = cv2.minAreaRect(contours[1]) box = cv2.boxPoints(r) # 提取其中的點 box = np.int0(box) # 將浮點型轉換為整型 cv2.drawContours(img, (box, ), 0, (0, 0, 255), 2)# 獲取最大外接矩形 x, y, w, h = cv2.boundingRect(contours[1]) cv2.rectangle(img2, (x, y), (x+w, y+h), (0, 0, 255), 2)cv2.imshow('org', img) cv2.imshow('org2', img2) cv2.waitKey(0)

四、車輛統計實戰

涉及的知識點:

  • 窗口展示
  • 圖像、視頻的加載
  • 基本圖形的繪制
  • 基本圖像運算與處理
  • 形態學
  • 輪廓查找

實現流程:

加載視頻 —— 通過形態學識別車輛 —— 對車輛進行統計 —— 顯示統計信息

1、加載視頻

這里就是一個簡單加載視頻的實現:

cap = cv2.VideoCapture('video.mp4') while True:ret, frame = cap.read()if(ret == True):cv2.imshow('video', frame)key = cv2.waitKey(1)if(key == 27): # Esc退出breakcap.release() cv2.destroyAllWindows()

2、去除背景

函數原型:

createBackgroundSubtractorMOG()

  • history:緩沖,表示多少毫秒,可不指定參數,用默認的即可;

具體實現原理比較復雜,用到了一些視頻序列關聯信息,把像素值不變的認為是背景;

注意:在opencv中已經不支持該函數,而是用createBackgroundSubtractorMOG2()替代;如果需要使用可以安裝opencv_contrib模塊,在其中的bgsegm中保留了該函數;

代碼實現:

cap = cv2.VideoCapture('video.mp4')bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG()while True:ret, frame = cap.read()if(ret == True):# 灰度處理cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 高斯去噪blur = cv2.GaussianBlur(frame, (3, 3), 5)mask = bgsubmog.apply(blur)cv2.imshow('video', mask)key = cv2.waitKey(1)if(key == 27): # Esc退出breakcap.release() cv2.destroyAllWindows()

這里盡量采用舊版的MOG函數,新版的MOG2函數比較精細,會將樹葉等信息輸出,去除效果沒那么好;

3、形態處理

這里主要是為了處理一些小的噪聲點以及目標中的黑色塊;

代碼實現:

cap = cv2.VideoCapture('video.mp4')bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG()# 形態學kernel kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))while True:ret, frame = cap.read()if(ret == True):# 灰度處理cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 高斯去噪blur = cv2.GaussianBlur(frame, (3, 3), 5)mask = bgsubmog.apply(blur)# 腐蝕erode = cv2.erode(mask, kernel)# 膨脹dilate = cv2.dilate(erode, kernel, 3)# 閉操作close = cv2.morphologyEx(dilate, cv2.MORPH_CLOSE, kernel)close = cv2.morphologyEx(close, cv2.MORPH_CLOSE, kernel)contours, h = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE,)for (i, c) in enumerate(contours):(x, y, w, h) = cv2.boundingRect(c)cv2.rectangle(frame, (x, y), (x+w, y+h), (0,0,255), 2)cv2.imshow('video', frame)key = cv2.waitKey(1)if(key == 27): # Esc退出breakcap.release() cv2.destroyAllWindows()

從圖中效果來看,還是會有很多小的檢測框,接下來就是處理重合檢測框以及去掉一些多余的檢測框,類似于NMS去重,當然原理還不太一樣;

4、車輛統計

首先需要過濾一些小的矩形,已經檢測框的長和寬,設定一些閾值即可;

代碼實現:

cap = cv2.VideoCapture('video.mp4')bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG()# 保存車輛中心點信息 cars = [] # 統計車的數量 car_n = 0# 形態學kernel kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))while True:ret, frame = cap.read()if(ret == True):# 灰度處理cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 高斯去噪blur = cv2.GaussianBlur(frame, (3, 3), 5)mask = bgsubmog.apply(blur)# 腐蝕erode = cv2.erode(mask, kernel)# 膨脹dilate = cv2.dilate(erode, kernel, 3)# 閉操作close = cv2.morphologyEx(dilate, cv2.MORPH_CLOSE, kernel)close = cv2.morphologyEx(close, cv2.MORPH_CLOSE, kernel)contours, h = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE,)# 畫一條線cv2.line(frame, (10, 550), (1200, 550), (0, 255, 255), 3)for (i, c) in enumerate(contours):(x, y, w, h) = cv2.boundingRect(c)# 過濾小的檢測框isshow = (w >= 90) and (h >= 90)if(not isshow):continue# 保存中心點信息cv2.rectangle(frame, (x, y), (x+w, y+h), (0,0,255), 2)centre_p = (x + int(w/2), y + int(h/2))cars.append(centre_p)cv2.circle(frame, (centre_p), 5, (0,0,255), -1)for (x, y) in cars:if(593 < y < 607):car_n += 1 cars.remove((x, y)) cv2.putText(frame, "Cars Count:" + str(car_n), (500, 60), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 5) cv2.imshow('video', frame)key = cv2.waitKey(1)if(key == 27): # Esc退出breakcap.release() cv2.destroyAllWindows()

簡單的效果已經出來了,對于大部分車輛都能夠很好的檢測并且計數了;

存在問題:

由于是用中心點與線的距離來判斷,車速過慢可能會在兩幀內重復計數,車速過快可能會計數不到;這就是傳統算法存在的一個問題,基于深度學習的方法可以很好解決這些問題,可關注目標跟蹤實戰的那一篇文章!

總結

項目到這里就介紹了,通過該項目主要是將所學的知識點進行串聯,重點在于形態學的運用!當然這個效果可能達不到實際應用的標準,這也是傳統算法的一個弊端;有能力的可以采用深度學習的方法進行實現,也可以關注我后續的目標跟蹤是實現車輛計數,效果會遠比這個好。

總結

以上是生活随笔為你收集整理的【OpenCV学习】(九)目标识别之车辆检测与计数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。