一、使用labelImg标注数据

labelImg已经打包好放在网盘中了

链接:https://pan.baidu.com/s/1gwfB2bsc0ygW2yOH-8t9Tg 提取码:ABCD

下载labelImg后解压得到两个文件,一个是可执行文件labelImg.exe,另一个是存放标签的文件data/predefined_classes.txt

打开labelImg.exe
使用说明:按W会出现光标,按A是前一张照片,按D是后一张照片,使用光标将目标物框住以后,输入标签名字,再保存即可
image.png

open Dir 打开是存放图片的文件夹 change save Dir 是设置标签保存的文件夹 PascalVOC 是修改数据集标签格式(有YOLO和VOC两种)

二、数据集划分

数据集需要按图片和标签划分为训练集和测试集,所以要对图片和标签进行划分,划分结果如下图所示:
image.png

数据集划分主要用到两个代码:make_txt.py和train_val.py,下面已给出完整代码
在数据集划分之前,先新建几个文件夹,把数据集图片保存在images中,数据集标签保存在labels中,文件夹名和路径如下所示:

  • images
    • 存放数据集图片
  • ImageSets
  • labels
    • 存放数据集标签
  • make_txt.py
  • train_val.py

先运行make_txt.py,会在ImageSets文件下生成四个文件test.txt, train.txt, trainval.txt, val.txt,里面存放的是划分好的图片名,如下所示:
image.png

再运行train_val.py ,需要修改的是最后四行中的文件路径,改成自己的数据集文件名,需要修改的部分如下:
image.png

  1. import os #路径处理包
  2. import random #随机数包
  3. trainval_percent = 0.1 #所有数据中测试用数据比例10%
  4. train_percent = 0.9 #训练数据比例90%
  5. #├── train 占90%
  6. #└── trainval 占10%
  7. # ├── test 占90%*10%
  8. # └── val 占10%*10%
  9. xmlfilepath = 'images' #图片所在路径
  10. txtsavepath = 'ImageSets' #生成txt文件路径
  11. total_xml = os.listdir(xmlfilepath)
  12. num = len(total_xml) #所有图片数
  13. list = range(num)
  14. #计算各类数据实际量
  15. tv = int(num * trainval_percent)
  16. tr = int(tv * train_percent)
  17. #随机生成固定个数序列
  18. trainval = random.sample(list, tv) #从所有list中返回tv个数量的项目
  19. train = random.sample(trainval, tr)
  20. if not os.path.exists('ImageSets/'):
  21. os.makedirs('ImageSets/')
  22. ftrainval = open('ImageSets/trainval.txt', 'w')
  23. ftest = open('ImageSets/test.txt', 'w')
  24. ftrain = open('ImageSets/train.txt', 'w')
  25. fval = open('ImageSets/val.txt', 'w')
  26. for i in list:
  27. name = total_xml[i][:-4] + '\n'
  28. if i in trainval:
  29. ftrainval.write(name)
  30. if i in train:
  31. ftest.write(name)
  32. else:
  33. fval.write(name)
  34. else:
  35. ftrain.write(name)
  36. ftrainval.close()
  37. ftrain.close()
  38. fval.close()
  39. ftest.close()
  1. import xml.etree.ElementTree as ET #Python标准库中处理xml的API
  2. import pickle # 可以将对象以文件的形式存放在磁盘上。
  3. import os # 路径处理包
  4. import shutil # python高级文件操作模块(例如复制文件内容,创建文件的新副本并进行归档)
  5. from os import listdir, getcwd
  6. from os.path import join
  7. sets = ['train', 'trainval'] #数据集名称
  8. classes = ['pinecone'] #类别名称
  9. # xyxy -> xywh########################
  10. # 返回值为ROI中心点相对于图片大小的比例坐标,和ROI的w、h相对于图片大小的比例
  11. # box里保存的是ROI感兴趣区域的坐标(xyxy)
  12. def convert(size, box):
  13. dw = 1. / size[0] #浮点数除法则执行精确除法
  14. dh = 1. / size[1]
  15. x = (box[0] + box[1]) / 2.0
  16. y = (box[2] + box[3]) / 2.0
  17. w = box[1] - box[0]
  18. h = box[3] - box[2]
  19. x = x * dw
  20. w = w * dw
  21. y = y * dh
  22. h = h * dh
  23. return (x, y, w, h)
  24. # 对于单个xml的处理
  25. def convert_annotation(image_id):
  26. in_file = open('Annotations/%s.xml' % (image_id))
  27. out_file = open('labels/%s.txt' % (image_id), 'w')
  28. tree = ET.parse(in_file)
  29. root = tree.getroot()
  30. size = root.find('size')
  31. w = int(size.find('width').text)
  32. h = int(size.find('height').text)
  33. for obj in root.iter('object'):
  34. difficult = obj.find('difficult').text
  35. cls = obj.find('name').text
  36. if cls not in classes or int(difficult) == 1:
  37. continue
  38. cls_id = classes.index(cls)
  39. xmlbox = obj.find('bndbox')
  40. b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
  41. float(xmlbox.find('ymax').text))
  42. print(b)
  43. bb = convert((w, h), b) #生成ROI
  44. # print(bb)
  45. out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
  46. #打印当前路径
  47. wd = getcwd()
  48. print(wd)
  49. #遍历所有数据集和类别,对每个数据进行处理并按结构保存
  50. for image_set in sets:
  51. if not os.path.exists('labels/'):
  52. os.makedirs('labels/')
  53. image_ids = open('ImageSets/%s.txt' % (image_set)).read().strip().split()
  54. image_list_file = open('images_%s.txt' % (image_set), 'w')
  55. labels_list_file=open('labels_%s.txt'%(image_set),'w')
  56. for image_id in image_ids:
  57. image_list_file.write('%s.JPG\n' % (image_id))
  58. labels_list_file.write('%s.txt\n'%(image_id))
  59. # convert_annotation(image_id) #如果标签已经是txt格式,将此行注释掉,所有的txt存放到all_labels文件夹。
  60. image_list_file.close()
  61. labels_list_file.close()
  62. #创建yolo训练格式新路径
  63. def copy_file(new_path,path_txt,search_path):#参数1:存放新文件的位置 参数2:为上一步建立好的train,val训练数据的路径txt文件 参数3:为搜索的文件位置
  64. if not os.path.exists(new_path):
  65. os.makedirs(new_path)
  66. with open(path_txt, 'r') as lines:
  67. filenames_to_copy = set(line.rstrip() for line in lines)
  68. # print('filenames_to_copy:',filenames_to_copy)
  69. # print(len(filenames_to_copy))
  70. for root, _, filenames in os.walk(search_path):
  71. # print('root',root)
  72. # print(_)
  73. # print(filenames)
  74. for filename in filenames:
  75. if filename in filenames_to_copy:
  76. shutil.copy(os.path.join(root, filename), new_path)
  77. #按照划分好的训练文件的路径搜索目标,并将其复制到yolo格式下的新路径
  78. copy_file('../VOCdevkit408409/images/train/', './images_train.txt', './images')
  79. copy_file('../VOCdevkit408409/images/val/', './images_trainval.txt', './images')
  80. copy_file('../VOCdevkit408409/labels/train/', './labels_train.txt', './labels')
  81. copy_file('../VOCdevkit408409/labels/val/', './labels_trainval.txt', './labels')