ubuntu16.04下使用YOLOV3訓練自己做的VOC數據集(VOC數據集製作+模型訓練步驟+訓練參數解析和問題解決+訓練日誌可視化(loss、IOU)+模型測試(單張、攝像頭、批量測試))

                                                                    前序


1、環境配置

  •      請自行參考其他博客
  •      本機環境
    • ubuntu16.04
    • python3
    • 英偉達顯卡驅動:nvidia-396
    • OpenCV3.4.5
    • CUDNN7.0.5
    • CUDA9.0

2、ubuntu16.04下安裝OpenCV

     參考:ubuntu16.04安裝C++版本的OpenCV3.4.5


                                                 一、數據集圖片的標註


1、使用labelImg標註軟件進行數據集中圖像的標註

      參考:LabelImg的詳細使用和圖像標註

2、具體改動的標註步驟

        注:不同的是,我們在標註的時候就讓每張圖片生成的是txt文件,而不是xml文件,這樣就省去了xml轉txt這個步驟

(1)紅色方框處選擇yolo,而非默認的PascalVOC

                                              

 (2)每標註一張圖片點擊保存,就會生成對應的圖片名的txt文件,在保存txt文件夾中也會存在一個所有類別的文件

  • 每個圖片標註後的文件

            

 

  • 類別txt文件                       

                                                                                          

(3)對於每個標註後生成的txt文件,其格式是如下所示

                                

 

 


                                                   

                                                  二、VOC2019數據集的製作 


 1、建立層次文件夾

  •    在下載的YOLOV3代碼目錄下,即darnet-master下建立voc/VOCdevkit/VOC2019層次目錄,自己的建立的數據集爲               VOC2019
  •    然後在VOC2019目錄下建立三個文件夾:Annotations、ImageSets、JPEGImages

         一級:darknet-master

          二級:——backup  (存儲訓練好的模型)

          二級:——cfg  (用於存放.cfg和.data文件)

          二級:——data  (存放標籤文件、圖片、名字文件(.name))

          三級:————data下的目錄 :images(存放圖片和yolo的txt文件,圖片名和txt文本名要對應,但是後面我們在                                                                              JPEGImages中這樣做了,因此此步就做了)          

          三級:————data下的目錄:labels (存放用於opencv回執圖片框的圖片文件)

          二級:——voc      (voc數據集目錄)

          三級:————VOCdevkit

          四級: ——————VOC2019(這個年號可以自行更換,根據自己的需求吧)

          五級:  ————————Annotations (存放使用labelImg軟件標註所有數據集圖片時生成的txt標註文件)

          五級:  ————————ImageSets(用來存放訓練和測試數據的名稱,其裏面存放的是Main文件夾)

          五級:  ———————— labels(存放Annotations中相同的內容)

          六級: ——————————Main(Main文件夾中存放的是4個txt文件,分別是存訓練集圖片名的train.txt、存驗證集圖片                                                                         名的val.txt、存測試集圖片名的test.txt、存測試和驗證集圖片名的trainval.txt,但是                                                                           自己只建了兩個,接下來會說明如何生成的)

           五級: ————————JPEGImages  (用於存放數據集中的圖片,後期還要將labels中的txt全部放到其中

  • 具體目錄層次如下:

             

 

2、一些txt文件的生成 

#####

    前提說明:因爲我們在標註時就已經生成了每個圖片對應的txt文檔,因此我們就不使用darknet-master/scripts下的voc_label.py文件了,而是自己寫腳本生成我們需要的文件。

######

(1)根據JPEGImages中的數據集圖片生成我們需要的ImageSets/Main目錄下的train.txt和val.txt,這兩個文件存的是每個圖片的名字,即.jpg之前的內容

  •  生成如上txt文件的腳本文件make_train_val.py如下
import os
from os import listdir, getcwd
from os.path import join
if __name__ == '__main__':
    source_folder='/*****(自己的路徑)/darknet-master/voc/VOCdevkit/VOC2019/JPEGImages/'#地址是所有圖片的保存地點
    dest='/*****(自己的路徑)/darknet-master/voc/VOCdevkit/VOC2019/ImageSets/Main/train.txt'  #保存train.txt的地址,對於train.txt(在ImageSets/Main/下)和2019_train.txt(在VOCdevkit下)是不同的路徑
    dest2='/*****(自己的路徑)/darknet-master/voc/VOCdevkit/VOC2019/ImageSets/Main/val.txt'  #保存val.txt的地址,對於val.txt(在ImageSets/Main/下)和2019_val.txt(在VOCdevkit下)是不同的路徑
    file_list=os.listdir(source_folder)       #賦值圖片所在文件夾的文件列表
    train_file=open(dest,'a')                 #打開文件
    val_file=open(dest2,'a')                  #打開文件
    for file_obj in file_list:                #訪問文件列表中的每一個文件
        file_path=os.path.join(source_folder,file_obj) 
        #file_path保存每一個文件的完整路徑
        file_name,file_extend=os.path.splitext(file_obj)
        #file_name 保存文件的名字,file_extend保存文件擴展名
        file_num=int(file_name)  
        if(file_num<620):                     #保留620個文件用於訓練
            train_file.write(file_name+'\n')  #用於訓練前620個的圖片路徑保存在train.txt裏面,結尾加回車換行/////////生成train.txt是file_name;生成2019_train.txt是file_path
        else :
            val_file.write(file_name+'\n')    #其餘的文件保存在val.txt裏面/////////生成val.txt是file_name;生成2019_val.txt是file_path
    train_file.close()#關閉文件
val_file.close()
  • 終端運行
python3 make_train_val.py

                    

  • 生成的文件目錄和文件內容如下

 

a)train.txt文件部分內容(保存的是圖片名字)

                                                  

b)val.txt文件中的內容(保存的是圖片名字)

                                                                          

 

(2)在VOCdevkit同級目錄下生成2019_train.txt和2019_val.txt兩個文件,yolo訓練時需要這兩個文件

  •   生成如上txt文件的腳本文件make_2019_train_val.py如下
import os
from os import listdir, getcwd
from os.path import join
if __name__ == '__main__':
    source_folder='/*****(自己的路徑)/darknet-master/voc/VOCdevkit/VOC2019/JPEGImages/'#地址是所有圖片的保存地點
    dest='/*****(自己的路徑)/darknet-master/voc/2019_train.txt'  #保存train.txt的地址,對於train.txt(在ImageSets/Main/下)和2019_train.txt(在VOCdevkit下)是不同的路徑
    dest2='/*****(自己的路徑)/darknet-master/voc/2019_val.txt'  #保存val.txt的地址,對於val.txt(在ImageSets/Main/下)和2019_val.txt(在VOCdevkit下)是不同的路徑
    file_list=os.listdir(source_folder)       #賦值圖片所在文件夾的文件列表
    train_file=open(dest,'a')                 #打開文件
    val_file=open(dest2,'a')                  #打開文件
    for file_obj in file_list:                #訪問文件列表中的每一個文件
        file_path=os.path.join(source_folder,file_obj) 
        #file_path保存每一個文件的完整路徑
        file_name,file_extend=os.path.splitext(file_obj)
        #file_name 保存文件的名字,file_extend保存文件擴展名
        file_num=int(file_name)  
        if(file_num<620):                     #保留620個文件用於訓練
            train_file.write(file_path+'\n')  #用於訓練前620個的圖片路徑保存在train.txt裏面,結尾加回車換行/////////生成train.txt是file_name;生成2019_train.txt是file_path
        else :
            val_file.write(file_path+'\n')    #其餘的文件保存在val.txt裏面/////////生成val.txt是file_name;生成2019_val.txt是file_path
    train_file.close()#關閉文件
val_file.close()
  • 終端運行該.py文件
python3 make_2019_train_val.py
  • 生成的文件目錄下的文件和每個txt文件中的內容如下

 

a)2019_train.txt文件中的部分內容如下(保存絕對路徑)

   

 

b)2019_val.txt文件中的部分內容如下(保存絕對路徑)

       

 

 

3、將Annotations中的txt文件(除了classes外)全部複製到labels中

 如果不在darknet-master/voc/VOCdevkit/VOC2019/下建立labels文件,則會出現以下錯誤,因此一定要這樣做

 

4、將labels中的txt全部複製到JPEGImages文件夾中,做到圖片和txt一一對應

  一開始是要吧JPEGImages文件中的圖片放到darknet-master/data/images目錄下,現在直接把yolo的標籤文件txt即labels中的內容複製到JPEGImages文件夾中就可以了。


 

 

                     三、Imagenet上預訓練權重的下載和yolo一些配置文件的修改


1、下載Imagenet上的預訓練的權重(將下載的權重文件存在darknet-master/scripts目錄下)

  • 方法一:在該文件夾下打開該文件下的終端命令,運行以下命令
wget https://pjreddie.com/media/files/darknet53.conv.74 
  • 方法二:直接在瀏覽器下輸入以下網址,然後彈出該權重的下載界面進行下載
https://pjreddie.com/media/files/darknet53.conv.74 

                                         以上兩種方式哪個快下載用哪種方式

 

2、修改darknet-master/cfg/voc.data文件

文件在:

voc.data修改爲: 

classes= 9 #classes爲訓練樣本集的類別總數,本實驗選的爲9類標籤
train  = /****(自己的路徑自己改)/darknet-master/voc/2019_train.txt  #train的路徑爲訓練樣本集所在的路徑
valid  = /****(自己的路徑自己改)/darknet-master/voc/2019_val.txt #valid的路徑爲驗證樣本集所在的路徑
names = data/voc.names #names的路徑爲data/voc.names文件所在的路徑 
backup = backup

 

3、修改darknet-master/data/voc.names文件,更換默認的類別爲自己的類別,然後保存

文件在:

voc.data修改爲: 

                               

  

4、修改darknet-master/cfg/yolov3-voc.cfg文件,根據自己的情況進行修改

 文件在:

yolov3-voc.cfg修改爲: 

                        Testing註釋掉                                 打開Training

[net]
# Testing
# batch=1        #這裏的batch跟subdivisions原來不是註釋掉的,但是訓練後沒成功,有的blog上說爲1的時候太小難以收斂,但是不知道下面訓練模式的 batch=64 subdivisions=8 會不會覆蓋掉,總之註釋掉後就成功了,不過這個腳本不是很明白,還來不及驗證 
# subdivisions=1
# Training            ### 訓練模式,每次前向的圖片數目 = batch/subdivisions 
batch=64             #根據自己的情況進行修改            
subdivisions=8        #根據自己的情況進行修改
width=416					    ### 網絡的輸入寬、高、通道數
height=416
channels=3
momentum=0.9 					### 動量 
decay=0.0005 					### 權重衰減
angle=0
saturation = 1.5				### 飽和度
exposure = 1.5					### 曝光度 
hue=.1						    ### 色調

learning_rate=0.001				### 學習率 
burn_in=1000					### 學習率控制的參數
max_batches = 50200				### 迭代次數  
policy=steps					### 學習率策略 
steps=40000,45000				### 學習率變動步長 
scales=.1,.1					### 學習率變動因子  

......
......
......


[convolutional]
size=1
stride=1
pad=1
filters=42        #---------------修改爲3*(classes+5)即3*(9+5)=42
activation=linear
[yolo]
mask = 6,7,8
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=9       #---------------修改爲標籤類別個數,9類
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0            #1,如果顯存很小,將random設置爲0,關閉多尺度訓練;(轉自別的blog,還不太明白)
......
[convolutional]
size=1
stride=1
pad=1
filters=42        #---------------修改同上
activation=linear
 
[yolo]
mask = 3,4,5
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=9        #---------------修改同上
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0       
......
[convolutional]
size=1
stride=1
pad=1
filters=42        #---------------修改同上
activation=linear
 
[yolo]
mask = 0,1,2
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=9       #---------------修改同上
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0        

注意:在以上源碼中不要有中文註釋,否則會出錯

解決方法:出現以下錯誤,刪除註釋後可以訓練了

錯誤提示:

##############

   81 Type not recognized: [convolutional]#接下來從此處開始修改
Unused field: 'size = 1'
Unused field: 'stride = 1'
Unused field: 'pad = 1'
Unused field: 'filters = 42#原來是75,現在修改成3*(classes+5)=3*(9+5)=42'
Unused field: 'activation = linear'
   82 Cuda malloc failed
: File exists
darknet: ./src/utils.c:256: error: Assertion `0' failed.
已放棄 (核心已轉儲)

###############

 

 

5、參數詳解

     以下參數是yolov3-voc.cfg參數說明:

  • batch:一批訓練樣本的樣本數量,每batch個樣本更新一次參數
  • subdivisions:將batch分割爲subdivisions個子batch,每個子batch的大小爲batch/subdivisions,作爲一次性送入訓練器的                            樣本數量。
  • A.filters數目是怎麼計算的:3x(classes數目+5),和聚類數目分佈有關,論文中有說明;
  • B.如果想修改默認anchors數值,使用k-means即可
  • C.如果顯存很小,將random設置爲0,即關閉多尺度訓練;

 


        四、YOLOV3的訓練過程、參數調節、問題解決、終止訓練、繼續訓練


1 、在darknet-master終端運行如下代碼進行訓練
 

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg scripts/darknet53.conv.74
 
#注意文件路徑

2、訓練默認的是前1000輪每100輪保存一次模型,1000輪後每10000輪保存一次模型。可以修改examples/detector.c文件的138行。修改完重新編譯一下,在darknet目錄下執行make。

make
  • 文件所在目錄

                           

  • 代碼更改處(根據自己的情況進行修改)

        

 

3、訓練的過程

  • 不保存訓練日誌的訓練執行命令
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg scripts/darknet53.conv.74
  • 保存訓練日誌的訓練執行命令
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg scripts/darknet53.conv.74 | tee train_yolov3-voc.log

 

 

4、訓練日誌參數說明

 

  • Region xx:cfg文件中yolo-layer的索引;
  • Avg IOU: 當前迭代中,預測的box與標註的box的平均交併比,越大越好,期望數值爲1;
  • Class:標註物體的分類準確率,越大越好,期望數值爲1;
  • obj:越大越好,期望數值爲1;
  • No obj:越小越好;
  • .5R:以IOU=0.5爲閾值時候的recall; recall = 檢出的正樣本/實際的正樣本
  • 0.75R:以IOU=0.75爲閾值時候的recall;
  • count:正樣本數目。

 

          

  • 20277: 指示當前訓練的迭代次數
  • 0.38915: 是總體的Loss(損失)
  • 0.42692 avg: 是平均Loss,這個數值應該越低越好,一般來說,一旦這個數值低於0.060730 avg就可以終止訓練了
  • 0.000100 rate: 代表當前的學習率,是在.cfg文件中定義的。
  • 0.302128 seconds: 表示當前批次訓練花費的總時間。
  • 162216 images: 這一行最後的這個數值表示到目前爲止,參與訓練的圖片的總量。

 

 

5、調參中遇到的問題

 

  • 在Region 82 Avg IOU、Region 94 Avg IOU、Region 106 Avg IOU中出現很多nan

前提說明:在訓練過程中,nan的屏幕佔比30%是正常的,如果太大,全是nan,則就是訓練出了問題

解決方法一:在顯存允許的情況下,可以適當增加batch(darknet-master/yolov3-voc.cfg中的batch)的大小(要視自己數據集                          的大小情況來增加batch,不能盲目的改大),這樣能夠一定程度減少nan的出現。

解決方法二:增加數據集的規模。若是對於10類以內的圖片,500張以內的訓練集未必是太少了,因此可以增加數據集,實在不                         行的話就進行數據增強,把數據集擴展到原來的幾倍到幾十倍不等。

 

  • CUDA Error: out of memory darknet: ./src/cuda.c:36: check_error: Assertio `0' failed.

 解決方法:顯存不夠,調小batch,關閉多尺度訓練:random=0.(*************親測有用**************)

 random所在(darknet-master/cfg/yolov3-voc.cfg):

           

 

 

更多問題可以參考此篇大佬的詳解:YOLOV3訓練調參詳解

 

6、訓練結果

  • 在訓練20000步以後可以看到在backup生成如下訓練過程中的權重文件

  • 保存的訓練日誌文件

                                                                                

7、在avg低於0.06以後,如何停止訓練

ubuntu系統下,在訓練終端處,使用ctrl+c終止訓練。

 

8、如何接着上一步停止處的訓練狀態繼續訓練

在終端輸入:

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc.backup

如下: 

 

9、訓練日誌的可視化

   因爲我們在訓練的時候已經保存了訓練日誌,因此我們使用以下python腳本對訓練日誌進行可視化,得到loss變化曲線Avg IOU曲線(Avg IOU是標記的框預測的框重複的部分除以他們的和,這個值越接近1越好)

(1)visualization_train_yolov3-voc_log.py

# -*- coding: utf-8 -*-
# @Func    :yolov3 訓練日誌可視化,把該腳本和日誌文件放在同一目錄下運行。

import pandas as pd
import matplotlib.pyplot as plt
import os

# ==================可能需要修改的地方=====================================#
g_log_path = "train_yolov3-voc.log"  # 此處修改爲你的訓練日誌文件名
# ==========================================================================#

def extract_log(log_file, new_log_file, key_word):
    '''
    :param log_file:日誌文件
    :param new_log_file:挑選出可用信息的日誌文件
    :param key_word:根據關鍵詞提取日誌信息
    :return:
    '''
    with open(log_file, "r") as f:
        with open(new_log_file, "w") as train_log:
            for line in f:
                # 去除多gpu的同步log
                if "Syncing" in line:
                    continue
                # 去除nan log
                if "nan" in line:
                    continue
                if key_word in line:
                    train_log.write(line)
    f.close()
    train_log.close()


def drawAvgLoss(loss_log_path):
    '''
    :param loss_log_path: 提取到的loss日誌信息文件
    :return: 畫loss曲線圖
    '''
    line_cnt = 0
    for count, line in enumerate(open(loss_log_path, "rU")):
        line_cnt += 1
    result = pd.read_csv(loss_log_path, skiprows=[iter_num for iter_num in range(line_cnt) if ((iter_num < 500))],
                         error_bad_lines=False,
                         names=["loss", "avg", "rate", "seconds", "images"])
    result["avg"] = result["avg"].str.split(" ").str.get(1)
    result["avg"] = pd.to_numeric(result["avg"])

    fig = plt.figure(1, figsize=(6, 4))
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(result["avg"].values, label="Avg Loss", color="#ff7043")
    ax.legend(loc="best")
    ax.set_title("Avg Loss Curve")
    ax.set_xlabel("Batches")
    ax.set_ylabel("Avg Loss")


def drawIOU(iou_log_path):
    '''
    :param iou_log_path: 提取到的iou日誌信息文件
    :return: 畫iou曲線圖
    '''
    line_cnt = 0
    for count, line in enumerate(open(iou_log_path, "rU")):
        line_cnt += 1
    result = pd.read_csv(iou_log_path, skiprows=[x for x in range(line_cnt) if (x % 39 != 0 | (x < 5000))],
                         error_bad_lines=False,
                         names=["Region Avg IOU", "Class", "Obj", "No Obj", "Avg Recall", "count"])
    result["Region Avg IOU"] = result["Region Avg IOU"].str.split(": ").str.get(1)

    result["Region Avg IOU"] = pd.to_numeric(result["Region Avg IOU"])

    result_iou = result["Region Avg IOU"].values
    # 平滑iou曲線
    for i in range(len(result_iou) - 1):
        iou = result_iou[i]
        iou_next = result_iou[i + 1]
        if abs(iou - iou_next) > 0.2:
            result_iou[i] = (iou + iou_next) / 2

    fig = plt.figure(2, figsize=(6, 4))
    ax = fig.add_subplot(1, 1, 1)
    ax.plot(result_iou, label="Region Avg IOU", color="#ff7043")
    ax.legend(loc="best")
    ax.set_title("Avg IOU Curve")
    ax.set_xlabel("Batches")
    ax.set_ylabel("Avg IOU")


if __name__ == "__main__":
    loss_log_path = "train_log_loss.txt"
    iou_log_path = "train_log_iou.txt"
    if os.path.exists(g_log_path) is False:
        exit(-1)
    if os.path.exists(loss_log_path) is False:
        extract_log(g_log_path, loss_log_path, "images")
    if os.path.exists(iou_log_path) is False:
        extract_log(g_log_path, iou_log_path, "IOU")
    drawAvgLoss(loss_log_path)
    drawIOU(iou_log_path)
    plt.show()

 

(2) 將上述python腳本文件和訓練日誌放在同一目錄下,打開此目錄下的終端,運行上述.py文件可以得到loss變化曲線和Avg IOU變化曲線。同時,在當前目錄下生成了train_log_iou.txt和train_log_loss.txt文件。

  • loss變化曲線和Avg IOU變化曲線(僅供參考)

 

  •  train_log_iou.txt和train_log_loss.txt文件

 

訓練日誌可視化參考博客: YOLO-V3可視化訓練過程中的參數,繪製loss、IOU、avg Recall等的曲線圖

                                             YOLOv3訓練自己的數據集(3)——小技巧和訓練日誌可視化


 

                                                         五、模型的測試


                        注:測試的時候要更改cfg/yolov3-voc.cfg文件,將Testing啓用,Training禁用

1、單張圖片測試

./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_20000.weights voc/VOCdevkit/VOC2019/JPEGImages/0000629.jpg

 

2、攝像頭實時測試

./darknet detector demo cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_20000.weights

 

                                                              批量測試


測試集:130張圖片


3、批量測試一下,並輸出記錄目標位置信息的txt文件存在darknet/result下,可以使用valid命令

 

./darknet detector valid cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_50000.weights
  • 對於cfg/voc.data爲測試路徑的配置,因此需要根據個人情況進行更改,2019_test.txt裏面的都是絕對路徑

                    

  • 檢測閾值的設定

        在detector.c文件中,validate_detector函數下,有個閾值設置thresh,默認是0.005,根據個人情況進行設置

                          

  • 在darknet文件目錄下打開終端執行上面的命令,可以在darknet/results/目錄下生成9類所對應的測試結果文件,其文件格式爲comp4_det_test_[類名].txt,保存的即爲測試結果
./darknet detector valid cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_50000.weights

           

  • 對於以上每個文件打開如下,按列來看,分別是: 圖像名稱 置信度 xmin ymin xmax ymax 

                    

參考博客


4、針對測試集,批量測試圖片並將測試的圖片顯示結果保存在自定義的文件夾下

 

(1)用下面的代碼替換detector.c文件(example文件夾下)的void test_detector函數此處有三處需要改成自己的路徑

void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh, float hier_thresh, char *outfile, int fullscreen)
{
    list *options = read_data_cfg(datacfg);
    char *name_list = option_find_str(options, "names", "data/names.list");
    char **names = get_labels(name_list);
 
    image **alphabet = load_alphabet();
    network *net = load_network(cfgfile, weightfile, 0);
    set_batch_network(net, 1);
    srand(2222222);
    double time;
    char buff[256];
    char *input = buff;
    float nms=.45;
    int i=0;
    while(1){
        if(filename){
            strncpy(input, filename, 256);
            image im = load_image_color(input,0,0);
            image sized = letterbox_image(im, net->w, net->h);
        //image sized = resize_image(im, net->w, net->h);
        //image sized2 = resize_max(im, net->w);
        //image sized = crop_image(sized2, -((net->w - sized2.w)/2), -((net->h - sized2.h)/2), net->w, net->h);
        //resize_network(net, sized.w, sized.h);
            layer l = net->layers[net->n-1];
 
 
            float *X = sized.data;
            time=what_time_is_it_now();
            network_predict(net, X);
            printf("%s: Predicted in %f seconds.\n", input, what_time_is_it_now()-time);
            int nboxes = 0;
            detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes);
            //printf("%d\n", nboxes);
            //if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);
            if (nms) do_nms_sort(dets, nboxes, l.classes, nms);
                draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);
                free_detections(dets, nboxes);
            if(outfile)
             {
                save_image(im, outfile);
             }
            else{
                save_image(im, "predictions");
#ifdef OPENCV
                cvNamedWindow("predictions", CV_WINDOW_NORMAL); 
                if(fullscreen){
                cvSetWindowProperty("predictions", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
                }
                show_image(im, "predictions");
                cvWaitKey(0);
                cvDestroyAllWindows();
#endif
            }
            free_image(im);
            free_image(sized);
            if (filename) break;
         } 
        else {
            printf("Enter Image Path: ");
            fflush(stdout);
            input = fgets(input, 256, stdin);
            if(!input) return;
            strtok(input, "\n");
   
            list *plist = get_paths(input);
            char **paths = (char **)list_to_array(plist);
             printf("Start Testing!\n");
            int m = plist->size;
            if(access("/home/FENGsl/darknet/data/out",0)==-1)//"/home/FENGsl/darknet/data"修改成自己的路徑
            {
              if (mkdir("/home/FENGsl/darknet/data/out",0777))//"/home/FENGsl/darknet/data"修改成自己的路徑
               {
                 printf("creat file bag failed!!!");
               }
            }
            for(i = 0; i < m; ++i){
             char *path = paths[i];
             image im = load_image_color(path,0,0);
             image sized = letterbox_image(im, net->w, net->h);
        //image sized = resize_image(im, net->w, net->h);
        //image sized2 = resize_max(im, net->w);
        //image sized = crop_image(sized2, -((net->w - sized2.w)/2), -((net->h - sized2.h)/2), net->w, net->h);
        //resize_network(net, sized.w, sized.h);
        layer l = net->layers[net->n-1];
 
 
        float *X = sized.data;
        time=what_time_is_it_now();
        network_predict(net, X);
        printf("Try Very Hard:");
        printf("%s: Predicted in %f seconds.\n", path, what_time_is_it_now()-time);
        int nboxes = 0;
        detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes);
        //printf("%d\n", nboxes);
        //if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);
        if (nms) do_nms_sort(dets, nboxes, l.classes, nms);
        draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);
        free_detections(dets, nboxes);
        if(outfile){
            save_image(im, outfile);
        }
        else{
             
             char b[2048];
            sprintf(b,"/home/FENGsl/darknet/data/out/%s",GetFilename(path));//"/home/FENGsl/darknet/data"修改成自己的路徑
            
            save_image(im, b);
            printf("save %s successfully!\n",GetFilename(path));
#ifdef OPENCV
            cvNamedWindow("predictions", CV_WINDOW_NORMAL); 
            if(fullscreen){
                cvSetWindowProperty("predictions", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
            }
            show_image(im, "predictions");
            cvWaitKey(0);
            cvDestroyAllWindows();
#endif
        }
 
        free_image(im);
        free_image(sized);
        if (filename) break;
        }
      }
    }
}

 

(2)在detector.c文件的最前面加上*GetFilename(char *p)函數(根據自己的情況更改註釋處的內容)

#include "darknet.h"

static int coco_ids[] = {1,2,3,4,5,6,7,8,9,10,11,13,14,15,16,17,18,19,20,21,22,23,24,25,27,28,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,67,70,72,73,74,75,76,77,78,79,80,81,82,84,85,86,87,88,89,90};
 
char *GetFilename(char *p)
{ 
    static char name[20]={""};
    char *q = strrchr(p,'/') + 1;
    strncpy(name,q,7);//注意後面的7,如果你的測試集的圖片的名字字符(不包括後綴)是其他長度,請改爲你需要的長度(官方的默認的長度是6)
    return name;
}

 

(3)在darknet下重新進行make一下

 

注:在make的時候可能會出現如下錯誤

     #ifdef OPENCV cvNamedWindow("predictions", CV_WINDOW_NORMAL); 提示找不到CV_WINDOW_NORMAL的定義? 報錯: error: ‘CV_WINDOW_NORMAL’ undeclared (first use in this function)      

解決方法:

      找到darknet下的Makefile文件將OPENCV=0

 

(4)開始批量測試

  • 在此終端下輸入批量測試的命令
./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_50000.weights 
  • 接下來會讓輸入:Enter Image Path:

        後面輸入你的txt文件路徑(你準備好的所有測試圖片的路徑全部存放在一個txt文件裏),你可以複製voc.data文件裏的valid後面的路徑,就可以了。

  • 批量測試過程

  • 批量測試結果

         在darknet下的data中生成out文件夾,裏面存放的是批量測試後的圖片標註結果


 

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