【自用记录向】YOLOv5模型训练,按进度更新

【自用记录向】YOLOv5模型训练,按进度更新

  • 图像收集
  • 标注文件转换
  • 数据扩增
  • 下载YOLOv5的初始化模型
  • 搭建数据训练集
  • 租用GPU服务器,搭建模型训练
  • 模型推理

图像收集

确定欲研究方向,搜集相关的图片,每种类别大概需要2百张左右。
代码来源:爬取百度图片——详细思路

import requests
import os
import urllib
 
class Spider_baidu_image():
    def __init__(self):
        self.url = 'http://image.baidu.com/search/acjson?'
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.\
            3497.81 Safari/537.36'}
        self.headers_image = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.\
            3497.81 Safari/537.36','Referer':'http://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1557124645631_R&pv=&ic=&nc=1&z=&hd=1&latest=0&copyright=0&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&sid=&word=%E8%83%A1%E6%AD%8C'}
        # self.keyword = '黄瓜幼苗'
        self.keyword = input("请输入搜索图片关键字:")
        self.paginator = int(input("请输入搜索页数,每页30张图片:"))
        # self.paginator = 50
        # print(type(self.keyword),self.paginator)
        # exit()
    def get_param(self):
        """
        获取url请求的参数,存入列表并返回
        :return: 
        """
        keyword = urllib.parse.quote(self.keyword)
        params = []
        for i in range(1,self.paginator+1):
            params.append('tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord={}&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=&hd=1&latest=0©right=0&word={}&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&cg=star&pn={}&rn=30&gsm=78&1557125391211='.format(keyword,keyword,30*i))
        return params
 
    def get_urls(self,params):
        """
        由url参数返回各个url拼接后的响应,存入列表并返回
        :return:
        """
        urls = []
        for i in params:
            urls.append(self.url+i)
        return urls
    def get_image_url(self,urls):
        image_url = []
        for url in urls:
            json_data = requests.get(url,headers = self.headers).json()
            json_data = json_data.get('data')
            for i in json_data:
                if i:
                    image_url.append(i.get('thumbURL'))
        return image_url
    def get_image(self,image_url):
        """
        根据图片url,在本地目录下新建一个以搜索关键字命名的文件夹,然后将每一个图片存入。
        :param image_url: 
        :return: 
        """
        cwd = os.getcwd()
        file_name = os.path.join(cwd,self.keyword)
        if not os.path.exists(self.keyword):
            os.mkdir(file_name)
        for index,url in enumerate(image_url,start=1):
            with open(file_name+'\\{}.jpg'.format(index),'wb') as f:
                f.write(requests.get(url,headers = self.headers_image).content)
            if index != 0 and index % 30 == 0:
                print('{}第{}页下载完成'.format(self.keyword,index/30))
    def __call__(self, *args, **kwargs):
        params = self.get_param()
        urls = self.get_urls(params)
        image_url = self.get_image_url(urls)
        self.get_image(image_url)
 
if __name__ == '__main__':
    spider = Spider_baidu_image()
    spider()
 

标注文件转换

YOLOv5模型要求.txt格式的标注文件,而一般标注出来的文件是.xml格式的标注文件,故需要转换。
代码参考:如何将xml格式转换为yolov5所需的txt格式

#导入的python模块
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
import glob

#分类名
classes = ["cucumber","Hydrocotyle L","Chlorophytum","eggplant","pakchoi","tomato","radish","sundew","majoram","petunia"]
#类名标识name: 黄瓜叶	   轮生香菇草      	吊兰         	茄子     	青菜	    番茄	       萝卜	 茅膏菜	   牛至	     矮牵牛


"""
方法作用:转换标注信息
方法参数:size,box
"""
#size数组含有图片的规格信息
#box数组含有标注框的具体信息
#.xml格式存储的是标注框的左上角坐标(xmin,ymin)和右下角坐标(xmax,ymax)
#.txt格式存储的是标注框在整张图片中的中心点相对坐标(x,y)和相对宽高(w,h)

def convert(size, box):
    dw = 1.0 / size[0]
    dh = 1.0 / size[1]
    x = (box[0] + box[1]) / 2.0
    y = (box[2] + box[3]) / 2.0
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x * dw #中心点相对横坐标
    w = w * dw #中心点相对纵坐标
    y = y * dh #相对宽
    h = h * dh #相对高
    return (x, y, w, h)

"""
方法作用:转换文件格式
方法参数:image_name(图片名)
"""
def convert_annotation(image_name):
    in_file = open('E:/大创项目/格式转换/formatConversion/labels/train_xml/' + image_name[:-3] + 'xml',encoding='utf-8')  # xml文件路径
    out_file = open('E:/大创项目/格式转换/formatConversion/labels/train_txt/' + image_name[:-3] + 'txt', 'w',encoding='utf-8')  # 转换后的txt文件存放路径
    f = in_file
    xml_text = f.read()
    root = ET.fromstring(xml_text)
    f.close()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)

    for obj in root.iter('object'):
        cls = obj.find('name').text
        if cls not in classes:
            print(cls)
            continue
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
             float(xmlbox.find('ymax').text))
        bb = convert((w, h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')


wd = getcwd()

if __name__ == '__main__':

    for image_path in glob.glob("E:/大创项目/格式转换/formatConversion/images/train/*.jpg"):  # 每一张图片都对应一个xml文件这里写xml对应的图片的路径
        image_name = image_path.split('\\')[-1]
        convert_annotation(image_name)

注意:linux路径需改动倒数第二句,改动如下:

image_name = image_path.split('/')[-1]

数据扩增

这部分工作交由其他小伙伴完成了。

下载YOLOv5的初始化模型

1、官网下载(慢):https://github.com/ultralytics/yolov5
2、网盘链接,提取码:tno6

搭建数据训练集

目录结构如下图
【自用记录向】YOLOv5模型训练,按进度更新_第1张图片

images文件夹存放样本图片
labels文件夹存储标注信息
train文件夹需要80%-90%左右的图片或样本,用于模型训练
val文件夹需要10%-20%左右的图片或样本,用于模型验证

1、按照文件结构进行布置

  1. 随机抽取一定比例图片,用作验证集。代码来源
#随机取一定比例的图片存入另一个文件夹的代码
import os, random, shutil
 
def moveFile(fileDir, tarDir):
    pathDir = os.listdir(fileDir)  # 取图片的原始路径
    filenumber = len(pathDir)
    rate = 0.2  # 自定义抽取图片的比例,比方说100张抽10张,那就是0.1
    picknumber = int(filenumber * rate)  # 按照rate比例从文件夹中取一定数量图片
    sample = random.sample(pathDir, picknumber)  # 随机选取picknumber数量的样本图片
    print(sample)
    print(len(sample))
    for name in sample:
        shutil.move(fileDir + name, tarDir + name)
 
 
if __name__ == '__main__':
    fileDir = "C:/KuoZeng/200-至少1种方式组合xml/"  # 源图片文件夹路径
    tarDir = 'C:/KuoZeng/'  # 移动到新的文件夹路径
    moveFile(fileDir, tarDir)
  1. 取出同名标注的代码,由以上代码改造而来
#根据前边所取图片名取出同名标注的代码
import os, random, shutil
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
import glob
 
def moveFile(fileDir, tarDir, image_name):
    pathDir = os.listdir(fileDir)  # 取图片的原始路径
    filenumber = len(pathDir)
   # rate = 0.5  # 自定义抽取图片的比例,比方说100张抽10张,那就是0.1
   # picknumber = int(filenumber * rate)  # 按照rate比例从文件夹中取一定数量图片
   # sample = random.sample(pathDir, picknumber)  # 随机选取picknumber数量的样本图片

    #print(sample)
    #print(len(sample))
    #for name in sample:
    shutil.move(fileDir + image_name[:-3] + 'txt', tarDir + image_name[:-3] + 'txt')
 
 
if __name__ == '__main__':
    fileDir = '/hy-tmp/datasets/demo2/lables/train/'  # 源图片文件夹路径
    tarDir = '/hy-tmp/datasets/demo2/lables/train-2/'  # 移动到新的文件夹路径
    for image_path in glob.glob("/hy-tmp/datasets/demo2/images/train-2/*.jpg"):  # 每一张图片都对应一个xml文件这里写xml对应的图片的路径
        image_name = image_path.split('/')[-1]
        moveFile(fileDir, tarDir, image_name)

注意:Windows路径需改动倒数第二句,改动如下:

image_name = image_path.split('\\')[-1]

2、创建数据集文件demo1.yaml
yaml的书写规范如下:

  1. 冒号: 后跟一个空格
  2. 路径用/ 而不用 \
  3. 以train.py为出发点,上上级别中找datasets文件夹,所以是../
path: ../datasets/demo1 # dataset root dir
#训练图片集路径
train: ../datasets/demo1/images/train  # train images (relative to 'path') 128 images
#验证图片集路径
val: ../datasets/demo1/images/val  # val images (relative to 'path') 128 images
#测试图片集路径
test:  
# test images (optional)
#分类数量:10
nc: 10
#分类名
names: ['cucumber','Hydrocotyle L','Chlorophytum','eggplant','pakchoi','tomato','radish','sundew','majoram','petunia']

3、修改配置模型的yaml文件
进入./yolov5-master/models/
选择欲训练的模型文件,修改nc个数,改成需要识别的分类数量
【自用记录向】YOLOv5模型训练,按进度更新_第2张图片

租用GPU服务器,搭建模型训练

我记录在了另一篇博客中,链接

模型推理

#(单张图)

python detect.py --source  ./data/images/1.jpg --weights ./runs/train/exp3/weights/best.pt  --device 0 --save-txt

#(整个文件夹中的所有图)

python detect1.py --source  ./data/images/ --weights ./runs/train/exp3/weights/best.pt  --device 0 --save-txt

说明:
python detect1.py --source 被推理图片所在路径 --weights 权重文件路径 --device 0 --save-txt
–save-txt可选,命令带有则会生成.txt文件记录推理出的标注框坐标信息等】
推理结果默认被存在:./runs/detect/exp*

【自用记录向】YOLOv5模型训练,按进度更新_第3张图片

参考链接:
1、yolov5 文件函数detect分析
2、yolov5修改detect.py生成新的txt文本
3、python:批量读取图片和批量添加文本

#图片添加文字代码解读
#导入相关模块
import cv2
import os
from PIL import Image,ImageDraw,ImageFont

src_path = /hy-tmp/src/1.jpg #读入的图片路径
des_path = /hy-tmp/des/1.jpg #保存的图片路径
pict=cv2.imread(src_path) #读取图片

font = cv2.FONT_HERSHEY_DUPLEX  # 字体样式
##在图片中添加文字
cv2.putText(pict, addText, (50,50), font,2, (255, 0, 0), 2 )
##putText()参数说明
#1.输入图像
#2.需要添加的文字
#3.左上角坐标
#4.字体类型
#5.字体大小
#6.文字颜色
#7.字体粗细
cv2.waitKey(0)
cv2.imwrite(des_path,pict) #写入

你可能感兴趣的:(深度学习)