记录一下训练yolov5识别工件,并用c++调用模型的过程
操作系统:Ubuntu18.04
使用网站https://app.roboflow.com/cv-rbynj进行数据标注。
创建一个新的工程,新建好的工程如下图所示
然后上传文件,点击上传好的图片,开始标注,框选出物体,并在左上角的框里写入物体的类别,这里为了识别工件,输入workpiece。
当数据都标注好了,点击左上角的白色返回按钮
然后点击右上角finish uploading
然后可以按照自己的需求进行设置,yolov5一般默认图片尺寸为640*640,所以可以把resize修改一下。这里全部当做训练集到出,后面再从训练集中取出一部分作为测试集
设置完成后点generate
然后点击export导出数据,导出时选择 Pascal VOC格式。
VOC格式下,jpg和xml文件会混在一起,将jpg和xml分到不同的文件夹下,可以使用如下代码:
import os
# from PIL import Image
import shutil
folder = "/home/victor/yolov5/workpiece.v1i.voc/train" #原始的路径
new_path_image = "/home/victor/yolov5/workpiece.v1i.voc/image" #图片路径
new_path_xml = "/home/victor/yolov5/workpiece.v1i.voc/xml" #xml文件路径
for index, i in enumerate(sorted(os.listdir(folder))):
filename1 = os.path.splitext(i)[1] # 读取文件后缀名
filename0 = os.path.splitext(i)[0] # 读取文件名
print(filename1)
# m = filename1 == '.xml'
# print(m)
if filename1 == '.xml':
full_path = os.path.join(folder, i)
despath = os.path.join(new_path_xml, i)
shutil.move(full_path, despath)
elif filename1 == '.jpg':
full_path = os.path.join(folder, i)
despath = os.path.join(new_path_image, i)
shutil.move(full_path, despath)
else:
pass
数据处理主要参考:链接
训练时会报错:AssertionError: train: No labels in /home/robot410/code/yolov5/data/ImageSets/Main/train.cache. Can not train without labels.
类似的错误
然后修改Main.py文件
"""
2021.01.19
author:alian
function: create train.txt and test.txt in ImageSets\Main
"""
import os
import random
trainval_percent = 0.2 # 可自行进行调节(设置训练和测试的比例是8:2)
train_percent = 1
xmlfilepath = 'Annotations'
txtsavepath = 'ImageSets\Main'
total_xml = os.listdir(xmlfilepath)
num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)
#ftrainval = open('ImageSets/Main/trainval.txt', 'w')
ftest = open('ImageSets/Main/test.txt', 'w')
ftrain = open('ImageSets/Main/train.txt', 'w')
#fval = open('ImageSets/Main/val.txt', 'w')
for i in list:
name = total_xml[i][:-4] + '.jpg'+'\n'
if i in trainval:
#ftrainval.write(name)
if i in train:
ftest.write('/home/robot410/code/yolov5/data/images/' + name)
#else:
#fval.write(name)
else:
ftrain.write('/home/robot410/code/yolov5/data/images/' + name)
#ftrainval.close()
ftrain.close()
#fval.close()
ftest.close()
主要是name那得加上+‘.jpg‘,以及ftest.write和ftrain.write要加上绝对路径,使其可以找到正确图像训练和测试路径,再运行一下:
python Main.py
训练命令参考:
python train.py --data data/workpiece.yaml --cfg models/yolov5s.yaml --weights weights/yolov5s.pt --batch-size 16 --epochs 100 --device 0
workpiece.yaml中的内容如下:
# train and val datasets (image directory or *.txt file with image paths)
train: /home/robot410/code/yolov5/data/ImageSets/Main/train.txt # 上一步我们生成的train.txt,根据自己的路径进行更改(建议用全路径)
val: /home/robot410/code/yolov5/data/ImageSets/Main/test.txt # 上一步我们生成的test.txt
#test: ../coco/test-dev2017.txt # 20k images for submission to https://competitions.codalab.org/competitions/20794
# number of classes
nc: 1 # 训练的类别
# class namesdata
names: ['workpiece']
weights选择yolo提供的几种模型中的一个即可。
训练好之后。测试命令参考:
python detect.py --weight /home/robot410/code/yolov5/runs/train/exp10/weights/best.pt --source /home/robot410/code/yolov5/2021-12-1/2021-12-10-16-35/rgb
weight后是训练好的模型的路径,source是测试图片的根目录,文件默认保存在runs/detect下。
C++下的部署主要参考https://github.com/UNeedCryDear/yolov5-opencv-dnn-cpp
适配于yolov5-6.0,这个代码是Windows系统下的代码,环境只依赖opencv,需要4.5及以上版本,这里附上自己的CMakeLists:
cmake_minimum_required(VERSION 2.8)
project(yolo)
IF(NOT CMAKE_BUILD_TYPE)
SET(CMAKE_BUILD_TYPE Release)
ENDIF()
MESSAGE("Build type: " ${CMAKE_BUILD_TYPE})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -march=native ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O3 -march=native")
# Check C++11 or C++0x support
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_definitions(-DCOMPILEDWITHC11)
message(STATUS "Using flag -std=c++11.")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
add_definitions(-DCOMPILEDWITHC0X)
message(STATUS "Using flag -std=c++0x.")
else()
message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake_modules)
set(OpenCV_DIR "/home/robot410/software/opencv-4.5.4/build")
find_package(OpenCV REQUIRED)
#if(NOT OpenCV_FOUND)
# find_package(OpenCV 2.4.3 QUIET)
# if(NOT OpenCV_FOUND)
# message(FATAL_ERROR "OpenCV > 2.4.3 not found.")
# endif()
#endif()
message( ${OpenCV_INCLUDE_DIRS})
message( ${OpenCV_LIBS})
#find_package(Eigen3 3.1.0 REQUIRED)
#find_package(Pangolin REQUIRED)
include_directories(
${PROJECT_SOURCE_DIR}
# ${PROJECT_SOURCE_DIR}/include
# ${EIGEN3_INCLUDE_DIR}
# ${Pangolin_INCLUDE_DIRS}
)
add_library(${PROJECT_NAME} SHARED
yolo.cpp
)
target_link_libraries(${PROJECT_NAME}
${OpenCV_LIBS}
)
add_executable(main
main.cpp)
target_link_libraries(main ${PROJECT_NAME})
需要将yolo训练好的pt模型转换成onnx模型才可以用c++的opencv调用,yolov5中的export.py文件可以直接拿来用,其中的opset需要设置成12(原来默认的是13,在opencv下面会报错),运行代码参考:
python export.py --weights /home/robot410/code/yolov5/runs/train/exp10/weights/best.pt --img 640 --include onnx
onnx模型默认会在pt模型的相同目录下
Ubuntu没有stdafx.h文件,直接把含有#include"stdafx.h"的都注释掉,不影响
修改main.cpp中的模型路径和测试图片路径,这里的测试路径最好用绝对路径,使用原本默认的相对路径会有问题
string img_path = "/home/robot410/code/yolov5/2021-12-1/2021-12-10-16-35/rgb/000066.png";
string model_path = "/home/robot410/yolov5-opencv-dnn-cpp/best.onnx";
yolo.h中的类型需要做相对应的修改:
std::vector<std::string> className = { "workpiece" };
然后对c++文件进行编译
mkdir build
cd build
cmake ..
make
最后运行:
./main
运行效果如下: