VS2015+OpenCV3.4.5實現Yolov3對象檢測

由於工作忙,好久沒有更新博客啦,最近在做對象檢測方面的項目,現將知識在此梳理下。
剛開始接觸Yolov3是在Ubuntu環境下跑的官方demo,然後訓練自己的數據集,得到權重文件,網上相關教程很多,不難實現。但是由於項目在Windows上實現的,因此特地在Win10環境下使用C++、OpenCV進一步實現。
實驗環境:Win10+VS2015+OpenCV3.4.5
一、原理介紹
(1)OpenCV3.3.1版本開始正式支持Darknet網絡結構,並且支持Yolov1,Yolov2以及Yolov3 Tiny網絡模型的導入與使用,支持C/C++/Python,但是在OpenCV中,YOLO只是前饋網絡,只支持預測,不能訓練,是一種比SSD還要快的對象檢測網絡模型,該算法的作者在其論文中提到其FPS是Fast R-CNN的100倍。是一種端到端的目標檢測模型,算法基本思想是:首先通過特徵提取網絡對輸入圖像提取特徵,得到特定大小的特徵圖輸出。輸入圖像分成13×13的grid cell,接着如果真實框中某個object的中心座標落在某個grid cell中,那麼就由該grid cell來預測該object。每個object有固定數量的bounding box,YOLO v3中有三個bounding box,使用邏輯迴歸確定用來預測的迴歸框。它是one-stage系檢檢測算法的鼻祖,即只通過一個stage就直接輸出bbox和類別標籤:
在這Yo裏插入圖片描述
(2) YOLOv3僅僅是作者近一年的一個工作報告(TECH REPORT),不算是一個完整的paper,因爲他們實際上是把其它論文的一些工作在YOLO上嘗試了一下。相比YOLOv2,我覺得YOLOv3最大的變化包括兩點:使用殘差模型和採用FPN架構。YOLOv3的特徵提取器是一個殘差模型,因爲包含53個卷積層,所以稱爲Darknet-53,從網絡結構上看,相比Darknet-19網絡使用了殘差單元,所以可以構建得更深。另外一個點是採用FPN架構(Feature Pyramid Networks for Object Detection)來實現多尺度檢測。YOLOv3採用了3個尺度的特徵圖(當輸入爲416×416時):(13×13) ,(26×26) ,(52×52)。
(3)從YOLO的三代變革中可以看到,在目標檢測領域比較好的策略包含:設置先驗框,採用全卷積做預測,採用殘差網絡,採用多尺度特徵圖做預測。
二、基於OpenCV實現YOLOv3

  1. 加載網絡模型和分類信息
//Give the configuration and weight files for the model
 String modelConfiguration = "..\\model\\yolov3.cfg";
 String modelWeights = "..\\model\\yolov3.weights";
 // Load names of classes
 string classesFile = "..\\model\\coco.names";
 ifstream ifs(classesFile.c_str());
 string line;
 while(getline(ifs, line))
 {
  classes.push_back(line);
 }
 //Load the network
 Net net = readNetFromDarknet(modelConfiguration, modelWeights);
  1. 加載測試圖像
//Load test image
 Mat frame = imread("..\\image\\test2.jpg");
 //start time
 start = clock();
 //Create a 4D blob from a frame. 創建神經網絡輸入圖像                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
 blobFromImage(frame, blob, 1 / 255.0, cvSize(inpWidth, inpHeight), Scalar(0, 0, 0), true, false); 

blobFromImage()函數主要用來對圖片進行預處理。包含兩個主要過程:
(1)整體像素值減去平均值(mean)
(2)通過縮放係數(scalefactor)對圖片像素值進行縮放
3. 將測試圖片輸入網絡

//Sets the input to the network 設置輸出
 net.setInput(blob);
  1. 檢測顯示與保存
//Runs the forward pass to get output of the output layers 獲取輸出層結果
 vector<Mat> outs;
 net.forward(outs, getOutputsNames(net));
 //Remove the bounding boxes with low confidence
 postprocess(frame, outs);
 finish = clock();
 cout << "Run time is " << double(finish - start) / CLOCKS_PER_SEC << endl;
 //Put efficiency information. The function getPerfProfile returns the overall time for inference(t) and the timings for each of the layers(in layersTimes)
 //輸出前向傳播的時間
 vector<double> layersTimes;
 double freq = getTickFrequency() / 1000;
 double t = net.getPerfProfile(layersTimes) / freq;
 string label = format("Inference time for a frame : %.2f ms", t);
 putText(frame, label, Point(0, 15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255));
 imshow("result", frame);
 //保存圖像
 imwrite("..\\image\\result.jpg", frame);

5.運行效果
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章