YOLOv3训练自己数据集中所用到的代码及命令总结

一. 将数据集整理为VOC2007标准格式所需要的一些代码:

1. 将所有图片重命名为000000.jpg的格式:

import os
path = "/home/Leequens/VOC/VOC2007/JPEG/test/YDXJ0013"
path1 = "/home/Leequens/VOC/VOC2007/JPEG/test/test6" # 生成到新路径中
filelist = os.listdir(path) #该文件夹下所有的文件(包括文件夹)
for file in filelist:   #遍历所有文件
    Olddir=os.path.join(path,file)   #原来的文件路径
    if os.path.isdir(Olddir):   #如果是文件夹则跳过
        continue
    filename=os.path.splitext(file)[0]   #文件名
    filetype=os.path.splitext(file)[1]   #文件扩展名
    Newdir=os.path.join(path1,str(int(filename)+7240).zfill(6)+filetype)  #用字符串函数zfill 以0补全所需位数
    os.rename(Olddir,Newdir)#重命名

2. 根据真值表生成每张图片所对应的xml文件:

# ! /usr/bin/python
# -*- coding:UTF-8 -*-
import os, sys
import glob
from PIL import Image

# VEDAI 图像存储位置
src_img_dir = os.path.abspath('.')+'/G0024173'
# VEDAI 图像的 ground truth 的 txt 文件存放位置
src_xml_dir = os.path.abspath('.')+'/xml/G0024173'


# 遍历目录读取图片
img_Lists = []
def get_img_list(dir_path):
    if os.path.isdir(dir_path):
        for x in os.listdir(dir_path):
            get_img_list(os.path.join(dir_path, x))
    elif os.path.isfile(dir_path) and dir_path.split('.')[-1] == 'jpg':
        img_Lists.append(dir_path)

get_img_list(src_img_dir)
img_Lists.sort(key=lambda x:x[-10:])
# for i in img_Lists:
#     print(i)

# 创建xml文件,存入图片信息
for img_item in img_Lists:
    im = Image.open(img_item)  #打开图片 为了记录图片的长宽数据
    img = os.path.split(img_item)[1].split('.')[0]
    width, height = im.size

    # write in xml file
    # os.mknod(src_xml_dir + '/' + img + '.xml')
    xml_file = open((src_xml_dir + '/' + str(img) + '.xml'), 'w')
    xml_file.write('<annotation>\n')
    xml_file.write('    <folder>VOC2007</folder>\n')
    xml_file.write('    <filename>' + str(img) + '.jpg' + '</filename>\n')
    xml_file.write('    <size>\n')
    xml_file.write('        <width>' + str(width) + '</width>\n')
    xml_file.write('        <height>' + str(height) + '</height>\n')
    xml_file.write('        <depth>3</depth>\n')
    xml_file.write('    </size>\n')
    xml_file.close()

    

# 读取全部信息
txt_file = open('G0024173_chage.txt')

for line in txt_file.readlines():
    gt = line.splitlines()
    # print(gt)
#     gt = txt_file.readline().splitlines()
#     # gt = open(src_txt_dir + '/gt_' + img + '.txt').read().splitlines()

    # write the region of image on xml file
    for img_each_label in gt:
        spt = img_each_label.split(' ')  # 这里如果txt里面是以逗号‘,’隔开的,那么就改为spt = img_each_label.split(',')。

        # 判断是否需要写入xml
        if spt[6] == '0': #因为上次比赛给的真值表第六列是loss,所以需要判断
            # print (gt)

            # 打开相应xml文件,下面具体写入哪一列根据真值表来修改
            # print(spt[5].zfill(6))
            xml_file = open((src_xml_dir + '/' + spt[5].zfill(6) + '.xml'), 'a') 
            xml_file.write('    <object>\n')
            xml_file.write('        <name>' + str(spt[9]) + '</name>\n')
            xml_file.write('        <pose>Unspecified</pose>\n')
            xml_file.write('        <truncated>0</truncated>\n')
            xml_file.write('        <difficult>0</difficult>\n')
            xml_file.write('        <bndbox>\n')
            xml_file.write('            <xmin>' + str(spt[1]) + '</xmin>\n')
            xml_file.write('            <ymin>' + str(spt[2]) + '</ymin>\n')
            xml_file.write('            <xmax>' + str(spt[3]) + '</xmax>\n')
            xml_file.write('            <ymax>' + str(spt[4]) + '</ymax>\n')
            xml_file.write('        </bndbox>\n')
            xml_file.write('    </object>\n')
            xml_file.close()

# 补上结尾,数值自己修改
for i in range(1800,3600): 
    xml_file = open((src_xml_dir + '/' + str(i).zfill(6) + '.xml'), 'a')
    xml_file.write('</annotation>')
    xml_file.close()

二.  一些关于YOLOv3的代码修改:

1. 开始训练命令

  先是合并txt文档

cat 2007_train.txt 2007_val.txt > train.txt

  训练之前要更改voc.data、yolov3-voc.cfg、voc.name、coco.name文件

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74

2. 使YOLOv3批量测试图片并保存到文件夹中。

(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/Leequens/darknet/data/out",0)==-1)//"/home/FENGsl/darknet/data"修改成自己的路径
            {
              if (mkdir("/home/Leequens/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/Leequens/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) 然后在前面添加*GetFilename(char *p)函数

#include"darknet.h"
#include<sys/stat.h>
#include<stdio.h>
#include<time.h>
#include<unistd.h>
#include<sys/types.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,6);
    return name;
}

(3) 重新在darknet下make

(4) 执行下面命令开始测试 (把权重名字修改)

./darknet detector test cfg/voc.data yolov3-voc.cfg weights/yolov3-voc.backup -thresh 0.1

  YOLOv3默认阈值为0.25,-thresh 0是设置阈值,设为0的话可以显示出所有检测结果。

  运行完直接会让你输入 Enter Image Path:

 这里直接输入voc生成好的test文档的绝对路径就可以,里面包含了所有测试集的绝对路径。

3.使YOLOv3输出测试结果保存在txt文档中

./darknet detector valid cfg/voc.data yolov3-voc.cfg weights/yolov3-voc.backup -out detect_result.txt -thresh 0.1

4. 此次目标大赛txt文档格式为 图片id 类id 置信度 4个坐标,需要修改刚刚生成的txt

cat 123.txt | awk '{$7=$6;$6=$5;$5=$4;$4=$3;$3=$2;$2=1; print $0;}' > 123_chage.txt

5. 将生成的几个txt合并到一起

cat 1.txt 2.txt 3.txt > result.txt

6. 对合并到一起的txt按第一列(图片ID)的值进行排序,目的是使同一图的信息罗列在一起

sort -t $'\t' -k1 -n result.txt > 1result.txt # k1指的是第一列

7. 可以通过修改detector.c文件使得完成3-6步骤

  先修改validate_detector中的第二个if语句,直接复制替换

    if(0==strcmp(type, "coco")){
        if(!outfile) outfile = "coco_results";
        snprintf(buff, 1024, "%s/%s.json", prefix, outfile);
        fp = fopen(buff, "w");
        fprintf(fp, "[\n");
        coco = 1;
    } else if(0==strcmp(type, "imagenet")){
        if(!outfile) outfile = "imagenet-detection";
        snprintf(buff, 1024, "%s/%s.txt", prefix, outfile);
        fp = fopen(buff, "w");
        imagenet = 1;
        classes = 200;
    } else {
        if(!outfile) outfile = "comp4_det_test_";
        snprintf(buff, 1024, "%s/%s.txt", prefix, outfile);
        fp = fopen(buff, "w"); 
    }

  再修改validate_detector函数中的语句 print_detector_detections(fps, id, dets, nboxes, classes, w, h); 

  将fps修改为fp:print_detector_detections(fp, id, dets, nboxes, classes, w, h);

  再用下面代码替换 print_detector_detections 函数

void print_detector_detections(FILE *fp, char *id, detection *dets, int total, int classes, int w, int h)
{
    int i, j;
    int nums[4]={1,2,3,4}; #自己class有几类就相应的改掉,这里的1234对应的顺序和voc.name中一样
    for(i = 0; i < total; ++i){
        float xmin = dets[i].bbox.x - dets[i].bbox.w/2. + 1;
        float xmax = dets[i].bbox.x + dets[i].bbox.w/2. + 1;
        float ymin = dets[i].bbox.y - dets[i].bbox.h/2. + 1;
        float ymax = dets[i].bbox.y + dets[i].bbox.h/2. + 1;

        if (xmin < 1) xmin = 1;
        if (ymin < 1) ymin = 1;
        if (xmax > w) xmax = w;
        if (ymax > h) ymax = h;

        for(j = 0; j < classes; ++j){
            if (dets[i].prob[j]) fprintf(fp, "%s %d %f %f %f %f %f\n", id, nums[j], dets[i].prob[j],
                    xmin, ymin, xmax, ymax);
        }
    }
}

  然后重新make,再执行生成txt文档的语句,就可以把所有class的检测结果输出在一个txt文档中。

  PS:make之前记得删除原有的darknet可执行文件

三、处理离线比赛给的xml节点的代码

1. 将xml中的三类object分别替换为1 2 3

import os
import sys
try:
    import xml.etree.cElementTree as ET
except ImportError:
    import xml.etree.ElementTree as ET
path = "/media/leequens/File/YOLO/test/xml/123" #文件夹路径
filelist = os.listdir(path) #读取该文件夹下的所有文件
for file in filelist: #循环每个文件
    filename = os.path.splitext(file)[0]  # 文件名
    filetype = os.path.splitext(file)[1]  # 文件扩展名
    tree = ET.parse('/media/leequens/File/YOLO/test/xml/123/'+str(int(filename)).zfill(6)+'.xml')
    for elem in tree.iter(tag='name'):  # 遍历树中的name节点
        if elem.text == '"scallop"':
            elem.text = '1'
        if elem.text == '"seaurchin"':
            elem.text = '2'
        if elem.text == '"seacucumber"':
            elem.text = '3'
    tree.write('/media/leequens/File/YOLO/test/xml/111/'+str(int(filename)).zfill(6)+'.xml') #修改完毕后写入另一个文件夹中

2. 将比赛官方给的xml中的frame改为自己重命名后的图片名

from xml.etree import ElementTree
import os
path = "/media/leequens/File/YOLO/test/xml/123"
filelist = os.listdir(path)
for file in filelist:
    filename = os.path.splitext(file)[0]  # 文件名
    filetype = os.path.splitext(file)[1]  # 文件扩展名
    xmldoc = ElementTree.parse('/media/leequens/File/YOLO/test/xml/123/'+str(int(filename)).zfill(6)+'.xml')
    node= xmldoc.find('./frame')  # 遍历树中的movie节点
    node.text=str(int(filename)).zfill(6) # 如果需要图片后缀 +'.jpg'
    xmldoc.write('/media/leequens/File/YOLO/test/xml/111/'+str(int(filename)).zfill(6)+'.xml')


3. 修改xml中节点frame为filename

from xml.etree import ElementTree
import os, sys
import glob
from PIL import Image

path = "/media/leequens/File/YOLO/test/xml/11"
filelist = os.listdir(path)
for file in filelist:
    filename = os.path.splitext(file)[0]  # 文件名
    filetype = os.path.splitext(file)[1]  # 文件扩展名
    xmldoc = ElementTree.parse('/media/leequens/File/YOLO/test/xml/rebox/'+str(int(filename)).zfill(6)+'.xml')
    root = xmldoc.getroot()
    for child in root:
        if child.tag == 'frame':
            temp_node = 'filename' # 不懂为啥需要一个临时的变量,直接赋值就不对
            child.tag = temp_node
            break	
    xmldoc.write('/media/leequens/File/YOLO/test/xml/'+str(int(filename)).zfill(6)+'.xml')

4. 给xml增加图片长宽等信息

from xml.dom import minidom, Node
from xml.etree import ElementTree

import os, sys
import glob
from PIL import Image

path = "/media/leequens/File/YOLO/test/xml/xmlwithjpg/1920-1080"
filelist = os.listdir(path)
for file in filelist:
    filename = os.path.splitext(file)[0]  # 文件名
    filetype = os.path.splitext(file)[1]  # 文件扩展名
    xmldoc = ElementTree.parse('/media/leequens/File/YOLO/test/xml/xmlwithjpg/1920-1080/'+str(int(filename)).zfill(6)+'.xml')
    root = xmldoc.getroot()
    folder=ElementTree.Element('folder')
    root.insert(0,folder)
    folder.text='VOC2007'
    size = ElementTree.Element("size")
    root.insert(2,size)
    width =ElementTree.Element('width')
    width.text = '1920'
    size.insert(0,width)
    height =ElementTree.Element('height')
    height.text = '1080'
    size.insert(1,height)
    depth =ElementTree.Element('depth ')
    depth.text = '3'
    size.insert(2,depth )
    xmldoc.write('/media/leequens/File/YOLO/test/xml/perfectxml/'+str(int(filename)).zfill(6)+'.xml')


  数值自己要改,可以用下面代码查看所有图片长宽

# ! /usr/bin/python
# -*- coding:UTF-8 -*-
import os, sys
import glob
from PIL import Image

# VEDAI 图像存储位置
src_img_dir = os.path.abspath('.')+'/2018image'


# 遍历目录读取图片
img_Lists = []
def get_img_list(dir_path):
    if os.path.isdir(dir_path):
        for x in os.listdir(dir_path):
            get_img_list(os.path.join(dir_path, x))
    elif os.path.isfile(dir_path) and dir_path.split('.')[-1] == 'jpg':
        img_Lists.append(dir_path)

get_img_list(src_img_dir)
img_Lists.sort(key=lambda x:x[-10:])

for img_item in img_Lists:
    filename = os.path.splitext(img_item)[0]
    im = Image.open(img_item)  #打开图片 为了记录图片的长宽数据
    img = os.path.split(img_item)[1].split('.')[0]
    width, height = im.size
    print(filename,width,height)

5. 给object加入difficult等节点

from xml.dom import minidom, Node
from xml.etree import ElementTree

import os, sys
import glob
from PIL import Image

path = "/media/leequens/File/YOLO/test/xml/111"
filelist = os.listdir(path)
for file in filelist:
    filename = os.path.splitext(file)[0]  # 文件名
    filetype = os.path.splitext(file)[1]  # 文件扩展名
    xmldoc = ElementTree.parse('/media/leequens/File/YOLO/test/xml/111/'+str(int(filename)).zfill(6)+'.xml')
    root = xmldoc.getroot()
    pose=ElementTree.Element('pose')
    pose.text='Unspecified'
    pose.tail='\n\t'
    truncated = ElementTree.Element('truncated')
    truncated.text='0'
    truncated.tail ='\n\t'
    difficult = ElementTree.Element('difficult')
    difficult.text = '0'
    difficult.tail ='\n\t'
    for node in xmldoc.iter(tag='object'):
    #node = root.find('./object')
    #objec=ElementTree.Element("object")
        node.insert(1,pose)
        node.insert(2,truncated)
        node.insert(3,difficult)
    xmldoc.write('/media/leequens/File/YOLO/test/xml/'+str(int(filename)).zfill(6)+'.xml')


6. 因为测试集是随机分配的,计算mAP时需要提取出测试集所对应的xml文件,测试集的名字都被存储到了test.txt文档里,所以需要编写一个程序把这些xml全部提取出来

import shutil
txt_file= open("111.txt","r",encoding="utf-8",errors="ignore")
while True:
    line = txt_file.readline() #表示一次读取一行
    line=line.strip('\n') # 这里要删除换行符,不然找不到对应文件,头疼
    if not line: #读到数据最后跳出,结束循环。数据的最后也就是读不到数据了,mystr为空的时候
        break
    oldname=u"/media/leequens/File/YOLO/test/xml/111/"+line+".xml" #旧目录
    newname=u"/media/leequens/File/YOLO/test/xml/"+line+".xml" # 新目录
    shutil.copyfile(oldname, newname)

./darknet detector demo cfg/voc.data yolov3-voc.cfg yolov3-voc_20000.weights "http://192.168.254.1:8090/?action=stream"

 

  • 1
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
YOLOv8是一种目标检测算法,它是YOLO(You Only Look Once)系列算法的最新版本。如果你想要训练自己的数据集,可以按照以下步骤进行操作: 1. 数据准备:首先,你需要准备自己的数据集数据集应包含标注好的图像和相应的标签。标签通常以XML或JSON格式存储,并包含每个目标的类别、边界框坐标等信息。 2. 数据预处理:在训练之前,你需要对数据进行预处理。这包括将图像调整为统一的大小、归一化像素值等操作。此外,还可以进行数据增强操作,如随机裁剪、旋转、翻转等,以增加数据的多样性。 3. 配置文件:YOLOv8的训练过程需要一个配置文件来指定网络结构、超参数等信息。你可以根据自己的需求创建一个配置文件,并设置相关参数,如类别数、输入图像大小、学习率、批大小等。 4. 模型训练:使用准备好的数据集和配置文件,可以开始进行模型训练了。你可以使用开源的YOLOv8代码库,如Darknet或PyTorch实现的YOLOv5,根据其提供的训练脚本进行训练。在训练过程,模型会根据输入的数据进行前向传播和反向传播,不断更新网络参数以提高检测性能。 5. 模型评估:在训练完成后,你可以使用测试集对训练好的模型进行评估。评估指标通常包括精确率、召回率、平均精确率均值(mAP)等,用于衡量模型的性能。 6. 模型应用:训练好的YOLOv8模型可以用于目标检测任务。你可以使用该模型对新的图像或视频进行目标检测,并获取目标的类别和位置信息。 希望以上步骤对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值