You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
7.2 KiB
Python

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import os
import cv2
from lxml.etree import Element, SubElement, tostring
import xml.etree.ElementTree as ET
# 解析原始XML标注文件获取人物的坐标信息
def parse_xml(xml_path,labels):
tree = ET.parse(xml_path)
root = tree.getroot()
labeks_list = []
for obj in root.findall('object'):
try:
name_labels = str(obj.find('name').text)
if name_labels == labels:
labels_dict = {}
labels_dict['name'] = name_labels
labels_dict['xmin'] = int(obj.find('bndbox/xmin').text)
labels_dict['ymin'] = int(obj.find('bndbox/ymin').text)
labels_dict['xmax'] = int(obj.find('bndbox/xmax').text)
labels_dict['ymax'] = int(obj.find('bndbox/ymax').text)
labeks_list.append(labels_dict)
except:
continue
#如果有需要的信息,就返回列表
if labeks_list:
return labeks_list
# 筛选手部和头部信息
def select_infors(xml_path,person):
infors_list = []
# 分别获得头部和手部信息
hands = parse_xml(xml_path=xml_path,labels='phone')
head = parse_xml(xml_path=xml_path,labels='head')
# 分别处理头部和手部信息
if hands:
for h,hand in enumerate(hands):
hand_result = change_bbox(infor=hand,contrast=person)
if hand_result:
infors_list.append(hand_result)
if head:
for h,head_infor in enumerate(head):
head_result = change_bbox(infor=head_infor,contrast=person)
if head_result:
infors_list.append(head_result)
else:
pass
return infors_list
# 转换坐标值
def change_bbox(infor,contrast):
if contrast['ymin'] <= infor['ymin'] and contrast['ymax'] >= infor['ymax'] and contrast['xmin'] <= infor['xmin'] and contrast['xmax'] >= infor['xmax']:
# 截取图片后的相对坐标
infor['ymin'] = infor['ymin'] - contrast['ymin']
infor['ymax'] = infor['ymax'] - contrast['ymin']
infor['xmin'] = infor['xmin'] - contrast['xmin']
infor['xmax'] = infor['xmax'] - contrast['xmin']
return infor
else:
pass
# 根据坐标值截图并保存
def cut_img_bbox(image_path,infors,num):
# # 读取大图
image = cv2.imread(image_path)
# 取大一些范围的截图尺寸
infors.update(ymin=infors['ymin'] - 25)
infors.update(ymax=infors['ymax'] + 25)
infors.update(xmin=infors['xmin'] - 25)
infors.update(xmax=infors['xmax'] + 25)
# 截取人物图片
person_image = image[infors['ymin']:infors['ymax'], infors['xmin']:infors['xmax']]
# 保存人物图片
person_filename = os.path.basename(image_path).split('.')[0] +'_'+ f"person_{num}.jpg"
# print(person_filename)
person_image_path = os.path.join(output_img_folder, person_filename)
cv2.imwrite(person_image_path, person_image)
return person_filename
# 读取大图并截取人物图片
def extract_people(image_path, xml_path, output_img_folder, output_xml_folder):
# 解析XML标注文件、获得人的标注信息
people = parse_xml(xml_path=xml_path,labels='person')
# 逐个截取人物图片
for i, person in enumerate(people):
# 截图保存并返回图片名
person_filename = cut_img_bbox(image_path=image_path,infors=person,num=i)
# 写xml
node_root = Element('annotation')
node_folder = SubElement(node_root, 'folder')
node_folder.text = 'Images'
node_filename = SubElement(node_root, 'filename')
node_filename.text = str(person_filename)
node_size = SubElement(node_root, 'size')
node_width = SubElement(node_size, 'width')
node_width.text = str(person['xmax'] - person['xmin'])
node_height = SubElement(node_size, 'height')
node_height.text = str(person['ymax'] - person['ymin'])
node_depth = SubElement(node_size, 'depth')
node_depth.text = str(3)
# 获得小图上的相对坐标
select_infor_list = select_infors(xml_path=xml_path,person=person)
if len(select_infor_list)>=1: # 循环写入box
for infors in select_infor_list:
node_object = SubElement(node_root, 'object')
node_name = SubElement(node_object, 'name')
node_name.text = str(infors['name'])
node_difficult = SubElement(node_object, 'difficult')
node_difficult.text = '0'
node_bndbox = SubElement(node_object, 'bndbox')
node_xmin = SubElement(node_bndbox, 'xmin')
node_xmin.text = str(int(infors['xmin']))
node_ymin = SubElement(node_bndbox, 'ymin')
node_ymin.text = str(int(infors['ymin']))
node_xmax = SubElement(node_bndbox, 'xmax')
node_xmax.text = str(int(infors['xmax']))
node_ymax = SubElement(node_bndbox, 'ymax')
node_ymax.text = str(int(infors['ymax']))
else:
pass
xml = tostring(node_root, pretty_print=True) # 格式化显示,该换行的换行
# # 保存新的XML标注文件
new_xml_filename = person_filename.split('.')[0] + '.xml'
new_xml_path = os.path.join(output_xml_folder, new_xml_filename)
new_xml = open(new_xml_path, "wb")
new_xml.write(xml)
new_xml.close()
print(f"Saved person image {person_filename} and corresponding annotation {new_xml_filename}")
# 读取文件
def main(image_path,xml_path,output_img_folder,output_xml_folder):
# 检查保存的文件路径
print("frame image save path{}".format(output_img_folder,output_xml_folder))
os.makedirs(output_img_folder, exist_ok=True)
os.makedirs(output_xml_folder, exist_ok=True)
img_file_list = os.listdir(image_path)
xml_file_list = os.listdir(xml_path)
for img_file in img_file_list:
img_file_full = os.path.join(image_path,img_file)
xml_file_combination_name = img_file.split('.')[0] + '.xml'
xml_file_combination = os.path.join(xml_path,xml_file_combination_name)\
if xml_file_combination_name in xml_file_list:
# 遍历文件处理数据
extract_people(image_path=img_file_full,
xml_path=xml_file_combination,
output_img_folder=output_img_folder,
output_xml_folder=output_xml_folder
)
else:
pass
if __name__ == '__main__':
# 原始大图像路径
image_path = "E:/Images_Data/XZ/bank2/yolov8/images"
# 原始XML标注文件路径
xml_path = "E:/Images_Data/XZ/bank2/yolov8/XML_collect"
# 输出文件夹路径
output_img_folder = "E:/Images_Data/XZ/bank2/yolov8/output_files/images"
output_xml_folder = 'E:/Images_Data/XZ/bank2/yolov8/output_files/Annotations'
# parse_xml('E:/Images_Data/XZ/bank2/yolov8/XML_collect/Test_1_000014.xml')
main(image_path=image_path,
xml_path=xml_path,
output_img_folder=output_img_folder,
output_xml_folder=output_xml_folder
)