| import os |
| import xml.etree.ElementTree as ET |
| from PIL import Image |
| import shutil |
| from tqdm import tqdm |
| import argparse |
| |
| |
| def create_voc_xml(image_path, boxes, labels, out_path): |
| img = Image.open(image_path) |
| width, height = img.size |
| |
| root = ET.Element("annotation") |
| ET.SubElement(root, "folder").text = os.path.basename(os.path.dirname(os.path.dirname(out_path))) |
| ET.SubElement(root, "filename").text = os.path.basename(image_path) |
| |
| size = ET.SubElement(root, "size") |
| ET.SubElement(size, "width").text = str(width) |
| ET.SubElement(size, "height").text = str(height) |
| ET.SubElement(size, "depth").text = str(3) |
| |
| for box, label in zip(boxes, labels): |
| obj = ET.SubElement(root, "object") |
| ET.SubElement(obj, "name").text = label |
| ET.SubElement(obj, "pose").text = "Unspecified" |
| ET.SubElement(obj, "truncated").text = "0" |
| ET.SubElement(obj, "difficult").text = "0" |
| |
| bbox = ET.SubElement(obj, "bndbox") |
| ET.SubElement(bbox, "xmin").text = str(int(box[0])) |
| ET.SubElement(bbox, "ymin").text = str(int(box[1])) |
| ET.SubElement(bbox, "xmax").text = str(int(box[2])) |
| ET.SubElement(bbox, "ymax").text = str(int(box[3])) |
| |
| tree = ET.ElementTree(root) |
| tree.write(out_path) |
| |
| |
| def yolo_to_voc_format(yolo_box, img_width, img_height): |
| x_center, y_center, w, h = yolo_box |
| w *= img_width |
| h *= img_height |
| x_center *= img_width |
| y_center *= img_height |
| |
| xmin = int(x_center - w / 2) |
| ymin = int(y_center - h / 2) |
| xmax = int(x_center + w / 2) |
| ymax = int(y_center + h / 2) |
| |
| return [xmin, ymin, xmax, ymax] |
| |
| |
| def convert_dataset(img_path, label_path, output_path, image_set): |
| os.makedirs(os.path.join(output_path, "Annotations"), exist_ok=True) |
| os.makedirs(os.path.join(output_path, "JPEGImages"), exist_ok=True) |
| os.makedirs(os.path.join(output_path, "ImageSets", "Main"), exist_ok=True) |
| |
| image_list = [] |
| |
| for img_file in tqdm(os.listdir(img_path), desc=f"Processing {image_set}"): |
| if img_file.lower().endswith(('.png', '.jpg', '.jpeg', '.tif', '.tiff')): |
| img_filename = os.path.splitext(img_file)[0] |
| image_list.append(img_filename) |
| |
| |
| shutil.copy( |
| os.path.join(img_path, img_file), |
| os.path.join(output_path, "JPEGImages", img_file) |
| ) |
| |
| |
| label_file = os.path.join(label_path, f"{img_filename}.txt") |
| if os.path.exists(label_file): |
| with open(label_file, 'r') as f: |
| lines = f.readlines() |
| |
| img = Image.open(os.path.join(img_path, img_file)) |
| img_width, img_height = img.size |
| |
| boxes = [] |
| labels = [] |
| for line in lines: |
| data = line.strip().split() |
| label = data[0] |
| box = list(map(float, data[1:])) |
| voc_box = yolo_to_voc_format(box, img_width, img_height) |
| boxes.append(voc_box) |
| labels.append(label) |
| |
| |
| xml_path = os.path.join(output_path, "Annotations", f"{img_filename}.xml") |
| create_voc_xml(os.path.join(img_path, img_file), boxes, labels, xml_path) |
| |
| |
| with open(os.path.join(output_path, "ImageSets", "Main", f"{image_set}.txt"), 'w') as f: |
| for item in image_list: |
| f.write(f"{item}\n") |
| |
| |
| def main(train_img_path, train_label_path, val_img_path, val_label_path, output_path): |
| |
| convert_dataset(train_img_path, train_label_path, output_path, "train") |
| |
| |
| convert_dataset(val_img_path, val_label_path, output_path, "val") |
| |
| print("转换完成!VOC格式数据集已保存到", output_path) |
| |
| |
| if __name__ == "__main__": |
| parser = argparse.ArgumentParser(description="Convert YOLO format dataset to VOC format") |
| parser.add_argument("--train_img", default="/home/lab/LJ/wampee/WampeeDataSets/train/images", help="Path to training images") |
| parser.add_argument("--train_label", default="/home/lab/LJ/wampee/WampeeDataSets/train/labels", |
| help="Path to training labels") |
| parser.add_argument("--val_img", default="/home/lab/LJ/wampee/WampeeDataSets/valid/images", help="Path to validation images") |
| parser.add_argument("--val_label", default="/home/lab/LJ/wampee/WampeeDataSets/valid/labels", help="Path to validation labels") |
| parser.add_argument("--output", default="/home/lab/LJ/wampee/Wampee_dataSets__Voc_Sec", help="Path to output VOC dataset") |
| |
| args = parser.parse_args() |
| |
| main(args.train_img, args.train_label, args.val_img, args.val_label, args.output) |