自己制作VOC转yolo的软件

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

mainUI.py

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

# VOC to yolo
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 UIComponents:
    def __init__(self, parent):
        self.parent = parent
        self.create_ui()

    def create_ui(self):
        tab_widget = QTabWidget()
        self.parent.setCentralWidget(tab_widget)

        # 创建第一个选项卡页 "VOC2YOLO"
        voc2yolo_tab = QWidget()
        tab_widget.addTab(voc2yolo_tab, "VOC2YOLO")
        voc2yolo_layout = QVBoxLayout()
        voc2yolo_tab.setLayout(voc2yolo_layout)

        # 文件加载部分
        load_layout = QHBoxLayout()
        self.load_button = QPushButton("加载标注文件夹")
        self.load_button.clicked.connect(self.parent.file_handler.load_dir)
        load_layout.addWidget(self.load_button)
        self.line_edit = QLineEdit()
        self.line_edit.setPlaceholderText("请输入文本...")
        load_layout.addWidget(self.line_edit)
        voc2yolo_layout.addLayout(load_layout)

        # 填写输出路径
        output_layout = QHBoxLayout()
        self.outputdir_load_button = QPushButton("输出文件夹路径")
        self.outputdir_load_button.clicked.connect(self.parent.file_handler.load_output_dir)
        output_layout.addWidget(self.outputdir_load_button)
        self.outputdir_edit = QLineEdit()
        self.outputdir_edit.setPlaceholderText("待输出文本...")
        output_layout.addWidget(self.outputdir_edit)
        voc2yolo_layout.addLayout(output_layout)

        # 填写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)
        voc2yolo_layout.addLayout(class_layout)

        # 转换部分
        button_layout = QHBoxLayout()
        self.start_button = QPushButton("开始转换")
        self.start_button.clicked.connect(self.parent.converter.start_conversion)
        button_layout.addWidget(self.start_button)
        self.defor_button = QPushButton("判断格式")
        self.defor_button.clicked.connect(self.parent.file_handler.modeDet)
        button_layout.addWidget(self.defor_button)
        voc2yolo_layout.addLayout(button_layout)

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

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

        # 创建第二个选项卡页 "YOLO2VOC"
        yolo2voc_tab = QWidget()
        tab_widget.addTab(yolo2voc_tab, "YOLO2VOC")
        yolo2voc_layout = QVBoxLayout()
        yolo2voc_tab.setLayout(yolo2voc_layout)

        # 在这里添加YOLO2VOC的布局和控件
        # ...

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

class FileHandler:
    def __init__(self, parent):
        self.parent = parent

    def load_dir(self):
        print("load_dir is running!")
        # 打开文件夹选择对话框
        self.dir_path = QFileDialog.getExistingDirectory(self.parent, 'Select Directory')
        if self.dir_path:
            self.parent.ui.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.parent.mode = "Qita"
                QMessageBox.information(self.parent, 'No message Found', 'No xml files found in the selected directory.')
                return
            self.parent.mode = "VOC"
            for file_name in self.files:
                self.parent.ui.textbox.append("文件名为:{}".format(file_name))
        else:
            QMessageBox.information(self.parent, 'Selection Cancelled', '您已取消文件夹选择')

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

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

class Converter:
    def __init__(self, parent):
        self.parent = parent

    def start_conversion(self):
        print("inter is running!")
        self.parent.ui.status_bar.showMessage("开始转换...")
        if not self.parent.ui.classwirte_edit.text():
            class_message = ["ok", "YiWu", "CanJiao", "CanXi","ShaoJian", "BianXing","PaoMianTiePian", "PaoMianLouTie"]
            #class_message = ["ok", "ShaoJian", "YiWu",  "ZangWu"]
        else:
            self.parent.ui.textbox.append("输入的值为:{}".format(self.parent.ui.classwirte_edit.text()))
            class_message = self.parent.ui.classwirte_edit.text()

        try:
            if self.parent.file_handler.dir_path and self.parent.file_handler.output_path and class_message:
                self.parent.ui.progress_bar.setValue(0)
                convert_voc_to_yolo(self.parent.file_handler.dir_path, self.parent.file_handler.output_path, class_message, progress_callback=self.update_progress)
                QMessageBox.information(self.parent, '转换完成!', '嘿嘿')
            else:
                QMessageBox.information(self.parent, '缺少信息', '请重新检查以上步骤!')
        except Exception as e:
            QMessageBox.information(self.parent, '报错!', '错误为:{}'.format(e))

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

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('YOLOv10数据集转换器')
        self.setGeometry(100, 100, 800, 400)
        self.setWindowIcon(QIcon('source/image/logo.ico'))  # 确保路径正确

        self.file_handler = FileHandler(self)
        self.converter = Converter(self)
        self.ui = UIComponents(self)

        # 连接信号到槽
        self.ui.line_edit.textChanged.connect(self.on_text_changed)
        self.ui.load_button.clicked.connect(self.on_load_button_clicked)
        self.ui.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.ui.status_bar.showMessage("加载标注文件夹...")
        # 在这里添加加载标注文件夹的逻辑

    def on_start_button_clicked(self):
        self.ui.status_bar.showMessage("开始转换...")
        # 在这里添加开始转换的逻辑

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_())

VOC2YOLO.py

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.
    """
    class_path = os.path.join(output_path, "classes.txt")
    with open(class_path, 'w', encoding='utf-8') as file:
        for line in class_names:
            file.write(line + '\n')  # 写入行并添加换行符

    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)




mainUI.spec

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

block_cipher = None

a = Analysis(
    ['mainUI.py','VOC2YOLO.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'
)

  





完整代码

from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QLabel, QLineEdit, QPushButton,
                             QListWidget, QProgressBar, QHBoxLayout, QMainWindow, QFileDialog, QMenu,
                             QDesktopWidget, QSplashScreen, QTimeEdit, QApplication, QStatusBar, QTextEdit, QMessageBox, QTabWidget)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QTime
from PyQt5.QtGui import QPixmap, QIcon
import sys
import os
import xml.etree.ElementTree as ET
import cv2
def get_image_size(image_path):
    """ 获取图像的宽度和高度。 """
    # print(image_path)
    image = cv2.imread(image_path)
    if image is None:
        raise ValueError(f"Cannot read image {image_path}")
    height, width, _ = image.shape
    return width, height

def yolo_to_voc(yolo_file_path, image_path, classes):
    """ Convert a YOLO format annotation to VOC format XML. """
    image_width, image_height = get_image_size(image_path)

    voc_root = ET.Element('annotation')

    ET.SubElement(voc_root, 'folder').text = 'images'
    ET.SubElement(voc_root, 'filename').text = os.path.basename(image_path)
    ET.SubElement(voc_root, 'path').text = os.path.join('images', os.path.basename(image_path))

    source = ET.SubElement(voc_root, 'source')
    ET.SubElement(source, 'database').text = 'Unknown'

    size = ET.SubElement(voc_root, 'size')
    ET.SubElement(size, 'width').text = str(image_width)
    ET.SubElement(size, 'height').text = str(image_height)
    ET.SubElement(size, 'depth').text = '3'  # Assuming RGB images

    ET.SubElement(voc_root, 'segmented').text = '0'

    with open(yolo_file_path, 'r') as f:
        for line in f:
            parts = line.strip().split()
            class_id = int(parts[0])
            x_center = float(parts[1])
            y_center = float(parts[2])
            width = float(parts[3])
            height = float(parts[4])

            xmin = int((x_center - width / 2) * image_width)
            xmax = int((x_center + width / 2) * image_width)
            ymin = int((y_center - height / 2) * image_height)
            ymax = int((y_center + height / 2) * image_height)

            obj = ET.SubElement(voc_root, 'object')
            ET.SubElement(obj, 'name').text = classes[class_id]
            ET.SubElement(obj, 'pose').text = 'Unspecified'
            ET.SubElement(obj, 'truncated').text = '0'
            ET.SubElement(obj, 'difficult').text = '0'

            bndbox = ET.SubElement(obj, 'bndbox')
            ET.SubElement(bndbox, 'xmin').text = str(xmin)
            ET.SubElement(bndbox, 'ymin').text = str(ymin)
            ET.SubElement(bndbox, 'xmax').text = str(xmax)
            ET.SubElement(bndbox, 'ymax').text = str(ymax)

    return ET.tostring(voc_root, encoding='unicode')

def process_annotations(yolo_folder, classes_file, images_folder, output_folder, process_callback=None):
    """ 将YOLO格式的标注文件转换为VOC格式. """
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    with open(classes_file, 'r') as f:
        classes = [line.strip() for line in f]
    process_file_bar = 0
    total_files = len(os.listdir(yolo_folder))
    for file_name in os.listdir(yolo_folder):
        if file_name.endswith('.txt'):
            yolo_file_path = os.path.join(yolo_folder, file_name)
            image_filename_list = os.listdir(images_folder)
            image_filename = ""
            for image_filename in image_filename_list:
                image_base_name = os.path.splitext(os.path.basename(image_filename))[0]           # 基本名称,无后缀无路径
                yolo_file_name =  os.path.splitext(os.path.basename(file_name))[0]
                if image_base_name == yolo_file_name:
                    break
            if image_filename == "":
                continue
            if file_name == "classes.txt":
                # print("file_name is ", file_name)
                continue
            image_path = os.path.join(images_folder, image_filename)       # 寻找同名图片

            if not os.path.exists(image_path):
                print(f"Warning: Image file {image_path} not found.")
                continue

            xml_data = yolo_to_voc(yolo_file_path, image_path, classes)
            xml_file_name = file_name.replace('.txt', '.xml')
            xml_file_path = os.path.join(output_folder, xml_file_name)

            with open(xml_file_path, 'w') as xml_file:
                xml_file.write(xml_data)
        process_file_bar += 1
        # print(process_file_bar, total_files, process_file_bar * 100 // total_files)
        if process_callback:
            process_callback(process_file_bar * 100 // total_files)

# 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.
    """
    class_path = os.path.join(output_path, "classes.txt")
    with open(class_path, 'w', encoding='utf-8') as file:
        for line in class_names:
            file.write(line + '\n')  # 写入行并添加换行符

    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)


# VOC to yolo
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 UIComponents:
    def __init__(self, parent):
        self.parent = parent
        self.create_ui()

    def create_ui(self):
        tab_widget = QTabWidget()
        self.parent.setCentralWidget(tab_widget)

        # 创建第一个选项卡页 "VOC2YOLO"
        voc2yolo_tab = QWidget()
        tab_widget.addTab(voc2yolo_tab, "VOC2YOLO")
        voc2yolo_layout = QVBoxLayout()
        voc2yolo_tab.setLayout(voc2yolo_layout)

        # 文件加载部分
        load_layout = QHBoxLayout()
        self.load_button = QPushButton("加载标注文件夹")
        self.load_button.clicked.connect(self.parent.file_handler.load_dir)
        load_layout.addWidget(self.load_button)
        self.line_edit = QLineEdit()
        self.line_edit.setPlaceholderText("待输出文本...")
        load_layout.addWidget(self.line_edit)
        voc2yolo_layout.addLayout(load_layout)

        # 填写输出路径
        output_layout = QHBoxLayout()
        self.outputdir_load_button = QPushButton("输出文件夹路径")
        self.outputdir_load_button.clicked.connect(self.parent.file_handler.load_output_dir)
        output_layout.addWidget(self.outputdir_load_button)
        self.outputdir_edit = QLineEdit()
        self.outputdir_edit.setPlaceholderText("待输出文本...")
        output_layout.addWidget(self.outputdir_edit)
        voc2yolo_layout.addLayout(output_layout)

        # 填写VOC类别
        class_layout = QHBoxLayout()
        self.write_class_button = QPushButton("输入类别信息:")
        self.write_class_button.clicked.connect(self.parent.file_handler.load_class_txt)
        class_layout.addWidget(self.write_class_button)
        self.classwirte_edit = QLineEdit()
        self.classwirte_edit.setPlaceholderText("请输入类别信息如:{};该信息默认".format(["ok", "YiWu", "CanJiao", "CanXi","ShaoJian",
                                                                              "BianXing","PaoMianTiePian", "PaoMianLouTie"]))
        class_layout.addWidget(self.classwirte_edit)
        voc2yolo_layout.addLayout(class_layout)

        # 转换部分
        button_layout = QHBoxLayout()
        self.start_button = QPushButton("开始转换")
        self.start_button.clicked.connect(self.parent.converter.start_conversion)
        button_layout.addWidget(self.start_button)
        self.defor_button = QPushButton("判断格式")
        self.defor_button.clicked.connect(self.parent.file_handler.modeDet)
        button_layout.addWidget(self.defor_button)
        voc2yolo_layout.addLayout(button_layout)

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

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

        # ------------------------------------------------------
        # 创建第二个选项卡页 "YOLO2VOC"
        # ------------------------------------------------------
        yolo2voc_tab = QWidget()
        tab_widget.addTab(yolo2voc_tab, "YOLO2VOC")
        yolo2voc_layout = QVBoxLayout()
        # 在这里添加YOLO2VOC的布局和控件
        # YOLO需要四个状态栏  YOLO标签保存的文件夹  图片文件夹  classes.txt路径  输出文件夹
        yololabel_layout = QHBoxLayout()
        self.yololabel_button = QPushButton("YOLO标签文件夹")
        self.yololabel_editeline = QLineEdit()
        self.yololabel_editeline.setPlaceholderText("yolo标签的文件夹路径,文件夹中均为txt文档")
        self.yololabel_editeline.setReadOnly(True)
        self.yololabel_button.clicked.connect(self.parent.file_handler.yolo_inputbiaozhu_dir)
        yololabel_layout.addWidget(self.yololabel_button)
        yololabel_layout.addWidget(self.yololabel_editeline)
        yolo2voc_layout.addLayout(yololabel_layout)
        # 图片文件夹
        yoloimage_layout = QHBoxLayout()
        self.yoloimage_button = QPushButton("YOLO图片文件夹")
        self.yoloimage_editeline = QLineEdit()
        self.yoloimage_editeline.setPlaceholderText("图片的文件夹路径,文件夹中均为图片")
        self.yoloimage_editeline.setReadOnly(True)
        self.yoloimage_button.clicked.connect(self.parent.file_handler.yolo_inputimage_dir)
        yoloimage_layout.addWidget(self.yoloimage_button)
        yoloimage_layout.addWidget(self.yoloimage_editeline)
        yolo2voc_layout.addLayout(yoloimage_layout)
        # classes.txt路径
        yolo_class_layout = QHBoxLayout()
        self.yoloclass_button = QPushButton("YOLO类别路径")
        self.yoloclass_editeline = QLineEdit()
        self.yoloclass_editeline.setPlaceholderText("YOLO类别的路径,选中一个txt文档")
        self.yoloclass_editeline.setReadOnly(True)
        self.yoloclass_button.clicked.connect(self.parent.file_handler.yolo_loadFile)
        yolo_class_layout.addWidget(self.yoloclass_button)
        yolo_class_layout.addWidget(self.yoloclass_editeline)
        yolo2voc_layout.addLayout(yolo_class_layout)
        # 输出文件夹
        yolo_output_layout = QHBoxLayout()
        self.yolo_output_button = QPushButton("转换标注输出路径")
        self.yolo_output_editeline = QLineEdit()
        self.yolo_output_editeline.setPlaceholderText("xml文件的输出路径")
        self.yolo_output_editeline.setReadOnly(True)
        self.yolo_output_button.clicked.connect(self.parent.file_handler.yolo_output_dir)
        yolo_output_layout.addWidget(self.yolo_output_button)
        yolo_output_layout.addWidget(self.yolo_output_editeline)
        yolo2voc_layout.addLayout(yolo_output_layout)

        # 开始转换 && 判断格式
        yolo_button_layout = QHBoxLayout()
        self.yolo_start_button = QPushButton("开始转换")
        self.yolo_start_button.clicked.connect(self.parent.converter.yolo_start_conversion)
        yolo_button_layout.addWidget(self.yolo_start_button)
        self.yolo_defor_button = QPushButton("判断格式")
        self.yolo_defor_button.clicked.connect(self.parent.file_handler.modeDet)
        yolo_button_layout.addWidget(self.yolo_defor_button)
        yolo2voc_layout.addLayout(yolo_button_layout)
        # 进度条
        yolo_progress_layout = QHBoxLayout()
        self.yolo_progress_bar = QProgressBar()
        yolo_progress_layout.addWidget(self.yolo_progress_bar)
        yolo2voc_layout.addLayout(yolo_progress_layout)
        # 状态栏
        yolo_system_layout = QVBoxLayout()
        self.yolo_text = QLabel('状态栏')
        yolo_system_layout.addWidget(self.yolo_text)
        self.yolo_textbox = QTextEdit(self.parent)
        self.yolo_textbox.setReadOnly(True)
        yolo_system_layout.addWidget(self.yolo_textbox)
        yolo2voc_layout.addLayout(yolo_system_layout)

        yolo2voc_tab.setLayout(yolo2voc_layout)

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

class FileHandler:
    def __init__(self, parent):
        self.parent = parent

    def load_dir(self):
        print("load_dir is running!")
        # 打开文件夹选择对话框
        self.dir_path = QFileDialog.getExistingDirectory(self.parent, 'Select Directory')
        if self.dir_path:
            self.parent.ui.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.parent.mode = "Qita"
                QMessageBox.information(self.parent, 'No message Found', 'No xml files found in the selected directory.')
                return
            self.parent.mode = "VOC"
            for file_name in self.files:
                self.parent.ui.textbox.append("文件名为:{}".format(file_name))
        else:
            QMessageBox.information(self.parent, 'Selection Cancelled', '您已取消文件夹选择')

    def load_output_dir(self):
        self.output_path = QFileDialog.getExistingDirectory(self.parent, 'Select Directory')
        print("load_output_dir执行! = ", self.output_path)
        if self.output_path:
            self.parent.ui.outputdir_edit.setText(self.output_path)
        else:
            QMessageBox.information(self.parent, 'Selection Cancelled', '您已取消文件夹选择')
    def load_class_txt(self):
        # 仅支持txt文件
        self.parent.ui.textbox.append("正在加载VOC类别文件!")
        # 打开文件夹选择对话框
        self.VOC_class_filepath, _ = QFileDialog.getOpenFileName(self.parent, 'Select Text File', '',
                                                             'Text Files (*.txt);;All Files (*)')
        if self.VOC_class_filepath:
            self.parent.ui.textbox.append("加载的classes.txt路径为:{}".format(self.VOC_class_filepath))
            self.VOC_class_list = []
            with open(self.VOC_class_filepath, 'r', encoding='utf-8') as file:
                for line in file:
                    self.VOC_class_list.append(line.strip())
        self.parent.ui.textbox.append("加载的类别为:\n{}".format(self.VOC_class_list))
        self.parent.ui.classwirte_edit.setPlaceholderText("加载的类别为:{}".format(self.VOC_class_list))
    # ----------------------------------
    #   处理YOLO
    #-----------------------------------
    def yolo_inputbiaozhu_dir(self):
        self.parent.ui.yolo_textbox.append("正在加载YOLO输入的标注!")
        # 打开文件夹选择对话框
        self.yoloinputbiaozhu_dir_path = QFileDialog.getExistingDirectory(self.parent, 'Select Directory')
        if self.yoloinputbiaozhu_dir_path:
            self.parent.ui.yololabel_editeline.setText(self.yoloinputbiaozhu_dir_path)
            # 获取目录中的所有文件
            self.yolobiaozhu_files = [f for f in os.listdir(self.yoloinputbiaozhu_dir_path) if f.lower().endswith(('.txt'))]
            if not self.yolobiaozhu_files:
                QMessageBox.information(self.parent, '标注加载错误', '文件夹中没有找到符合要求的标注')
                return
            for file_name in self.yolobiaozhu_files:
                self.parent.ui.yolo_textbox.append("输入标注文件名为:{}".format(file_name))
        else:
            QMessageBox.information(self.parent, '取消', '您已取消文件夹选择')
    def yolo_inputimage_dir(self):
        self.parent.ui.yolo_textbox.append("正在加载YOLO输入的图片!")
        self.yoloinputimage_path = QFileDialog.getExistingDirectory(self.parent, 'Select Directory')
        if self.yoloinputimage_path:
            self.parent.ui.yoloimage_editeline.setText(self.yoloinputimage_path)
            # 获取目录中的所有文件
            self.image_files = [f for f in os.listdir(self.yoloinputimage_path)
                                if f.lower().endswith(('.jpg', '.jpeg', '.png'))]
            if not self.image_files:
                QMessageBox.information(self.parent, '图片加载错误', '文件夹内没有找到图片')
                return
            self.parent.mode = "VOC"
            for file_name in self.image_files:
                self.parent.ui.textbox.append("输入图片文件名为:{}".format(file_name))
        else:
            QMessageBox.information(self.parent, '取消', '您已取消文件夹选择')

    def yolo_loadFile(self):
        self.parent.ui.yolo_textbox.append("正在加载输入路径!")
        # 打开文件夹选择对话框
        self.class_filepath, _ = QFileDialog.getOpenFileName(self.parent, 'Select Text File', '', 'Text Files (*.txt);;All Files (*)')
        if self.class_filepath:
            self.parent.ui.yolo_textbox.append("加载的classes.txt路径为:{}".format(self.class_filepath))
            self.parent.ui.yoloclass_editeline.setText(self.class_filepath)
            with open(self.class_filepath, 'r', encoding='utf-8') as file:
                content = file.read()
                self.parent.ui.yolo_textbox.append("classes类别为:\n{}".format(content))

    def yolo_output_dir(self):
        self.parent.ui.yolo_textbox.append("正在加载最终输出路径!")
        # 打开文件夹选择对话框
        self.yolo_output_path = QFileDialog.getExistingDirectory(self.parent, 'Select Directory')
        if self.yolo_output_path:
            self.parent.ui.yolo_textbox.append("最终的输出路径为:{}".format(self.yolo_output_path))
            self.parent.ui.yolo_output_editeline.setText(self.yolo_output_path)
        else:
            QMessageBox.information(self.parent, 'Selection Cancelled', '您已取消文件夹选择')

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

class Converter:
    def __init__(self, parent):
        self.parent = parent

    def start_conversion(self):
        print("inter is running!")
        self.parent.ui.status_bar.showMessage("开始转换...")
        if not self.parent.ui.classwirte_edit.text():
            # class_message = ["YiWu", "CanJiao", "CanXi"]
            # class_message = ["PaoMianTiePian"]
            # class_message = ["ok", "CanLiu", "YiWu", "ShaoJian", "BianXing", "PaoMianLouTie"]
            class_message = ["YiWu", "CanLiu"]
            class_message = ["canjiao", "shaoxi", "duoxi", "duojiao", "shaojiao", "lianjiao", "pinayi", "yiwu",
                             "lianxi", "wugaiban"]

            class_message = ["ok", "YiWu", "CanJiao", "CanXi","ShaoJian", "BianXing","PaoMianTiePian", "PaoMianLouTie"]
            class_message = ['OK', '偏移', '多胶', '多锡', '少胶', '少锡', '异物', '无盖板', '残胶', '连胶', '連锡']
            class_message = ["OK", "pinayi", "duojiao", "duoxi", "shaojiao", "shaoxi", "yiwu",
                             "wugaiban", "canjiao", "lianjiao", "lianxi"]
            class_message = ["ok", "YiWu", "CanLiu", "ShaoJian", "BianXing", "PaoMianTiePian", "PaoMianLouTie"]
            class_message = self.parent.file_handler.VOC_class_list
        else:
            self.parent.ui.textbox.append("输入的值为:{}".format(self.parent.ui.classwirte_edit.text()))
            class_message = self.parent.ui.classwirte_edit.text()

        try:
            if self.parent.file_handler.dir_path and self.parent.file_handler.output_path and class_message:
                self.parent.ui.progress_bar.setValue(0)
                convert_voc_to_yolo(self.parent.file_handler.dir_path, self.parent.file_handler.output_path, class_message, progress_callback=self.update_progress)
                QMessageBox.information(self.parent, '转换完成!', '嘿嘿')
            else:
                QMessageBox.information(self.parent, '缺少信息', '请重新检查以上步骤!')
        except Exception as e:
            QMessageBox.information(self.parent, 'VOC转YOLO报错!', '错误为:{}'.format(e))
    def yolo_start_conversion(self):
        try:
            if (self.parent.file_handler.yoloinputbiaozhu_dir_path and self.parent.file_handler.class_filepath
                    and self.parent.file_handler.yoloinputimage_path and self.parent.file_handler.yolo_output_path):
                self.parent.ui.yolo_textbox.append("yolo转VOC正在转换!")
                # classes_path = self.parent.file_handler.class_filepath

                process_annotations(self.parent.file_handler.yoloinputbiaozhu_dir_path, self.parent.file_handler.class_filepath,
                                    self.parent.file_handler.yoloinputimage_path, self.parent.file_handler.yolo_output_path, process_callback=self.yolo_update_process)
                self.parent.ui.yolo_textbox.append("yolo转VOC转换完成!")
                QMessageBox.information(self.parent, 'YOLO2VOC转换完成!', 'yolo转VOC转换完成!')
            else:
                QMessageBox.information(self.parent, 'YOLO2VOC缺少信息', '请重新检查以上步骤!')
        except Exception as e:
            QMessageBox.information(self.parent, 'YOLO转VOC报错!', '错误为:{}'.format(e))
    def yolo_update_process(self, value):
        self.parent.ui.yolo_progress_bar.setValue(value)

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

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('YOLOv10数据集转换器')
        self.setGeometry(100, 100, 800, 400)
        self.setWindowIcon(QIcon(resource_path('source/image/dingding.png')))  #x 确保路径正确

        self.file_handler = FileHandler(self)
        self.converter = Converter(self)
        self.ui = UIComponents(self)

        # 连接信号到槽
        self.ui.line_edit.textChanged.connect(self.on_text_changed)
        self.ui.load_button.clicked.connect(self.on_load_button_clicked)
        self.ui.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.ui.status_bar.showMessage("加载标注文件夹...")
        # 在这里添加加载标注文件夹的逻辑

    def on_start_button_clicked(self):
        self.ui.status_bar.showMessage("开始转换...")
        # 在这里添加开始转换的逻辑

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_())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

风栖柳白杨

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

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

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

打赏作者

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

抵扣说明:

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

余额充值