用opencv的dnn模組做yolov5目標檢測

2021-10-21 03:11:39 字數 2789 閱讀 6495

**:

在yolov5之前的yolov3和yolov4的官方**都是基於darknet框架的實現的,因此opencv的dnn模組做目標檢測時,讀取的是.cfg和.weight檔案,那時候編寫程式很順暢,沒有遇到bug。但是yolov5的官方**(是基於pytorch框架實現的,但是opencv的dnn模組不支援讀取pytorch的訓練模型檔案的。如果想要把pytorch的訓練模型.pt**件載入到opencv的dnn模組裡,需要先把pytorch的訓練模型.pt**件轉換到.onnx檔案,然後才能載入到opencv的dnn模組裡。

因此,用opencv的dnn模組做yolov5目標檢測的程式,包含兩個步驟:(1).把pytorch的訓練模型.pt**件轉換到.onnx檔案。(2).opencv的dnn模組讀取.onnx檔案做前向計算。

(1).把pytorch的訓練模型.pt**件轉換到.onnx檔案

檢視models\yolo.py裡的detect類,在建構函式裡,有這麼兩行**:

它的作用是做特徵圖的輸出通道對齊,通過1x1卷積把三種尺度特徵圖的輸出通道都調整到 num_anchors*(num_classes+5)。

pwh = (ps[:, 2:4].sigmoid() * 2) ** 2 * anchors[i]

沒有採用exp操作,而是直接乘上anchors[i],這是yolov5與yolov3v4的乙個最大區別(還有乙個區別就是在訓練階段的loss函式裡,yolov5採用鄰域的正樣本anchor匹配策略,增加了正樣本。其它的是一些小區別,比如yolov5的第乙個模組採用focus把輸入資料2倍下取樣切分成4份,在channel維度進行拼接,然後進行卷積操作,yolov5的啟用函式沒有使用mish)。

現在可以明白detect類的作用是計算**框的中心座標和高寬,簡單來說就是生成proposal,作為後續nms的輸入,進而輸出最終的檢測框。我覺得在detect類裡定義的1x1卷積是不恰當的,應該把它定義在detect類的外面,緊鄰著detect類之前定義1x1卷積。

在官方**裡,有轉換到onnx檔案的程式: python models/export.py --weights yolov5s.pt --img 640 --batch 1

在pytorch1.7版本裡,程式是能正常執行生成onnx檔案的。觀察export.py裡的**,在執行torch.onnx.export之前,有這麼一段**:

注意其中的for迴圈,我試驗過注釋掉它,重新執行就會出錯,列印出的錯誤如下:

由此可見,這段for迴圈**是必需的。

(2).opencv的dnn模組讀取.onnx檔案做前向計算

在生成.onnx檔案後,就可以用opencv的dnn模組裡的cv2.dnn.readnet讀取它。然而,在讀取時,出現了如下錯誤:

於是檢視yolov5的**,在common.py檔案的focus類,torch.cat的輸入裡有4次切片操作,**如下:

那麼現在需要更換索引式的切片操作,觀察到注釋的contract類,它就是用view和permute函式完成切片操作的,於是修改**如下:

其次,在models\yolo.py裡的detect類裡,也有切片操作,**如下:

前面說過,detect類的作用是計算**框的中心座標和高寬,生成proposal,這個是屬於後處理的,因此不需要把它寫入到onnx檔案裡。

總結一下,按照上面的截圖**,修改focus類,把detect類裡面的1x1卷積定義在緊鄰著detect類之前的外面,然後去掉detect類,組成新的model,作為torch.onnx.export的輸入,

torch.onnx.export(model, inputs, output_onnx, verbose=false, opset_version=12, input_names=['images'], output_names=['out0', 'out1', 'out2'])

最後生成的onnx檔案,opencv的dnn模組就能成功讀取了,接下來對照detect類裡的forward函式,用python或者c++編寫計算**框的中心座標和高寬的功能。

週末這兩天,我在win10+cpu機器裡編寫了用opencv的dnn模組做yolov5目標檢測的程式,包含python和c++兩個版本的。程式都除錯通過了,執行結果也是正確的。我把這套**發布在github上,位址是  

後處理模組,python版本用numpy array實現的,c++版本的用vector和陣列實現的,整套程式只依賴opencv庫(opencv4版本以上的)就能正常執行,徹底擺脫對深度學習框架pytorch,tensorflow,caffe,mxnet等等的依賴。用openvino作目標檢測,需要把onnx檔案轉換到.bin和.xml檔案,相比於用dnn模組載入onnx檔案做目標檢測是多了乙個步驟的。因此,我就想編寫一套用opencv的dnn模組做yolov5目標檢測的程式,用opencv的dnn模組做深度學習目標檢測,在win10和ubuntu,在cpu和gpu上都能執行,可見dnn模組的通用性更好,很接地氣。

OpenCV 3 3 0中DNN模組測試記錄

前言 在移植opencv 3.3.0的過程中發現還有dnn 深層神經網路 模組,順便就在pc上測試了其效能,沒有gpu,所以只有用e3 1230v2 將就試了,從目前的介面上看貌似也不支援gpu加速。1 使用cmake gui設定編譯選項時,記得把build example和dnn相關的都勾選上 2...

用zuul做路由模組

用war包佈署 經常要重啟tomcat而且一旦其中一塊出問題,會導致整個tomcat全部killed 為此改用jar部署,但是這時候,為了都能從80埠進行訪問,就需要加乙個路由模組 這裡只是最很簡單的 不進行負載均衡,所以不需要使用,註冊中心 需要注意的就是部署的時候這些包 zuul ribbon ...

opencv用拉普拉斯運算元做銳化

opencv9 sharpening.cpp 此檔案包含 main 函式。程式執行將在此處開始並結束。include include include using namespace cv using namespace std debug下在lib檔案的名稱後加d,release下不加d。void ...