不多说,直接贴源码,很简单,直接复制下来运行就行
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_())
2174

被折叠的 条评论
为什么被折叠?



