因为准备训练keras-yolo3,开源代码上给出了voc_annotation.py文件,只要将自己的数据格式处理成PASCAL VOC格式,那么运行voc_annotation.py就可以将自己的数据集处理成模型需要的数据集。

现在我的标注数据格式如下(CSV文件,第一列是文件名,第二列对应bbox):

图片是文件:

不管如何先写一个读写CSV文件的脚本utils.py:

# -*- coding: utf-8 -*-

# @Author : matthew

# @File : utils.py

# @Software: PyCharm

import csv

import os

def read_csv(csv_path, pre_dir):

'''

:param csv_path:csv文件路径

:param pre_dir: 图片数据所在的文件夹

:return:

'''

label_dict = {}

with open(csv_path, "r") as f:

reader = csv.reader(f)

header = True

for line in reader:

# 除去文件头

if header:

header = False

continue

# 处理文件存储路径,当做标签

image_path = os.path.join(pre_dir, line[0])

# 处理后面的bbox

bbox = []

if line[1] is not None and len(line[1].strip()) > 0:

for i in line[1].split(';'):

if i is not None and len(i.strip()) > 0:

bbox.append(list(map(lambda x: round(float(x.strip())), i.split('_'))))

# 添加到label_dict

label_dict.setdefault(image_path, bbox)

return label_dict

def write_csv(result_dict, out_path='out.csv'):

'''

:param result_dict: 只一个图片路径,对应存储相应bbox的list的字典

:param out_path:

:return:

'''

with open(out_path, 'w', newline='') as f:

writer = csv.writer(f)

# 写文件头

writer.writerow(['name', 'coordinate'])

for image in result_dict.keys():

image_name = os.path.split(image)[-1]

bbox = result_dict.get(image, [])

bbox_rs = ';'.join(['_'.join(str(int(id)) for id in i) for i in bbox])

writer.writerow([image_name, bbox_rs])

if __name__ == '__main__':

label_dict = utils.read_csv(csv_path=r'./train_b.csv',

pre_dir=r'/home/matthew/dataset')

write_csv(label_dict)

下面开始正式制作数据集!

第一步:改名

VOC标准数据集中图片名称是“000001.jpg”都为6-9位数字,jpg格式的。

因为是第一次制作,以为这种命名是必须的,我看网上也有不少人说要改名的问题。(制作完毕后,发现这一步是大可不必的,所以想省就省了吧。)

为了规范,还是进行了改名操作。

# -*- coding: utf-8 -*-

# @Author : matthew

# @File : pack2voc.py

# @Software: PyCharm

import os

import utils

def rename_image(label_dict={}, out_file='rename_train_b.csv'):

'''

改文件名的同时,修改标签文件。并存储成新的CSV文件rename_train_b.csv

:param label_dict:

:param out_file:

:return:

'''

new_label_dict = {}

i = 1

with open(out_file, 'w') as f:

for key in label_dict.keys():

if not os.path.isfile(key):

continue

image_name = os.path.split(key)[-1]

new_image_name = '%09d' % i + '.jpg'

i = i + 1

# 改名

new_key = key.replace(image_name, new_image_name)

os.renames(key, new_key)

new_label_dict.setdefault(new_key, label_dict.get(key, []))

utils.write_csv(new_label_dict, out_path=out_file)

return out_file

if __name__ == '__main__':

label_dict = utils.read_csv(csv_path=r'./train_b.csv',

pre_dir=r'/home/matthew/dataset')

rename_image(label_dict)

第二步:建立VOC2007目录

首先了解一下VOC的目录结构:

--VOC2007

--Annotations

--ImageSets

--Main

--Layout

--Segmentation

--JPEGImages

--SegmentationClass

--SegmentationObject

Annotations 中主要存放xml文件,每一个xml对应一张图像,

并且每个xml中存放的是标记的各个目标的位置和类别信息,命名通常与对应的原始图像一样

JPEGImages 自己的原始图像放在JPEGImages文件夹

ImageSets

Layout存放人体部位的数据。(用不上)

Main 存放的是目标识别的数据,主要有test.txt , train.txt, val.txt,

trainval.txt四个文件。

Segmentation存放分割的数据。(用不上)

写了个脚本生成这些文件夹:

def make_voc_dir():

os.makedirs('VOC2007/Annotations')

os.makedirs('VOC2007/ImageSets')

os.makedirs('VOC2007/ImageSets/Main')

os.makedirs('VOC2007/ImageSets/Layout')

os.makedirs('VOC2007/ImageSets/Segmentation')

os.makedirs('VOC2007/JPEGImages')

os.makedirs('VOC2007/SegmentationClass')

os.makedirs('VOC2007/SegmentationObject')

if __name__ == '__main__':

make_voc_dir()

同时,将所有的原始图片文件(这时候已经是命名成这种‘000000001.jpg’)移动到'JPEGImages’目录下。

第三步:生成相应的Annotations目录下的XML文件

首先,一份标准的VOC标注XML,格式如下:

VOC2012

2007_000392.jpg //文件名

//图像来源(不重要)

The VOC2007 Database

PASCAL VOC2007

flickr

//图像尺寸(长宽以及通道数)

500

332

3

1//是否用于分割(在图像物体识别中01无所谓)

//检测到的物体

horse //物体类别

Right //拍摄角度

0 //是否被截断(0表示完整)

0 //目标是否难以识别(0表示容易识别)

//bounding-box(包含左下角和右上角xy坐标)

100

96

355

324

//检测到多个物体

person

Unspecified

0

0

198

58

286

197

我们的主要任务就是将CSV中的每一行数据转换成这种格式,然而网上找到的最多的竟然是一堆matlab的代码。什么鬼?!所以,只好自己动手撸代码。

def save_xml(image_name, bbox, save_dir='./VOC2007/Annotations', width=1609, height=500, channel=3):

'''

将CSV中的一行

000000001.jpg [[1,2,3,4],...]

转化成

000000001.xml

:param image_name:图片名

:param bbox:对应的bbox

:param save_dir:

:param width:这个是图片的宽度,博主使用的数据集是固定的大小的,所以设置默认

:param height:这个是图片的高度,博主使用的数据集是固定的大小的,所以设置默认

:param channel:这个是图片的通道,博主使用的数据集是固定的大小的,所以设置默认

:return:

'''

from lxml.etree import Element, SubElement, tostring

from xml.dom.minidom import parseString

node_root = Element('annotation')

node_folder = SubElement(node_root, 'folder')

node_folder.text = 'JPEGImages'

node_filename = SubElement(node_root, 'filename')

node_filename.text = image_name

node_size = SubElement(node_root, 'size')

node_width = SubElement(node_size, 'width')

node_width.text = '%s' % width

node_height = SubElement(node_size, 'height')

node_height.text = '%s' % height

node_depth = SubElement(node_size, 'depth')

node_depth.text = '%s' % channel

for x, y, w, h in bbox:

left, top, right, bottom = x, y, x + w, y + h

node_object = SubElement(node_root, 'object')

node_name = SubElement(node_object, 'name')

node_name.text = 'car'

node_difficult = SubElement(node_object, 'difficult')

node_difficult.text = '0'

node_bndbox = SubElement(node_object, 'bndbox')

node_xmin = SubElement(node_bndbox, 'xmin')

node_xmin.text = '%s' % left

node_ymin = SubElement(node_bndbox, 'ymin')

node_ymin.text = '%s' % top

node_xmax = SubElement(node_bndbox, 'xmax')

node_xmax.text = '%s' % right

node_ymax = SubElement(node_bndbox, 'ymax')

node_ymax.text = '%s' % bottom

xml = tostring(node_root, pretty_print=True)

dom = parseString(xml)

save_xml = os.path.join(save_dir, image_name.replace('jpg', 'xml'))

with open(save_xml, 'wb') as f:

f.write(xml)

return

def change2xml(label_dict={}):

for image in label_dict.keys():

image_name = os.path.split(image)[-1]

bbox = label_dict.get(image, [])

save_xml(image_name, bbox)

return

if __name__ == '__main__':

# step 2

# make_voc_dir()

# step 3

# label_dict = utils.read_csv(csv_path=r'./train_b.csv',

# pre_dir=r'/home/matthew/dataset')

# rename_image(label_dict)

# step 3

label_dict = utils.read_csv(csv_path=r'./rename_train_b.csv',

pre_dir=r'/home/matthew/VOC2007/JPEGImages')

change2xml(label_dict)

第四步:生成Main目录下的txt文件

这一步很简单,就是生成测试、验证数据集合等等,然后存储成txt文件,网上有博主提供了代码,照搬如下。

建立make_train_val_test_set.py,放在VOC2007目录下,然后运行。

# -*- coding: utf-8 -*-

# @Author : matthew

# @File : make_train_val_test_set.py

# @Software: PyCharm

import os

import random

def _main():

trainval_percent = 0.1

train_percent = 0.9

xmlfilepath = 'Annotations'

total_xml = os.listdir(xmlfilepath)

num = len(total_xml)

list = range(num)

tv = int(num * trainval_percent)

tr = int(tv * train_percent)

trainval = random.sample(list, tv)

train = random.sample(trainval, tr)

ftrainval = open('ImageSets/Main/trainval.txt', 'w')

ftest = open('ImageSets/Main/test.txt', 'w')

ftrain = open('ImageSets/Main/train.txt', 'w')

fval = open('ImageSets/Main/val.txt', 'w')

for i in list:

name = total_xml[i][:-4] + '\n'

if i in trainval:

ftrainval.write(name)

if i in train:

ftest.write(name)

else:

fval.write(name)

else:

ftrain.write(name)

ftrainval.close()

ftrain.close()

fval.close()

ftest.close()

if __name__ == '__main__':

_main()

第五步:运行voc_annotation.py

运行的时候,注意修改这个脚本里面的一些路径和参数。

import xml.etree.ElementTree as ET

from os import getcwd

# 注意这里的‘2007’,也许你的就需要修改

sets=[('2007', 'train'), ('2007', 'val'), ('2007', 'test')]

# 注意类别

classes = ["car"]

def convert_annotation(year, image_id, list_file):

# 注意路径

in_file = open('VOC%s/Annotations/%s.xml'%(year, image_id))

tree=ET.parse(in_file)

root = tree.getroot()

for obj in root.iter('object'):

difficult = obj.find('difficult').text

cls = obj.find('name').text

if cls not in classes or int(difficult)==1:

continue

cls_id = classes.index(cls)

xmlbox = obj.find('bndbox')

b = (int(xmlbox.find('xmin').text), int(xmlbox.find('ymin').text), int(xmlbox.find('xmax').text), int(xmlbox.find('ymax').text))

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

wd = getcwd()

for year, image_set in sets:

# 注意路径

image_ids = open('VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()

list_file = open('%s_%s.txt'%(year, image_set), 'w')

for image_id in image_ids:

# 注意路径

list_file.write('%s/VOC%s/JPEGImages/%s.jpg'%(wd, year, image_id))

convert_annotation(year, image_id, list_file)

list_file.write('\n')

list_file.close()

后记

成功之后,会生成三个文件,像这样

打开看一下:

/home/matthew/VOC2007/JPEGImages/000000160.jpg 186,192,353,349,0 579,286,850,500,0

/home/matthew/VOC2007/JPEGImages/000000162.jpg 403,22,458,60,0 400,245,552,389,0 432,0,459,12,0 926,1,999,15,0

/home/matthew/VOC2007/JPEGImages/000000166.jpg 146,246,340,428,0

呵呵,有没有很失望!!!

原来需要的这种格式的文件:

文件的绝对路径 left,top,right,bottom,类别编号

一开始就知道的话,分分钟的事就可以完成转化,结果折腾了一圈~2333333333333

写博不易,喜欢请打赏。

主要参考

建立自己的voc数据集_一次将自己的数据集制作成PASCAL VOC格式的惨痛经历相关推荐

  1. kitti数据集_超全的3D视觉数据集汇总

    加入极市专业CV交流群,与6000+来自腾讯,华为,百度,北大,清华,中科院等名企名校视觉开发者互动交流!更有机会与李开复老师等大牛群内互动! 同时提供每月大咖直播分享.真实项目需求对接.干货资讯汇总 ...

  2. 立体相机标定数据集_超全的3D视觉数据集汇总

    作者:Tom Hardy Date:2019-12-31 文章来源:超全的3D视觉数据集汇总 1.KITTI数据集 KITTI数据集由德国卡尔斯鲁厄理工学院和丰田美国技术研究院联合创办,是目前国际上最 ...

  3. 齿轮箱数据集_一种旋转机械齿轮箱故障数据集优化方法与流程

    本发明涉及一种旋转机械齿轮箱故障数据集优化方法,具体涉及一种基于遗传算法与支持向量机的旋转机械齿轮箱故障数据集优化方法. 背景技术: 齿轮箱是重要工程领域(如:石化产业.航天.机械制造等)的关键设备之 ...

  4. python创建数据集_使用Python从图像创建数据集以进行人脸识别

    我正在尝试用Python编写人脸识别程序(我将应用k-nn算法进行分类). 首先,我将图像转换为灰度,然后创建了一个长列向量(通过使用Opencv的imagedata函数),该向量具有图像的像素(总共 ...

  5. 数据湖 多维数据集_按汇总分组/多维数据集

    数据湖 多维数据集 时不时地,您会遇到一个使您达到SQL限制的要求. 我们中的许多人可能会早早放弃并使用Java / [或您的语言]计算内容. 相反,使用SQL可能是如此简单快捷. 如果您使用的是高级 ...

  6. ssas报表项目数据集_如何部署SSAS多维数据集

    ssas报表项目数据集 In this article, I'm going to discuss the different ways in which we can deploy SSAS cub ...

  7. 自动驾驶数据集_奥迪推出大型自动驾驶数据集A2D2

    今天奥迪公司的研究人员在发布的论文 A2D2: Audi Autonomous Driving Dataset 中,公布了其大型自动驾驶数据集A2D2,并提供开放下载. 目标为推进计算机视觉.机器学习 ...

  8. 疲劳驾驶数据集_奥迪开放的自动驾驶数据集

    奥迪发了最新的数据集. 4月14日,奥迪公司的研究人员发布了一篇论文A2D2: Audi Autonomous Driving Dataset 中,介绍了其大型自动驾驶数据集A2D2,并提供开放下载. ...

  9. 将dll制作成控件_全国首例将“影视作品”制作成“网络图片集”方式侵权案宣判...

    最早知道"图解电影"是在百度贴吧,以前贴吧会有很多以截取电影主要剧情截图,介绍电影故事梗概的推荐电影形式,目前也有很多短视频平台和视频平台,推出电影主要内容的剪辑片段,那么,以这样 ...

最新文章

  1. HTML5学习笔记三
  2. Java实现前中后序线索化二叉树以及遍历
  3. 用aspiration造句_aspiration
  4. python class函数报错_Python multiprocess pool模块报错pickling error问题解决方法分析
  5. 连续投影算法_中航国画荣获“2020 IAV国际视听嘉年华” 大屏幕投影显示行业三大奖项!...
  6. Linux-Ubantu-常见命令
  7. 标准 mysql 数据库 jdbc 的两种写法 懒汉式 和 饿汉式
  8. 计算机基础应用模拟考试软件,全国计算机等级考试全真训练模拟考试软件一级基础及MS-Office应用...
  9. gateface php,XAMPP下载-Xampp(PHP环境套件)V8.01 官方win版-ucbug软件站
  10. 智能音箱---TAS5754M 音频DSP 到Android
  11. 杀毒奇招:用安全网关消灭蠕虫病毒(转)
  12. Python Windows发出警报声、蜂鸣器、声音报警
  13. 【EMC电磁兼容】01.13——窄带与宽带
  14. 《操作系统》总结四(文件管理)
  15. DASH MPD 文件内容解析
  16. 城市如何缓解交通拥堵
  17. 在知乎发文章基本没流量
  18. 9.1 了解导航窗格
  19. java 未初始化_Java中初始化问题
  20. 项目E-shopping cart记录

热门文章

  1. 陈天奇:我是如何从机器学习小白一步一步成长为你们心目中的大神的
  2. 收藏一波:常用正则表达式公式总结
  3. 互掐了半辈子的两个数学巨头,到最后连单身问题都没解决
  4. 路由器连接帧中继网络的接口是(11),连接双绞线以太网的接口是(12)。 【答案】D B
  5. 收藏 | YOLO系列综述:从V1到V4
  6. 使用Python分析姿态估计数据集COCO的教程
  7. 基于计算机视觉的构件表面缺陷特征提取
  8. 论文标题,这么写才算好!
  9. 使用Python+OpenCV进行图像处理之入门教程
  10. 通过SID查找历史执行的SQL语句