前序
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標註軟件進行數據集中圖像的標註
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文件夾,裏面存放的是批量測試後的圖片標註結果