用python3脚本把labelme的json格式文件转png/xml格式文件

拿到手的标注集是json格式的,结果模型训练需要png格式,非常头疼

  • 写在前面
  • json转xml
  • json转png
    • labelme自带的程序labelme_json_to_dataset
    • 批量转换json为png
    • 批量处理图片目录
  • 写在后面

写在前面

个人是在conda的虚拟环境里安装的labelme,Python是3.6版本的,但是3.x应该问题都不大。因为之前没有查到很合适的解决方法,所以自己摸索了半天多才搞完。写个blog给遇到相同问题的hxd快速解决!
我需要png格式文件的模型是TensorFlow2.x+Deeplabv3+的语义分割模型,官方的TF1.x版本好像是需要xml。但是无论如何,拿到手的数据是json也没办法,开整!
ps:labelimg应该是可以直接标记出xml文件的,需要的xd也可以直接用labelimg,安装的时候记得用虚拟环境哦哦!

json转xml

在这个地方走了一点弯路,这个TensorFlow2.x+Deeplabv3+的模型我只是下下来训练过然后跑了demo,并没有仔细去看用于训练的VOC数据集就想当然地以为是xml文件(YOLO用的是xml)。所以我还先完成了json转xml的工作(完全白干)。但是做都做了一定要发上来看看,说不定有人需要呢。
借鉴了这个博主的方法:Labelme标注的json文件转成xml文件(voc2007所需格式)
这个代码还能顺便生成ImageSet文件夹下需要的训练集和测试集文件
代码在这:

#json_to_xml.py

"""
Created on Sun May 31 10:19:23 2020
@author: ywx
"""

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

# 1.标签路径
labelme_path = "./labels/"
# 原始labelme标注数据路径
saved_path = "./VOC2007/"
# 保存路径
isUseTest = True  # 是否创建test集
# 2.创建要求文件夹
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/")
# 3.获取待处理文件
files = glob(labelme_path + "*.json")
files = [i.replace("\\", "/").split("/")[-1].split(".json")[0] for i in files]
print(files)
# 4.读取标注信息并写入 xml
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('./images/' + json_file_ + ".jpg").shape
    with codecs.open(saved_path + "Annotations/" + json_file_ + ".xml", "w", "utf-8") as xml:

        xml.write('\n')
        xml.write('\t' + 'WH_data' + '\n')
        xml.write('\t' + json_file_ + ".jpg" + '\n')
        xml.write('\t\n')
        xml.write('\t\tWH Data\n')
        xml.write('\t\tWH\n')
        xml.write('\t\tflickr\n')
        xml.write('\t\tNULL\n')
        xml.write('\t\n')
        xml.write('\t\n')
        xml.write('\t\tNULL\n')
        xml.write('\t\tWH\n')
        xml.write('\t\n')
        xml.write('\t\n')
        xml.write('\t\t' + str(width) + '\n')
        xml.write('\t\t' + str(height) + '\n')
        xml.write('\t\t' + str(channels) + '\n')
        xml.write('\t\n')
        xml.write('\t\t0\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\n')
                xml.write('\t\t' + labelName + '\n')
                xml.write('\t\tUnspecified\n')
                xml.write('\t\t1\n')
                xml.write('\t\t0\n')
                xml.write('\t\t\n')
                xml.write('\t\t\t' + str(int(xmin)) + '\n')
                xml.write('\t\t\t' + str(int(ymin)) + '\n')
                xml.write('\t\t\t' + str(int(xmax)) + '\n')
                xml.write('\t\t\t' + str(int(ymax)) + '\n')
                xml.write('\t\t\n')
                xml.write('\t\n')
                print(json_filename, xmin, ymin, xmax, ymax, label)
        xml.write('')
# 5.复制图片到 VOC2007/JPEGImages/下
image_files = glob("./images/" + "*.jpg")
print("copy image files to VOC007/JPEGImages/")
for image in image_files:
    shutil.copy(image, saved_path + "JPEGImages/")
# 6.split files for txt
txtsavepath = saved_path + "ImageSets/Main/"
ftrainval = open(txtsavepath + '/trainval.txt', 'w')
ftest = open(txtsavepath + '/test.txt', 'w')
ftrain = open(txtsavepath + '/train.txt', 'w')
fval = open(txtsavepath + '/val.txt', 'w')
total_files = glob("./VOC2007/Annotations/*.xml")
total_files = [i.replace("\\", "/").split("/")[-1].split(".xml")[0] for i in total_files]
trainval_files = []
test_files = []
if isUseTest:
    trainval_files, test_files = train_test_split(total_files, test_size=0.15, random_state=55)
else:
    trainval_files = total_files
for file in trainval_files:
    ftrainval.write(file + "\n")
# split
train_files, val_files = train_test_split(trainval_files, test_size=0.15, random_state=55)
# train
for file in train_files:
    ftrain.write(file + "\n")
# val
for file in val_files:
    fval.write(file + "\n")
for file in test_files:
    print(file)
    ftest.write(file + "\n")
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()

json转png

labelme自带的程序labelme_json_to_dataset

这个自带的程序可以帮你转换单个json文件为png文件,不过我觉得直接使用应该不能满足大部分人的需求,所以在下面写了一个脚本,用来批量处理json文件

批量转换json为png

先把批量处理的代码挂出来:

#json_to_png.py
import os

#	Linux环境下下面这句去掉r
json_folder = r"./labels/"
#  获取文件夹内的文件名
FileNameList = os.listdir(json_folder)
#  激活labelme环境,如果不是用conda虚拟环境来配置的话,就把下面这句备注掉
os.system("activate labelme")
for i in range(len(FileNameList)):
    #  判断当前文件是否为json文件
    if(os.path.splitext(FileNameList[i])[1] == ".json"):
        json_file = json_folder + "\\" + FileNameList[i]
        #  将该json文件转为png
        os.system("labelme_json_to_dataset " + json_file)

在目录下运行python json_to_png.py就可以啦(Linux用python3
这边如果没有使用conda虚拟环境activate labelme的话可能就要把文件放到labelme的文件夹下操作了…因为labelme_json_to_dataset是在labelme文件夹下的exe,如果要用具体路径的话我这里是"~\labelme\Scripts/",这个故事告诉我们,conda真好用!

批量处理图片目录

想象中批量处理之后就会得到一整个文件夹我需要的png图片然后放上服务器快乐训练,事实上…
真的要吐槽一下为什么是exe啊!!!!包装起来的后果就是,它为每一个json文件生成了一整个文件夹,每一个文件夹下面有四个png文件…实际上我只需要这四个中的其中一个,而且目录完全不对。一个一个文件改名然后拖出来的话又费时又无聊。
所以这里我又写了一个脚本,把每个文件夹里的我需要的png批量改名并且挪出来,这样我就可以真的扔去训练了。
把批量改名+换地址的代码放在这:

#change_name.py
import os
import string
import shutil

#	Linux系统的把r去了,改自己的路径, '\'要改成'/'
dst = r'C:\Users\Administrator\Desktop\tobacco0819\labels/'
os.chdir(dst)
files = os.listdir(dst)
for file in files:
	if os.path.isdir(dst + file):
		os.chdir(dst + file)
		new_name = str(file).strip('_json') +'.png'
		#	由需要的文件不一样的记得改原文件的名字
		old_name = 'label.png'
		os.rename(old_name, new_name)
		shutil.move(dst+file+"/"+new_name, dst)
		os.chdir('../')

然后运行python change_name.py(Linux用python3
最后放进模型里训练吧!

写在后面

有什么问题发评论就好,第一次写,之后应该还会更tf,yolo,deeplab的,整一两个系列什么的。有问题可以评论探讨!

你可能感兴趣的:(json,xml,python,计算机视觉,tensorflow)