辅助工具
- 坏图像扫描与检查
- 所有文件连续重命名排号
- 划分数据集为训练集、测试集和验证集
- 将标注的json文件转换成yolo格式文件,即txt文件
- 将xml格式文件转换成yolo格式可读取的文件
- 将gt后缀的图像数据文件进行解析
- 统计yolo存储文件下各类标签下所对应标注目标的数量,累积打印数据分布情况
坏图像扫描与检查
import os
import cv2# 检查的图像数据和保存的路径设置一样,则会检测出坏图像
dataDir = r"/home/s22030812007/faster-rcnn-pytorch/VOCdevkit1/VOC2007/JPEGImages/"
saveDir = r"/home/s22030812007/faster-rcnn-pytorch/VOCdevkit1/VOC2007/JPEGImages/"if not os.path.exists(saveDir):os.makedirs(saveDir)
c = 0
for one_pic in os.listdir(dataDir):one_path = dataDir + one_picone_img = cv2.imread(one_path)new_path = saveDir + one_picd = cv2.imwrite(new_path, one_img)c = c + 1print(d, c)
所有文件连续重命名排号
import os
if __name__ == '__main__':path = r"C:/Users/27801/Documents/Datasets/5551" # 需要出来的图片文件所在路径(即文件夹路径),注意斜杠的方向file_names = os.listdir(path) # 获取该文件夹下所有的文件名称(包括文件夹)print(f'file_names:{file_names}')count = 6563 # 设置变量count,为重命名文件的起始编号for file in file_names: # 遍历所有文件名print(f"file:{file}")old_name = os.path.join(path, file)print(f'old_name:{old_name}')if os.path.isdir(old_name): # 如果是文件夹则跳过continuefilename = os.path.splitext(file)[0] # 文件名filetype = os.path.splitext(file)[1] # 文件扩展名new_name = os.path.join(path, str(count).zfill(6) + filetype) # 用字符串函数zfill 以0补全所需位数print(f'new_name:{new_name}')os.rename(old_name, new_name) # 重命名 用新的文件名代替旧的文件名count += 1 # count的作用是给文件名计数的,以及累积的步幅
划分数据集为训练集、测试集和验证集
import os, shutil, randomrandom.seed(201)
import numpy as np
from sklearn.model_selection import train_test_split# 验证集、测试集的占比,剩余的比例为训练集数据,0.1为占比百分之十
val_size = 0.1
test_size = 0.1
postfix = 'jpg'# 图像数据的路径
imgpath = r'C:/Users/27801/Desktop/JPEGImages/'#txt后缀的文件路径
txtpath = r'C:/Users/27801/Desktop/txts/'#创建目录文件夹,用于存放划分数据后的图像,且若不存在则自动创建文件夹
os.makedirs('Logos3/images/train', exist_ok=True)
os.makedirs('Logos3/images/val', exist_ok=True)
os.makedirs('Logos3/images/test', exist_ok=True)
os.makedirs('Logos3/labels/train', exist_ok=True)
os.makedirs('Logos3/labels/val', exist_ok=True)
os.makedirs('Logos3/labels/test', exist_ok=True)# 列出txtpath目录下所有包含'txt'字符串的文件名 将这些文件名存储在一个列表中
listdir = np.array([i for i in os.listdir(txtpath) if 'txt' in i])# 随机打乱列表中文件名
random.shuffle(listdir)
# 按照比例划分
train, val, test = listdir[:int(len(listdir) * (1 - val_size - test_size))], \listdir[int(len(listdir) * (1 - val_size - test_size)):int(len(listdir) * (1 - test_size))], \listdir[int(len(listdir) * (1 - test_size)):]
print(f'train set size:{len(train)} val set size:{len(val)} test set size:{len(test)}')# 将分配好的文件进行转移到指定文件夹下
for i in train:shutil.copy('{}/{}.{}'.format(imgpath, i[:-4], postfix), 'Logos3/images/train/{}.{}'.format(i[:-4], postfix))shutil.copy('{}/{}'.format(txtpath, i), 'Logos3/labels/train/{}'.format(i))for i in val:shutil.copy('{}/{}.{}'.format(imgpath, i[:-4], postfix), 'Logos3/images/val/{}.{}'.format(i[:-4], postfix))shutil.copy('{}/{}'.format(txtpath, i), 'Logos3/labels/val/{}'.format(i))for i in test:shutil.copy('{}/{}.{}'.format(imgpath, i[:-4], postfix), 'Logos3/images/test/{}.{}'.format(i[:-4], postfix))shutil.copy('{}/{}'.format(txtpath, i), 'Logos3/labels/test/{}'.format(i))
将标注的json文件转换成yolo格式文件,即txt文件
import json
import os## json格式转换成yolo格式
# 设置:标签对应的编号
# !!!一定要查看自己标注数据集时对应的编号
name2id = {'figure': 0, 'text': 1, 'mix': 2}def convert(img_size, box):dw = 1. / (img_size[0])dh = 1. / (img_size[1])x = (box[0] + box[2]) / 2.0 - 1y = (box[1] + box[3]) / 2.0 - 1w = box[2] - box[0]h = box[3] - box[1]x = x * dww = w * dwy = y * dhh = h * dhreturn (x, y, w, h)def decode_json(json_folder_path, json_name):# 设置:转换好格式后的标签存放的路径txt_name = 'C:/Users/27801/Documents/Datasets/mydata/txt/' + json_name[0:-5] + '.txt'txt_file = open(txt_name, 'w')json_path = os.path.join(json_folder_path, json_name)data = json.load(open(json_path, 'r', encoding='gb2312'))img_w = data['imageWidth']img_h = data['imageHeight']for i in data['shapes']:label_name = i['label']if (i['shape_type'] == 'rectangle'):x1 = int(i['points'][0][0])y1 = int(i['points'][0][1])x2 = int(i['points'][1][0])y2 = int(i['points'][1][1])bb = (x1, y1, x2, y2)bbox = convert((img_w, img_h), bb)txt_file.write(str(name2id[label_name]) + " " + " ".join([str(a) for a in bbox]) + '\n')if __name__ == "__main__":# 路径设置:需要进行格式转换的.json文件夹存放路径json_folder_path = 'C:/Users/27801/Documents/Datasets/mydata/labels'json_names = os.listdir(json_folder_path)for json_name in json_names:decode_json(json_folder_path, json_name)
将xml格式文件转换成yolo格式可读取的文件
import cv2
import os
import xml.etree.ElementTree as ET
import numpy as npclasses = ['text', 'mix', 'figure']def convert(size, box):dw = 1. / (size[0])dh = 1. / (size[1])x = (box[0] + box[1]) / 2.0 - 1y = (box[2] + box[3]) / 2.0 - 1w = box[1] - box[0]h = box[3] - box[2]x = x * dww = w * dwy = y * dhh = h * dhreturn (x, y, w, h)def convert_annotation(xmlpath, xmlname):with open(xmlpath, "r", encoding='utf-8') as in_file:txtname = xmlname[:-4] + '.txt'txtfile = os.path.join(txtpath, txtname)tree = ET.parse(in_file)root = tree.getroot()filename = root.find('filename')img = cv2.imdecode(np.fromfile('{}/{}.{}'.format(imgpath, xmlname[:-4], postfix), np.uint8), cv2.IMREAD_COLOR)h, w = img.shape[:2]res = []for obj in root.iter('object'):cls = obj.find('name').textif cls not in classes:classes.append(cls)cls_id = classes.index(cls)xmlbox = obj.find('bndbox')b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),float(xmlbox.find('ymax').text))bb = convert((w, h), b)res.append(str(cls_id) + " " + " ".join([str(a) for a in bb]))if len(res) != 0:with open(txtfile, 'w+') as f:f.write('\n'.join(res))if __name__ == "__main__":# 图像后缀为jpg,图像文件路径、xml标注文件路径postfix = 'jpg'imgpath = r'C:/Users/27801/Desktop/JPEGImages/'xmlpath = r'C:/Users/27801/Desktop/Annotations/'# txt为yolo的表现格式,若没有存在,则自动创建文件夹txtpath = r'C:/Users/27801/Desktop/txts/'if not os.path.exists(txtpath):os.makedirs(txtpath, exist_ok=True)list = os.listdir(xmlpath)error_file_list = []for i in range(0, len(list)):try:path = os.path.join(xmlpath, list[i])if ('.xml' in path) or ('.XML' in path):convert_annotation(path, list[i])print(f'file {list[i]} convert success.')else:print(f'file {list[i]} is not xml format.')except Exception as e:print(f'file {list[i]} convert error.')print(f'error message:\n{e}')error_file_list.append(list[i])print(f'this file convert failure\n{error_file_list}')print(f'Dataset Classes:{classes}')
将gt后缀的图像数据文件进行解析
if __name__ == "__main__":# 下载的数据为gt格式存放label_path = r'C:\Users\27801\Desktop\BelgaLogos\qset3_internal_and_local.gt'labels_origin = []with open(label_path, "r") as f:for line in f.readlines():l = " ".join(line.split("\t"))labels_origin.append(l.strip("\n"))imgs_label = {}# 数据包括的所有标签classes = [['Adidas', 'Adidas-text', 'Airness', 'Base', 'BFGoodrich', 'Bik', 'Bouigues', 'Bridgestone','Bridgestone-text', 'Carglass', 'Citroen', 'Citroen-text', 'CocaCola', 'Cofidis', 'Dexia','ELeclerc', 'Ferrari', 'Gucci', 'Kia', 'Mercedes', 'Nike', 'Peugeot', 'Puma', 'Puma-text','Quick', 'Reebok', 'Roche', 'Shell', 'SNCF', 'Standard_Liege', 'StellaArtois', 'TNT','Total', 'Umbro', 'US_President', 'Veolia', 'VRT']]for i in labels_origin:if i.split()[2] not in imgs_label.keys():imgs_label[i.split()[2]] = []if i.split()[1] not in classes:classes.append(i.split()[1])imgs_label[i.split()[2]].append([int(i.split()[5]), int(i.split()[6]), int(i.split()[7]), int(i.split()[8]), i.split()[1]])print('imgs_label', imgs_label)
统计yolo存储文件下各类标签下所对应标注目标的数量,累积打印数据分布情况
import matplotlib.pyplot as plt
import osplt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = Falsecn_path = open(r"C:\Users\27801\Desktop\BelgaLogos\classes.txt") # 存有类别的文本路径,如:"C:/Users/Admin/Desktop/classes.txt"classes = [i.replace("\n", "") for i in cn_path.readlines()]
print(classes)class_dict = {i: 0 for i in classes}
print("类别数", len(class_dict))def main(base_path):# 列出指定路径base_path下的所有文件和目录名fileList = os.listdir(base_path)for file in fileList:if file == "classes.txt":continuewith open(base_path + file, 'r') as f:for i in f.readlines():i = i.split(' ') # 按照空格进行划分文件内数值,首字符代表标签类别class_dict[classes[int(i[0])]] += 1fig, ax = plt.subplots(figsize=(10, 8))plt.title('数量')plt.xticks(rotation=90) # x轴文字方向旋转90度bars = plt.bar(class_dict.keys(), class_dict.values())# 绘制柱形图部分for b in bars:height = b.get_height()ax.annotate(f'{height}',# xy控制的是,标注哪个点,x=x坐标+width/2, y=height,即柱子上平面的中间xy=(b.get_x() + b.get_width() / 2, height),xytext=(0, 3), # 文本放置的位置,如果有textcoords,则表示是针对xy位置的偏移,否则是图中的固定位置textcoords="offset points", # 两个选项 'offset pixels','offset pixels'va='bottom', ha='center' # 代表verticalalignment 和horizontalalignment,控制水平对齐和垂直对齐。)plt.savefig('./统计.png', # ⽂件名:png、jpg、pdfdpi=100, # 保存图⽚像素密度bbox_inches='tight') # 保存图⽚完整plt.show()if __name__ == '__main__':# 存放txt文件的路径,末尾的反斜杠不可少base_path = r"C:/Users/27801/Desktop/BelgaLogos/txts/"main(base_path)
如果你觉得这篇文章对你有所启发的话,期待你的点赞、收藏和打赏,对我创作的支持!!!