👨💻个人简介: 深度学习图像领域工作者
🎉总结链接:
链接中主要是个人工作的总结,每个链接都是一些常用demo,代码直接复制运行即可。包括:
📌1.工作中常用深度学习脚本
📌2.torch、numpy等常用函数详解
📌3.opencv 图片、视频等操作
📌4.个人工作中的项目总结(纯干活)
链接: https://blog.csdn.net/qq_28949847/article/details/128552785
🎉视频讲解: 以上记录,通过B站等平台进行了视频讲解使用,可搜索 ‘Python图像识别’ 进行观看
B站:Python图像识别
抖音:Python图像识别
西瓜视频:Python图像识别
1. 目标检测矩形框转换
(1)labelme标注的数据json文件转为labelimg格式的xml文件
目前只能支持 json中 ‘rectangle
’ 和 ‘polygon
’ 两种模式的转换,其中 ‘polygon
’ 的转换方式为,替换成最小外接矩形的左上角和右下角坐标。
输入:由labelme的rectangle或这polygon方式标注生成的json文件;
输出:类似于labelImg的rectangle方式标注生成的xml文件,是左上角和右下角的坐标。
个人只需修改相应的路径。
# -*- coding: utf-8 -*-
import numpy as np
import json
from lxml import etree
import os
from tqdm import tqdm
class ReadJson(object):
'''
读取json文件,获取相应的标签信息
'''
def __init__(self, json_path):
self.json_data = json.load(open(json_path, encoding="utf-8"))
self.filename = self.json_data['imagePath']
self.width = self.json_data['imageWidth']
self.height = self.json_data['imageHeight']
self.coordis = []
# 构建坐标
self.process_shapes()
def process_shapes(self):
for single_shape in self.json_data['shapes']:
if single_shape['shape_type'] == "rectangle":
bbox_class = single_shape['label']
xmin = single_shape['points'][0][0]
ymin = single_shape['points'][0][1]
xmax = single_shape['points'][1][0]
ymax = single_shape['points'][1][1]
self.coordis.append([xmin, ymin, xmax, ymax, bbox_class])
elif single_shape['shape_type'] == 'polygon':
bbox_class = single_shape['label']
temp_points = single_shape['points']
temp_points = np.array(temp_points)
xmin, ymin = temp_points.min(axis=0)
xmax, ymax = temp_points.max(axis=0)
self.coordis.append([xmin, ymin, xmax, ymax, bbox_class])
else:
print("shape type error, shape_type not in ['rectangle', 'polygon']")
def get_width_height(self):
return self.width, self.height
def get_filename(self):
return self.filename
def get_coordis(self):
return self.coordis
class labelimg_Annotations_xml:
def __init__(self, folder_name, filename, path, database="Unknown"):
self.root = etree.Element("annotation")
child1 = etree.SubElement(self.root, "folder")
child1.text = folder_name
child2 = etree.SubElement(self.root, "filename")
child2.text = filename
child3 = etree.SubElement(self.root, "path")
child3.text = path
child4 = etree.SubElement(self.root, "source")
child5 = etree.SubElement(child4, "database")
child5.text = database
def set_size(self, width, height, channel):
size = etree.SubElement(self.root, "size")
widthn = etree.SubElement(size, "width")
widthn.text = str(width)
heightn = etree.SubElement(size, "height")
heightn.text = str(height)
channeln = etree.SubElement(size, "channel")
channeln.text = str(channel)
def set_segmented(self, seg_data=0):
segmented = etree.SubElement(self.root, "segmented")
segmented.text = str(seg_data)
def set_object(self, label, x_min, y_min, x_max, y_max,
pose='Unspecified', truncated=0, difficult=0):
object = etree.SubElement(self.root, "object")
namen = etree.SubElement(object, "name")
namen.text = label
posen = etree.SubElement(object, "pose")
posen.text = pose
truncatedn = etree.SubElement(object, "truncated")
truncatedn.text = str(truncated)
difficultn = etree.SubElement(object, "difficult")
difficultn.text = str(difficult)
bndbox = etree.SubElement(object, "bndbox")
xminn = etree.SubElement(bndbox, "xmin")
xminn.text = str(x_min)
yminn = etree.SubElement(bndbox, "ymin")
yminn.text = str(y_min)
xmaxn = etree.SubElement(bndbox, "xmax")
xmaxn.text = str(x_max)
ymaxn = etree.SubElement(bndbox, "ymax")
ymaxn.text = str(y_max)
def savefile(self, filename):
tree = etree.ElementTree(self.root)
tree.write(filename, pretty_print=True, xml_declaration=False, encoding='utf-8')
def json_transform_xml(json_path, xml_path):
json_anno = ReadJson(json_path)
width, height = json_anno.get_width_height()
channel = 3
filename = json_anno.get_filename()
coordis = json_anno.get_coordis()
anno = labelimg_Annotations_xml('JPEGImages', filename, 'JPEGImages')
anno.set_size(width, height, channel)
anno.set_segmented()
for data in coordis:
x_min, y_min, x_max, y_max, label = data
anno.set_object(label, int(x_min), int(y_min), int(x_max), int(y_max))
anno.savefile(xml_path)
if __name__ == "__main__":
'''
目前只能支持 json中 rectangle 和 polygon 两种模式的转换,其中 polygon 的转换方式为,替换成最小外接矩形的左上角和右下角坐标
'''
root_json_dir = r"C:\Users\JoelYang\Desktop\111111\bbox_20230417_gjx"
# root_save_xml_dir = r"\\SHARE\public\Time_Plus\traindata\bbox\tiaoshui3m\20230418_zxl"
root_save_xml_dir = root_json_dir
for json_filename in tqdm(os.listdir(root_json_dir)):
if not json_filename.endswith(".json"):
continue
json_path = os.path.join(root_json_dir, json_filename)
save_xml_path = os.path.join(root_save_xml_dir, json_filename.replace(".json", ".xml"))
json_transform_xml(json_path, save_xml_path)
效果如下图:
json文件:
xml文件:
(2)labelimg xml文件转 labelme json文件
import xml.etree.ElementTree as ET
import os
import json
def xml_transform_json(xml_path, file, save_path):
print(os.path.join(xml_path, file))
# 读取xml文件
path_file_xml = os.path.join(xml_path, file)
# 解析读取xml函数
root = ET.parse(path_file_xml)
folder = root.find('folder').text
filename = root.find('filename').text
path = root.find('path').text
sz = root.find('size')
width = int(sz[0].text)
height = int(sz[1].text)
# 构建json数据
data = {}
data['flags'] = {}
data['version'] = "4.5.6"
data["shapes"] = []
for child in root.findall('object'): # 找到图片中的所有框
sub = child.find('bndbox') # 找到框的标注值并进行读取
xmin = float(sub[0].text)
ymin = float(sub[1].text)
xmax = float(sub[2].text)
ymax = float(sub[3].text)
points = [[xmin, ymin], [xmax, ymax]]
itemData = {'points': []}
itemData['points'].extend(points)
name = child.find("name").text
itemData["flag"] = {}
itemData["group_id"] = None
itemData["shape_type"] = "rectangle"
itemData["label"] = name
data["shapes"].append(itemData)
data['imageWidth'] = width
data['imageHeight'] = height
data['imageData'] = None
data['imagePath'] = filename
filename, extension = os.path.splitext(file)
jsonName = ".".join([filename, "json"])
# 写入json
json_path = os.path.join(save_path, jsonName)
with open(json_path, "w") as f:
json.dump(data, f)
print(json_path, "加载入文件完成...")
if __name__ == '__main__':
xml_path = r"C:\Users\JoelYang\Desktop\111111\bbox_20230417_gjx"
# save_path = r"C:\Users\JoelYang\Desktop\111111\bbox_20230417_gjx"
save_path = xml_path
for root, dirs, files in os.walk(xml_path):
for file in files:
if not file.endswith(".xml"):
continue
xml_transform_json(root, file, save_path)
效果如下:
xml文件
转后的json文件
文章来源:https://www.toymoban.com/news/detail-422041.html
(3)VOC xml格式转yolo txt格式
import os
import xml.etree.ElementTree as ET
# VOC数据集路径
voc_ann_path = r"D:\lg\BaiduSyncdisk\project\person_code\project_self\chepai_OCR\data\traindata\xml"
voc_img_path = r"D:\lg\BaiduSyncdisk\project\person_code\project_self\chepai_OCR\data\traindata\VOC\images\train\images\train"
# YOLO数据集路径
yolo_out_path = r"D:\lg\BaiduSyncdisk\project\person_code\project_self\chepai_OCR\data\traindata\txt"
# VOC类别名称和对应的编号
classes = {"blue": 0, "green": 1} # 根据实际情况修改
# 遍历VOC数据集文件夹
for filename in os.listdir(voc_ann_path):
# 解析XML文件
tree = ET.parse(os.path.join(voc_ann_path, filename))
root = tree.getroot()
# 获取图片尺寸
size = root.find("size")
width = int(size.find("width").text)
height = int(size.find("height").text)
# 创建YOLO标注文件
yolo_filename = filename.replace(".xml", ".txt")
yolo_file = open(os.path.join(yolo_out_path, yolo_filename), "w")
# 遍历XML文件中的所有目标
for obj in root.findall("object"):
# 获取目标类别名称和边界框坐标
name = obj.find("name").text
xmin = int(obj.find("bndbox").find("xmin").text)
ymin = int(obj.find("bndbox").find("ymin").text)
xmax = int(obj.find("bndbox").find("xmax").text)
ymax = int(obj.find("bndbox").find("ymax").text)
# 计算边界框中心点坐标和宽高
x = (xmin + xmax) / 2 / width
y = (ymin + ymax) / 2 / height
w = (xmax - xmin) / width
h = (ymax - ymin) / height
# 将目标写入YOLO标注文件
class_id = classes[name]
yolo_file.write(f"{class_id} {x} {y} {w} {h}\n")
yolo_file.close()
划分为 train、val、test且生成为yolo训练集的文件夹结构文章来源地址https://www.toymoban.com/news/detail-422041.html
import os
import random
import shutil
import xml.etree.ElementTree as ET
########################################################################
# 只需修改voc_ann_path、voc_img_path、yolo_out_path三个路径,自动生成为yolo
# 训练格式的数据集
########################################################################
# VOC数据集路径
voc_ann_path = r"D:\lg\BaiduSyncdisk\project\person_code\project_self\11_fruit_detect\data\VOC\Annotations"
voc_img_path = r"D:\lg\BaiduSyncdisk\project\person_code\project_self\11_fruit_detect\data\VOC\JPEGImages"
# YOLO数据集路径
yolo_out_path = r"D:\lg\BaiduSyncdisk\project\person_code\project_self\11_fruit_detect\data\yolo"
train_img_path = os.path.join(yolo_out_path, 'train', 'images', 'train')
train_labels_path = train_img_path.replace('images', 'labels')
test_img_path = os.path.join(yolo_out_path, 'test', 'images', 'test')
test_labels_path = test_img_path.replace('images', 'labels')
val_img_path = os.path.join(yolo_out_path, 'val', 'images', 'val')
val_labels_path = val_img_path.replace('images', 'labels')
# VOC类别名称和对应的编号
classes = data_dict = {
"白菜": 0,
"白萝卜": 1,
"胡萝卜": 2,
"番茄": 3
}
# 随机划分比例
train_ratio = 0.8
val_ratio = 0.1
test_ratio = 0.1
# 获取所有文件名
all_files = os.listdir(voc_img_path)
# 随机打乱文件顺序
random.shuffle(all_files)
# 计算划分的索引位置
train_index = int(len(all_files) * train_ratio)
val_index = train_index + int(len(all_files) * val_ratio)
# 创建保存txt文件的文件夹
os.makedirs(train_labels_path, exist_ok=True)
os.makedirs(test_labels_path, exist_ok=True)
os.makedirs(val_labels_path, exist_ok=True)
# 创建保存图片的文件夹
os.makedirs(train_img_path, exist_ok=True)
os.makedirs(test_img_path, exist_ok=True)
os.makedirs(val_img_path, exist_ok=True)
# 遍历VOC数据集文件夹
for i, filename in enumerate(all_files):
name, ext = os.path.splitext(filename)
xml_name = name + '.xml'
xml_path = os.path.join(voc_ann_path, xml_name)
if not os.path.exists(xml_path):
continue
# 解析XML文件
tree = ET.parse(xml_path)
root = tree.getroot()
# 获取图片尺寸
size = root.find("size")
width = int(size.find("width").text)
height = int(size.find("height").text)
# 创建YOLO标注文件
yolo_filename = xml_name.replace(".xml", ".txt")
if i < train_index:
yolo_file = open(os.path.join(train_labels_path, yolo_filename), "w")
img_dest_path = train_img_path
elif i < val_index:
yolo_file = open(os.path.join(val_labels_path, yolo_filename), "w")
img_dest_path = val_img_path
else:
yolo_file = open(os.path.join(test_labels_path, yolo_filename), "w")
img_dest_path = test_img_path
# 遍历XML文件中的所有目标
for obj in root.findall("object"):
# 获取目标类别名称和边界框坐标
name = obj.find("name").text
xmin = int(obj.find("bndbox").find("xmin").text)
ymin = int(obj.find("bndbox").find("ymin").text)
xmax = int(obj.find("bndbox").find("xmax").text)
ymax = int(obj.find("bndbox").find("ymax").text)
# 计算边界框中心点坐标和宽高
x = (xmin + xmax) / 2 / width
y = (ymin + ymax) / 2 / height
w = (xmax - xmin) / width
h = (ymax - ymin) / height
# 将目标写入YOLO标注文件
class_id = classes[name]
yolo_file.write(f"{class_id} {x} {y} {w} {h}\n")
yolo_file.close()
# 复制图片到对应的划分文件夹
# img_filename = filename.replace(".xml", ".jpg")
img_src_path = os.path.join(voc_img_path, filename)
shutil.copy(img_src_path, img_dest_path)
到了这里,关于数据格式转换(labelme、labelimg、yolo格式相互转换)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!