自己制作VOC转yolo的软件

不多说,直接贴源码,很简单,直接复制下来运行就行

from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QLabel, QLineEdit, QPushButton,
                             QListWidget, QProgressBar, QHBoxLayout, QMainWindow, QFileDialog, QMenu,
                             QDesktopWidget, QSplashScreen, QTimeEdit, QApplication, QStatusBar, QTextEdit, QMessageBox)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QTime
from PyQt5.QtGui import QPixmap, QIcon
import sys
import os
import fnmatch
import subprocess
# from VOCToYOLO import convert_voc_to_yolo

import os
import xml.etree.ElementTree as ET
# VOC to yolo
def convert_voc_to_yolo(voc_path, output_path, class_names, progress_callback=None):
    """
    Convert VOC format annotations to YOLO format annotations.

    :param voc_path: Directory containing VOC format XML files.
    :param output_path: Directory to save YOLO format TXT files.
    :param class_names: List of class names in the same order as their indices.
    :param progress_callback: Callback function to update progress bar.
    """
    if not os.path.exists(output_path):
        os.makedirs(output_path)

    xml_files = [f for f in os.listdir(voc_path) if f.endswith('.xml')]
    total_files = len(xml_files)
    processed_files = 0

    for xml_file in xml_files:
        xml_path = os.path.join(voc_path, xml_file)
        tree = ET.parse(xml_path)
        root = tree.getroot()

        # Extract the image file name without extension
        filename_without_ext = xml_file.split(".xml")[0]
        img_width = int(root.find('size/width').text)
        img_height = int(root.find('size/height').text)

        yolo_lines = []
        for obj in root.findall('object'):
            class_name = obj.find('name').text
            if class_name not in class_names:
                continue

            class_id = class_names.index(class_name)
            bbox = obj.find('bndbox')
            xmin = float(bbox.find('xmin').text)
            ymin = float(bbox.find('ymin').text)
            xmax = float(bbox.find('xmax').text)
            ymax = float(bbox.find('ymax').text)

            # Convert to YOLO format
            x_center = (xmin + xmax) / 2 / img_width
            y_center = (ymin + ymax) / 2 / img_height
            width = (xmax - xmin) / img_width
            height = (ymax - ymin) / img_height

            yolo_lines.append(f"{class_id} {x_center} {y_center} {width} {height}")

        # Save to YOLO format with the same name as the image file
        yolo_file = os.path.join(output_path, filename_without_ext + '.txt')
        with open(yolo_file, 'w') as f:
            f.write("\n".join(yolo_lines))

        processed_files += 1
        if progress_callback:
            progress_callback(processed_files * 100 // total_files)

def resource_path(relative_path):
    """ 获取资源文件的绝对路径 """
    try:
        # PyInstaller创建的临时文件夹路径
        base_path = sys._MEIPASS
    except AttributeError:
        # 如果不是打包的环境,使用当前文件夹
        base_path = os.path.dirname(__file__)
    return os.path.join(base_path, relative_path)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('YOLOv10数据集转换器')
        self.setGeometry(100, 100, 800, 400)

        self.setWindowIcon(QIcon(resource_path('source/image/logo.ico')))
        main_layout = QVBoxLayout()

        # ----------------------------------------------------
        #   文件加载部分
        # ----------------------------------------------------
        load_layout = QHBoxLayout()
        self.load_button = QPushButton("加载标注文件夹")
        self.load_button.clicked.connect(self.load_dir)
        load_layout.addWidget(self.load_button)
        self.line_edit = QLineEdit()
        self.line_edit.setPlaceholderText("请输入文本...")
        load_layout.addWidget(self.line_edit)
        # 填写输出路径
        output_layout = QHBoxLayout()
        self.outputdir_load_button = QPushButton("输出文件夹路径")
        self.outputdir_load_button.clicked.connect(self.load_output_dir)
        output_layout.addWidget(self.outputdir_load_button)
        self.outputdir_edit = QLineEdit()
        self.outputdir_edit.setPlaceholderText("待输出文本...")
        output_layout.addWidget(self.outputdir_edit)
        # 填写VOC类别
        class_layout = QHBoxLayout()
        self.write_class_message = QLabel("输入类别信息:")
        class_layout.addWidget(self.write_class_message)
        self.classwirte_edit = QLineEdit()
        self.classwirte_edit.setPlaceholderText("请输入类别信息如:{};该信息默认".format(["ok", "YiWu", "CanJiao", "CanXi","ShaoJian",
                                                                              "BianXing","PaoMianTiePian", "PaoMianLouTie"]))
        class_layout.addWidget(self.classwirte_edit)

        main_layout.addLayout(load_layout)
        main_layout.addLayout(output_layout)
        main_layout.addLayout(class_layout)
        # ----------------------------------------------------
        #   转换部分
        # ----------------------------------------------------
        button_layout = QHBoxLayout()
        self.start_button = QPushButton("开始转换")
        button_layout.addWidget(self.start_button)
        self.defor_button = QPushButton("判断格式")
        self.defor_button.clicked.connect(self.modeDet)
        button_layout.addWidget(self.defor_button)
        main_layout.addLayout(button_layout)

        # ----------------------------------------------------
        #   进度条部分
        # ----------------------------------------------------
        progress_layout = QHBoxLayout()
        self.progress_bar = QProgressBar()
        progress_layout.addWidget(self.progress_bar)
        main_layout.addLayout(progress_layout)

        # ----------------------------------------------------
        #   状态栏部分
        # ----------------------------------------------------
        system_layout = QVBoxLayout()
        self.text = QLabel('状态栏')
        system_layout.addWidget(self.text)
        self.textbox = QTextEdit(self)
        self.textbox.setReadOnly(True)
        system_layout.addWidget(self.textbox)
        main_layout.addLayout(system_layout)

        # 创建中心窗口部件
        central_widget = QWidget()
        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)

        # 创建状态栏
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)

        # 连接信号到槽
        self.line_edit.textChanged.connect(self.on_text_changed)
        self.load_button.clicked.connect(self.on_load_button_clicked)
        self.start_button.clicked.connect(self.on_start_button_clicked)
        self.mode = "Unknow"

    def on_text_changed(self, text):
        print(f"输入的文本: {text}")

    def on_load_button_clicked(self):
        self.status_bar.showMessage("加载标注文件夹...")
        # 在这里添加加载标注文件夹的逻辑

    def load_dir(self):
        print("load_dir is running!")
        # 打开文件夹选择对话框
        self.dir_path = QFileDialog.getExistingDirectory(self, 'Select Directory')
        if self.dir_path:
            self.line_edit.setText(self.dir_path)
            # 获取目录中的所有文件
            self.files = [f for f in os.listdir(self.dir_path) if f.lower().endswith(('.xml'))]
            if not self.files:
                self.mode = "Qita"
                QMessageBox.information(self, 'No message Found', 'No xml files found in the selected directory.')
                return
            self.mode = "VOC"
            for file_name in self.files:
                self.textbox.append("文件名为:{}".format(file_name))
        else:
            QMessageBox.information(self, 'Selection Cancelled', '您已取消文件夹选择')

    def load_output_dir(self):
        self.output_path = QFileDialog.getExistingDirectory(self, 'Select Directory')
        print(self.output_path)
        if self.output_path:
            self.outputdir_edit.setText(self.output_path)
        else:
            QMessageBox.information(self, 'Selection Cancelled', '您已取消文件夹选择')

    def modeDet(self):
        self.status_bar.showMessage("数据集格式为:{}".format(self.mode))

    def on_start_button_clicked(self):
        print("inter is running!")
        self.status_bar.showMessage("开始转换...")
        if not self.classwirte_edit.text():
            class_message = ["ok", "YiWu", "CanJiao", "CanXi","ShaoJian", "BianXing","PaoMianTiePian", "PaoMianLouTie"]
        else:
            class_message = self.classwirte_edit.text().split(',')

        try:
            if self.dir_path and self.output_path and class_message:
                self.progress_bar.setValue(0)
                convert_voc_to_yolo(self.dir_path, self.output_path, class_message, progress_callback=self.update_progress)
                QMessageBox.information(self, '转换完成!', '嘿嘿')
            else:
                QMessageBox.information(self, '缺少信息', '请重新检查以上步骤!')
        except Exception as e:
            QMessageBox.information(self, '报错!', '错误为:{}'.format(e))
        # 在这里添加开始转换的逻辑

    def update_progress(self, value):
        self.progress_bar.setValue(value)

if __name__ == '__main__':
    app = QApplication(sys.argv)

    splash_pix = QPixmap(resource_path('source/image/loading.png'))
    splash = QSplashScreen(splash_pix)
    splash.show()

    window = MainWindow()

    QTimer.singleShot(500, lambda: (splash.close(), window.show()))

    screen = QDesktopWidget().screenGeometry()
    size = window.geometry()
    window.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2-120)

    sys.exit(app.exec_())

mainUI.spec

# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(
    ['mainUI.py'],
    pathex=['E:\\0_ALL_Cpde\\PyQt5_practice1\\YoloDatasetProcess'],
    binaries=[],
    datas=[('source/image/loading.png', 'source/image/'), ('source/image/logo.ico', 'source/image/')],
    hiddenimports=[],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
)
pyz = PYZ(a.pure)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.datas,
    [],
    name='VOC2YOLO转换器',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
    icon='source/image/logo.ico'
)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要将VOC格式换为YOLO格式,可以参考以下步骤: 1. 首先,需要解析VOC格式的XML文件,获取图像的宽度、高度和目标的位置信息。可以使用Python中的ElementTree库来实现XML文件的解析。 2. 接下来,需要根据VOC格式的目标位置信息计算出目标的中心坐标、宽度和高度。YOLO格式要求目标的位置信息是相对于图像宽度和高度的百分比。 3. 根据计算出的目标位置信息,将其换为YOLO格式的标注。YOLO格式的标注通常是一个文本文件,每一行代表一个目标,包括目标的类别和位置信息。 4. 最后,将换后的YOLO格式的标注文件与对应的图像一起用于训练深度学习网络。 以上是将VOC格式换为YOLO格式的一般步骤。具体实现的代码可以参考引用中提供的代码。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [YOLO格式换成VOC格式](https://download.csdn.net/download/weixin_38342596/10605709)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [将VOC格式标注文件换为Yolo格式](https://blog.csdn.net/qq_40641713/article/details/127078704)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风栖柳白杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值