如何将yolo的标注(annotations).txt 坐标转换成tensorflow-yolov3(YunYang1994)的.txt 标注坐标?

mac2024-04-07  35

文章目录

原理示例实现代码实际操作方法

原理

示例

如,这是Yolo的: 转换后就变成酱紫了: 注意:图像坐标原点在左上角

注意:作者引用图片路径时使用的时绝对路径,我们使用相对路径不知是否会出问题? https://github.com/Dontla/tensorflow-yolov3/blob/master/data/dataset/voc_train.txt

文件批量重命名参考:python 将指定路径(目录)下的图片或文本文件按给定序号重新排序,并批量重命名 yolo、tensorflow数据集批量处理

实现代码

# -*- encoding: utf-8 -*- """ @File : convert.py @Time : 2019/10/22 9:26 @Author : Dontla @Email : sxana@qq.com @Software: PyCharm """ import os import re import cv2 import random # 排序函数,对文件列表进行排序(filenames为文件夹文件的文件名的字符串列表,pattern为正则表达式,它是字符串类型) def sort_filenames(filenames, pattern): # (1)可以以len排序,len相同的字符串,会再以0-9排序,能获得我们想要的结果 # filenames.sort(key=len) # (2)这种排序失败了 # filenames.sort(key=lambda x: x[16:]) # print(filenames[0][16:]) # 1).txt # (3)用lambda配合正则表达式(将filenames中对象一一取出赋给x,通过冒号后的表达式运算后将结果返回给key) # 数字字符串排序貌似还是以字符顺序而不是数字大小来排的,可能要先转化为数字(而re.findall('\((.*?)\)', x)返回的是字符串列表,要把它转换成数字列表) filenames.sort(key=lambda x: list(map(eval, re.findall(pattern, x)))) # 注意括号前一定要添加转义字符“\”,不过有一个疑问,按照'((.*?))'排序为啥结果也正确?? # print(filenames[0]) # f_cotton-g_top (1).txt # print(re.findall('\((.*?)\)', filenames[0])) # ['1'] # print(re.findall('((.*?))', filenames[0])) # [('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', ''), ('', '')] def extract_content(content): content_extract = re.findall('(.*?) (.*?) (.*?) (.*?) (.*?)\n', content) return content_extract if __name__ == '__main__': # 记得路径尾部加“/”,不然调用join方法是它会用“\”替代,那样不好,容易造成转义字符问题。 # ../表示上一层路径 # 最终写入的文件路径信息是要给tensorflow-yolov3用的,我们要向其指定我们图片的位置: source_img_path_related_to_train_py = '../Dontla_Dataset/20190822_Artificial_Flower/20191023_f_cotton_g/' # 以下三个路径是相对当前文件的 source_img_path = '../20191023_f_cotton_g/' source_txt_path = '../20191023_f_cotton_g_Annotations_Yolo/' target_txt_path = '../20191023_f_cotton_g_Annotations_Tensorflow-Yolov3_dataset/' # 读取source_txt_path路径下所有文件(包括子文件夹下文件) filenames = os.listdir(source_txt_path) # 调用自定义的sort_filenames函数对filenames重新排序(如果不重新排序它貌似会以1、10、100...的顺序排而不是以1、2、3...的顺序) pattern = '\((.*?)\)' sort_filenames(filenames, pattern) # print(filenames) # ['f_cotton-g_top (1).txt', 'f_cotton-g_top (2).txt', 'f_cotton-g_top (3).txt',...] # TODO(Dontla): 提取filenames中数字 ''' for filename in filenames: if filename.endswith('.txt'): filepath = os.path.join(source_txt_path, filename) # print(filepath) ''' # 获取所有txt文件的路径列表 # 这么优雅的语法是从哪学来的?如实招来! # filepaths = [os.path.join(source_txt_path, filename) for filename in filenames if filename.endswith('.txt')] # 打开俩文件准备写入 train_file = open(target_txt_path + 'train.txt', 'w', encoding='utf-8') test_file = open(target_txt_path + 'test.txt', 'w', encoding='utf-8') # 创建写入内容字符串变量 train_file_content = '' test_file_content = '' # 打开文件提取其中数字并将内容重构后写入新文件 for filename in filenames: # 打开文件: with open(os.path.join(source_txt_path, filename), 'r', encoding='utf-8') as f: # 读取文件内容 content = f.read() # 提取数据 content_extract = extract_content(content) # print(content_extract) # [('0', '0.228125', '0.670833', '0.164063', '0.227778'), ('0', '0.382031', '0.845139', '0.140625', '0.218056'),...] # 获取当前图片分辨率信息(这样不论图片尺寸多少都能成功转换)(re.findall()返回的是列表,需要将它转换成字符串) # 读取图片 img = cv2.imread('{}{}.jpg'.format(source_img_path, ''.join(re.findall('(.*?).txt', filename)))) # print(''.join(re.findall('(.*?).txt', filename))) # f_cotton-g_top (1) # 显示图片 # cv2.namedWindow('test', cv2.WINDOW_AUTOSIZE) # cv2.imshow('test', img) # cv2.waitKey(0) # 获取图片分辨率 img_width = img.shape[1] img_height = img.shape[0] # print(img.shape) # (720, 1280, 3) # f2.write('{}{}.jpg'.format(source_img_path_related_to_train_py, ''.join(re.findall('(.*?).txt', filename)))) # 创建单行写入字符串 object_strs = source_img_path_related_to_train_py + os.path.splitext(filename)[0] + '.jpg' # print(os.path.splitext(filename)) # ('f_cotton-g_top (1)', '.txt') # 将数据格式从相对坐标转换成绝对坐标 for object_str in content_extract: # print(object_str) # ('0', '0.228125', '0.670833', '0.164063', '0.227778') # ('0', '0.382031', '0.845139', '0.140625', '0.218056') # ('0', '0.380859', '0.652778', '0.135156', '0.200000') # ... # print(type(object_str)) # <class 'tuple'> # 将元组字符串转换成列表数字 object_evar = list(map(eval, object_str)) # print(object_evar) # [0, 0.228125, 0.670833, 0.164063, 0.227778] # ... # 映射变量 class_id = object_evar[0] (x, y) = (object_evar[1] * img_width, object_evar[2] * img_height) (w, h) = (object_evar[3] * img_width, object_evar[4] * img_height) # 将映射变量格式化后加入到object_strs中: object_strs += ' {},{},{},{},{}'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2), round(y + h / 2), class_id) # 拆分训练集和测试集 # 训练集占比 train_scale = 0.75 # 设置随机概率 proba = random.random() # 判断该写入哪个文件 if (proba < train_scale): train_file_content += object_strs + '\n' else: test_file_content += object_strs + '\n' # 将两个即将写入的内容去除首位的无效字符(如空格,换行符,制表符,回车符) train_file_content = train_file_content.strip() test_file_content = test_file_content.strip() # 将内容写入俩文件 train_file.write(train_file_content) test_file.write(test_file_content) # 关闭俩文件 train_file.close() test_file.close() ''' all = os.walk(source_txt_path) # dirpath:从all中存储的source_txt_path下文件夹及子文件夹列表中取出每个文件夹及子文件夹路径 # dirnames :dirpath下的文件夹列表(不包括子文件夹) # filenames :dirpath下文件的文件名列表 for dirpath, dirnames, filenames in all: # print('path:',dirpath) # print('dir:',dirnames) # print('filelist:',filenames) for filename in filenames: # print(filename) # 20190822_Artificial_Flower (1).txt if filename.endswith('.txt'): filepath = os.path.join(dirpath, filename) # print(filepath) # ../20190822_Artificial_Flower_Annotations_Yolo/20190822_Artificial_Flower (99).txt with open(filepath, 'r', encoding='utf-8') as f: content=f.read() # 不能省略\n不然就识别不出来了 # content_extract=re.findall('(.*) (.*) (.*) (.*) (.*)\n',content) content_extract=re.findall('(.*?) (.*?) (.*?) (.*?) (.*?)\n',content) # print(content_extract) # [('0', '0.491797', '0.772917', '0.103906', '0.170833'), ('0', '0.355078', '0.569444', '0.116406', '0.183333')] # Dontla deleted 20191023 # with open(filepath,'r',encoding='utf-8') as f: # content_list=f.readlines() # # # print(content_list) # # ['0 0.491797 0.772917 0.103906 0.170833\n', '0 0.355078 0.569444 0.116406 0.183333\n'] # # for content in content_list: # break # # target_info=re.findall('(.*?) ') '''

实际操作方法

升级版:添加了数据清洗,参见:将yolo标注转换为tensorflow_yolov3标注生成train.txt和test.txt同时做数据清洗

最新回复(0)