3.从labelme格式->VOC格式
前言
标注软件常用的也就LabelImg和Labelme,分别用于目标检测与分割的标注。但是吧,咱不能被工具限制死,公开的是是分割,咱可以转换为检测需要的格式啊。 下面就以labelme的标注文件json为例,生成所要的VOC格式 JPEGImages夹下就是原始图片,Annotions文件夹中是xml格式的标注文件,Main下就是数据集切分的训练验证测试的txt存储对应的文件名
先看下labelme的json格式:
{
"version": "4.5.13",
"flags": {},
"shapes": [
{
"label": "tank",
"points": [
[
1219.6581196581196,
921.3675213675215
],
[
1298.2905982905984,
931.1965811965813
],
[
1337.6068376068376,
939.3162393162394
],
[
1342.3076923076924,
947.0085470085471
],
[
1342.7350427350427,
962.8205128205129
],
[
1389.3162393162395,
971.3675213675215
],
[
1392.3076923076924,
974.7863247863248
],
[
1392.3076923076924,
977.7777777777778
],
[
1344.871794871795,
970.5128205128206
],
[
1342.7350427350427,
1003.8461538461539
],
[
1336.7521367521367,
1004.2735042735044
],
[
1226.923076923077,
985.8974358974359
],
[
1213.2478632478633,
978.6324786324786
]
],
"group_id": null,
"shape_type": "polygon",
"flags": {}
}
],
"imagePath": "1552.jpg",
"imageData": null,
"imageHeight": 1080,
"imageWidth": 1920
}
labelImg的xml格式:
<annotation>
<folder>WH_data</folder>
<filename>1552.jpg</filename>
<source>
<database>WH Data</database>
<annotation>WH</annotation>
<image>flickr</image>
<flickrid>NULL</flickrid>
</source>
<owner>
<flickrid>NULL</flickrid>
<name>WH</name>
</owner>
<size>
<width>1920</width>
<height>1080</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>tank</name>
<pose>Unspecified</pose>
<truncated>1</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>1213</xmin>
<ymin>921</ymin>
<xmax>1392</xmax>
<ymax>1004</ymax>
</bndbox>
</object>
</annotation>
下面我们看一下如何转换吧
labelme2Xml
转换json格式为矩形的xml,然后拷贝原始图片至JPEGImages
labelme2Xml.py # ps:json文件和原始图片在同一个文件夹下
import os
from typing import List, Any
import numpy as np
import codecs
import json
from glob import glob
import cv2
import shutil
from sklearn.model_selection import train_test_split
labelme_path = r"C:\\Users\\fei\Downloads\\json2xml\\tank_zhu\\"
saved_path = "VOC2007/"
isUseTest=True
if not os.path.exists(saved_path + "Annotations"):
os.makedirs(saved_path + "Annotations")
if not os.path.exists(saved_path + "JPEGImages/"):
os.makedirs(saved_path + "JPEGImages/")
if not os.path.exists(saved_path + "ImageSets/Main/"):
os.makedirs(saved_path + "ImageSets/Main/")
files = glob(labelme_path + "*.json")
files = [i.replace("\\","/").split("/")[-1].split(".json")[0] for i in files]
print(files)
for json_file_ in files:
json_filename = labelme_path + json_file_ + ".json"
json_file = json.load(open(json_filename, "r", encoding="utf-8"))
height, width, channels = cv2.imread(labelme_path + json_file_ + ".jpg").shape
with codecs.open(saved_path + "Annotations/" + json_file_ + ".xml", "w", "utf-8") as xml:
xml.write('<annotation>\n')
xml.write('\t<folder>' + 'WH_data' + '</folder>\n')
xml.write('\t<filename>' + json_file_ + ".jpg" + '</filename>\n')
xml.write('\t<source>\n')
xml.write('\t\t<database>WH Data</database>\n')
xml.write('\t\t<annotation>WH</annotation>\n')
xml.write('\t\t<image>flickr</image>\n')
xml.write('\t\t<flickrid>NULL</flickrid>\n')
xml.write('\t</source>\n')
xml.write('\t<owner>\n')
xml.write('\t\t<flickrid>NULL</flickrid>\n')
xml.write('\t\t<name>WH</name>\n')
xml.write('\t</owner>\n')
xml.write('\t<size>\n')
xml.write('\t\t<width>' + str(width) + '</width>\n')
xml.write('\t\t<height>' + str(height) + '</height>\n')
xml.write('\t\t<depth>' + str(channels) + '</depth>\n')
xml.write('\t</size>\n')
xml.write('\t\t<segmented>0</segmented>\n')
for multi in json_file["shapes"]:
points = np.array(multi["points"])
labelName=multi["label"]
xmin = min(points[:, 0])
xmax = max(points[:, 0])
ymin = min(points[:, 1])
ymax = max(points[:, 1])
label = multi["label"]
if xmax <= xmin:
pass
elif ymax <= ymin:
pass
else:
xml.write('\t<object>\n')
xml.write('\t\t<name>' + labelName+ '</name>\n')
xml.write('\t\t<pose>Unspecified</pose>\n')
xml.write('\t\t<truncated>1</truncated>\n')
xml.write('\t\t<difficult>0</difficult>\n')
xml.write('\t\t<bndbox>\n')
xml.write('\t\t\t<xmin>' + str(int(xmin)) + '</xmin>\n')
xml.write('\t\t\t<ymin>' + str(int(ymin)) + '</ymin>\n')
xml.write('\t\t\t<xmax>' + str(int(xmax)) + '</xmax>\n')
xml.write('\t\t\t<ymax>' + str(int(ymax)) + '</ymax>\n')
xml.write('\t\t</bndbox>\n')
xml.write('\t</object>\n')
print(json_filename, xmin, ymin, xmax, ymax, label)
xml.write('</annotation>')
image_files = glob(labelme_path + "*.jpg")
print("copy image files to VOC007/JPEGImages/")
for image in image_files:
shutil.copy(image, saved_path + "JPEGImages/")
训练、验证划分
splitData_labelImg.py
import os
import random
trainval_percent = 1.0
train_percent = 0.8
xmlfilepath = 'VOC2007/Annotations'
txtsavepath = 'VOC2007/ImageSets/Main'
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('VOC2007/ImageSets/Main/trainval.txt', 'w')
ftest = open('VOC2007/ImageSets/Main/test.txt', 'w')
ftrain = open('VOC2007/ImageSets/Main/train.txt', 'w')
fval = open('VOC2007/ImageSets/Main/val.txt', 'w')
for i in list:
if total_xml[i].endswith(".xml"):
print(total_xml[i])
name=total_xml[i][:-4]+'\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftrain.write(name)
else:
fval.write(name)
else:
ftest.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
|