用OpenCV計算道路交通流量的一個直觀教程
這篇文章將向你展示一個非常簡單但功能強大的示例,說明如何使用你可以在裝置上執行的演算法來計算交通流量。
閱讀本文之前,建議你閱讀這篇關於道路交通分類的文章,它提到了我們在本專案中將要介紹的基礎管道架構的一部分。
文章地址:http://www.atyun.com/7883_基於計算機視覺和opencv:建立一個能夠計算道路交通.html
本專案需要的完整程式碼:
https://github.com/creotiv/object_detection_projects/tree/master/opencv_traffic_capacity_counting
這個演算法包括4個步驟:
1.獲得車架邊緣 2.模糊車架邊緣以得到更多填充區 3.二進位制閾值將影象變得模糊 4.重疊閾值影象中你感興趣的區域(重點區域),你可以在你的計算位置上進行掩膜,並在提供了最大車輛通行量的情況下計算黑畫素/白畫素。
下面你可以看到每一個步驟的圖示:
class CapacityCounter(PipelineProcessor): def __init__(self, area_mask, save_image=False, image_dir='./'): super(CapacityCounter,self).__init__() self.area_mask= area_mask self.all = np.count_nonzero(area_mask) self.image_dir= image_dir self.save_image= save_image def calculate_capacity(self, frame, frame_number): base_frame= frame # CLAHE (Contrast Limited Adaptive Histogram Equalization) # this used for noise reduction at night time frame= cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) clahe= cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) cl1= clahe.apply(frame) # getting edges with Canny filter edges= cv2.Canny(frame,50,70) # invert them to get white background edges= ~edges # blur with additional use of bilateralFilter to remove color noise blur= cv2.bilateralFilter(cv2.blur(edges,(21,21),100),9,200,200) # threshold with ROI overlapping _, threshold= cv2.threshold(blur,230,255,cv2.THRESH_BINARY) t= cv2.bitwise_and(threshold,threshold,mask= self.area_mask) # counting capacity area free= np.count_nonzero(t) capacity= 1 - float(free)/self.all # creating plot for debugging and visualization if self.save_image: img= np.zeros(base_frame.shape, base_frame.dtype) img[:, :]= EXIT_COLOR mask= cv2.bitwise_and(img, img, mask=self.area_mask) cv2.addWeighted(mask,1, base_frame,1,0, base_frame) fig= plt.figure() fig.suptitle("Capacity: {}%".format(capacity*100), fontsize=16) plt.subplot(221),plt.imshow(base_frame),plt.title('Original') plt.xticks([]), plt.yticks([]) plt.subplot(222),plt.imshow(edges),plt.title('Cany edges') plt.xticks([]), plt.yticks([]) plt.subplot(223),plt.imshow(blur),plt.title('Blur') plt.xticks([]), plt.yticks([]) plt.subplot(224),plt.imshow(t),plt.title('Threshold with ROI mask') plt.xticks([]), plt.yticks([]) fig.savefig(self.image_dir+ ("/processed_%s.png" % frame_number), dpi=500) return capacity def __call__(self, context): frame= context['frame'].copy() frame_number= context['frame_number'] capacity= self.calculate_capacity(frame, frame_number) self.log.debug("Capacity: {}%".format(capacity*100)) context['capacity']= capacity return context
邊緣
使用CLAHE(限制對比度的自適應直方圖均衡)來消除影象上的噪聲,然後使用Canny邊緣檢測器從影象中獲取邊緣。最後把它轉化成白色背景(只是為了方便視覺)。
更多資訊:CLAHE:http://docs.opencv.org/3.1.0/d5/daf/tutorial_py_histogram_equalization.html
Canny邊緣檢測器:http://docs.opencv.org/trunk/da/d22/tutorial_py_canny.html
模糊
我們使用基本的模糊和雙邊濾波(Bilateral filter)演算法來消除一些顏色的噪聲,並提供更好的分割。
閾值
最後的濾波是一個二進位制的閾值,只使用白色和黑色的畫素作為我們對汽車/非汽車的分割。
計算
最後一個簡單的步驟就是將黑畫素的數量與白畫素的數量進行區分,以獲得最大車流量。
問題
由於一些相機的噪聲和戶外條件不同,精確度可能不會達到70-85%。但這並不是一個大問題,因為我們可以設定最小值/最大值的限制,或者根據光照條件使用額外的濾波,比如測試一些重點區域的邊緣(例如一些白矩形)。而且這些資料主要用作額外的資料,所以只需要相對值。
為什麼需要這些資料?
所有資料都是必需的,即使你現在不知道如何使用它們。在使用這些資料的情況下,我們可以解釋為什麼在某個時間點上最大車流量是有限的。
為什麼不使用一個大的演算法來完成所有的工作呢?
你必須記住的主要事情是,在資料科學專案中,它們不僅應該在領域中有效,而且對於業務來說也應該具有成本效益,包括速度、記憶體使用、可伸縮性、一小時執行時的成本和規模。
高效執行在任何條件下是沒有演算法的,例如,排序演算法,被用於本地專案而不會被用於大資料專案因為它的速度十分緩慢,大資料演算法不會用於本地專案的原因也同理(因為它們只有在大的資料量上更快)。
因此,你應該瞭解你的專案和業務限制,從而構建你的管道。