最近一直在做图片数据集,积累了很多心得。我把我所使用的python脚本全部拿出来,当然这些脚本大部分网上都有,只不过比较分散。

我已经把所有代码上传到github上,觉得写的好的话,请给我一个star

https://github.com/gzz1529657064/Python-scripts-used-to-make-datasets

由于我的数据集是在拍摄路面的一些物体。因此分为视频和图片两种。视频分辨率1920x1080,帧率为60fps,图片分辨率为1920x1080。光拍摄图片比较慢,拍摄视频获取图片速度很快,毕竟可以将视频分解成帧,这样就可以在短时间内获取大量图片。顺便说一句,录制视频的时候可以缓慢的上下、左右移动镜头,这样得到的图片数据比较丰富。不是那种高度重复的

1. 视频分解为帧 video_to_picture.py

  1. import cv2
  2. vc = cv2.VideoCapture('E:/HDV-2019-5-8/Movie/20190508_0095.MP4')
  3. c=0
  4. rval=vc.isOpened()
  5. timeF = 30
  6. while rval:
  7. c = c + 1
  8. rval, frame = vc.read()
  9. if (c % timeF == 0):
  10. cv2.imwrite('E:/HDV-2019-5-8/digital_light/95/'+str(c).zfill(5) + '.jpg', frame)
  11. cv2.waitKey(1)
  12.  
  13. vc.release()

其中 timeF 表示帧率,你也可以改小一点。一秒中获取2帧到4帧左右;zfill(5):表示图片从00000~99999,数字的位数。如果视频很长,可以把5调大一点。

2. 手动删除不需要的图片

3. 按照VOC数据集的格式。详情请看我上篇博客 : 在Ubuntu内制作自己的VOC数据集

4. 把所有图片放入JPEGImages文件中,后缀名一般为 .jpg .png .JPG。需要批量重命名文件夹中图片文件。使用rename.py

  1. # -*- coding:utf8 -*-
  2.  
  3. import os
  4. class BatchRename():
  5. '''
  6. 批量重命名文件夹中的图片文件
  7. '''
  8. def __init__(self):
  9. self.path = '/home/z/work/train' #存放图片的文件夹路径
  10. def rename(self):
  11. filelist = os.listdir(self.path)
  12. total_num = len(filelist)
  13. i = 1
  14. for item in filelist:
  15. if item.endswith('.jpg') or item.endswith('.JPG'): #图片格式为jpg、JPG
  16.  
  17. src = os.path.join(os.path.abspath(self.path), item)
  18. dst = os.path.join(os.path.abspath(self.path), str(i).zfill(5) + '.jpg') #设置新的图片名称
  19. try:
  20. os.rename(src, dst)
  21. print ("converting %s to %s ..." % (src, dst))
  22. i = i + 1
  23. except:
  24. continue
  25.  
  26. print ("total %d to rename & converted %d jpgs" % (total_num, i))
  27. if __name__ == '__main__':
  28. demo = BatchRename()
  29.  
  30. demo.rename()

只需要修改图片路径、增添图片格式、zfill(5)表示图片名称从00001~99999,可以按照自己的图片数量进行修改。

5. 使用labelImg进行标注。标注是一个非常漫长而又无聊的过程,坚持住!

每个图片都会产生一个xml文件。

6. 检查xml文件。check_annotations.py

  1. import os
  2. def getFilePathList(dirPath, partOfFileName=''):
  3. allFileName_list = list(os.walk(dirPath))[0][2]
  4. fileName_list = [k for k in allFileName_list if partOfFileName in k]
  5. filePath_list = [os.path.join(dirPath, k) for k in fileName_list]
  6. return filePath_list
  7.  
  8. def check_1(dirPath):
  9. jpgFilePath_list = getFilePathList(dirPath, '.jpg')
  10. allFileMarked = True
  11. for jpgFilePath in jpgFilePath_list:
  12. xmlFilePath = jpgFilePath[:-4] + '.xml'
  13. if not os.path.exists(xmlFilePath):
  14. print('%s this picture is not marked.' %jpgFilePath)
  15. allFileMarked = False
  16. if allFileMarked:
  17. print('congratulation! it is been verified that all jpg file are marked.')
  18.  
  19. import xml.etree.ElementTree as ET
  20. def check_2(dirPath, className_list):
  21. className_set = set(className_list)
  22. xmlFilePath_list = getFilePathList(dirPath, '.xml')
  23. allFileCorrect = True
  24. for xmlFilePath in xmlFilePath_list:
  25. with open(xmlFilePath, 'rb') as file:
  26. fileContent = file.read()
  27. root = ET.XML(fileContent)
  28. object_list = root.findall('object')
  29. for object_item in object_list:
  30. name = object_item.find('name')
  31. className = name.text
  32. if className not in className_set:
  33. print('%s this xml file has wrong class name "%s" ' %(xmlFilePath, className))
  34. allFileCorrect = False
  35. if allFileCorrect:
  36. print('congratulation! it is been verified that all xml file are correct.')
  37.  
  38. if __name__ == '__main__':
  39. dirPath = 'Picture/'
  40. className_list = ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]
  41. check_1(dirPath)
  42. check_2(dirPath, className_list)

此时图片和xml在一个文件夹下。文件夹名称为dirPath。

两个功能:1. 是否有图片漏标。2. 标注的类别是否有拼写错误。在className_list中填写正确的所有类别。

如果存在漏标、类别拼写错误,会打印出图片的名称。

7. 如果出现大数量的类别拼写错误。比如:行人(pedestrian)拼写成 pedestrain。可以使用replace_xml_label.py

  1. # coding=utf-8
  2. import os
  3. import os.path
  4. import xml.dom.minidom
  5.  
  6. path = 'Annotations'
  7. files = os.listdir(path)
  8. s = []
  9. for xmlFile in files:
  10. portion = os.path.splitext(xmlFile)
  11. if not os.path.isdir(xmlFile):
  12.  
  13. dom = xml.dom.minidom.parse(os.path.join(path, xmlFile))
  14.  
  15. root = dom.documentElement
  16. name = root.getElementsByTagName('name')
  17.  
  18. for i in range(len(name)):
  19. if name[i].firstChild.data == 'pedestrain':
  20. name[i].firstChild.data = 'pedestrian'
  21. with open(os.path.join(path, xmlFile), 'w', encoding='UTF-8') as fh:
  22. dom.writexml(fh)
  23. print('replace filename OK!')

8. 获取每个类的数目,查看数据是否平衡。 getClasses.py

  1. import os
  2. import xml.etree.ElementTree as ET
  3. import numpy as np
  4.  
  5. np.set_printoptions(suppress=True, threshold=np.nan)
  6. import matplotlib
  7. from PIL import Image
  8.  
  9. def parse_obj(xml_path, filename):
  10. tree = ET.parse(xml_path + filename)
  11. objects = []
  12. for obj in tree.findall('object'):
  13. obj_struct = {}
  14. obj_struct['name'] = obj.find('name').text
  15. objects.append(obj_struct)
  16. return objects
  17.  
  18. def read_image(image_path, filename):
  19. im = Image.open(image_path + filename)
  20. W = im.size[0]
  21. H = im.size[1]
  22. area = W * H
  23. im_info = [W, H, area]
  24. return im_info
  25.  
  26. if __name__ == '__main__':
  27. xml_path = 'Annotations/'
  28. filenamess = os.listdir(xml_path)
  29. filenames = []
  30. for name in filenamess:
  31. name = name.replace('.xml', '')
  32. filenames.append(name)
  33. recs = {}
  34. obs_shape = {}
  35. classnames = []
  36. num_objs = {}
  37. obj_avg = {}
  38. for i, name in enumerate(filenames):
  39. recs[name] = parse_obj(xml_path, name + '.xml')
  40. for name in filenames:
  41. for object in recs[name]:
  42. if object['name'] not in num_objs.keys():
  43. num_objs[object['name']] = 1
  44. else:
  45. num_objs[object['name']] += 1
  46. if object['name'] not in classnames:
  47. classnames.append(object['name'])
  48. for name in classnames:
  49. print('{}:{}个'.format(name, num_objs[name]))
  50. print('信息统计算完毕。')

9. 生成ImageSets\Main文件夹下的4个txt文件:test.txt,train.txt,trainval.txt,val.txt

这四个文件存储的是上一步xml文件的文件名。trainval和test内容相加为所有xml文件,train和val内容相加为trainval。使用CreateTxt.py生成。要将该文件与ImageSets和Annotations放在同一目录下

  1. import os
  2. import random
  3.  
  4. trainval_percent = 0.8 # trainval数据集占所有数据的比例
  5. train_percent = 0.5 # train数据集占trainval数据的比例
  6. xmlfilepath = 'Annotations'
  7. txtsavepath = 'ImageSets/Main'
  8. total_xml = os.listdir(xmlfilepath)
  9.  
  10. num = len(total_xml)
  11. print('total number is ', num)
  12. list = range(num)
  13. tv = int(num * trainval_percent)
  14. print('trainVal number is ', tv)
  15. tr = int(tv * train_percent)
  16. print('train number is ', tr)
  17. print('test number is ', num - tv)
  18. trainval = random.sample(list, tv)
  19. train = random.sample(trainval, tr)
  20.  
  21. ftrainval = open('ImageSets/Main/trainval.txt', 'w')
  22. ftest = open('ImageSets/Main/test.txt', 'w')
  23. ftrain = open('ImageSets/Main/train.txt', 'w')
  24. fval = open('ImageSets/Main/val.txt', 'w')
  25.  
  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. ftrain.write(name)
  32. else:
  33. fval.write(name)
  34. else:
  35. ftest.write(name)
  36.  
  37. ftrainval.close()
  38. ftrain.close()
  39. fval.close()
  40. ftest.close()

10. 将test.txt,train.txt,trainval.txt,val.txt转化为下面这种格式。使用voc_annotation.py

路径 类别名 xmin ymin xmax ymax

例如:

xxx/xxx/a.jpg 0 453 369 473 391 1 588 245 608 268

xxx/xxx/b.jpg 1 466 403 485 422 2 793 300 809 320

  1. import xml.etree.ElementTree as ET
  2. from os import getcwd
  3.  
  4. sets=[('', 'train'), ('', 'val'), ('', 'test'), ('', 'trainval')]
  5.  
  6. classes = ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]
  7.  
  8. def convert_annotation(year, image_id, list_file):
  9. in_file = open('VOCdevkit\VOC%s\Annotations\%s.xml'%(year, image_id), encoding = 'utf-8')
  10. tree=ET.parse(in_file)
  11. root = tree.getroot()
  12.  
  13. for obj in root.iter('object'):
  14. difficult = obj.find('difficult').text
  15. cls = obj.find('name').text
  16. if cls not in classes or int(difficult)==1:
  17. continue
  18. cls_id = classes.index(cls)
  19. xmlbox = obj.find('bndbox')
  20. b = (int(xmlbox.find('xmin').text), int(xmlbox.find('ymin').text), int(xmlbox.find('xmax').text), int(xmlbox.find('ymax').text))
  21. #list_file.write(" " + ",".join([str(a) for a in b]) + ',' + str(cls_id))
  22. list_file.write(" " + str(cls_id) + ' ' + " ".join([str(a) for a in b]))
  23.  
  24. wd = getcwd()
  25.  
  26. for year, image_set in sets:
  27. image_ids = open('VOCdevkit\VOC%s\ImageSets\Main\%s.txt'%(year, image_set)).read().strip().split()
  28. list_file = open('%s_%s.txt'%(year, image_set), 'w')
  29. for image_id in image_ids:
  30. list_file.write('%s\VOCdevkit\VOC%s\JPEGImages\%s.jpg'%(wd, year, image_id))
  31. convert_annotation(year, image_id, list_file)
  32. list_file.write('\n')
  33.  
  34. list_file.close()

同样地在classes里面填写你自己实际的类别。

如果碰到图片输入是这样:路径 xmin ymin xmax ymax 类别名。将代码中标红的部分调换一下顺序即可

  1. list_file.write(" " + " ".join([str(a) for a in b]) + ' ' + str(cls_id))

总结

后面可能还会有将图片制作成 tfrecord文件用于tensorflow训练,lmdb文件用于caffe训练。脚本会继续增加。

从零开始制作数据集所需要的所有python脚本的更多相关文章

  1. 从零开始制作Minecraft启动器(C++开源)

    从零开始制作Minecraft启动器(C++开源) 新手飙车了~~~,MC启动器源码大放送,随心所欲打造自己的专属MC启动器,这不是易语言,是C++...分析原理,关键源码都有详细的注释,代码编好就打 ...

  2. 从零开始制作 Hexo 主题

    原文地址:从零开始制作 Hexo 主题 · Ahonn 写在前面 本文将会从零开始开发一个简单的博客主题.样式主要参考 Hexo theme 中的 Noise 主题. 开始之前你需要了解: 模板引擎  ...

  3. WordPress 主题教程:从零开始制作 WordPress 主题

    为什么要开发WordPress主题? WordPress主题由一系列文件和样式表单组成,这些文件和样式表单共同作用生成WordPress网站的外观.每个主题都不同,用户可以通过这些主题随心所欲地更换自 ...

  4. #3使用html+css+js制作网页 番外篇 使用python flask 框架 (II)

    #3使用html+css+js制作网页 番外篇 使用python flask 框架 II第二部 0. 本系列教程 1. 登录功能准备 a.python中操控mysql b. 安装数据库 c.安装mys ...

  5. #3使用html+css+js制作网页 番外篇 使用python flask 框架 (I)

    #3使用html+css+js制作网页 番外篇 使用python flask 框架(I 第一部) 0. 本系列教程 1. 准备 a.python b. flask c. flask 环境安装 d. f ...

  6. 如何在命令行里运行python脚本

    python是一款应用非常广泛的脚本程序语言,谷歌公司的网页就是用python编写.python在生物信息.统计.网页制作.计算等多个领域都体现出了强大的功能.python和其他脚本语言如java.R ...

  7. WEB中间件--tomcat爆破,burp和python脚本

    1.tomcat 用burpsuit进行弱口令爆破 先抓包 发送到inturder payload type 选择custom iterater 第一个payload选用户名文件,第二个payload ...

  8. ArcGis Python脚本——根据接图表批量裁切分幅影像

    年前写了一个用渔网工具制作图幅接图表的文章,链接在这里: 使用ArcMap做一个1:5000标准分幅图并编号 本文提供一个使用ArcMap利用接图表图斑裁切一幅影像为多幅的方法. 第一步,将接图表拆分 ...

  9. ArcGis Python脚本——要素图斑自动编号,自上而下,从左到右

    原理: 利用图斑最小外包矩形的左上角坐标(数学坐标)Y坐标将序.X坐标升序的方式获取自上而下,从左到右的要素记录排序,然后遍历编号. "!shape.extent.xmin!"计算 ...

随机推荐

  1. (js描述的)数据结构[树结构1.2](12)

    1.先序遍历 2.中序遍历 3.后序遍历 4.递归调用栈详解: 详细见: https://zhuanlan.zhihu.com/p/24291978 5.删除节点操作分析: 5.代码封装 //封装二叉 ...

  2. SQL表的简单操作

    创建数据库表,进行增删改查是我们操作数据库的最基础的操作,很简单,熟悉的请关闭,免得让费时间. 1.创建表: sql中创建数值类型字段要根据该字段值的增长情况选择类型: tinyint 占1个字节,长 ...

  3. easy-mock 本地部署(挤需体验三番钟,里造会干我一样,爱象节款mock)

    前言 很多小伙伴问我怎么在自己公司的项目里面添加配置mock,在vue项目里面都知道怎么配置mock,在大型前端项目里面就一脸疑惑了. 我就回答他,你今天会在vue项目里面用,那天换公司是用angul ...

  4. Tomcat启动过程原理详解 -- 非常的报错:涉及了2个web.xml等文件的加载流程

    Tomcat启动过程原理详解 发表于: Tomcat, Web Server, 旧文存档 | 作者: 谋万世全局者 标签: Tomcat,原理,启动过程,详解 基于Java的Web 应用程序是 ser ...

  5. 小小的锁,大大的疑问?Lock疑问?

    Lock锁 怎么使用?怎么把下面的这个锁弄得比较合适,大家都能去买票?? 和synchronized相比的好处? lock的使用规范try finnally private final Reentra ...

  6. AJ学IOS 之CoreLocation指南针小应用

    AJ分享,必须精品 一:效果图示 简单的用到CoreLocation获取方位做的指南针小应用 二:制作思路 具体用到了CoreLocation相关的知识,请看上一篇博客有写 然后获取方向不需要进行授权 ...

  7. 1个工具,助你提升K8S故障排查效率!

    Kubernetes的故障排查一直困扰众多运维团队或DevOps,除了Kubernetes本身的复杂性之外,还有Kubernetes的工作负载是动态的原因.本文将介绍1个工具可以帮助你可视化K8S的网 ...

  8. [一道蓝鲸安全打卡Web分析] 文件上传引发的二次注入

    蓝鲸打卡的一个 web 文件上传引发二次注入的题解和思考 蓝鲸文件管理系统 源代码地址:http://www.whaledu.com/course/290/task/2848/show 首先在设置文件 ...

  9. mysql参数max_binlog_cache_size设置不当引发的血案

    日常运维中的坑真是防不胜防,不一小心就遇到别人给你挖的坑.最近又遇到经验不足的DBA不知道从哪拷贝的配置文件(据说是当时参加某培训机构视频培训是资料里的模板,真的是误人子弟呀),其中把max_binl ...

  10. 数值计算方法实验之Hermite 多项式插值 (Python 代码)

    一.实验目的 在已知f(x),x∈[a,b]的表达式,但函数值不便计算,或不知f(x),x∈[a,b]而又需要给出其在[a,b]上的值时,按插值原则f(xi)= yi(i= 0,1…….,n)求出简单 ...