車輛檢測識別(YOLOV2)

車輛檢測識別(YOLOV2)

基於YOLOV2-tiny實現車輛檢測:

https://www.zhihu.com/video/979038485164756992

代碼地址:yang1688899/Vehicle-Detection-YOLO-keras

YOLO簡介:

YOLO意為 You Only Look Once,是一種基於深度學習的端對端(end to end)物體檢測方法.與R-CNN,Fast-R-CNN,Faster-R-CNN等通過region proposal產生大量的可能包含待檢測物體的 potential bounding box,再用分類器去判斷每個 bounding box里是否包含有物體,以及物體所屬類別的方法不同,YOLO將物體檢測任務當做一個regression問題來處理.

YOLO檢測思路:

(這裡以輸入為416x416的YOLOV2為例)

首先將圖片劃分為13x13個柵格(grid cell):

每個柵格負責預測5個bounding box(bounding box包括中心點坐標x,y及其寬w,高h,共4個值)。對於每個bounding box預測其是否包含物體的confidence score(1個值),及其所包含物體class的possibility分布(由於有20個class,這裡有20個值)。最終模型的的輸出為13x13x125.這裡13x13對應13x13個柵格(grid cell).每個bounding box 一共有4+1+20=25個值,每個柵格檢測5個bounding box,則有每個柵格對應5x25=125個值,因此13x13x125.

以下為每個柵格的對應輸出:

模型最終檢測到13x13x5=845個bounding box把所有的bounding box都畫到原圖上可能會是這樣子的:

大多數的bounding box 的confidence score都是非常低的(也就是沒有檢測到物體的),只要少數的bounding box 是高confidence score的,檢測到物體的。通過confidence score與最大的class的possibility相乘可以得到該bounding box 包含某物體的置信度,對這一置信度進行閾值過濾可以把大部分無意義的bounding box過濾掉。剩下的bounding box 可能存在的多重檢測問題(即一個物體被多個bounding box檢測)可以用NMS,heatmap等方法進行過濾整合,得到最終檢測結果。

經過過濾處理的檢測結果會是這樣的:

實現步驟

ps:本來是打算keras構建模型結構,然後載入weights文件訓練後了參數實現的,但一直沒有搞清楚weights文件的參數是怎麼和模型各層對應上,最後找了YAD2K,裡面提供了把YOLOV2 weights文件直接轉換成keras model文件的方法,就直接拿來用了。

  • 使用YAD2K把weights文件轉化為keras的h5文件
  • 使用model預測bounding box
  • 閾值篩選bounding box

使用YAD2K把weights文件轉化為keras的h5文件

下載相應的YOLO weights和cfg文件:

weight文件下載;

獲得YAD2K;

運行yad2k.py文件,參數依次為:cfg文件路徑,weights文件路徑,model文件輸出路徑.

這裡使用yolov2-tiny模型的voc版本,運行如下命令:

python ./yad2k.py ./yolov2-tiny-voc.cfg ./yolov2-tiny-voc.weights ./model/yolov2-tiny-voc.h5

使用model預測bounding box

這裡是一個使用keras的predict_generator對視頻進行預測的示例(在內存顯存足夠的情況下可以直接用predict):

首先使用opencv讀取視頻,並進行resize,normalize等預處理:

#把給定視頻轉換為圖片def preprocess_video(src_path): cap = cv2.VideoCapture(src_path) num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) fps = int(cap.get(cv2.CAP_PROP_FPS)) fourcc = int(cap.get(cv2.CAP_PROP_FOURCC)) video_frames = [] for i in range(num_frames): ret, frame = cap.read() if ret: frame = cv2.resize(frame, (416, 416)) frame = preprocess_image(frame) video_frames.append(frame) video_frames = np.array(video_frames) cap.release() return video_frames,num_frames,fps,fourcc

利用yield寫一個generator function,用於在預測時生成指定batch_size大小的圖片batch:

#prediction_generatordef video_batch_gen(video_frames,batch_size=32): for offset in range(0,len(video_frames),batch_size): yield video_frames[offset:offset+batch_size]

最後載入model,使用predict_generator進行預測:

video_frames, num_frames, fps, fourcc = utils.preprocess_video(src_path)gen = utils.video_batch_gen(video_frames,batch_size=batch_size)model = load_model("./model/yolov2-tiny-voc.h5")print("predicting......")predictions = model.predict_generator(gen)

閾值篩選bounding box

得到predictions後,還要對predictions進行進一步處理,目的是過濾掉置信度低的及重疊的bounding box,使得圖片的每一個物體對應一個置信度最高的bounding box。 為了方便對predictions進行處理,這裡定義一個box類對bounding box的參數進行存儲:

class Box: def __init__(self): self.w = float() self.h = float() self.p_max = float() self.clas = int() self.x1 = int() self.y1 = int() self.x2 = int() self.y2 = int()

模型預測的是bounding box的中心點坐標x,y及其寬w,高h及是否包含物體的confidence score和其所包含物體class的possibility,其中中心點坐標x,y及其寬w,高h都是相對於每個柵格(grid cell)而言的,因此這些參數都需要進行轉換。使用confidence score與最大的class的possibility相乘可以得到置信度,對這個置信度進行一些閾值過濾可以過濾掉置信度不高的bounding box:

prediction = np.reshape(prediction, (n_grid, n_grid, n_box, 5+n_class))boxes = []for row in range(n_grid): for col in range(n_grid): for b in range(n_box): tx, ty, tw, th, tc = prediction[row, col, b, :5] box = Box() box.w = np.exp(tw) * anchors[2 * b + 0] * 32.0 box.h = np.exp(th) * anchors[2 * b + 1] * 32.0 c_probs = softmax(prediction[row, col, b, 5:]) box.clas = np.argmax(c_probs) box.p_max = np.max(c_probs) * sigmoid(tc) center_x = (float(col) + sigmoid(tx)) * 32.0 center_y = (float(row) + sigmoid(ty)) * 32.0 box.x1 = int(center_x - (box.w / 2.)) box.x2 = int(center_x + (box.w / 2.)) box.y1 = int(center_y - (box.h / 2.)) box.y2 = int(center_y + (box.h / 2.)) if box.p_max > probs_threshold: boxes.append(box)

經過初步處理後的bounding box仍會有大量重疊的情況:

這裡使用非極大值抑制(NMS)對bounding box進行過濾(ps:也可以使用車輛識別(特徵提取+svm分類器)中介紹的heatmap進行過濾,只要達到使每個物體對應一個合適的bounding box的目的):

#使用non_maxsuppression 篩選boxdef non_maximal_suppression(thresholded_boxes, iou_threshold=0.3): nms_boxes = [] if len(thresholded_boxes) > 0: # 添加置信度最高的box nms_boxes.append(thresholded_boxes[0]) i = 1 while i < len(thresholded_boxes): n_boxes_to_check = len(nms_boxes) to_delete = False j = 0 while j < n_boxes_to_check: curr_iou = iou(thresholded_boxes[i], nms_boxes[j]) if (curr_iou > iou_threshold): to_delete = True j = j + 1 if to_delete == False: nms_boxes.append(thresholded_boxes[i]) i = i + 1 return nms_boxes

最後把過濾後的bounding box展示在圖片上,以下為示例代碼:

#在圖片上畫出boxdef draw_boxes(image,boxes): for i in range(len(boxes)): color = colors[boxes[i].clas] best_class_name = classes[boxes[i].clas] image = cv2.rectangle(image, (boxes[i].x1, boxes[i].y1), (boxes[i].x2, boxes[i].y2),color) cv2.putText( image, best_class_name + : %.2f % boxes[i].p_max, (int(boxes[i].x1 + 5), int(boxes[i].y1 - 7)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1) return image

結果:


推薦閱讀:

Paper Notes:Mask R-CNN
[論文筆記] two-stream和two-stream fusion
[CVPR2018筆記]Deep Layer Aggregation
【CVPR2018正式公布】行人重識別論文
skimage例子學習(七)filters模塊介紹之邊緣檢測的實現

TAG:計算機視覺 | 深度學習DeepLearning | Keras |