更新顯卡驅動程式:詳細請參閱【第3天】資料前處理-YOLOv4與自動框選中文字
Visual stutio 2019 與 Microsoft Visual C++ 2015-2019:建議先安裝Visual stutio 2019 與 Microsoft Visual C++ 2015-2019,再安裝CUDA與cuDNN。
2.1 下載:請點擊此處
2.2 安裝:
點擊安裝Visual stutio 2019
勾選使用C++的桌面開發
CUDA與cuDNN:CUDA版本10.1、cuDNN版本7.6,詳細請參閱【第3天】資料前處理-YOLOv4與自動框選中文字
OpenCV:版本4.5.4
4.1 下載:請點擊此處
4.2 安裝並記下安裝路徑
4.3 新增環境變數(系統變數)
OpenDIR:C:\Users\88691\Desktop\YOLOV4\opencv\build
Path:C:\Users\88691\Desktop\YOLOV4\opencv\build\x64\vc15\bin
Cmake:請點擊此處下載
ZED SDK:請點擊此處下載
AlexeyAB/darknet:請點擊此處下載
建立專案
1.1 開啟Visula Studio 2019,點擊建立新的專案。
1.2 點擊空白專案。
1.3 點擊新增項目,並新增C++檔(.cpp),供後續驗證OpenCV是否成功設定。
設定OpenCV路徑
2.1 點擊左下方「屬性管理員」,右鍵點擊release X64,並點選「加入新的屬性專案工作表」。
2.2 設定「屬性專案工作表」
點擊PropertySheet開啟屬性 → VC++目錄 → Include目錄 → 新增下列3個路徑。(上圖編號3)
C:\Users\88691\Desktop\YOLOV4\opencv\build\include
C:\Users\88691\Desktop\YOLOV4\opencv\build\include\opencv
C:\Users\88691\Desktop\YOLOV4\opencv\build\include\opencv2
VC++目錄 → 程式庫目錄 → 新增下列路徑。(上圖編號4)
C:\Users\88691\Desktop\YOLOV4\opencv\build\x64\vc15\lib
※ 注意:Visula Studio 2015選擇vc14;Visula Studio 2017、2019選擇vc15。
連結器 → 輸入 → 其他相依性 → 新增下列路徑。
opencv_world454.lib
驗證OpenCV正常啟用
將待驗證圖片放入Project2
程式碼:在剛剛新增的C++檔(.cpp)中輸入下列程式碼。
//Opencv 僅支援64位元處理器
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main() {
Mat img; //宣告一個儲存影像的矩陣
img = imread("123.jpg"); //讀取影像
if (img.empty())
{
cout << "請確認影像檔路徑正確" << endl;
return -1;
}
imshow("test", img); //印出圖片
waitKey(0);
system("pause");
return 0;
}
執行結果:選取Release與x64,點擊「本機Windows偵錯工具」,成功顯示影像。
2.3 若執行後出現錯誤,解決方法如下。
找不到opencv_world454.lib:
C:\Users\88691\Desktop\YOLOV4\opencv\build\x64\vc15\lib
找不到opencv_world454.dll
C:\Users\88691\Desktop\YOLOV4\opencv\build\x64\vc15\bin
編譯Darknet
3.1 將AlexeyAB/darknet下載的darknet-master.zip解壓縮。
3.2 開啟Cmake並設定路徑
3.3 點擊ConFigure → 輸入x64 → 點擊finish
3.4 若出現Looking for a CUDA compiler – NOTFOUND,解決方法如下。確認是否改善時,記得要重新開啟Cmake,Delete Cache後,再次點擊ConFigure → 輸入x64 → 點擊finish。
重新安裝:先安裝Visual Stutio再安裝CUDA
到控制台 → 新增移除程式 → 查看是否有安裝到NVIDIA Tools Extension SDK(NVTX)
確認路徑中是否存在下列4個檔案,否則將路徑1的檔案複製到路徑2。
路徑1:C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\extras\visual_studio_integration\MSBuildExtensions
路徑2:C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Microsoft\VC\v160\BuildCustomizations
嘗試安裝不同版本的CUDA
3.5 點擊Generate(產出新的Darknet.sln) → Open Project
3.6 生成解決方案:選取Release與x64,點擊建置 → 建置方案
3.7 若生成解決方案時,出現拒絕存取。
點擊方案總管 → 分別點擊滑鼠右鍵建置ALL_BUILD與INSTALL。
3.8 成功生成解方方案後,將 \build\darknet\Release5 中5個檔案複製到 \build\darknet\x64。
執行Darknet訓練模型
4.1 事前準備
按此下載train.rar,並解壓縮成train資料夾。
將資料集放進train下的\VOCdevkit\VOC2021\JPEGImages
將LabelImg標記產生的XML檔,放進train底下\VOCdevkit\VOC2021\Annotations
將train資料夾移到C:\Users\88691\Desktop\YOLOV4\darknet-master\build\darknet\x64
4.2 執行gen_train_val.py:分配訓練集與測試集。
4.3 執行voc_label.py:datasets預處理,標記Train/Test/Val資料集。
4.4 開啟obj.data,將路徑修改成絕對路徑。
4.5 開啟cmd視窗,輸入指令cd C:\Users\88691\Desktop\YOLOV4\darknet-master\build\darknet\x64
4.6 輸入指令darknet detector train C:\Users\88691\Desktop\YOLOV4\darknet-master\build\darknet\x64\train\obj.data C:\Users\88691\Desktop\YOLOV4\darknet-master\build\darknet\x64\train\yolov4-tiny-myobj.cfg C:\Users\88691\Desktop\YOLOV4\darknet-master\build\darknet\x64\train\yolov4-tiny.conv.29 -map
4.7 若執行時出現錯誤,解決方法如下。
找不到 pthreadVC2.dll:
C:\Users\88691\Desktop\YOLOV4\darknet-master\3rdparty\pthreads\bin
複製pthreadVC2.dll。C:\Windows\System32
和C:\Windows\System64
資料夾內。找不到 opencv_world454.dll
C:\Users\88691\Desktop\YOLOV4\opencv\build\x64\vc15\bin
複製opencv_world454.dllC:\Users\88691\Desktop\YOLOV4\darknet-master\build\darknet\x64
資料夾4.8 YOLOV4模型訓練完成
4.9 模型預測
import cv2
import numpy as np
import os
import shutil
#讀取模型與訓練權重
def initNet():
CONFIG = './train_finished_1/yolov4-tiny-myobj.cfg'
WEIGHT = './yolov4-tiny-myobj_last.weights'
# WEIGHT = './train_finished/yolov4-tiny-myobj_last.weights'
net = cv2.dnn.readNet(CONFIG, WEIGHT)
model = cv2.dnn_DetectionModel(net)
model.setInputParams(size=(416, 416), scale=1/255.0)
model.setInputSwapRB(True)
return model
#物件偵測
def nnProcess(image, model):
classes, confs, boxes = model.detect(image, 0.4, 0.1)
return classes, confs, boxes
#框選偵測到的物件,並裁減
def drawBox(image, classes, confs, boxes):
new_image = image.copy()
for (classid, conf, box) in zip(classes, confs, boxes):
x, y, w, h = box
if x - 18 < 0:
x = 18
if y - 18 < 0:
y = 18
cv2.rectangle(new_image, (x - 18, y - 18), (x + w + 20, y + h + 24), (0, 255, 0), 3)
return new_image
# 裁減圖片
def cut_img(image, classes, confs, boxes):
cut_img_list = []
for (classid, conf, box) in zip(classes, confs, boxes):
x, y, w, h = box
if x - 18 < 0:
x = 18
if y - 18 < 0:
y = 18
cut_img = image[y - 18:y + h + 20, x - 18:x + w + 25]
cut_img_list.append(cut_img)
return cut_img_list[0]
# 儲存已完成前處理之圖檔(中文路徑)
def saveClassify(image, output):
cv2.imencode(ext='.jpg', img=image)[1].tofile(output)
if __name__ == '__main__':
source = './public_training_data/public_training_data/'
# source = './public_training_data/public_testing_data/'
files = os.listdir(source)
print('※ 資料夾共有 {} 張圖檔'.format(len(files)))
print('※ 開始執行YOLOV4物件偵測...')
model = initNet()
success = fail = uptwo = 0
number = 1
for file in files:
print(' ▼ 第{}張'.format(number))
img = cv2.imdecode(np.fromfile(source+file, dtype=np.uint8), -1)
classes, confs, boxes = nnProcess(img, model)
if len(boxes) == 0:
# 儲存原始除檔照片
# saveClassify(img, './public_training_data/YOLOV4_pre/fail/' + file)
# saveClassify(img, './test123/fail/' + file)
fail += 1
print(' 字元偵測失敗:{}'.format(file))
# cv2.imshow('img', img)
elif len(boxes) >= 2:
print(' 字元偵測超過2個')
box_img = drawBox(img, classes, confs, boxes)
# saveClassify(box_img, './public_training_data/YOLOV4_pre/uptwo/' + file)
# saveClassify(img, './test123/uptwo/' + file)
# cv2.imshow('img', img)
uptwo += 1
else:
# 框選後圖檔
frame = drawBox(img, classes, confs, boxes)
# 裁剪後圖檔
cut = cut_img(img, classes, confs, boxes)
# 儲存裁剪後圖檔
# saveClassify(cut, './public_training_data/YOLOV4_pre/success/' + file)
# saveClassify(img, './test123/success/' + file)
success += 1
print(' 字元偵測成功:{}'.format(file))
# cv2.imshow('img', frame)
# cv2.imshow('cut', cut)
print('=' * 60)
# cv2.waitKey()
number += 1
print('※ 程式執行完畢')
print('※ 總計:成功 {} 張、失敗 {} 張'.format(success, fail))
print('※ 偵測超過兩個字元組 {} 張'.format(uptwo))
讓我們繼續看下去...