将yolo标注转换为tensorflow_yolov3标注生成train.txt和test.txt同时做数据清洗
生活随笔
收集整理的這篇文章主要介紹了
将yolo标注转换为tensorflow_yolov3标注生成train.txt和test.txt同时做数据清洗
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 代碼:
- 20200218 貌似上面代碼有點bug,新的如下(解決了目標只有單行無法提取的bug,新增了將空目標圖片匯總到文件夾的功能):
代碼:
# -*- 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_extractif __name__ == '__main__':# 記得路徑尾部加“/”,不然調用join方法是它會用“\”替代,那樣不好,容易造成轉義字符問題。# ../表示上一層路徑# 最終寫入的文件路徑信息是要給tensorflow-yolov3用的,我們要向其指定我們圖片的位置:# source_img_path_related_to_train_py = '../Dontla_Dataset/20190822_Artificial_Flower/20191023_f_cotton_g/'source_img_path_related_to_train_py = './dontla_source_img/'# 以下三個路徑是相對當前文件的source_img_path = './source_img_path/'source_txt_path = './source_txt_path/'target_txt_path = './target_txt_path/'# 讀取source_txt_path路徑下所有文件(包括子文件夾下文件)filenames = os.listdir(source_txt_path)# 調用自定義的sort_filenames函數對filenames重新排序(如果不重新排序它貌似會以1、10、100...的順序排而不是以1、2、3...的順序)# \是轉義字符# pattern = '\((.*?)\)'# Dontla 20200204 現在文件名就是純數字,所以pattern也得改pattern = '(.*?).txt'sort_filenames(filenames, pattern)# print(filenames)# ['f_cotton-g_top (1).txt', 'f_cotton-g_top (2).txt', 'f_cotton-g_top (3).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))))# 創建單行寫入字符串的路徑頭字符串path_str = source_img_path_related_to_train_py + os.path.splitext(filename)[0] + '.jpg'# 創建單行寫入字符串的目標坐標字符串obj_strs = ''# print(os.path.splitext(filename))# ('f_cotton-g_top (1)', '.txt')# 將數據格式從相對坐標轉換成絕對坐標for obj_str in content_extract:# print(obj_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, obj_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_heightw, h = object_evar[3] * img_width, object_evar[4] * img_height# 判斷數據是否超出限制(數據清洗)(包括清洗超限坐標和錯誤class_id)if class_id != 0 \or round(x - w / 2) < 0 \or round(x + w / 2) > img_width \or round(x - w / 2) >= round(x + w / 2) \or round(y - h / 2) < 0 \or round(y + h / 2) > img_height \or round(y - h / 2) >= round(y + h / 2):print('錯誤標注:')print(filename)print(object_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))continue# 將映射變量格式化后加入到obj_strs中:obj_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()# 如果該張圖片經過數據清洗后沒有目標,則跳過,不將其加入到train.txt和test.txt文件中if obj_strs == '':print('空文件')continueelse:write_strs = path_str + obj_strs# 判斷該寫入哪個文件if proba < train_scale:train_file_content += write_strs + '\n'else:test_file_content += write_strs + '\n'# print(write_strs)# ./dontla_source_img/1.jpg 275,138,374,226,0 669,36,782,153,0# ./dontla_source_img/2.jpg 453,228,623,366,0# ./dontla_source_img/3.jpg 723,269,847,414,0 339,376,541,494,0# ...# 將兩個即將寫入的內容去除首位的無效字符(如空格,換行符,制表符,回車符)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()生成結果:
此代碼是如何將yolo的標注(annotations).txt 坐標轉換成tensorflow-yolov3(YunYang1994)的.txt 標注坐標?的升級版!!!
20200218 貌似上面代碼有點bug,新的如下(解決了目標只有單行無法提取的bug,新增了將空目標圖片匯總到文件夾的功能):
# -*- 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 shutilimport 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_):# 注意,一開始用的第一種,結果只有一行的情況沒有被提取出來,要去掉后面的\n,謹記# content_extract = re.findall('(.*?) (.*?) (.*?) (.*?) (.*?)\n', content)# content_extract = re.findall('(.*?) (.*?) (.*?) (.*?) (.*?)', content)content_extract_ = re.findall('(\d+.?\d*) (\d+.?\d*) (\d+.?\d*) (\d+.?\d*) (\d+.?\d*)', content_)# print(content_extract_)return content_extract_# 20200216:直接從文件按行讀取 def extract_content_readlines(content):content_extract = []for line in content:line = line.strip()# print('line:{}'.format(line))# line:0 0.248438 0.255556 0.128125 0.194444# line:0 0.571094 0.118056 0.118750 0.180556# line:0 0.457422 0.530556 0.113281 0.180556# ...# content_extract.append(re.findall('(.*?) (.*?) (.*?) (.*?) (.*?)', line))content_extract.append(re.findall('(\d+.?\d*) (\d+.?\d*) (\d+.?\d*) (\d+.?\d*) (\d+.?\d*)', line))print(content_extract)return content_extractif __name__ == '__main__':# 記得路徑尾部加“/”,不然調用join方法是它會用“\”替代,那樣不好,容易造成轉義字符問題。# ../表示上一層路徑# 最終寫入的文件路徑信息是要給tensorflow-yolov3用的,我們要向其指定我們圖片的位置:# source_img_path_related_to_train_py = '../Dontla_Dataset/20190822_Artificial_Flower/20191023_f_cotton_g/'source_img_path_related_to_train_py = './dontla_source_img/'# 以下三個路徑是相對當前文件的source_img_path = './source_img_path/'source_txt_path = './source_txt_path/'target_txt_path = './target_txt_path/'# 讀取source_txt_path路徑下所有文件(包括子文件夾下文件)filenames = os.listdir(source_txt_path)# 調用自定義的sort_filenames函數對filenames重新排序(如果不重新排序它貌似會以1、10、100...的順序排而不是以1、2、3...的順序)# \是轉義字符# pattern = '\((.*?)\)'# Dontla 20200204 現在文件名就是純數字,所以pattern也得改pattern = '(.*?).txt'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.readlines()content = f.read()# 提取數據content_extract = extract_content(content)# 提取數據# content_extract = extract_content_readlines(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))))# 創建單行寫入字符串的路徑頭字符串path_str = source_img_path_related_to_train_py + os.path.splitext(filename)[0] + '.jpg'# 創建單行寫入字符串的目標坐標字符串obj_strs = ''# print(os.path.splitext(filename))# ('f_cotton-g_top (1)', '.txt')# 將數據格式從相對坐標轉換成絕對坐標for obj_str in content_extract:# print(obj_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, obj_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_heightw, h = object_evar[3] * img_width, object_evar[4] * img_height# 判斷數據是否超出限制(數據清洗)(包括清洗超限坐標和錯誤class_id)if class_id != 0 \or round(x - w / 2) < 0 \or round(x + w / 2) > img_width \or round(x - w / 2) >= round(x + w / 2) \or round(y - h / 2) < 0 \or round(y + h / 2) > img_height \or round(y - h / 2) >= round(y + h / 2):print('錯誤標注:')print(filename)print(object_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))continue# 將映射變量格式化后加入到obj_strs中:obj_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()# 如果該張圖片經過數據清洗后沒有目標,則跳過,不將其加入到train.txt和test.txt文件中if obj_strs == '':print('空文件:{}'.format(filename))print('content:{}'.format(content))# print('content_extract:{}'.format(content_extract))# print(re.findall('(.*?) (.*?) (.*?) (.*?) (.*?)\n', content))cv2.imwrite('null_img\\{}.jpg'.format(''.join(re.findall('(.*?).txt', filename))), img)print('將圖片拷貝到“空文件”文件夾')continueelse:write_strs = path_str + obj_strsprint(write_strs)# 判斷該寫入哪個文件if proba < train_scale:train_file_content += write_strs + '\n'else:test_file_content += write_strs + '\n'# print(write_strs)# ./dontla_source_img/1.jpg 275,138,374,226,0 669,36,782,153,0# ./dontla_source_img/2.jpg 453,228,623,366,0# ./dontla_source_img/3.jpg 723,269,847,414,0 339,376,541,494,0# ...# 將兩個即將寫入的內容去除首位的無效字符(如空格,換行符,制表符,回車符)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).txtif filename.endswith('.txt'):filepath = os.path.join(dirpath, filename)# print(filepath)# ../20190822_Artificial_Flower_Annotations_Yolo/20190822_Artificial_Flower (99).txtwith 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('(.*?) ')'''參考文章:yuyang1994 tensorflow_yolov3訓練報錯:IndexError: index 68 is out of bounds for axis 1 with size 68(數據清洗)
總結
以上是生活随笔為你收集整理的将yolo标注转换为tensorflow_yolov3标注生成train.txt和test.txt同时做数据清洗的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: yunyang1994 tensorfl
- 下一篇: 怎么修改CSDN上传图片水印的字体大小?