txt_json和xml_json

txt_json

复制代码
import cv2
import os
import json
'''
该脚本实现将yolo格式标签转为json格式标签
需要的数据:原始图像 原始yolo格式标签(txt文件)
'''
 
imgs_path = "D:/.../images/"  # 图像路径
txt_dir = "D:/.../labels/"  # txt标签目录路径
out_json_dir = 'D:/.../json/'  # 保存的json文件路径
 
# 确保输出目录存在
os.makedirs(out_json_dir, exist_ok=True)
 
# 定义YOLO标签类别映射
name_label = ['A', 'B', 'C']  # 需要与训练时的类别顺序一致
 
 
def convert_yolo_bbox(box, img_shape):
    """将YOLO格式的归一化坐标转换为像素坐标"""
    x_center, y_center, w, h = box
    img_h, img_w = img_shape[:2]
 
    x1 = int((x_center - w / 2) * img_w)
    y1 = int((y_center - h / 2) * img_h)
    x2 = int((x_center + w / 2) * img_w)
    y2 = int((y_center + h / 2) * img_h)
 
    return [x1, y1, x2, y2]
 
 
def parse_yolo_txt(img_path, txt_path):
    """解析YOLO标签文件"""
    img = cv2.imread(img_path)
    if img is None:
        raise FileNotFoundError(f"无法读取图像: {img_path}")
 
    bboxes = []
    if not os.path.exists(txt_path):
        return img, bboxes  # 返回空列表表示没有目标
 
    with open(txt_path, 'r') as f:
        for line in f.readlines():
            parts = line.strip().split()
            if len(parts) != 5:
                continue
 
            # 解析YOLO格式
            label_idx = int(parts[0])
            label = name_label[label_idx]
            x_center = float(parts[1])
            y_center = float(parts[2])
            width = float(parts[3])
            height = float(parts[4])
 
            # 转换坐标
            bbox = convert_yolo_bbox([x_center, y_center, width, height], img.shape)
            bbox.append(label)
            bboxes.append(bbox)
 
    return img, bboxes
 
 
def create_labelme_json(img_name, img_dir, txt_dir, output_dir):
    """创建Labelme格式的JSON标注文件"""
    # 构建完整路径
    img_path = os.path.join(img_dir, img_name)
    txt_path = os.path.join(txt_dir, img_name.replace('.jpg', '.txt'))
 
    # 解析数据
    try:
        img, gt_boxes = parse_yolo_txt(img_path, txt_path)
    except Exception as e:
        print(f"处理 {img_name} 时出错: {str(e)}")
        return
 
    # 构建基础字典
    label_dict = {
        "version": "5.5.0",
        "flags": {},
        "shapes": [],
        "imagePath": img_path,
        "imageData": None,
        "imageHeight": img.shape[0],
        "imageWidth": img.shape[1]
    }
 
    # 添加标注形状
    for box in gt_boxes:
        shape = {
            "label": box[-1],
            "points": [[box[0], box[1]], [box[2], box[3]]],
            "group_id": None,
            "description": "",
            "shape_type": "rectangle",
            "flags": {},
            "mask": None
        }
        label_dict["shapes"].append(shape)
 
    # 写入JSON文件
    output_path = os.path.join(output_dir, img_name.replace('.jpg', '.json'))
    with open(output_path, 'w') as f:
        json.dump(label_dict, f, indent=2)
 
    print(f"已生成: {output_path}")
 
 
# 主处理循环
img_files = [f for f in os.listdir(imgs_path) if f.lower().endswith('.jpg')]
 
for idx, img_name in enumerate(img_files):
    if idx % 100 == 0:
        print(f"处理进度: {idx}/{len(img_files)}")
 
    create_labelme_json(img_name, imgs_path, txt_dir, out_json_dir)
 
print("转换完成!")

xml_json

复制代码
import os
import json
import xml.etree.ElementTree as ET
from typing import List, Dict, Any
import numpy as np
from pathlib import Path

class VOC2LabelMe:
    def __init__(self):
        self.version = "5.0.1"  # LabelMe的版本号
        
    def parse_voc_xml(self, xml_path: str) -> Dict[str, Any]:
        """解析VOC格式的XML文件"""
        tree = ET.parse(xml_path)
        root = tree.getroot()
        
        # 解析图片信息
        size = root.find('size')
        img_width = int(size.find('width').text)
        img_height = int(size.find('height').text)
        
        # 解析所有目标
        objects = []
        for obj in root.findall('object'):
            label = obj.find('name').text
            bndbox = obj.find('bndbox')
            
            xmin = float(bndbox.find('xmin').text)
            ymin = float(bndbox.find('ymin').text)
            xmax = float(bndbox.find('xmax').text)
            ymax = float(bndbox.find('ymax').text)
            
            # 转换为多边形格式(矩形四个顶点)
            points = [
                [xmin, ymin],  # 左上
                [xmax, ymin],  # 右上
                [xmax, ymax],  # 右下
                [xmin, ymax]   # 左下
            ]
            
            # 创建LabelMe格式的shape
            shape = {
                "label": label,
                "points": points,
                "group_id": None,
                "shape_type": "polygon",
                "flags": {}
            }
            objects.append(shape)
        
        return {
            "width": img_width,
            "height": img_height,
            "objects": objects
        }
    
    def convert_single_file(self, xml_path: str, image_path: str = None) -> Dict[str, Any]:
        """转换单个XML文件到LabelMe JSON格式"""
        # 解析XML
        parsed_data = self.parse_voc_xml(xml_path)
        
        # 获取文件名
        xml_file = Path(xml_path)
        image_file_name = xml_file.stem + ".jpg"  # 假设图片是jpg格式
        
        # 如果提供了图片路径,使用提供的路径
        if image_path:
            image_path_str = str(Path(image_path).resolve())
        else:
            # 假设图片和XML在同一目录
            image_path_str = str(xml_file.parent / image_file_name)
        
        # 构建LabelMe JSON结构
        labelme_json = {
            "version": self.version,
            "flags": {},
            "shapes": parsed_data["objects"],
            "imagePath": image_file_name,
            "imageData": None,  # 可以设置为None,LabelMe会从imagePath加载图片
            "imageHeight": parsed_data["height"],
            "imageWidth": parsed_data["width"]
        }
        
        return labelme_json
    
    def convert_folder(self, xml_folder: str, image_folder: str = None, 
                       output_folder: str = None, save_image_data: bool = False):
        """转换整个文件夹的XML文件"""
        xml_folder = Path(xml_folder)
        
        # 设置输出文件夹
        if output_folder:
            output_folder = Path(output_folder)
        else:
            output_folder = xml_folder / "labelme_json"
        
        output_folder.mkdir(parents=True, exist_ok=True)
        
        # 获取所有XML文件
        xml_files = list(xml_folder.glob("*.xml"))
        
        print(f"找到 {len(xml_files)} 个XML文件")
        
        for xml_file in xml_files:
            try:
                # 构建图片路径
                if image_folder:
                    img_path = Path(image_folder) / f"{xml_file.stem}.jpg"
                else:
                    img_path = None
                
                # 转换单个文件
                labelme_json = self.convert_single_file(str(xml_file), str(img_path) if img_path else None)
                
                # 保存JSON文件
                output_path = output_folder / f"{xml_file.stem}.json"
                with open(output_path, 'w', encoding='utf-8') as f:
                    json.dump(labelme_json, f, indent=2, ensure_ascii=False)
                
                print(f"✓ 已转换: {xml_file.name} -> {output_path.name}")
                
            except Exception as e:
                print(f"✗ 转换失败 {xml_file.name}: {str(e)}")
        
        print(f"\n转换完成!JSON文件保存在: {output_folder}")

# 使用示例
if __name__ == "__main__":
    converter = VOC2LabelMe()
    
    # 方法1: 转换单个文件
    # xml_path = "path/to/your/annotation.xml"
    # image_path = "path/to/your/image.jpg"  # 可选
    # result = converter.convert_single_file(xml_path, image_path)
    # 
    # # 保存JSON
    # with open("output.json", 'w', encoding='utf-8') as f:
    #     json.dump(result, f, indent=2, ensure_ascii=False)
    
    # 方法2: 批量转换整个文件夹
    # 假设XML文件和对应的图片文件在同一文件夹
    xml_folder = "D:\\hat\\VOC2028\\Annotations"  # 请修改为你的XML文件夹路径
    image_folder = "D:\\hat\\VOC2028\\JPEGImages"  # 如果图片在不同文件夹,可以指定
    output_folder = "D:\\hat\\VOC2028\\json"  # 可选,默认会在XML文件夹下创建labelme_json文件夹
    
    converter.convert_folder(
        xml_folder=xml_folder,
        image_folder=None,  # 如果图片在不同文件夹,请指定
        output_folder=None
    )

json_txt

复制代码
import json
import os
input_folder = 'D:/.../json'
output_folder = 'D:/.../txt'
os.makedirs(output_folder, exist_ok=True)
# 标注类别名
label_to_id_mapping = {
    'A': 0,
    'B': 1,
    'C': 2,
    'D': 3
    # Add more mappings as needed
}
 
def convert_annotation(json_file, txt_file, label_to_id_mapping):
    # Read the JSON file
    with open(json_file, 'r', encoding='utf-8') as f:
        data = json.load(f)
 
        # Extract image dimensions, assuming 'imageWidth' and 'imageHeight' fields are present
    image_width = data.get('imageWidth')
    image_height = data.get('imageHeight')
 
    # Check if image dimensions are present
    if image_width is None or image_height is None:
        raise ValueError(f"Missing image dimensions in {json_file}")
 
        # Iterate over all shapes (annotations)
    with open(txt_file, 'w', encoding='utf-8') as out_file:
        for shape in data.get('shapes', []):
            # Extract point coordinates, assuming each shape has a 'points' field
            points = shape.get('points', [])
 
            # Check if points are present
            if not points:
                raise ValueError(f"Missing points in a shape in {json_file}")
 
            x_values = [point[0] for point in points]
            y_values = [point[1] for point in points]
 
            x_min = min(x_values)
            y_min = min(y_values)
            x_max = max(x_values)
            y_max = max(y_values)
 
            # Calculate bounding box center, width, and height
            bbox_center_x = (x_min + x_max) / 2
            bbox_center_y = (y_min + y_max) / 2
            bbox_width = x_max - x_min
            bbox_height = y_max - y_min
 
            # Convert bounding box coordinates to ratios relative to image dimensions
            bbox_center_x_ratio = bbox_center_x / image_width
            bbox_center_y_ratio = bbox_center_y / image_height
            bbox_width_ratio = bbox_width / image_width
            bbox_height_ratio = bbox_height / image_height
 
            # Get the category ID, assuming each shape has a 'label' field
            category_id = shape.get('label', "unknown")
            if isinstance(category_id, str):
                # If the label is a string, map it to a numeric ID using the provided mapping
                category_id = label_to_id_mapping.get(category_id, -1)  # Default to -1 if label is unknown
 
            # Write the result to the TXT file in YOLO format
            out_file.write(
                f"{int(category_id)} {bbox_center_x_ratio} {bbox_center_y_ratio} {bbox_width_ratio} {bbox_height_ratio}\n")
 
        # Input and output folder paths
 
 
# Iterate over all JSON files in the input folder
for filename in os.listdir(input_folder):
    if filename.endswith('.json'):
        json_file = os.path.join(input_folder, filename)
        txt_file = os.path.join(output_folder, filename.replace('.json', '.txt'))
        try:
            convert_annotation(json_file, txt_file, label_to_id_mapping)
            print(f'{txt_file},Conversion successful!')
        except Exception as e:
            print(f"An error occurred while processing {json_file}: {e}")

参考链接:https://blog.csdn.net/chao_xy/article/details/147363834

相关推荐
DevOpenClub3 小时前
语义化获取站点 JSON 结构内容 API 接口
json
zyq99101_13 小时前
DFS算法实战:经典例题代码解析
python·算法·蓝桥杯·深度优先
数据知道3 小时前
claw-code 源码分析:从 TypeScript 心智到 Python/Rust——跨栈移植时类型、边界与错误模型怎么对齐?
python·ai·rust·typescript·claude code·claw code
20YC编程社区4 小时前
一分钟了解XML语言格式,使用场景,和它的优缺点
xml
hhh3u3u3u4 小时前
Visual C++ 6.0中文版安装包下载教程及win11安装教程
java·c语言·开发语言·c++·python·c#·vc-1
好家伙VCC4 小时前
**发散创新:基于Python与ROS的机器人运动控制实战解析**在现代机器人系统开发中,**运动控制**是实现智能行为的核心
java·开发语言·python·机器人
2401_827499994 小时前
python项目实战09-AI智能伴侣(ai_partner_2-3)
开发语言·python
派葛穆4 小时前
汇川PLC-Python与汇川easy521plc进行Modbustcp通讯
开发语言·python
代码小书生5 小时前
Matplotlib,Python 数据可视化核心库!
python·信息可视化·matplotlib