一文多图搞定制作自己的VOC数据集+使用yolov4训练自己的数据集+封装video测试脚本(基于ubuntu)

制作VOC数据集

目前大多数的神经网络都是采用VOC的数据格式来进行训练的,yolo系列亦是如此。

标注自己的数据集

首先用labelImg生成的是xml格式标记文件
下载
方式一:labelimg下载网站:https://github.com/tzutalin/labelImg
下载后将labelImg-master.zip移动至home主文件夹下解压,得到LabelImg-master文件,打开后如下图所示。
在这里插入图片描述方式二:使用git命令

git clone https://github.com/tzutalin/labelImg

下载后是自动在home目录下解压好的,文件名为LabelImg,里面的内容同上图。
安装方式:



    $ sudo apt-get install pyqt4-dev-tools # 安装PyQt4

    $ sudo pip install lxml # 安装lxml,如果报错,可以试试下面语句

    $ sudo apt-get install python-lxml


然后打开终端,进入LabelImg目录后使用make编译



    cd LabelImg

    make all

使用:在labelImg目录下使用终端执行

python labelImg.py

快捷键:

Ctrl + u 加载目录中的所有图像,鼠标点击Open dir同功能
Ctrl + r 更改默认注释目标目录(xml文件保存的地址)
Ctrl + s 保存
Ctrl + d 复制当前标签和矩形框
space 将当前图像标记为已验证
w 创建一个矩形框
d 下一张图片
a 上一张图片
del 删除选定的矩形框
Ctrl++ 放大
Ctrl-- 缩小
↑→↓← 键盘箭头移动选定的矩形框

整理数据集路径格式

建立文件夹层次为 darknet / data/VOCdevkit / VOC2020,voc2020下面有三个文件夹:
在这里插入图片描述先按照上面格式准备好数据
Annotations是存放标签xml文件
JPEGImage 存放图片
ImageSets 里面新建Main文件夹,在Main下新建3个txt在这里插入图片描述ImageSets/Main 里面txt按行存放着图片名字(只含文件名不带文件名后缀),如:
000001
000002
000003…
生成train.txt的教程:
自己制作数据集,一个类别的图片标记完了需要做成一个train.txt,包含所有的训练图片的名称,实现过程如下:

1、在包含训练图片的文件夹中新建TXT文件。

2、在TXT文件中输入 DIR ./B>train.txt (DIR命令后须有一空格)

3、保存后将后缀名改为BAT。

4、双击该文件即可生成一个train.txt。

5、打开再根据自己要求修改即可(将文件后缀等多余信息删除)。

训练数据集

yolov4:
论文
代码

环境

Ubuntu 18.04
Python3.7
cuda 10
首先把代码下载下来,可以在终端用下面命令下载,也可以直接点击上面代码链接下载。

git clone https://github.com/AlexeyAB/darknet.git

在Linux上编译

make在darknet目录中,由于底层是C++写的,所以要先通过Cmake编译,才能通过python运行。如果需要使用GPU加速,那么得先打开项目里面的makefile文件修改一些参数的值。修改完成之后再通过终端直接make。

GPU=1
CUDNN=1
CUDNN_HALF=1
OPENCV=1
OPENMP=1
LIBSO=1
DEBUG=1

make命令如下:

# cd到darknet-master目录下
make
或者 make -j8

测试一下源权重(所有测试命令可以在.sh文件里查看)

# 测试图片,结果保存在darknet-master/predictions.jpg
./darknet detect cfg/yolov4.cfg yolov4.weights data/dog.jpg

在这里插入图片描述

制作yolov4需要的label以及txt

在上文中VOCdevkit文件中进行以下操作:
这个时候只用voc数据集的格式是不满足我们这里需要的格式。首先打开路径下/home/alex/darknet/scripts/voc_label.py,修改voc_label.py里面的相应内容如下。

7 sets=[('2020', 'train'), ('2020', 'val'), ('2020', 'test')]#改成自己的年份的
8
9 classes = ["0", "1", "2", "3", "4"]#改成自己的类别

给每个路径前面加个data,如下图
在这里插入图片描述在这里插入图片描述修改完了之后,将voc_label.py剪切到在主目录darknet下,并且执行voc_label.py,否则哪些文件会生成在build/darknet//data下面,执行完成后你会看到主目录下的data/目录下会生成几个txt。主目录darknet下的data/VOCdevkit/VOC2020/下面会生成一个label文件夹。

修改配置文件

1.cfg/目录下复制coco.data,并且重命名为obj.data。然后使用修改下面以下内容
在这里插入图片描述2.cfg/目录下复制coco.names,并且重命名为obj.names。改成自己类别的名称
在这里插入图片描述
3.复制cfg/yolov4-custom.cfg,并且重命名为yolo-obj.cfg,同时修改一下内容(batches可以根据自己的修改)
在这里插入图片描述上图中修改width和height为416,修改最大batch迭代多少个数max_batches = 6000,修改steps多久学习率下降一次,一般设置为batch个数的80%和90%。
然后三个classes的地方要修改
在这里插入图片描述
还有三个filters=255的地方要修改成自己的
在这里插入图片描述

开始训练自己的数据集

./darknet detector train cfg/obj.data cfg/yolo-obj.cfg yolov4.conv.137

预测

训练完自己的数据集生成权重后,可以通过一些测试数据来检验权重模型的效果,如下命令通过test.jpg检验了效果:

./darknet detector test ./cfg/yolo-obj.data ./cfg/obj.cfg ./yolo-obj_final.weights data/test.jpg -i 0 -thresh 0.25

封装video测试脚本

将测试video的算法封装成PY文件,打开终端CD到darknet_sanhu,运行如下命令:

python3 darknet_video.py
from ctypes import *
import math
import random
import os
import cv2
import numpy as np
import time
import darknet

def convertBack(x, y, w, h):
    xmin = int(round(x - (w / 2)))
    xmax = int(round(x + (w / 2)))
    ymin = int(round(y - (h / 2)))
    ymax = int(round(y + (h / 2)))
    return xmin, ymin, xmax, ymax
    
def cvDrawBoxes(detections, img):
    color_dict = {
        'bottle': [0, 255, 255], 'plastic_bag': [238, 123, 158], 'leaves_branches': [24, 245, 217], 'float_plants': [224, 119, 227],
        'rubbish': [154, 52, 104]
    }
    count = 0
    for detection in detections:
        x, y, w, h = detection[2][0],\
            detection[2][1],\
            detection[2][2],\
            detection[2][3]
        # name_tag = str(detection[0].decode("ascii"))
        name_tag = str(detection[0])
        for name_key, color_val in color_dict.items():
            if name_key == name_tag:
                color = color_val
                xmin, ymin, xmax, ymax = convertBack(
                    float(x), float(y), float(w), float(h))
                pt1 = (xmin, ymin)
                pt2 = (xmax, ymax)
                cv2.rectangle(img, pt1, pt2, color, 1)
                # python round()参数:返回四舍五入值,小数点位数
                cv2.putText(img,
                            # detection[0].decode() +
                            detection[0] +
                            " [" + str(round(float(detection[1]))) + "% ]",
                            (pt1[0], pt1[1] - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
                            color, 2)
                count += 1
    cv2.putText(img, "Num: %s" % str(count), (25, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, [255, 255, 0], 2)
    return img

netMain = None
# metaMain = None
metaMain = ['bottle', 'plastic_bag', 'leaves_branches', 'float_plants', 'rubbish']
altNames = None


def YOLO():

    global metaMain, netMain, altNames
    configPath = "/home/alex/darknet_sanhu/cfg/yolo-obj.cfg"
    weightPath = "/home/alex/darknet_sanhu/backup/yolo-obj_6000.weights"
    metaPath = "./cfg/obj.data"
    if not os.path.exists(configPath):
        raise ValueError("Invalid config path `" +
                         os.path.abspath(configPath)+"`")
    if not os.path.exists(weightPath):
        raise ValueError("Invalid weight path `" +
                         os.path.abspath(weightPath)+"`")
    if not os.path.exists(metaPath):
        raise ValueError("Invalid data file path `" +
                         os.path.abspath(metaPath)+"`")
    if netMain is None:
        netMain = darknet.load_net_custom(configPath.encode(
            "ascii"), weightPath.encode("ascii"), 0, 1)  # batch size = 1
    if metaMain is None:
        metaMain = darknet.load_meta(metaPath.encode("ascii"))
    if altNames is None:
        try:
            with open(metaPath) as metaFH:
                metaContents = metaFH.read()
                import re
                match = re.search("names *= *(.*)$", metaContents,
                                  re.IGNORECASE | re.MULTILINE)
                if match:
                    result = match.group(1)
                else:
                    result = None
                try:
                    if os.path.exists(result):
                        with open(result) as namesFH:
                            namesList = namesFH.read().strip().split("\n")
                            altNames = [x.strip() for x in namesList]
                except TypeError:
                    pass
        except Exception:
            pass
    cap = cv2.VideoCapture(0)      #摄像头测试
    #cap = cv2.VideoCapture("/home/alex/video/smoke/smoke.mp4") #路径测试
    #cap = cv2.VideoCapture("/home/alex/darknet-master/4.mp4")
    cap.set(3, 1280)
    cap.set(4, 720)
    
    #out = cv2.VideoWriter(
     #   "output.mp4", cv2.VideoWriter_fourcc(*"MJPG"), 10.0,
      #  (darknet.network_width(netMain), darknet.network_height(netMain)))
    out = cv2.VideoWriter(
        "output.avi", cv2.VideoWriter_fourcc('M', 'P', '4', '2'), 10.0,
        (darknet.network_width(netMain), darknet.network_height(netMain)))
    print("Starting the YOLO loop...")

    # Create an image we reuse for each detect
    darknet_image = darknet.make_image(darknet.network_width(netMain),
                                    darknet.network_height(netMain),3)
    while True:
        prev_time = time.time()
        ret, frame_read = cap.read()
        frame_rgb = cv2.cvtColor(frame_read, cv2.COLOR_BGR2RGB)
        frame_resized = cv2.resize(frame_rgb,
                                   (darknet.network_width(netMain),
                                    darknet.network_height(netMain)),
                                   interpolation=cv2.INTER_LINEAR)

        darknet.copy_image_from_bytes(darknet_image,frame_resized.tobytes())

        detections = darknet.detect_image(netMain, metaMain, darknet_image, thresh=0.25)

        for detection in detections:
            x, y, w, h = detection[2][0],\
                detection[2][1],\
                detection[2][2],\
                detection[2][3]
            a=x-207.5
            b=y-207.5
            c=280/h
            print(a,b)
            print("x: %.2f mm y: %.2f mm"%(a*c,b*c))
        image = cvDrawBoxes(detections, frame_resized)
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        print(1/(time.time()-prev_time))
        cv2.imshow('Demo', image)
        cv2.waitKey(3)
    cap.release()
    out.release()

if __name__ == "__main__":
    YOLO()

迁移学习

有时候训练的结果不够满意,或者训练到一半突然终止了,这时候从头开始训练又很费时间,此时我们可以将自己之前保存的权重作为预训练权重。但是直接使用yolo-obj_last.weights会报错。需要做出如下转变。

#首先用第一行代码将yolo-obj_last.weights转化为olo-obj_last.conv.23
./darknet partial cfg/yolo-obj.cfg backup/yolo-obj_last.weights backup/yolo-obj_last.conv.23 23
#第二行将我们刚转化好的yolo-obj_last.conv.23作为预训练权重训练
./darknet detector train cfg/obj.data cfg/yolo-obj.cfg backup/yolo-obj_last.conv.23
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值