赞
踩
#coding:utf-8 import os import glob import json import shutil import numpy as np import xml.etree.ElementTree as ET # 项目根目录下放置data/coco文件夹,里面分别有annotations、train2017、val2017三个文件夹。 # 格式转化前要将xml和图片全部放入annotation文件夹中,train2017、val2017里面为空。 # 转换后生成的json文件会放在根目录下,要把annotations里面的图片和xml文件删除,并把两个json文件放进去, # 并且转换后train2017、val2017里面分别为训练集和验证集对应图片。 path2 = "." START_BOUNDING_BOX_ID = 1 def get(root, name): return root.findall(name) def get_and_check(root, name, length): vars = root.findall(name) if len(vars) == 0: raise NotImplementedError('Can not find %s in %s.'%(name, root.tag)) if length > 0 and len(vars) != length: raise NotImplementedError('The size of %s is supposed to be %d, but is %d.'%(name, length, len(vars))) if length == 1: vars = vars[0] return vars def convert(xml_list, json_file): json_dict = {"images": [], "type": "instances", "annotations": [], "categories": []} categories = pre_define_categories.copy() bnd_id = START_BOUNDING_BOX_ID all_categories = {} for index, line in enumerate(xml_list): # print("Processing %s"%(line)) xml_f = line tree = ET.parse(xml_f) root = tree.getroot() filename = os.path.basename(xml_f)[:-4] + ".jpg" image_id = 20190000001 + index size = get_and_check(root, 'size', 1) width = int(get_and_check(size, 'width', 1).text) height = int(get_and_check(size, 'height', 1).text) image = {'file_name': filename, 'height': height, 'width': width, 'id':image_id} json_dict['images'].append(image) ## Cruuently we do not support segmentation # segmented = get_and_check(root, 'segmented', 1).text # assert segmented == '0' for obj in get(root, 'object'): category = get_and_check(obj, 'name', 1).text if category in all_categories: all_categories[category] += 1 else: all_categories[category] = 1 if category not in categories: if only_care_pre_define_categories: continue new_id = len(categories) + 1 print("[warning] category '{}' not in 'pre_define_categories'({}), create new id: {} automatically".format(category, pre_define_categories, new_id)) categories[category] = new_id category_id = categories[category] bndbox = get_and_check(obj, 'bndbox', 1) xmin = int(float(get_and_check(bndbox, 'xmin', 1).text)) ymin = int(float(get_and_check(bndbox, 'ymin', 1).text)) xmax = int(float(get_and_check(bndbox, 'xmax', 1).text)) ymax = int(float(get_and_check(bndbox, 'ymax', 1).text)) assert(xmax > xmin), "xmax <= xmin, {}".format(line) assert(ymax > ymin), "ymax <= ymin, {}".format(line) o_width = abs(xmax - xmin) o_height = abs(ymax - ymin) ann = {'area': o_width*o_height, 'iscrowd': 0, 'image_id': image_id, 'bbox':[xmin, ymin, o_width, o_height], 'category_id': category_id, 'id': bnd_id, 'ignore': 0, 'segmentation': []} json_dict['annotations'].append(ann) bnd_id = bnd_id + 1 for cate, cid in categories.items(): cat = {'supercategory': 'none', 'id': cid, 'name': cate} json_dict['categories'].append(cat) json_fp = open(json_file, 'w') json_str = json.dumps(json_dict) json_fp.write(json_str) json_fp.close() print("------------create {} done--------------".format(json_file)) print("find {} categories: {} -->>> your pre_define_categories {}: {}".format(len(all_categories), all_categories.keys(), len(pre_define_categories), pre_define_categories.keys())) print("category: id --> {}".format(categories)) print(categories.keys()) print(categories.values()) if __name__ == '__main__': classes = ['person'] #改为你需要检测的类别 pre_define_categories = {} for i, cls in enumerate(classes): pre_define_categories[cls] = i + 1 # pre_define_categories = {'a1': 1, 'a3': 2, 'a6': 3, 'a9': 4, "a10": 5} only_care_pre_define_categories = True # only_care_pre_define_categories = False train_ratio = 0.9 save_json_train = 'instances_train2017.json' save_json_val = 'instances_val2017.json' xml_dir = "data/coco/annotations" xml_list = glob.glob(xml_dir + "/*.xml") xml_list = np.sort(xml_list) np.random.seed(100) np.random.shuffle(xml_list) train_num = int(len(xml_list)*train_ratio) xml_list_train = xml_list[:train_num] xml_list_val = xml_list[train_num:] convert(xml_list_train, save_json_train) convert(xml_list_val, save_json_val) if os.path.exists(path2 + "/annotations"): shutil.rmtree(path2 + "/annotations") os.makedirs(path2 + "/annotations") if os.path.exists(path2 + "/images/train2017"): shutil.rmtree(path2 + "/images/train2017") os.makedirs(path2 + "/images/train2017") if os.path.exists(path2 + "/images/val2017"): shutil.rmtree(path2 +"/images/val2017") os.makedirs(path2 + "/images/val2017") f1 = open("train.txt", "w") for xml in xml_list_train: img = xml[:-4] + ".jpg" f1.write(os.path.basename(xml)[:-4] + "\n") shutil.copyfile(img, path2 + "/data/coco/train2017/" + os.path.basename(img)) f2 = open("val.txt", "w") for xml in xml_list_val: img = xml[:-4] + ".jpg" f2.write(os.path.basename(xml)[:-4] + "\n") shutil.copyfile(img, path2 + "/data/coco/val2017/" + os.path.basename(img)) f1.close() f2.close() print("-------------------------------") print("train number:", len(xml_list_train)) print("val number:", len(xml_list_val))
# coco2voc.py # pip install pycocotools import os import time import json import pandas as pd from tqdm import tqdm from pycocotools.coco import COCO #json文件路径和用于存放xml文件的路径 anno = 'C:/Users/user/Desktop/val/instances_val2017.json' xml_dir = 'C:/Users/user/Desktop/val/xml/' coco = COCO(anno) # 读文件 cats = coco.loadCats(coco.getCatIds()) # 这里loadCats就是coco提供的接口,获取类别 # Create anno dir dttm = time.strftime("%Y%m%d%H%M%S", time.localtime()) def trans_id(category_id): names = [] namesid = [] for i in range(0, len(cats)): names.append(cats[i]['name']) namesid.append(cats[i]['id']) index = namesid.index(category_id) return index def convert(anno,xml_dir): with open(anno, 'r') as load_f: f = json.load(load_f) imgs = f['images'] #json文件的img_id和图片对应关系 imgs列表表示多少张图 cat = f['categories'] df_cate = pd.DataFrame(f['categories']) # json中的类别 df_cate_sort = df_cate.sort_values(["id"], ascending=True) # 按照类别id排序 categories = list(df_cate_sort['name']) # 获取所有类别名称 print('categories = ', categories) df_anno = pd.DataFrame(f['annotations']) # json中的annotation for i in tqdm(range(len(imgs))): # 大循环是images所有图片,Tqdm是可扩展的Python进度条,可以在长循环中添加一个进度提示信息 xml_content = [] file_name = imgs[i]['file_name'] # 通过img_id找到图片的信息 height = imgs[i]['height'] img_id = imgs[i]['id'] width = imgs[i]['width'] version =['"1.0"','"utf-8"'] # xml文件添加属性 xml_content.append("<?xml version=" + version[0] +" "+ "encoding="+ version[1] + "?>") xml_content.append("<annotation>") xml_content.append(" <filename>" + file_name + "</filename>") xml_content.append(" <size>") xml_content.append(" <width>" + str(width) + "</width>") xml_content.append(" <height>" + str(height) + "</height>") xml_content.append(" <depth>"+ "3" + "</depth>") xml_content.append(" </size>") # 通过img_id找到annotations annos = df_anno[df_anno["image_id"].isin([img_id])] # (2,8)表示一张图有两个框 for index, row in annos.iterrows(): # 一张图的所有annotation信息 bbox = row["bbox"] category_id = row["category_id"] cate_name = categories[trans_id(category_id)] # add new object xml_content.append(" <object>") xml_content.append(" <name>" + cate_name + "</name>") xml_content.append(" <truncated>0</truncated>") xml_content.append(" <difficult>0</difficult>") xml_content.append(" <bndbox>") xml_content.append(" <xmin>" + str(int(bbox[0])) + "</xmin>") xml_content.append(" <ymin>" + str(int(bbox[1])) + "</ymin>") xml_content.append(" <xmax>" + str(int(bbox[0] + bbox[2])) + "</xmax>") xml_content.append(" <ymax>" + str(int(bbox[1] + bbox[3])) + "</ymax>") xml_content.append(" </bndbox>") xml_content.append(" </object>") xml_content.append("</annotation>") x = xml_content xml_content = [x[i] for i in range(0, len(x)) if x[i] != "\n"] ### list存入文件 #xml_path = os.path.join(xml_dir, file_name.replace('.xml', '.jpg')) xml_path = os.path.join(xml_dir, file_name.split('j')[0]+'xml') print(xml_path) with open(xml_path, 'w+', encoding="utf8") as f: f.write('\n'.join(xml_content)) xml_content[:] = [] if __name__ == '__main__': convert(anno,xml_dir)
# xml解析包 import xml.etree.ElementTree as ET import pickle import os # os.listdir() 方法用于返回指定的文件夹包含的文件或文件夹的名字的列表 from os import listdir, getcwd from os.path import join from PIL import Image sets = ['train', 'test', 'val'] classes = ['two_wheeler'] #类别 #根目录下设置data文件夹,data下放置Annotations和labels文件夹,Annotations里面为要转换的xml文件,labels用来存放转化好的txt文件。 # 进行归一化操作 def convert(size, box): # size:(原图w,原图h) , box:(xmin,xmax,ymin,ymax) dw = 1./size[0] # 1/w dh = 1./size[1] # 1/h x = (box[0] + box[1])/2.0 # 物体在图中的中心点x坐标 y = (box[2] + box[3])/2.0 # 物体在图中的中心点y坐标 w = box[1] - box[0] # 物体实际像素宽度 h = box[3] - box[2] # 物体实际像素高度 x = x*dw # 物体中心点x的坐标比(相当于 x/原图w) w = w*dw # 物体宽度的宽度比(相当于 w/原图w) y = y*dh # 物体中心点y的坐标比(相当于 y/原图h) h = h*dh # 物体宽度的宽度比(相当于 h/原图h) return (x, y, w, h) # 返回 相对于原图的物体中心点的x坐标比,y坐标比,宽度比,高度比,取值范围[0-1] # year ='2012', 对应图片的id(文件名) def convert_annotation(image_id): ''' 将对应文件名的xml文件转化为label文件,xml文件包含了对应的bunding框以及图片长款大小等信息, 通过对其解析,然后进行归一化最终读到label文件中去,也就是说 一张图片文件对应一个xml文件,然后通过解析和归一化,能够将对应的信息保存到唯一一个label文件中去 labal文件中的格式:calss x y w h 同时,一张图片对应的类别有多个,所以对应的bunding的信息也有多个 ''' # 对应的通过year 找到相应的文件夹,并且打开相应image_id的xml文件,其对应bund文件 in_file = open('data/Annotations/%s.xml' % (image_id), encoding='utf-8') # print(in_file.name) # 准备在对应的image_id 中写入对应的label,分别为 # <object-class> <x> <y> <width> <height> out_file = open('data/labels/%s.txt' % (image_id), 'w', encoding='utf-8') # print(out_file.name) # 解析xml文件 tree = ET.parse(in_file) # 获得对应的键值对 root = tree.getroot() # 获得图片的尺寸大小 size = root.find('size') # 获得宽 w = int(size.find('width').text) # 获得高 h = int(size.find('height').text) # 遍历目标obj for obj in root.iter('object'): # 获得difficult ?? difficult = obj.find('difficult').text # 获得类别 =string 类型 cls = obj.find('name').text # 如果类别不是对应在我们预定好的class文件中,或difficult==1则跳过 if cls not in classes or int(difficult) == 1: continue # 通过类别名称找到id cls_id = classes.index(cls) # 找到bndbox 对象 xmlbox = obj.find('bndbox') # 获取对应的bndbox的数组 = ['xmin','xmax','ymin','ymax'] b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text)) print(image_id, cls, b) # 带入进行归一化操作 # w = 宽, h = 高, b= bndbox的数组 = ['xmin','xmax','ymin','ymax'] bb = convert((w, h), b) # bb 对应的是归一化后的(x,y,w,h) # 生成 calss x y w h 在label文件中 out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') # 返回当前工作目录 wd = getcwd() print(wd) for image_set in sets: ''' 对所有的文件数据集进行遍历 做了两个工作: 1.讲所有图片文件都遍历一遍,并且将其所有的全路径都写在对应的txt文件中去,方便定位 2.同时对所有的图片文件进行解析和转化,将其对应的bundingbox 以及类别的信息全部解析写到label 文件中去 最后再通过直接读取文件,就能找到对应的label 信息 ''' # 先找labels文件夹如果不存在则创建 if not os.path.exists('data/labels/'): os.makedirs('data/labels/') # 读取在ImageSets/Main 中的train、test..等文件的内容 # 包含对应的文件名称 image_ids = open('data/ImageSets/%s.txt' % (image_set)).read().strip().split() # 打开对应的2012_train.txt 文件对其进行写入准备 list_file = open('data/%s.txt' % (image_set), 'w') # 将对应的文件_id以及全路径写进去并换行 for image_id in image_ids: list_file.write('data/images/%s.jpg\n' % (image_id)) # 调用 year = 年份 image_id = 对应的文件名_id convert_annotation(image_id) # 关闭文件 list_file.close()
import glob import cv2 xml_head = '''<annotation> <folder>VOC2007</folder> <filename>{}</filename>. <source> <database>The VOC2007 Database</database> <annotation>PASCAL VOC2007</annotation> <image>flickr</image> </source> <size> <width>{}</width> <height>{}</height> <depth>{}</depth> </size> <segmented>0</segmented> ''' xml_obj = ''' <object> <name>{}</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>{}</xmin> <ymin>{}</ymin> <xmax>{}</xmax> <ymax>{}</ymax> </bndbox> </object> ''' xml_end = ''' </annotation>''' #文件夹设置 #--data #----train 训练集图片 #----train_txt 对应的txt标签 #----train_xml 对应的xml标签 root='D:/A-new-tjw/works/2022.14-/data/' labels = ['mask', 'face', 'incorrect mask'] # 数据集类别名 txt_Lists = glob.glob(root +'train'+ '/*.jpg') print(len(txt_Lists)) # print(txt_Lists) cnt=0 for txt_path in txt_Lists: filename=txt_path.split('\\') filename=filename[-1] filename=filename.split('.') filename=filename[0] txt = root+'train_txt/'+filename+'.txt' jpg=root+'train/'+filename+'.jpg' #jpg path xml=root+'train_xml/'+filename+'.xml' print(txt) print(jpg) print(xml) obj = '' img = cv2.imread(jpg) img_h, img_w = img.shape[0], img.shape[1] print('h_factor:',img_h,' w_factor:',img_w) # cv2.imshow("img", img) #显示图片 # cv2.waitKey(0) # cv2.destroyWindow("img") head = xml_head.format(str(filename), str(img_w), str(img_h), "3") with open(txt, 'r') as f: for line in f.readlines(): yolo_datas = line.strip().split(' ') label = int(float(yolo_datas[0].strip())) center_x = round(float(str(yolo_datas[1]).strip()) * img_w) center_y = round(float(str(yolo_datas[2]).strip()) * img_h) bbox_width = round(float(str(yolo_datas[3]).strip()) * img_w) bbox_height = round(float(str(yolo_datas[4]).strip()) * img_h) xmin = str(int(center_x - bbox_width / 2)) ymin = str(int(center_y - bbox_height / 2)) xmax = str(int(center_x + bbox_width / 2)) ymax = str(int(center_y + bbox_height / 2)) obj += xml_obj.format(labels[label], xmin, ymin, xmax, ymax) with open(xml, 'w') as f_xml: f_xml.write(head + obj + xml_end) cnt += 1 print(cnt)
import os import json import cv2 import random import time from PIL import Image coco_format_save_path='D:\\A-new-tjw\\works\\2022.5.19\\people\\labels_json\\val' #要生成的标准coco格式标签所在文件夹 yolo_format_classes_path='D:\\A-new-tjw\\works\\2022.5.19\\people\\people.names' #类别文件,一行一个类 yolo_format_annotation_path='D:\\A-new-tjw\\works\\2022.5.19\\people\\labels_txt\\val' #yolo格式标签所在文件夹 img_pathDir='D:\\A-new-tjw\\works\\2022.5.19\\people\\images\\val' #图片所在文件夹 with open(yolo_format_classes_path,'r') as fr: #打开并读取类别文件 lines1=fr.readlines() # print(lines1) categories=[] #存储类别的列表 for j,label in enumerate(lines1): label=label.strip() categories.append({'id':j+1,'name':label,'supercategory':'None'}) #将类别信息添加到categories中 # print(categories) write_json_context=dict() #写入.json文件的大字典 write_json_context['info']= {'description': '', 'url': '', 'version': '', 'year': 2021, 'contributor': '', 'date_created': '2021-07-25'} write_json_context['licenses']=[{'id':1,'name':None,'url':None}] write_json_context['categories']=categories write_json_context['images']=[] write_json_context['annotations']=[] #接下来的代码主要添加'images'和'annotations'的key值 imageFileList=os.listdir(img_pathDir) #遍历该文件夹下的所有文件,并将所有文件名添加到列表中 for i,imageFile in enumerate(imageFileList): imagePath = os.path.join(img_pathDir,imageFile) #获取图片的绝对路径 image = Image.open(imagePath) #读取图片,然后获取图片的宽和高 W, H = image.size img_context={} #使用一个字典存储该图片信息 #img_name=os.path.basename(imagePath) #返回path最后的文件名。如果path以/或\结尾,那么就会返回空值 img_context['file_name']=imageFile img_context['height']=H img_context['width']=W img_context['date_captured']='2021-07-25' img_context['id']=i #该图片的id img_context['license']=1 img_context['color_url']='' img_context['flickr_url']='' write_json_context['images'].append(img_context) #将该图片信息添加到'image'列表中 txtFile=imageFile[:6]+'.txt' #获取该图片获取的txt文件,这个数字"6"要根据自己图片名修改 with open(os.path.join(yolo_format_annotation_path,txtFile),'r') as fr: lines=fr.readlines() #读取txt文件的每一行数据,lines2是一个列表,包含了一个图片的所有标注信息 for j,line in enumerate(lines): bbox_dict = {} #将每一个bounding box信息存储在该字典中 # line = line.strip().split() # print(line.strip().split(' ')) class_id,x,y,w,h=line.strip().split(' ') #获取每一个标注框的详细信息 class_id,x, y, w, h = int(class_id), float(x), float(y), float(w), float(h) #将字符串类型转为可计算的int和float类型 xmin=(x-w/2)*W #坐标转换 ymin=(y-h/2)*H xmax=(x+w/2)*W ymax=(y+h/2)*H w=w*W h=h*H bbox_dict['id']=i*10000+j #bounding box的坐标信息 bbox_dict['image_id']=i bbox_dict['category_id']=class_id+1 #注意目标类别要加一 bbox_dict['iscrowd']=0 height,width=abs(ymax-ymin),abs(xmax-xmin) bbox_dict['area']=height*width bbox_dict['bbox']=[xmin,ymin,w,h] bbox_dict['segmentation']=[[xmin,ymin,xmax,ymin,xmax,ymax,xmin,ymax]] write_json_context['annotations'].append(bbox_dict) #将每一个由字典存储的bounding box信息添加到'annotations'列表中 name = os.path.join(coco_format_save_path,"val"+ '.json') with open(name,'w') as fw: #将字典信息写入.json文件中 json.dump(write_json_context,fw,indent=2)
# 处理同一个数据集下多个json文件时,仅运行一次class_txt即可 import json import os "存储标签与预测框到txt文件中" def json_txt(json_path, txt_path): "json_path: 需要处理的json文件的路径" "txt_path: 将json文件处理后txt文件存放的文件夹名" # 生成存放json文件的路径 if not os.path.exists(txt_path): os.mkdir(txt_path) # 读取json文件 with open(json_path, 'r') as f: dict = json.load(f) # 得到images和annotations信息 images_value = dict.get("images") # 得到某个键下对应的值 annotations_value = dict.get("annotations") # 得到某个键下对应的值 # 使用images下的图像名的id创建txt文件 list=[] # 将文件名存储在list中 for i in images_value: open(txt_path + str(i.get("id")) + '.txt', 'w') list.append(i.get("id")) # 将id对应图片的bbox写入txt文件中 for i in list: for j in annotations_value: if j.get("image_id") == i: # bbox标签归一化处理 num = sum(j.get('bbox')) new_list = [round(m / num, 6) for m in j.get('bbox')] # 保留六位小数 with open(txt_path + str(i) + '.txt', 'a') as file1: # 写入txt文件中 print(j.get("category_id"), new_list[0], new_list[1], new_list[2], new_list[3], file=file1) "将id对应的标签存储在class.txt中" def class_txt(json_path, class_txt_path): "json_path: 需要处理的json文件的路径" "txt_path: 将json文件处理后存放所需的txt文件名" # 生成存放json文件的路径 with open(json_path, 'r') as f: dict = json.load(f) # 得到categories下对应的信息 categories_value = dict.get("categories") # 得到某个键下对应的值 # 将每个类别id与类别写入txt文件中 with open(class_txt_path, 'a') as file0: for i in categories_value: print(i.get("id"), i.get('name'), file=file0) json_txt("train.json", "train_annotations/") # class_txt("eval.json", "id_categories.txt")
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。