保持图片格式统一
import os
import cv2 as cv
image_path = 'J:/102HorizontalProject/zong/image' #设置图片读取的路径
save_path = 'J:/yolov5-master-cow/data/images' #设置图片保存的路径
if not os.path.exists(save_path): #判断路径是否正确,如果正确就打开
os.makedirs(save_path)
image_file = os.listdir(image_path)
for image in image_file:
if image.split('.')[-1] in ['bmp', 'jpg', 'jpeg', 'png', 'JPG', 'PNG']:
str = image.rsplit(".", 1) #从右侧判断是否有符号“.”,并对image的名称做一次分割。如112345.jpeg分割后的str为["112345","jpeg"]
output_img_name = str[0] + ".jpg" #取列表中的第一个字符串与“.jpg”放在一起。
src = cv.imread(os.path.join(image_path, image))
newimg = cv.imwrite(save_path + '/' + output_img_name, src)
print('FINISHED')
拍照后的图像进行缩放resize到指定长宽大小。用到cv2。
import os
import cv2
'''设置原始图片存放路径,不能有中文'''
datadir = "F:/picdata/SISD10raw/"
'''设置目标像素大小,此处设为1280'''
IMG_SIZE = 1280
'''使用os.path模块的join方法生成路径'''
path = os.path.join(datadir)
'''使用os.listdir(path)函数,返回path路径下所有文件的名字,以及文件夹的名字'''
img_list = os.listdir(path)
for i in img_list:
img_array = cv2.imread(os.path.join(path, i), cv2.IMREAD_COLOR)
'''调用cv2.resize函数resize图片'''
new_array = cv2.resize(img_array, (IMG_SIZE, IMG_SIZE))
img_name = str(i) # 保存的图片与处理前图片同名
'''生成图片存储的目标路径'''
save_path = 'F:/picdata/SISD10/'+str(i)
'''调用cv.2的imwrite函数保存图片'''
cv2.imwrite(save_path, new_array)
jpg图片名字批量重命名rename,总位数一致,都是0开头,右对齐。
import os
def myrename(path):
file_list = os.listdir(path)
for i, fi in enumerate(file_list):
old_dir = os.path.join(path, fi)
filename = str(i + 1) + "." + str(fi.split(".")[-1])
new_dir = os.path.join(path, filename)
try:
os.rename(old_dir, new_dir)
except Exception as e:
print(e)
print("Failed!")
else:
print("SUcess!")
if __name__ == "__main__":
path = r"F:/picdata/SISD10"
myrename(path)
# myrename执行后图片按1,2,3,,,,顺序
# 执行后面的代码,将进一步修改为00001,00002,00003,,,,
filelist = os.listdir(path)
filetype = '.jpg'
for file in filelist:
Olddir = os.path.join(path, file)
if os.path.isdir(Olddir):
continue
# os.path.splitext("path"):分离文件名与扩展名
filename = os.path.splitext(file)[0]
filetype = os.path.splitext(file)[1]
print(filename.zfill(5))
# zfill() 方法返回指定长度的字符串,原字符串右对齐,前面填充0
Newdir = os.path.join(path, filename.zfill(5) + filetype) # 数字5是定义为5位数,可随意修改需要的
print(Newdir)
os.rename(Olddir, Newdir)
多人协同打标的情况下,xml文件路径可能不同, 需要把 <path>F:\picdata\SISD10\00001.jpg</path>
批量改成G盘目录,保持一致。注意转义符\\
<path>G:\picdata\SISD10\00001.jpg</path>
多字段要替换,就继续用if
import os
if __name__=='__main__':
work_dir = 'F:/picdata/test/test1/'
new_dir = 'F:/picdata/test/test2/'
for parent, dirnames, filenames in os.walk(work_dir, followlinks=True):
for filename in filenames:
file_path = os.path.join(parent, filename)
file = open(file_path,"r+",encoding='UTF-8')
newFile = open(new_dir + filename,"w",encoding='UTF-8')
for line in file.readlines():
if("F:\\" in line):
line = line.replace("F:\\","G:\\")
newFile.writelines(line)
print (filename)
newFile.close()
file.close()
yolov7需要的数据文件结构,如果已经有yolov5格式划分好的数据集,如
datasets
├─images
│ ├─test
│ ├─train
│ └─val
├─labels
├─test
├─train
└─val
则用这个代码生成datasets目录下3个txt文件:train.txt
、val.txt
、test.txt
。
import os
from tqdm import tqdm
if __name__ == '__main__':
rootdir = 'G:/A_lwd_paper/linetrash_datasets_new/A_data_samewithautol911'
rootimagesdir = os.path.join(rootdir, 'images')
rootlabelsdir = os.path.join(rootdir, 'labels')
assert os.path.exists(rootimagesdir), f'{rootimagesdir} not exists.'
assert os.path.exists(rootlabelsdir), f'{rootlabelsdir} not exists.'
imagesets = ['train', 'val', 'test'] # 将images/train val test中的图像的绝对地址分别写入txt中
for sets in imagesets:
imagesdir = os.path.join(rootimagesdir, sets)
with open(os.path.join(rootdir, f'{sets}.txt'), 'w') as f:
filelist = os.listdir(imagesdir)
for images in tqdm(filelist):
f.write(os.path.join(imagesdir, images) + '\n')
labelme2voc
#!/usr/bin/env python
from __future__ import print_function
import argparse
import glob
import os
import os.path as osp
import sys
import imgviz
import numpy as np
import labelme
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument("input_dir", help="input annotated directory")
parser.add_argument("output_dir", help="output dataset directory")
parser.add_argument("--labels", help="labels file", required=True)
parser.add_argument(
"--noviz", help="no visualization", action="store_true"
)
args = parser.parse_args()
if osp.exists(args.output_dir):
print("Output directory already exists:", args.output_dir)
sys.exit(1)
os.makedirs(args.output_dir)
os.makedirs(osp.join(args.output_dir, "JPEGImages"))
os.makedirs(osp.join(args.output_dir, "SegmentationClass"))
os.makedirs(osp.join(args.output_dir, "SegmentationClassPNG"))
if not args.noviz:
os.makedirs(
osp.join(args.output_dir, "SegmentationClassVisualization")
)
os.makedirs(osp.join(args.output_dir, "SegmentationObject"))
os.makedirs(osp.join(args.output_dir, "SegmentationObjectPNG"))
if not args.noviz:
os.makedirs(
osp.join(args.output_dir, "SegmentationObjectVisualization")
)
print("Creating dataset:", args.output_dir)
class_names = []
class_name_to_id = {}
for i, line in enumerate(open(args.labels).readlines()):
class_id = i - 1 # starts with -1
class_name = line.strip()
class_name_to_id[class_name] = class_id
if class_id == -1:
assert class_name == "__ignore__"
continue
elif class_id == 0:
assert class_name == "_background_"
class_names.append(class_name)
class_names = tuple(class_names)
print("class_names:", class_names)
out_class_names_file = osp.join(args.output_dir, "class_names.txt")
with open(out_class_names_file, "w") as f:
f.writelines("\n".join(class_names))
print("Saved class_names:", out_class_names_file)
for filename in glob.glob(osp.join(args.input_dir, "*.json")):
print("Generating dataset from:", filename)
label_file = labelme.LabelFile(filename=filename)
base = osp.splitext(osp.basename(filename))[0]
out_img_file = osp.join(args.output_dir, "JPEGImages", base + ".jpg")
out_cls_file = osp.join(
args.output_dir, "SegmentationClass", base + ".npy"
)
out_clsp_file = osp.join(
args.output_dir, "SegmentationClassPNG", base + ".png"
)
if not args.noviz:
out_clsv_file = osp.join(
args.output_dir,
"SegmentationClassVisualization",
base + ".jpg",
)
out_ins_file = osp.join(
args.output_dir, "SegmentationObject", base + ".npy"
)
out_insp_file = osp.join(
args.output_dir, "SegmentationObjectPNG", base + ".png"
)
if not args.noviz:
out_insv_file = osp.join(
args.output_dir,
"SegmentationObjectVisualization",
base + ".jpg",
)
img = labelme.utils.img_data_to_arr(label_file.imageData)
imgviz.io.imsave(out_img_file, img)
cls, ins = labelme.utils.shapes_to_label(
img_shape=img.shape,
shapes=label_file.shapes,
label_name_to_value=class_name_to_id,
)
ins[cls == -1] = 0 # ignore it.
# class label
labelme.utils.lblsave(out_clsp_file, cls)
np.save(out_cls_file, cls)
if not args.noviz:
clsv = imgviz.label2rgb(
cls,
imgviz.rgb2gray(img),
label_names=class_names,
font_size=15,
loc="rb",
)
imgviz.io.imsave(out_clsv_file, clsv)
# instance label
labelme.utils.lblsave(out_insp_file, ins)
np.save(out_ins_file, ins)
if not args.noviz:
instance_ids = np.unique(ins)
instance_names = [str(i) for i in range(max(instance_ids) + 1)]
insv = imgviz.label2rgb(
ins,
imgviz.rgb2gray(img),
label_names=instance_names,
font_size=15,
loc="rb",
)
imgviz.io.imsave(out_insv_file, insv)
if __name__ == "__main__":
main()
xml_to_yolo_rotation
类别,cx,cy,w,h,angle
#!/usr/bin/env python
# coding: utf-8
# ## convert xml to [yolov5-rotation](https://github.com/acai66/yolov5_rotation) format. [旋转版yolov5](https://github.com/acai66/yolov5_rotation)标签格式转换
# In[1]:
import xml.etree.ElementTree as ET
from tqdm import tqdm # pip install tqdm
import os
import math
# In[2]:
workdir = 'H:/picdata/' # datasets root path. 数据集路径
images_dir = os.path.join(workdir, 'SISD10') # images path. 图像路径
labels_dir = os.path.join(workdir, 'SID10rotatelabelxml') # xml labels path. xml标签路径
# yolov5_all_images = os.path.join(workdir, 'yolov5_all_images') # all images for yolov5 rotation. 转换后旋转版yolov5可用的图像路径
yolov5_all_labels = os.path.join(workdir, 'SID10rotatetxt') # all labels for yolov5 rotation. 转换后旋转版yolov5可用的txt标签路径
for d in [yolov5_all_labels]:
if not os.path.exists(d):
os.mkdir(d)
# In[3]:
all_files = [i for i in os.listdir(labels_dir) if i[-4:] == '.xml']
# In[4]:
print('labels count: ', len(all_files))
# In[5]:
#todo
keep_class_names = ['cup','forceps','kidneydish','needleholder','retractor','scalpel','scalpelhandle','scissors','sutureneedle','tampon'] # auto scan if blank. 如果留空,会自动扫描类别
# In[6]:
class_names = dict(zip(keep_class_names, range(len(keep_class_names))))
# ## convert. 转换
# In[7]:
auto_scan = False
class_index = 0
if len(class_names) == 0:
auto_scan = True
print('Auto scan classnames enabled.')
for file in tqdm(all_files):
file_path = os.path.join(labels_dir, file)
tree = ET.parse(file_path)
root = tree.getroot()
img_size = root.find('size')
width = float(img_size.find('width').text)
height = float(img_size.find('height').text)
objs = root.findall('object')
with open(os.path.join(yolov5_all_labels, file[:-4] + '.txt'), 'w+') as f:
for obj in objs:
name = obj.find('name').text.strip()
if name not in class_names.keys():
if auto_scan:
class_names[name] = class_index
class_index = class_index + 1
else:
continue
rbb = obj.find('robndbox')
if not rbb:
print('no robndbox in %s' % (file_path))
cx = float(rbb.find('cx').text)
cy = float(rbb.find('cy').text)
w = float(rbb.find('w').text)
h = float(rbb.find('h').text)
angle = float(rbb.find('angle').text)
if angle > math.pi:
angle = angle - math.pi
degree = round(angle / math.pi * 180)
if h > w: # swap w,h if w is not longside. 宽不是长边时,交换宽高
w, h = h, w
if degree < 90:
degree = degree + 90
else:
degree = degree - 90
cv_degree = degree # 180 - degree # opencv angle format. opencv格式角度
if cv_degree == 180:
cv_degree = 0
assert cv_degree >= 0 and cv_degree < 180
f.write('{} {} {} {} {} {}\n'.format(class_names[name], cx/width, cy/height, w/width, h/height, cv_degree))
# break
# In[8]:
print('class_names: ', class_names)
# In[9]:
sorted_keys = [i[0] for i in sorted(class_names.items(), key = lambda kv:(kv[1], kv[0]))]
# In[10]:
print('names: [ "{}" ]'.format('", "'.join(sorted_keys)))
yolo_rotation_to_xml
旋转yolo转回到xml文件。angle角度稍微有小数点后3位误差,原因可能是txt中保留的小数点位数,原xml转txt约了一次。txt转回xml又约了一次。原xml中w和h不一定w>h,但转出到txt一定是w>h,再转回xml时,和原xml不一样。
# 参考 https://deepinout.com/python/python-qa/t_how-to-generate-xml-using-python.html
# 参考 https://zhuanlan.zhihu.com/p/383660741
import os
# import xml.etree.ElementTree as ET
from lxml import etree as ET
from PIL import Image
import numpy as np
import math
# 图片文件夹
img_path = 'E:\picdata\SISD10\\'
# txt文件夹
labels_path = './SID10rotatelabeltxt/'
# xml存放的文件夹
annotations_path = './test4/'
labels = os.listdir(labels_path)
# 类别
classes = ['cup','forceps','kidneydish','needleholder','retractor','scalpel','scalpelhandle','scissors','sutureneedle','tampon'] #类别名
# 图片的高度、宽度、深度
sh =1280
sw =1280
sd =3
def write_xml(imgname, sw, sh, sd, filepath, labeldicts):
'''
imgname: 没有扩展名的图片名称
'''
# 创建Annotation根节点
root = ET.Element('annotation', {'verified': 'no'})
ET.SubElement(root, 'folder').text = "SISD10"
# 创建filename子节点,无扩展名
ET.SubElement(root, 'filename').text = str(imgname)
ET.SubElement(root, 'path').text = str(img_path+img_id+'.jpg')
source = ET.SubElement(root,'source')
ET.SubElement(source, 'database').text = "Unknown"
# 创建size子节点
size = ET.SubElement(root,'size')
ET.SubElement(size, 'width').text = str(sw)
ET.SubElement(size, 'height').text = str(sh)
ET.SubElement(size, 'depth').text = str(sd)
ET.SubElement(root, 'segmented').text = "0"
for labeldict in labeldicts:
objects = ET.SubElement(root, 'object')
ET.SubElement(objects, 'type').text = 'robndbox'
ET.SubElement(objects, 'name').text = labeldict['name']
ET.SubElement(objects, 'pose').text = 'Unspecified'
ET.SubElement(objects, 'truncated').text = '0'
ET.SubElement(objects, 'difficult').text = '0'
robndbox = ET.SubElement(objects,'robndbox')
ET.SubElement(robndbox, 'cx').text = str(round(labeldict['cx'],6))
ET.SubElement(robndbox, 'cy').text = str(round(labeldict['cy'],6))
ET.SubElement(robndbox, 'w').text = str(round(labeldict['w'],6))
ET.SubElement(robndbox, 'h').text = str(round(labeldict['h'],6))
ET.SubElement(robndbox, 'angle').text = str(round(labeldict['angle'],6))
tree = ET.ElementTree(root)
tree.write(filepath, encoding='utf-8',pretty_print=True)#每个元素会自动换行和缩进
for label in labels:
with open(labels_path + label, 'r') as f:
img_id = os.path.splitext(label)[0]
contents = f.readlines()
labeldicts = []
for content in contents:
# 图片格式,我这里是jpg,你如果是png注意修改
img = np.array(Image.open(img_path + label.strip('.txt') + '.jpg'))
# 图片的高度、宽度、深度
sh, sw, sd = img.shape[0], img.shape[1], img.shape[2]
content = content.strip('\n').split()
cx = float(content[1])*sw
cy = float(content[2])*sh
w = float(content[3])*sw
h = float(content[4])*sh
angle = float(content[5])*math.pi/180
# 坐标的转换,x_center y_center width height angle -> cx cy w h angle
new_dict = {'name': classes[int(content[0])],
'difficult': '0',
'cx': cx,
'cy': cy,
'w': w,
'h': h,
'angle': angle
}
labeldicts.append(new_dict)
write_xml(img_id, sw, sh, sd, annotations_path + label.strip('.txt') + '.xml', labeldicts)
print(img_id + '.txt to .xml is Done')
roxml2xml
https://githubfast.com/walynlee/RoLabelImg_Transform/blob/master/roxml2xml.py
import xml.etree.ElementTree as ET
import math
import os
def rotate_point(point, angle, origin):
angle_rad = math.radians(angle) # 将角度angle从度数转换为弧度
ox, oy = origin
px, py = point
qx = ox + math.cos(angle_rad) * (px - ox) - math.sin(angle_rad) * (py - oy)
qy = oy + math.sin(angle_rad) * (px - ox) + math.cos(angle_rad) * (py - oy)
return qx, qy
def rotate_bbox(bbox, angle, origin):
rotated_bbox = []
for point in bbox:
rotated_point = rotate_point(point, angle, origin)
rotated_bbox.append(rotated_point)
return rotated_bbox
def process_xml(xml_path):
tree = ET.parse(xml_path)
root = tree.getroot()
# Iterate through each object in the XML and update the bounding box coordinates
for obj in root.findall('object'):
robndbox = obj.find('robndbox')
if robndbox is not None:
cx = float(robndbox.find('cx').text)
cy = float(robndbox.find('cy').text)
w = float(robndbox.find('w').text)
h = float(robndbox.find('h').text)
angle = float(robndbox.find('angle').text)
rotated_bbox = rotate_bbox([(cx, cy), (cx + w, cy), (cx + w, cy + h), (cx, cy + h)], angle, (cx, cy))
min_x = min(rotated_bbox[0][0], rotated_bbox[3][0])
max_x = max(rotated_bbox[1][0], rotated_bbox[2][0])
min_y = min(rotated_bbox[0][1], rotated_bbox[1][1])
max_y = max(rotated_bbox[2][1], rotated_bbox[3][1])
# Create new <bndbox> elements
bndbox = ET.SubElement(obj, 'bndbox')
xmin = ET.SubElement(bndbox, 'xmin')
ymin = ET.SubElement(bndbox, 'ymin')
xmax = ET.SubElement(bndbox, 'xmax')
ymax = ET.SubElement(bndbox, 'ymax')
# Set the values for <bndbox> elements
xmin.text = str(int(min_x))
ymin.text = str(int(min_y))
xmax.text = str(int(max_x))
ymax.text = str(int(max_y))
# Remove the <robndbox> element
obj.remove(robndbox)
# Save the modified XML back to the original file
tree.write(xml_path)
# Specify the input directory containing XML files and the output directory
input_directory = r'F:\walyn\walyn\nanodet\retinal_hole\val_xml'
# Iterate through each XML file in the input directory
for filename in os.listdir(input_directory):
if filename.endswith('.xml'):
xml_path = os.path.join(input_directory, filename)
print(xml_path)
process_xml(xml_path)
print("Processing complete.")
xml_to_yolo_obb
4个点坐标(x,y) + 类别
# 文件名称 :roxml_to_dota.py
# 功能描述 :把rolabelimg标注的xml文件转换成dota能识别的xml文件,
# 再转换成dota格式的txt文件
# 把旋转框 cx,cy,w,h,angle,或者矩形框cx,cy,w,h,转换成四点坐标x1,y1,x2,y2,x3,y3,x4,y4
import os
import xml.etree.ElementTree as ET
import math
cls_list=['你的类别']
def edit_xml(xml_file, dotaxml_file):
"""
修改xml文件
:param xml_file:xml文件的路径
:return:
"""
tree = ET.parse(xml_file)
objs = tree.findall('object')
for ix, obj in enumerate(objs):
x0 = ET.Element("x0") # 创建节点
y0 = ET.Element("y0")
x1 = ET.Element("x1")
y1 = ET.Element("y1")
x2 = ET.Element("x2")
y2 = ET.Element("y2")
x3 = ET.Element("x3")
y3 = ET.Element("y3")
# obj_type = obj.find('bndbox')
# type = obj_type.text
# print(xml_file)
if (obj.find('robndbox') == None):
obj_bnd = obj.find('bndbox')
obj_xmin = obj_bnd.find('xmin')
obj_ymin = obj_bnd.find('ymin')
obj_xmax = obj_bnd.find('xmax')
obj_ymax = obj_bnd.find('ymax')
#以防有负值坐标
xmin = max(float(obj_xmin.text),0)
ymin = max(float(obj_ymin.text),0)
xmax = max(float(obj_xmax.text),0)
ymax = max(float(obj_ymax.text),0)
obj_bnd.remove(obj_xmin) # 删除节点
obj_bnd.remove(obj_ymin)
obj_bnd.remove(obj_xmax)
obj_bnd.remove(obj_ymax)
x0.text = str(xmin)
y0.text = str(ymax)
x1.text = str(xmax)
y1.text = str(ymax)
x2.text = str(xmax)
y2.text = str(ymin)
x3.text = str(xmin)
y3.text = str(ymin)
else:
obj_bnd = obj.find('robndbox')
obj_bnd.tag = 'bndbox' # 修改节点名
obj_cx = obj_bnd.find('cx')
obj_cy = obj_bnd.find('cy')
obj_w = obj_bnd.find('w')
obj_h = obj_bnd.find('h')
obj_angle = obj_bnd.find('angle')
cx = float(obj_cx.text)
cy = float(obj_cy.text)
w = float(obj_w.text)
h = float(obj_h.text)
angle = float(obj_angle.text)
obj_bnd.remove(obj_cx) # 删除节点
obj_bnd.remove(obj_cy)
obj_bnd.remove(obj_w)
obj_bnd.remove(obj_h)
obj_bnd.remove(obj_angle)
x0.text, y0.text = rotatePoint(cx, cy, cx - w / 2, cy - h / 2, -angle)
x1.text, y1.text = rotatePoint(cx, cy, cx + w / 2, cy - h / 2, -angle)
x2.text, y2.text = rotatePoint(cx, cy, cx + w / 2, cy + h / 2, -angle)
x3.text, y3.text = rotatePoint(cx, cy, cx - w / 2, cy + h / 2, -angle)
# obj.remove(obj_type) # 删除节点
obj_bnd.append(x0) # 新增节点
obj_bnd.append(y0)
obj_bnd.append(x1)
obj_bnd.append(y1)
obj_bnd.append(x2)
obj_bnd.append(y2)
obj_bnd.append(x3)
obj_bnd.append(y3)
tree.write(dotaxml_file, method='xml', encoding='utf-8') # 更新xml文件
# 转换成四点坐标
def rotatePoint(xc, yc, xp, yp, theta):
xoff = xp - xc;
yoff = yp - yc;
cosTheta = math.cos(theta)
sinTheta = math.sin(theta)
pResx = cosTheta * xoff + sinTheta * yoff
pResy = - sinTheta * xoff + cosTheta * yoff
return str(int(xc + pResx)), str(int(yc + pResy))
def totxt(xml_path, out_path):
# 想要生成的txt文件保存的路径,这里可以自己修改
files = os.listdir(xml_path)
i=0
for file in files:
tree = ET.parse(xml_path + os.sep + file)
root = tree.getroot()
name = file.split('.')[0]
output = out_path +'\\'+name + '.txt'
file = open(output, 'w')
i=i+1
objs = tree.findall('object')
for obj in objs:
cls = obj.find('name').text
box = obj.find('bndbox')
x0 = int(float(box.find('x0').text))
y0 = int(float(box.find('y0').text))
x1 = int(float(box.find('x1').text))
y1 = int(float(box.find('y1').text))
x2 = int(float(box.find('x2').text))
y2 = int(float(box.find('y2').text))
x3 = int(float(box.find('x3').text))
y3 = int(float(box.find('y3').text))
if x0<0:
x0=0
if x1<0:
x1=0
if x2<0:
x2=0
if x3<0:
x3=0
if y0<0:
y0=0
if y1<0:
y1=0
if y2<0:
y2=0
if y3<0:
y3=0
for cls_index,cls_name in enumerate(cls_list):
if cls==cls_name:
file.write("{} {} {} {} {} {} {} {} {} {}\n".format(x0, y0, x1, y1, x2, y2, x3, y3, cls,cls_index))
file.close()
# print(output)
print(i)
if __name__ == '__main__':
# -----**** 第一步:把xml文件统一转换成旋转框的xml文件 ****-----
roxml_path = r" 已标注并需要转换的xml文件"
dotaxml_path = r'存储dota格式的xml文件的输出路径' #
out_path = r'存储data格式yolov5_obb可训练的txt文件的路径'
filelist = os.listdir(roxml_path)
for file in filelist:
edit_xml(os.path.join(roxml_path, file), os.path.join(dotaxml_path, file))
# -----**** 第二步:把旋转框xml文件转换成txt格式 ****-----
totxt(dotaxml_path, out_path)
xml2yolo
import copy
from lxml.etree import Element, SubElement, tostring, ElementTree
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
classes = ["cup","forceps","kidneydish","needleholder","retractor","scapel","scapelhandle","scissors","sutureneedle","tampon"] # 目标类别
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
def convert(size, box):
dw = 1. / size[0]
dh = 1. / size[1]
x = (box[0] + box[1]) / 2.0
y = (box[2] + box[3]) / 2.0
w = box[1] - box[0]
h = box[3] - box[2]
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return (x, y, w, h)
def convert_annotation(image_id):
in_file = open('F:/picdata/SISD10label/%s.xml' % (image_id), encoding='UTF-8') # xml文件路径
out_file = open('F:/picdata/SISD10labelyolo/%s.txt' % (image_id), 'w') # 生成txt格式文件
tree = ET.parse(in_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
cls = obj.find('name').text
# print(cls)
if cls not in classes:
continue
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)
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
xml_path = os.path.join(CURRENT_DIR, 'F:/picdata/SISD10label')
# xml list
img_xmls = os.listdir(xml_path)
for img_xml in img_xmls:
label_name = img_xml.split('.')[0]
print(label_name)
convert_annotation(label_name)
json2txt
import json
import os
import glob
import os.path as osp
def labelme2yolov2Seg(jsonfilePath="", resultDirPath="", classList=["bowl","cup","forceps","kidneydish","needleholder","retractor","scapel","scapelhandle","sutureneedle","tampon"]):
"""
此函数用来将labelme软件标注好的数据集转换为yolov5_7.0sege中使用的数据集
:param jsonfilePath: labelme标注好的*.json文件所在文件夹
:param resultDirPath: 转换好后的*.txt保存文件夹
:param classList: 数据集中的类别标签
:return:
"""
# 0.创建保存转换结果的文件夹
if(not os.path.exists(resultDirPath)):
os.mkdir(resultDirPath)
# 1.获取目录下所有的labelme标注好的Json文件,存入列表中
jsonfileList = glob.glob(osp.join(jsonfilePath, "*.json"))
print(jsonfileList) # 打印文件夹下的文件名称
# 2.遍历json文件,进行转换
for jsonfile in jsonfileList:
# 3. 打开json文件
with open(jsonfile, "r") as f:
file_in = json.load(f)
# 4. 读取文件中记录的所有标注目标
shapes = file_in["shapes"]
# 5. 使用图像名称创建一个txt文件,用来保存数据
with open(resultDirPath + "\\" + jsonfile.split("\\")[-1].replace(".json", ".txt"), "w") as file_handle:
# 6. 遍历shapes中的每个目标的轮廓
for shape in shapes:
# 7.根据json中目标的类别标签,从classList中寻找类别的ID,然后写入txt文件中
file_handle.writelines(str(classList.index(shape["label"])) + " ")
# 8. 遍历shape轮廓中的每个点,每个点要进行图像尺寸的缩放,即x/width, y/height
for point in shape["points"]:
x = point[0]/file_in["imageWidth"] # mask轮廓中一点的X坐标
y = point[1]/file_in["imageHeight"] # mask轮廓中一点的Y坐标
file_handle.writelines(str(x) + " " + str(y) + " ") # 写入mask轮廓点
# 9.每个物体一行数据,一个物体遍历完成后需要换行
file_handle.writelines("\n")
# 10.所有物体都遍历完,需要关闭文件
file_handle.close()
# 10.所有物体都遍历完,需要关闭文件
f.close()
if __name__ == "__main__":
jsonfilePath = "F:\picdata\SISD10dataset\data_annotated" # 要转换的json文件所在目录
resultDirPath = "F:\picdata\SISD10dataset\data_txt" # 要生成的txt文件夹
labelme2yolov2Seg(jsonfilePath=jsonfilePath, resultDirPath=resultDirPath, classList=["__ignore__","_background_","bowl","cup","forceps","kidneydish","needleholder","retractor","scapel","scapelhandle","sutureneedle","tampon"]) # 更改为自己的类别名
划分train val test
import os, shutil, random
import numpy as np
postfix = 'jpg' # 这里要注意下,文件夹里的图片格式要都是jpg,如果是PNG那就都得是PNG
base_path = 'F:\数据集处理\SISD10dataset\img_data' # 先手动把txt文件放进图片文件夹JPEGImages中
dataset_path = 'F:\数据集处理\SISD10dataset\SISD10seg' # 自动新建一个文件夹SISDseg
val_size, test_size = 0.1, 0.0 # 这里把test设置为0,也就是train:val = 9:1
# val_size = 0.1
os.makedirs(dataset_path, exist_ok=True)
os.makedirs(f'{dataset_path}/images', exist_ok=True)
os.makedirs(f'{dataset_path}/images/train', exist_ok=True)
os.makedirs(f'{dataset_path}/images/val', exist_ok=True)
os.makedirs(f'{dataset_path}/images/test', exist_ok=True)
os.makedirs(f'{dataset_path}/labels/train', exist_ok=True)
os.makedirs(f'{dataset_path}/labels/val', exist_ok=True)
os.makedirs(f'{dataset_path}/labels/test', exist_ok=True)
path_list = np.array([i.split('.')[0] for i in os.listdir(base_path) if 'txt' in i])
random.shuffle(path_list)
train_id = path_list[:int(len(path_list) * (1 - val_size - test_size))]
# train_id = path_list[:int(len(path_list) * (1 - val_size))]
# val_id = path_list[int(len(path_list) * (1 - val_size - test_size)):int(len(path_list) * (1 - test_size))]
val_id = path_list[int(len(path_list) * (1 - val_size - test_size)):int(len(path_list) * (1 - test_size))]
test_id = path_list[int(len(path_list) * (1 - test_size)):]
for i in train_id:
shutil.copy(f'{base_path}/{i}.{postfix}', f'{dataset_path}/images/train/{i}.{postfix}')
shutil.copy(f'{base_path}/{i}.txt', f'{dataset_path}/labels/train/{i}.txt')
for i in val_id:
shutil.copy(f'{base_path}/{i}.{postfix}', f'{dataset_path}/images/val/{i}.{postfix}')
shutil.copy(f'{base_path}/{i}.txt', f'{dataset_path}/labels/val/{i}.txt')
for i in test_id:
shutil.copy(f'{base_path}/{i}.{postfix}', f'{dataset_path}/images/test/{i}.{postfix}')
shutil.copy(f'{base_path}/{i}.txt', f'{dataset_path}/labels/test/{i}.txt')
anaconda 手动添加系统变量
Pycharm中Terminal用不了conda指令解决办法
PowerShell窗口
Set-ExecutionPolicy RemoteSigned
Y 回车
conda init powershell
conda配置国内镜像源将Anaconda设置为国内镜像源的方法_anaconda国内源_流沙没尘居士的博客-CSDN博客
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels http://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/fastai/
conda config --set show_channel_urls yes
改变conda虚拟环境的默认路径
创建新环境,并指定python版本
conda create --name=labelImg python=3.6
进入刚建立的新环境
conda activate labelimg
pip升级到最新版
python -m pip install --upgrade pip
pip配置国内镜像源
Python-pip镜像源配置及国内常用镜像源_pypi镜像源_KwokRoot的博客-CSDN博客
windows下:新建文件C:\Users\Administrator\pip\pip.ini
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = https://pypi.tuna.tsinghua.edu.cn
pip install pyqt5
pip install labelImg==1.8.6 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
(labelImg) F:\picdata>labelImg SISD10 predefined_classes.txt
..
..