first commit
|
|
@ -0,0 +1,3 @@
|
|||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.xml filter=lfs diff=lfs merge=lfs -text
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.9" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="PyDocumentationSettings">
|
||||
<option name="format" value="PLAIN" />
|
||||
<option name="myDocStringFormat" value="Plain" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
cff-version: 1.2.0
|
||||
preferred-citation:
|
||||
type: software
|
||||
message: If you use this software, please cite it as below.
|
||||
authors:
|
||||
- family-names: Jocher
|
||||
given-names: Glenn
|
||||
orcid: "https://orcid.org/0000-0001-5950-6979"
|
||||
- family-names: Chaurasia
|
||||
given-names: Ayush
|
||||
orcid: "https://orcid.org/0000-0002-7603-6750"
|
||||
- family-names: Qiu
|
||||
given-names: Jing
|
||||
orcid: "https://orcid.org/0000-0003-3783-7069"
|
||||
title: "YOLO by Ultralytics"
|
||||
version: 8.0.0
|
||||
# doi: 10.5281/zenodo.3908559 # TODO
|
||||
date-released: 2023-1-10
|
||||
license: AGPL-3.0
|
||||
url: "https://github.com/ultralytics/ultralytics"
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
#coding:utf-8
|
||||
import cv2
|
||||
from ultralytics import YOLO
|
||||
|
||||
# 所需加载的模型目录
|
||||
path = 'models/best.pt'
|
||||
|
||||
# Load the YOLOv8 model
|
||||
model = YOLO(path)
|
||||
|
||||
ID = 0
|
||||
|
||||
while(ID<10):
|
||||
cap = cv2.VideoCapture(ID)
|
||||
# get a frame
|
||||
ret, frame = cap.read()
|
||||
if ret == False:
|
||||
ID += 1
|
||||
else:
|
||||
print('摄像头ID:',ID)
|
||||
break
|
||||
|
||||
|
||||
# Loop through the video frames
|
||||
while cap.isOpened():
|
||||
# Read a frame from the video
|
||||
success, frame = cap.read()
|
||||
|
||||
if success:
|
||||
# Run YOLOv8 inference on the frame
|
||||
results = model(frame)
|
||||
|
||||
# Visualize the results on the frame
|
||||
annotated_frame = results[0].plot()
|
||||
|
||||
# Display the annotated frame
|
||||
cv2.imshow("YOLOv8 Inference", annotated_frame)
|
||||
|
||||
# Break the loop if 'q' is pressed
|
||||
if cv2.waitKey(1) & 0xFF == ord("q"):
|
||||
break
|
||||
else:
|
||||
# Break the loop if the end of the video is reached
|
||||
break
|
||||
|
||||
# Release the video capture object and close the display window
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#coding:utf-8
|
||||
|
||||
# 图片及视频检测结果保存路径
|
||||
save_path = 'save_data'
|
||||
|
||||
# 使用的模型路径
|
||||
# model_path = 'models/best.pt'
|
||||
|
||||
# names = {0: 'Rescued', 1: 'Rescuing'}
|
||||
|
||||
# CH_names = ['已救援', '救援中']
|
||||
|
||||
|
||||
# 猫和狗
|
||||
# 训练好的模型路径
|
||||
# model_path = 'runs/detect/train5/weights/best.pt'
|
||||
# # 类别名称
|
||||
# names = {0: 'cat', 1: 'dog'}
|
||||
# # 中文类别名称
|
||||
# CH_names = ['猫', '狗']
|
||||
|
||||
|
||||
# # 马甲
|
||||
# # 训练好的模型路径
|
||||
# model_path = 'runs/detect/train5/weights/best.pt'
|
||||
# # # 类别名称
|
||||
# names = {0: 'vest', 1: 'novest'}
|
||||
# # # 中文类别名称
|
||||
# CH_names = ['有马甲', '无马甲']
|
||||
|
||||
# # 仪表盘
|
||||
# # 训练好的模型路径
|
||||
# model_path = 'runs/detect/train6/weights/best.pt'
|
||||
# # # 类别名称
|
||||
# names = {0: 'dashboard', 1: 'nodashboard'}
|
||||
# # # 中文类别名称
|
||||
# CH_names = ['仪表盘', '无仪表盘']
|
||||
|
||||
|
||||
# # 搭电设备
|
||||
# # 训练好的模型路径
|
||||
# model_path = 'runs/detect/train9/weights/best.pt'
|
||||
# # # 类别名称
|
||||
# names = {0: 'JumperCable', 1: 'NoJumperCable'}
|
||||
# # # 中文类别名称
|
||||
# CH_names = ['有搭电设备', '无搭电设备']
|
||||
|
||||
|
||||
# 搭电测试
|
||||
# 训练好的模型路径
|
||||
model_path = 'runs/segment/train11/weights/best.pt'
|
||||
# # 类别名称
|
||||
names = {0: 'da_dian_xian', 1: 'tuo_che_shang_you_che',2:'yi_biao_pan',3:'lun_tai',4:'ping_an_ma_jia',5:'jian_ce_yi'}
|
||||
|
||||
# # 中文类别名称
|
||||
CH_names = ['搭电线','拖车上油车','仪表盘','轮台','平安马甲','检测仪']
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,625 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
from PyQt5.QtWidgets import QApplication , QMainWindow, QFileDialog, \
|
||||
QMessageBox,QWidget,QHeaderView,QTableWidgetItem, QAbstractItemView
|
||||
import sys
|
||||
import os
|
||||
from PIL import ImageFont
|
||||
from ultralytics import YOLO
|
||||
sys.path.append('UIProgram')
|
||||
from UIProgram.UiMain import Ui_MainWindow
|
||||
import sys
|
||||
from PyQt5.QtCore import QTimer, Qt, QThread, pyqtSignal,QCoreApplication
|
||||
import detect_tools as tools
|
||||
import cv2
|
||||
import Config
|
||||
from UIProgram.QssLoader import QSSLoader
|
||||
from UIProgram.precess_bar import ProgressBar
|
||||
import numpy as np
|
||||
import torch
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self, parent=None):
|
||||
super(QMainWindow, self).__init__(parent)
|
||||
self.ui = Ui_MainWindow()
|
||||
self.ui.setupUi(self)
|
||||
self.initMain()
|
||||
self.signalconnect()
|
||||
|
||||
# 加载css渲染效果
|
||||
style_file = 'UIProgram/style.css'
|
||||
qssStyleSheet = QSSLoader.read_qss_file(style_file)
|
||||
self.setStyleSheet(qssStyleSheet)
|
||||
|
||||
self.conf = 0.25
|
||||
self.iou = 0.7
|
||||
|
||||
def signalconnect(self):
|
||||
self.ui.PicBtn.clicked.connect(self.open_img)
|
||||
self.ui.comboBox.activated.connect(self.combox_change)
|
||||
self.ui.VideoBtn.clicked.connect(self.vedio_show)
|
||||
self.ui.CapBtn.clicked.connect(self.camera_show)
|
||||
self.ui.SaveBtn.clicked.connect(self.save_detect_video)
|
||||
self.ui.ExitBtn.clicked.connect(QCoreApplication.quit)
|
||||
self.ui.FilesBtn.clicked.connect(self.detact_batch_imgs)
|
||||
|
||||
def initMain(self):
|
||||
self.show_width = 770
|
||||
self.show_height = 480
|
||||
|
||||
self.org_path = None
|
||||
|
||||
self.is_camera_open = False
|
||||
self.cap = None
|
||||
|
||||
self.device = 0 if torch.cuda.is_available() else 'cpu'
|
||||
|
||||
# 加载检测模型
|
||||
self.model = YOLO(Config.model_path, task='detect')
|
||||
self.model(np.zeros((48, 48, 3)), device=self.device) #预先加载推理模型
|
||||
self.fontC = ImageFont.truetype("Font/platech.ttf", 25, 0)
|
||||
|
||||
# 用于绘制不同颜色矩形框
|
||||
self.colors = tools.Colors()
|
||||
|
||||
# 更新视频图像
|
||||
self.timer_camera = QTimer()
|
||||
|
||||
# 更新检测信息表格
|
||||
# self.timer_info = QTimer()
|
||||
# 保存视频
|
||||
self.timer_save_video = QTimer()
|
||||
|
||||
# 表格
|
||||
self.ui.tableWidget.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
|
||||
self.ui.tableWidget.verticalHeader().setDefaultSectionSize(40)
|
||||
self.ui.tableWidget.setColumnWidth(0, 80) # 设置列宽
|
||||
self.ui.tableWidget.setColumnWidth(1, 200)
|
||||
self.ui.tableWidget.setColumnWidth(2, 150)
|
||||
self.ui.tableWidget.setColumnWidth(3, 90)
|
||||
self.ui.tableWidget.setColumnWidth(4, 230)
|
||||
# self.ui.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # 表格铺满
|
||||
# self.ui.tableWidget.horizontalHeader().setSectionResizeMode(0, QHeaderView.Interactive)
|
||||
# self.ui.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers) # 设置表格不可编辑
|
||||
self.ui.tableWidget.setSelectionBehavior(QAbstractItemView.SelectRows) # 设置表格整行选中
|
||||
self.ui.tableWidget.verticalHeader().setVisible(False) # 隐藏列标题
|
||||
self.ui.tableWidget.setAlternatingRowColors(True) # 表格背景交替
|
||||
|
||||
# 设置主页背景图片border-image: url(:/icons/ui_imgs/icons/camera.png)
|
||||
# self.setStyleSheet("#MainWindow{background-image:url(:/bgs/ui_imgs/bg3.jpg)}")
|
||||
|
||||
def open_img(self):
|
||||
if self.cap:
|
||||
# 打开图片前关闭摄像头
|
||||
self.video_stop()
|
||||
self.is_camera_open = False
|
||||
self.ui.CaplineEdit.setText('摄像头未开启')
|
||||
self.cap = None
|
||||
|
||||
# 弹出的窗口名称:'打开图片'
|
||||
# 默认打开的目录:'./'
|
||||
# 只能打开.jpg与.gif结尾的图片文件
|
||||
# file_path, _ = QFileDialog.getOpenFileName(self.ui.centralwidget, '打开图片', './', "Image files (*.jpg *.gif)")
|
||||
file_path, _ = QFileDialog.getOpenFileName(None, '打开图片', './', "Image files (*.jpg *.jpeg *.png *.bmp)")
|
||||
if not file_path:
|
||||
return
|
||||
|
||||
self.ui.comboBox.setDisabled(False)
|
||||
self.org_path = file_path
|
||||
self.org_img = tools.img_cvread(self.org_path)
|
||||
|
||||
# 目标检测
|
||||
t1 = time.time()
|
||||
self.results = self.model(self.org_path, conf=self.conf, iou=self.iou)[0]
|
||||
t2 = time.time()
|
||||
take_time_str = '{:.3f} s'.format(t2 - t1)
|
||||
self.ui.time_lb.setText(take_time_str)
|
||||
|
||||
location_list = self.results.boxes.xyxy.tolist()
|
||||
self.location_list = [list(map(int, e)) for e in location_list]
|
||||
cls_list = self.results.boxes.cls.tolist()
|
||||
self.cls_list = [int(i) for i in cls_list]
|
||||
self.conf_list = self.results.boxes.conf.tolist()
|
||||
self.conf_list = ['%.2f %%' % (each*100) for each in self.conf_list]
|
||||
|
||||
# now_img = self.cv_img.copy()
|
||||
# for loacation, type_id, conf in zip(self.location_list, self.cls_list, self.conf_list):
|
||||
# type_id = int(type_id)
|
||||
# color = self.colors(int(type_id), True)
|
||||
# # cv2.rectangle(now_img, (int(x1), int(y1)), (int(x2), int(y2)), colors(int(type_id), True), 3)
|
||||
# now_img = tools.drawRectBox(now_img, loacation, Config.CH_names[type_id], self.fontC, color)
|
||||
now_img = self.results.plot()
|
||||
self.draw_img = now_img
|
||||
# 获取缩放后的图片尺寸
|
||||
self.img_width, self.img_height = self.get_resize_size(now_img)
|
||||
resize_cvimg = cv2.resize(now_img,(self.img_width, self.img_height))
|
||||
pix_img = tools.cvimg_to_qpiximg(resize_cvimg)
|
||||
self.ui.label_show.setPixmap(pix_img)
|
||||
self.ui.label_show.setAlignment(Qt.AlignCenter)
|
||||
# 设置路径显示
|
||||
self.ui.PiclineEdit.setText(self.org_path)
|
||||
|
||||
# 目标数目
|
||||
target_nums = len(self.cls_list)
|
||||
self.ui.label_nums.setText(str(target_nums))
|
||||
|
||||
# 设置目标选择下拉框
|
||||
choose_list = ['全部']
|
||||
target_names = [Config.names[id]+ '_'+ str(index) for index,id in enumerate(self.cls_list)]
|
||||
# object_list = sorted(set(self.cls_list))
|
||||
# for each in object_list:
|
||||
# choose_list.append(Config.CH_names[each])
|
||||
choose_list = choose_list + target_names
|
||||
|
||||
self.ui.comboBox.clear()
|
||||
self.ui.comboBox.addItems(choose_list)
|
||||
|
||||
if target_nums >= 1:
|
||||
self.ui.type_lb.setText(Config.CH_names[self.cls_list[0]])
|
||||
self.ui.label_conf.setText(str(self.conf_list[0]))
|
||||
# 默认显示第一个目标框坐标
|
||||
# 设置坐标位置值
|
||||
self.ui.label_xmin.setText(str(self.location_list[0][0]))
|
||||
self.ui.label_ymin.setText(str(self.location_list[0][1]))
|
||||
self.ui.label_xmax.setText(str(self.location_list[0][2]))
|
||||
self.ui.label_ymax.setText(str(self.location_list[0][3]))
|
||||
else:
|
||||
self.ui.type_lb.setText('')
|
||||
self.ui.label_conf.setText('')
|
||||
self.ui.label_xmin.setText('')
|
||||
self.ui.label_ymin.setText('')
|
||||
self.ui.label_xmax.setText('')
|
||||
self.ui.label_ymax.setText('')
|
||||
|
||||
# # 删除表格所有行
|
||||
self.ui.tableWidget.setRowCount(0)
|
||||
self.ui.tableWidget.clearContents()
|
||||
self.tabel_info_show(self.location_list, self.cls_list, self.conf_list,path=self.org_path)
|
||||
|
||||
|
||||
def detact_batch_imgs(self):
|
||||
if self.cap:
|
||||
# 打开图片前关闭摄像头
|
||||
self.video_stop()
|
||||
self.is_camera_open = False
|
||||
self.ui.CaplineEdit.setText('摄像头未开启')
|
||||
self.cap = None
|
||||
directory = QFileDialog.getExistingDirectory(self,
|
||||
"选取文件夹",
|
||||
"./") # 起始路径
|
||||
if not directory:
|
||||
return
|
||||
self.org_path = directory
|
||||
img_suffix = ['jpg','png','jpeg','bmp']
|
||||
for file_name in os.listdir(directory):
|
||||
full_path = os.path.join(directory,file_name)
|
||||
if os.path.isfile(full_path) and file_name.split('.')[-1].lower() in img_suffix:
|
||||
# self.ui.comboBox.setDisabled(False)
|
||||
img_path = full_path
|
||||
self.org_img = tools.img_cvread(img_path)
|
||||
# 目标检测
|
||||
t1 = time.time()
|
||||
self.results = self.model(img_path,conf=self.conf, iou=self.iou)[0]
|
||||
t2 = time.time()
|
||||
take_time_str = '{:.3f} s'.format(t2 - t1)
|
||||
self.ui.time_lb.setText(take_time_str)
|
||||
|
||||
location_list = self.results.boxes.xyxy.tolist()
|
||||
self.location_list = [list(map(int, e)) for e in location_list]
|
||||
cls_list = self.results.boxes.cls.tolist()
|
||||
self.cls_list = [int(i) for i in cls_list]
|
||||
self.conf_list = self.results.boxes.conf.tolist()
|
||||
self.conf_list = ['%.2f %%' % (each * 100) for each in self.conf_list]
|
||||
|
||||
now_img = self.results.plot()
|
||||
|
||||
self.draw_img = now_img
|
||||
# 获取缩放后的图片尺寸
|
||||
self.img_width, self.img_height = self.get_resize_size(now_img)
|
||||
resize_cvimg = cv2.resize(now_img, (self.img_width, self.img_height))
|
||||
pix_img = tools.cvimg_to_qpiximg(resize_cvimg)
|
||||
self.ui.label_show.setPixmap(pix_img)
|
||||
self.ui.label_show.setAlignment(Qt.AlignCenter)
|
||||
# 设置路径显示
|
||||
self.ui.PiclineEdit.setText(img_path)
|
||||
|
||||
# 目标数目
|
||||
target_nums = len(self.cls_list)
|
||||
self.ui.label_nums.setText(str(target_nums))
|
||||
|
||||
# 设置目标选择下拉框
|
||||
choose_list = ['全部']
|
||||
target_names = [Config.names[id] + '_' + str(index) for index, id in enumerate(self.cls_list)]
|
||||
choose_list = choose_list + target_names
|
||||
|
||||
self.ui.comboBox.clear()
|
||||
self.ui.comboBox.addItems(choose_list)
|
||||
|
||||
if target_nums >= 1:
|
||||
self.ui.type_lb.setText(Config.CH_names[self.cls_list[0]])
|
||||
self.ui.label_conf.setText(str(self.conf_list[0]))
|
||||
# 默认显示第一个目标框坐标
|
||||
# 设置坐标位置值
|
||||
self.ui.label_xmin.setText(str(self.location_list[0][0]))
|
||||
self.ui.label_ymin.setText(str(self.location_list[0][1]))
|
||||
self.ui.label_xmax.setText(str(self.location_list[0][2]))
|
||||
self.ui.label_ymax.setText(str(self.location_list[0][3]))
|
||||
else:
|
||||
self.ui.type_lb.setText('')
|
||||
self.ui.label_conf.setText('')
|
||||
self.ui.label_xmin.setText('')
|
||||
self.ui.label_ymin.setText('')
|
||||
self.ui.label_xmax.setText('')
|
||||
self.ui.label_ymax.setText('')
|
||||
|
||||
# # 删除表格所有行
|
||||
# self.ui.tableWidget.setRowCount(0)
|
||||
# self.ui.tableWidget.clearContents()
|
||||
self.tabel_info_show(self.location_list, self.cls_list, self.conf_list, path=img_path)
|
||||
self.ui.tableWidget.scrollToBottom()
|
||||
QApplication.processEvents() #刷新页面
|
||||
|
||||
def draw_rect_and_tabel(self, results, img):
|
||||
now_img = img.copy()
|
||||
location_list = results.boxes.xyxy.tolist()
|
||||
self.location_list = [list(map(int, e)) for e in location_list]
|
||||
cls_list = results.boxes.cls.tolist()
|
||||
self.cls_list = [int(i) for i in cls_list]
|
||||
self.conf_list = results.boxes.conf.tolist()
|
||||
self.conf_list = ['%.2f %%' % (each * 100) for each in self.conf_list]
|
||||
|
||||
for loacation, type_id, conf in zip(self.location_list, self.cls_list, self.conf_list):
|
||||
type_id = int(type_id)
|
||||
color = self.colors(int(type_id), True)
|
||||
# cv2.rectangle(now_img, (int(x1), int(y1)), (int(x2), int(y2)), colors(int(type_id), True), 3)
|
||||
now_img = tools.drawRectBox(now_img, loacation, Config.CH_names[type_id], self.fontC, color)
|
||||
|
||||
# 获取缩放后的图片尺寸
|
||||
self.img_width, self.img_height = self.get_resize_size(now_img)
|
||||
resize_cvimg = cv2.resize(now_img, (self.img_width, self.img_height))
|
||||
pix_img = tools.cvimg_to_qpiximg(resize_cvimg)
|
||||
self.ui.label_show.setPixmap(pix_img)
|
||||
self.ui.label_show.setAlignment(Qt.AlignCenter)
|
||||
# 设置路径显示
|
||||
self.ui.PiclineEdit.setText(self.org_path)
|
||||
|
||||
# 目标数目
|
||||
target_nums = len(self.cls_list)
|
||||
self.ui.label_nums.setText(str(target_nums))
|
||||
if target_nums >= 1:
|
||||
self.ui.type_lb.setText(Config.CH_names[self.cls_list[0]])
|
||||
self.ui.label_conf.setText(str(self.conf_list[0]))
|
||||
self.ui.label_xmin.setText(str(self.location_list[0][0]))
|
||||
self.ui.label_ymin.setText(str(self.location_list[0][1]))
|
||||
self.ui.label_xmax.setText(str(self.location_list[0][2]))
|
||||
self.ui.label_ymax.setText(str(self.location_list[0][3]))
|
||||
else:
|
||||
self.ui.type_lb.setText('')
|
||||
self.ui.label_conf.setText('')
|
||||
self.ui.label_xmin.setText('')
|
||||
self.ui.label_ymin.setText('')
|
||||
self.ui.label_xmax.setText('')
|
||||
self.ui.label_ymax.setText('')
|
||||
|
||||
# 删除表格所有行
|
||||
self.ui.tableWidget.setRowCount(0)
|
||||
self.ui.tableWidget.clearContents()
|
||||
self.tabel_info_show(self.location_list, self.cls_list, self.conf_list, path=self.org_path)
|
||||
return now_img
|
||||
|
||||
def combox_change(self):
|
||||
com_text = self.ui.comboBox.currentText()
|
||||
if com_text == '全部':
|
||||
cur_box = self.location_list
|
||||
cur_img = self.results.plot()
|
||||
self.ui.type_lb.setText(Config.CH_names[self.cls_list[0]])
|
||||
self.ui.label_conf.setText(str(self.conf_list[0]))
|
||||
else:
|
||||
index = int(com_text.split('_')[-1])
|
||||
cur_box = [self.location_list[index]]
|
||||
cur_img = self.results[index].plot()
|
||||
self.ui.type_lb.setText(Config.CH_names[self.cls_list[index]])
|
||||
self.ui.label_conf.setText(str(self.conf_list[index]))
|
||||
|
||||
# 设置坐标位置值
|
||||
self.ui.label_xmin.setText(str(cur_box[0][0]))
|
||||
self.ui.label_ymin.setText(str(cur_box[0][1]))
|
||||
self.ui.label_xmax.setText(str(cur_box[0][2]))
|
||||
self.ui.label_ymax.setText(str(cur_box[0][3]))
|
||||
|
||||
resize_cvimg = cv2.resize(cur_img, (self.img_width, self.img_height))
|
||||
pix_img = tools.cvimg_to_qpiximg(resize_cvimg)
|
||||
self.ui.label_show.clear()
|
||||
self.ui.label_show.setPixmap(pix_img)
|
||||
self.ui.label_show.setAlignment(Qt.AlignCenter)
|
||||
|
||||
|
||||
def get_video_path(self):
|
||||
file_path, _ = QFileDialog.getOpenFileName(None, '打开视频', './', "Image files (*.avi *.mp4 *.wmv *.mkv)")
|
||||
if not file_path:
|
||||
return None
|
||||
self.org_path = file_path
|
||||
self.ui.VideolineEdit.setText(file_path)
|
||||
return file_path
|
||||
|
||||
def video_start(self):
|
||||
# 删除表格所有行
|
||||
self.ui.tableWidget.setRowCount(0)
|
||||
self.ui.tableWidget.clearContents()
|
||||
|
||||
# 清空下拉框
|
||||
self.ui.comboBox.clear()
|
||||
|
||||
# 定时器开启,每隔一段时间,读取一帧
|
||||
self.timer_camera.start(1)
|
||||
self.timer_camera.timeout.connect(self.open_frame)
|
||||
|
||||
def tabel_info_show(self, locations, clses, confs, path=None):
|
||||
path = path
|
||||
for location, cls, conf in zip(locations, clses, confs):
|
||||
row_count = self.ui.tableWidget.rowCount() # 返回当前行数(尾部)
|
||||
self.ui.tableWidget.insertRow(row_count) # 尾部插入一行
|
||||
item_id = QTableWidgetItem(str(row_count+1)) # 序号
|
||||
item_id.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter) # 设置文本居中
|
||||
item_path = QTableWidgetItem(str(path)) # 路径
|
||||
# item_path.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
|
||||
|
||||
item_cls = QTableWidgetItem(str(Config.CH_names[cls]))
|
||||
item_cls.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter) # 设置文本居中
|
||||
|
||||
item_conf = QTableWidgetItem(str(conf))
|
||||
item_conf.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter) # 设置文本居中
|
||||
|
||||
item_location = QTableWidgetItem(str(location)) # 目标框位置
|
||||
# item_location.setTextAlignment(Qt.AlignHCenter | Qt.AlignVCenter) # 设置文本居中
|
||||
|
||||
self.ui.tableWidget.setItem(row_count, 0, item_id)
|
||||
self.ui.tableWidget.setItem(row_count, 1, item_path)
|
||||
self.ui.tableWidget.setItem(row_count, 2, item_cls)
|
||||
self.ui.tableWidget.setItem(row_count, 3, item_conf)
|
||||
self.ui.tableWidget.setItem(row_count, 4, item_location)
|
||||
self.ui.tableWidget.scrollToBottom()
|
||||
|
||||
def video_stop(self):
|
||||
self.cap.release()
|
||||
self.timer_camera.stop()
|
||||
# self.timer_info.stop()
|
||||
|
||||
def open_frame(self):
|
||||
ret, now_img = self.cap.read()
|
||||
if ret:
|
||||
# 目标检测
|
||||
t1 = time.time()
|
||||
results = self.model(now_img,conf=self.conf, iou=self.iou)[0]
|
||||
t2 = time.time()
|
||||
take_time_str = '{:.3f} s'.format(t2 - t1)
|
||||
self.ui.time_lb.setText(take_time_str)
|
||||
|
||||
location_list = results.boxes.xyxy.tolist()
|
||||
self.location_list = [list(map(int, e)) for e in location_list]
|
||||
cls_list = results.boxes.cls.tolist()
|
||||
self.cls_list = [int(i) for i in cls_list]
|
||||
self.conf_list = results.boxes.conf.tolist()
|
||||
self.conf_list = ['%.2f %%' % (each * 100) for each in self.conf_list]
|
||||
|
||||
now_img = results.plot()
|
||||
|
||||
# 获取缩放后的图片尺寸
|
||||
self.img_width, self.img_height = self.get_resize_size(now_img)
|
||||
resize_cvimg = cv2.resize(now_img, (self.img_width, self.img_height))
|
||||
pix_img = tools.cvimg_to_qpiximg(resize_cvimg)
|
||||
self.ui.label_show.setPixmap(pix_img)
|
||||
self.ui.label_show.setAlignment(Qt.AlignCenter)
|
||||
|
||||
# 目标数目
|
||||
target_nums = len(self.cls_list)
|
||||
self.ui.label_nums.setText(str(target_nums))
|
||||
|
||||
# 设置目标选择下拉框
|
||||
choose_list = ['全部']
|
||||
target_names = [Config.names[id] + '_' + str(index) for index, id in enumerate(self.cls_list)]
|
||||
# object_list = sorted(set(self.cls_list))
|
||||
# for each in object_list:
|
||||
# choose_list.append(Config.CH_names[each])
|
||||
choose_list = choose_list + target_names
|
||||
|
||||
self.ui.comboBox.clear()
|
||||
self.ui.comboBox.addItems(choose_list)
|
||||
|
||||
if target_nums >= 1:
|
||||
self.ui.type_lb.setText(Config.CH_names[self.cls_list[0]])
|
||||
self.ui.label_conf.setText(str(self.conf_list[0]))
|
||||
# 默认显示第一个目标框坐标
|
||||
# 设置坐标位置值
|
||||
self.ui.label_xmin.setText(str(self.location_list[0][0]))
|
||||
self.ui.label_ymin.setText(str(self.location_list[0][1]))
|
||||
self.ui.label_xmax.setText(str(self.location_list[0][2]))
|
||||
self.ui.label_ymax.setText(str(self.location_list[0][3]))
|
||||
else:
|
||||
self.ui.type_lb.setText('')
|
||||
self.ui.label_conf.setText('')
|
||||
self.ui.label_xmin.setText('')
|
||||
self.ui.label_ymin.setText('')
|
||||
self.ui.label_xmax.setText('')
|
||||
self.ui.label_ymax.setText('')
|
||||
|
||||
|
||||
# 删除表格所有行
|
||||
# self.ui.tableWidget.setRowCount(0)
|
||||
# self.ui.tableWidget.clearContents()
|
||||
self.tabel_info_show(self.location_list, self.cls_list, self.conf_list, path=self.org_path)
|
||||
|
||||
else:
|
||||
self.cap.release()
|
||||
self.timer_camera.stop()
|
||||
|
||||
def vedio_show(self):
|
||||
if self.is_camera_open:
|
||||
self.is_camera_open = False
|
||||
self.ui.CaplineEdit.setText('摄像头未开启')
|
||||
|
||||
video_path = self.get_video_path()
|
||||
if not video_path:
|
||||
return None
|
||||
self.cap = cv2.VideoCapture(video_path)
|
||||
self.video_start()
|
||||
self.ui.comboBox.setDisabled(True)
|
||||
|
||||
def camera_show(self):
|
||||
self.is_camera_open = not self.is_camera_open
|
||||
if self.is_camera_open:
|
||||
self.ui.CaplineEdit.setText('摄像头开启')
|
||||
self.cap = cv2.VideoCapture(0)
|
||||
self.video_start()
|
||||
self.ui.comboBox.setDisabled(True)
|
||||
else:
|
||||
self.ui.CaplineEdit.setText('摄像头未开启')
|
||||
self.ui.label_show.setText('')
|
||||
if self.cap:
|
||||
self.cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
self.ui.label_show.clear()
|
||||
|
||||
def get_resize_size(self, img):
|
||||
_img = img.copy()
|
||||
img_height, img_width , depth= _img.shape
|
||||
ratio = img_width / img_height
|
||||
if ratio >= self.show_width / self.show_height:
|
||||
self.img_width = self.show_width
|
||||
self.img_height = int(self.img_width / ratio)
|
||||
else:
|
||||
self.img_height = self.show_height
|
||||
self.img_width = int(self.img_height * ratio)
|
||||
return self.img_width, self.img_height
|
||||
|
||||
def save_detect_video(self):
|
||||
if self.cap is None and not self.org_path:
|
||||
QMessageBox.about(self, '提示', '当前没有可保存信息,请先打开图片或视频!')
|
||||
return
|
||||
|
||||
if self.is_camera_open:
|
||||
QMessageBox.about(self, '提示', '摄像头视频无法保存!')
|
||||
return
|
||||
|
||||
if self.cap:
|
||||
res = QMessageBox.information(self, '提示', '保存视频检测结果可能需要较长时间,请确认是否继续保存?',QMessageBox.Yes | QMessageBox.No , QMessageBox.Yes)
|
||||
if res == QMessageBox.Yes:
|
||||
self.video_stop()
|
||||
com_text = self.ui.comboBox.currentText()
|
||||
self.btn2Thread_object = btn2Thread(self.org_path, self.model, com_text,self.conf,self.iou)
|
||||
self.btn2Thread_object.start()
|
||||
self.btn2Thread_object.update_ui_signal.connect(self.update_process_bar)
|
||||
else:
|
||||
return
|
||||
else:
|
||||
if os.path.isfile(self.org_path):
|
||||
fileName = os.path.basename(self.org_path)
|
||||
name , end_name= fileName.rsplit(".",1)
|
||||
save_name = name + '_detect_result.' + end_name
|
||||
save_img_path = os.path.join(Config.save_path, save_name)
|
||||
# 保存图片
|
||||
cv2.imwrite(save_img_path, self.draw_img)
|
||||
QMessageBox.about(self, '提示', '图片保存成功!\n文件路径:{}'.format(save_img_path))
|
||||
else:
|
||||
img_suffix = ['jpg', 'png', 'jpeg', 'bmp']
|
||||
for file_name in os.listdir(self.org_path):
|
||||
full_path = os.path.join(self.org_path, file_name)
|
||||
if os.path.isfile(full_path) and file_name.split('.')[-1].lower() in img_suffix:
|
||||
name, end_name = file_name.rsplit(".",1)
|
||||
save_name = name + '_detect_result.' + end_name
|
||||
save_img_path = os.path.join(Config.save_path, save_name)
|
||||
results = self.model(full_path,conf=self.conf, iou=self.iou)[0]
|
||||
now_img = results.plot()
|
||||
# 保存图片
|
||||
cv2.imwrite(save_img_path, now_img)
|
||||
|
||||
QMessageBox.about(self, '提示', '图片保存成功!\n文件路径:{}'.format(Config.save_path))
|
||||
|
||||
|
||||
def update_process_bar(self,cur_num, total):
|
||||
if cur_num == 1:
|
||||
self.progress_bar = ProgressBar(self)
|
||||
self.progress_bar.show()
|
||||
if cur_num >= total:
|
||||
self.progress_bar.close()
|
||||
QMessageBox.about(self, '提示', '视频保存成功!\n文件在{}目录下'.format(Config.save_path))
|
||||
return
|
||||
if self.progress_bar.isVisible() is False:
|
||||
# 点击取消保存时,终止进程
|
||||
self.btn2Thread_object.stop()
|
||||
return
|
||||
value = int(cur_num / total *100)
|
||||
self.progress_bar.setValue(cur_num, total, value)
|
||||
QApplication.processEvents()
|
||||
|
||||
|
||||
class btn2Thread(QThread):
|
||||
"""
|
||||
进行检测后的视频保存
|
||||
"""
|
||||
# 声明一个信号
|
||||
update_ui_signal = pyqtSignal(int,int)
|
||||
|
||||
def __init__(self, path, model, com_text,conf,iou):
|
||||
super(btn2Thread, self).__init__()
|
||||
self.org_path = path
|
||||
self.model = model
|
||||
self.com_text = com_text
|
||||
self.conf = conf
|
||||
self.iou = iou
|
||||
# 用于绘制不同颜色矩形框
|
||||
self.colors = tools.Colors()
|
||||
self.is_running = True # 标志位,表示线程是否正在运行
|
||||
|
||||
def run(self):
|
||||
# VideoCapture方法是cv2库提供的读取视频方法
|
||||
cap = cv2.VideoCapture(self.org_path)
|
||||
# 设置需要保存视频的格式“xvid”
|
||||
# 该参数是MPEG-4编码类型,文件名后缀为.avi
|
||||
fourcc = cv2.VideoWriter_fourcc(*'XVID')
|
||||
# 设置视频帧频
|
||||
fps = cap.get(cv2.CAP_PROP_FPS)
|
||||
# 设置视频大小
|
||||
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
|
||||
# VideoWriter方法是cv2库提供的保存视频方法
|
||||
# 按照设置的格式来out输出
|
||||
fileName = os.path.basename(self.org_path)
|
||||
name, end_name = fileName.split('.')
|
||||
save_name = name + '_detect_result.avi'
|
||||
save_video_path = os.path.join(Config.save_path, save_name)
|
||||
out = cv2.VideoWriter(save_video_path, fourcc, fps, size)
|
||||
|
||||
prop = cv2.CAP_PROP_FRAME_COUNT
|
||||
total = int(cap.get(prop))
|
||||
print("[INFO] 视频总帧数:{}".format(total))
|
||||
cur_num = 0
|
||||
|
||||
# 确定视频打开并循环读取
|
||||
while (cap.isOpened() and self.is_running):
|
||||
cur_num += 1
|
||||
print('当前第{}帧,总帧数{}'.format(cur_num, total))
|
||||
# 逐帧读取,ret返回布尔值
|
||||
# 参数ret为True 或者False,代表有没有读取到图片
|
||||
# frame表示截取到一帧的图片
|
||||
ret, frame = cap.read()
|
||||
if ret == True:
|
||||
# 检测
|
||||
results = self.model(frame,conf=self.conf,iou=self.iou)[0]
|
||||
frame = results.plot()
|
||||
out.write(frame)
|
||||
self.update_ui_signal.emit(cur_num, total)
|
||||
else:
|
||||
break
|
||||
# 释放资源
|
||||
cap.release()
|
||||
out.release()
|
||||
|
||||
def stop(self):
|
||||
self.is_running = False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
win = MainWindow()
|
||||
win.show()
|
||||
sys.exit(app.exec_())
|
||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 286 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 246 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 206 KiB |
|
After Width: | Height: | Size: 75 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
|
@ -0,0 +1,8 @@
|
|||
class QSSLoader:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def read_qss_file(qss_file_name):
|
||||
with open(qss_file_name, 'r', encoding='UTF-8') as file:
|
||||
return file.read()
|
||||
|
|
@ -0,0 +1,522 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'UiMain.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
MainWindow.setObjectName("MainWindow")
|
||||
MainWindow.resize(1250, 830)
|
||||
MainWindow.setMinimumSize(QtCore.QSize(1250, 830))
|
||||
MainWindow.setMaximumSize(QtCore.QSize(1250, 830))
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(":/icons/ui_imgs/icons/目标检测.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
MainWindow.setWindowIcon(icon)
|
||||
self.centralwidget = QtWidgets.QWidget(MainWindow)
|
||||
self.centralwidget.setObjectName("centralwidget")
|
||||
self.frame = QtWidgets.QFrame(self.centralwidget)
|
||||
self.frame.setGeometry(QtCore.QRect(10, 100, 791, 711))
|
||||
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.frame.setObjectName("frame")
|
||||
self.frame_2 = QtWidgets.QFrame(self.frame)
|
||||
self.frame_2.setGeometry(QtCore.QRect(10, 0, 771, 481))
|
||||
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.frame_2.setObjectName("frame_2")
|
||||
self.label_show = QtWidgets.QLabel(self.frame_2)
|
||||
self.label_show.setGeometry(QtCore.QRect(0, 0, 770, 480))
|
||||
self.label_show.setMinimumSize(QtCore.QSize(770, 480))
|
||||
self.label_show.setMaximumSize(QtCore.QSize(770, 480))
|
||||
self.label_show.setStyleSheet("border-image: url(:/icons/ui_imgs/11.png);")
|
||||
self.label_show.setText("")
|
||||
self.label_show.setObjectName("label_show")
|
||||
self.frame_3 = QtWidgets.QFrame(self.frame)
|
||||
self.frame_3.setGeometry(QtCore.QRect(10, 480, 771, 221))
|
||||
self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||
self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.frame_3.setObjectName("frame_3")
|
||||
self.groupBox_3 = QtWidgets.QGroupBox(self.frame_3)
|
||||
self.groupBox_3.setGeometry(QtCore.QRect(0, 10, 771, 221))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("华文楷体")
|
||||
font.setPointSize(16)
|
||||
self.groupBox_3.setFont(font)
|
||||
self.groupBox_3.setObjectName("groupBox_3")
|
||||
self.tableWidget = QtWidgets.QTableWidget(self.groupBox_3)
|
||||
self.tableWidget.setGeometry(QtCore.QRect(10, 30, 751, 181))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("华文楷体")
|
||||
font.setPointSize(14)
|
||||
self.tableWidget.setFont(font)
|
||||
self.tableWidget.setObjectName("tableWidget")
|
||||
self.tableWidget.setColumnCount(5)
|
||||
self.tableWidget.setRowCount(0)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(0, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(1, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(2, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(3, item)
|
||||
item = QtWidgets.QTableWidgetItem()
|
||||
self.tableWidget.setHorizontalHeaderItem(4, item)
|
||||
self.frame_4 = QtWidgets.QFrame(self.centralwidget)
|
||||
self.frame_4.setGeometry(QtCore.QRect(810, 100, 431, 711))
|
||||
self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||
self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.frame_4.setObjectName("frame_4")
|
||||
self.groupBox = QtWidgets.QGroupBox(self.frame_4)
|
||||
self.groupBox.setGeometry(QtCore.QRect(0, 0, 431, 171))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("华文楷体")
|
||||
font.setPointSize(16)
|
||||
self.groupBox.setFont(font)
|
||||
self.groupBox.setObjectName("groupBox")
|
||||
self.PiclineEdit = QtWidgets.QLineEdit(self.groupBox)
|
||||
self.PiclineEdit.setGeometry(QtCore.QRect(70, 40, 311, 31))
|
||||
self.PiclineEdit.setInputMask("")
|
||||
self.PiclineEdit.setObjectName("PiclineEdit")
|
||||
self.VideolineEdit = QtWidgets.QLineEdit(self.groupBox)
|
||||
self.VideolineEdit.setGeometry(QtCore.QRect(70, 80, 311, 31))
|
||||
self.VideolineEdit.setObjectName("VideolineEdit")
|
||||
self.CapBtn = QtWidgets.QPushButton(self.groupBox)
|
||||
self.CapBtn.setGeometry(QtCore.QRect(30, 120, 30, 30))
|
||||
self.CapBtn.setStyleSheet("border-image: url(:/icons/ui_imgs/icons/camera.png);")
|
||||
self.CapBtn.setText("")
|
||||
self.CapBtn.setObjectName("CapBtn")
|
||||
self.PicBtn = QtWidgets.QPushButton(self.groupBox)
|
||||
self.PicBtn.setGeometry(QtCore.QRect(30, 40, 30, 30))
|
||||
self.PicBtn.setStyleSheet("border-image: url(:/icons/ui_imgs/icons/img.png);")
|
||||
self.PicBtn.setText("")
|
||||
self.PicBtn.setObjectName("PicBtn")
|
||||
self.VideoBtn = QtWidgets.QPushButton(self.groupBox)
|
||||
self.VideoBtn.setGeometry(QtCore.QRect(30, 80, 30, 30))
|
||||
self.VideoBtn.setStyleSheet("border-image: url(:/icons/ui_imgs/icons/video.png);")
|
||||
self.VideoBtn.setText("")
|
||||
self.VideoBtn.setObjectName("VideoBtn")
|
||||
self.CaplineEdit = QtWidgets.QLineEdit(self.groupBox)
|
||||
self.CaplineEdit.setGeometry(QtCore.QRect(70, 120, 311, 31))
|
||||
self.CaplineEdit.setObjectName("CaplineEdit")
|
||||
self.FilesBtn = QtWidgets.QPushButton(self.groupBox)
|
||||
self.FilesBtn.setGeometry(QtCore.QRect(390, 40, 30, 30))
|
||||
self.FilesBtn.setStyleSheet("border-image: url(:/icons/ui_imgs/icons/folder.png);")
|
||||
self.FilesBtn.setText("")
|
||||
self.FilesBtn.setObjectName("FilesBtn")
|
||||
self.groupBox_2 = QtWidgets.QGroupBox(self.frame_4)
|
||||
self.groupBox_2.setGeometry(QtCore.QRect(0, 180, 431, 371))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("华文楷体")
|
||||
font.setPointSize(16)
|
||||
self.groupBox_2.setFont(font)
|
||||
self.groupBox_2.setObjectName("groupBox_2")
|
||||
self.frame_6 = QtWidgets.QFrame(self.groupBox_2)
|
||||
self.frame_6.setGeometry(QtCore.QRect(0, 190, 431, 171))
|
||||
self.frame_6.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||
self.frame_6.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.frame_6.setObjectName("frame_6")
|
||||
self.label_4 = QtWidgets.QLabel(self.frame_6)
|
||||
self.label_4.setGeometry(QtCore.QRect(10, 10, 131, 41))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("华文楷体")
|
||||
font.setPointSize(16)
|
||||
self.label_4.setFont(font)
|
||||
self.label_4.setStyleSheet("")
|
||||
self.label_4.setObjectName("label_4")
|
||||
self.layoutWidget = QtWidgets.QWidget(self.frame_6)
|
||||
self.layoutWidget.setGeometry(QtCore.QRect(20, 60, 161, 37))
|
||||
self.layoutWidget.setObjectName("layoutWidget")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget)
|
||||
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.label_6 = QtWidgets.QLabel(self.layoutWidget)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("华文楷体")
|
||||
font.setPointSize(16)
|
||||
font.setBold(False)
|
||||
font.setWeight(50)
|
||||
self.label_6.setFont(font)
|
||||
self.label_6.setObjectName("label_6")
|
||||
self.horizontalLayout.addWidget(self.label_6)
|
||||
self.label_xmin = QtWidgets.QLabel(self.layoutWidget)
|
||||
palette = QtGui.QPalette()
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(120, 120, 120))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||
self.label_xmin.setPalette(palette)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(16)
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.label_xmin.setFont(font)
|
||||
self.label_xmin.setText("")
|
||||
self.label_xmin.setObjectName("label_xmin")
|
||||
self.horizontalLayout.addWidget(self.label_xmin)
|
||||
self.layoutWidget1 = QtWidgets.QWidget(self.frame_6)
|
||||
self.layoutWidget1.setGeometry(QtCore.QRect(210, 60, 161, 37))
|
||||
self.layoutWidget1.setObjectName("layoutWidget1")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.layoutWidget1)
|
||||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||
self.label_8 = QtWidgets.QLabel(self.layoutWidget1)
|
||||
self.label_8.setObjectName("label_8")
|
||||
self.horizontalLayout_2.addWidget(self.label_8)
|
||||
self.label_ymin = QtWidgets.QLabel(self.layoutWidget1)
|
||||
palette = QtGui.QPalette()
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(120, 120, 120))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||
self.label_ymin.setPalette(palette)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(16)
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.label_ymin.setFont(font)
|
||||
self.label_ymin.setText("")
|
||||
self.label_ymin.setObjectName("label_ymin")
|
||||
self.horizontalLayout_2.addWidget(self.label_ymin)
|
||||
self.layoutWidget2 = QtWidgets.QWidget(self.frame_6)
|
||||
self.layoutWidget2.setGeometry(QtCore.QRect(20, 120, 161, 37))
|
||||
self.layoutWidget2.setObjectName("layoutWidget2")
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.layoutWidget2)
|
||||
self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||
self.label_7 = QtWidgets.QLabel(self.layoutWidget2)
|
||||
self.label_7.setObjectName("label_7")
|
||||
self.horizontalLayout_3.addWidget(self.label_7)
|
||||
self.label_xmax = QtWidgets.QLabel(self.layoutWidget2)
|
||||
palette = QtGui.QPalette()
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(120, 120, 120))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||
self.label_xmax.setPalette(palette)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(16)
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.label_xmax.setFont(font)
|
||||
self.label_xmax.setText("")
|
||||
self.label_xmax.setObjectName("label_xmax")
|
||||
self.horizontalLayout_3.addWidget(self.label_xmax)
|
||||
self.layoutWidget3 = QtWidgets.QWidget(self.frame_6)
|
||||
self.layoutWidget3.setGeometry(QtCore.QRect(210, 120, 161, 37))
|
||||
self.layoutWidget3.setObjectName("layoutWidget3")
|
||||
self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.layoutWidget3)
|
||||
self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
|
||||
self.label_9 = QtWidgets.QLabel(self.layoutWidget3)
|
||||
self.label_9.setObjectName("label_9")
|
||||
self.horizontalLayout_4.addWidget(self.label_9)
|
||||
self.label_ymax = QtWidgets.QLabel(self.layoutWidget3)
|
||||
palette = QtGui.QPalette()
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(120, 120, 120))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||
self.label_ymax.setPalette(palette)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(16)
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.label_ymax.setFont(font)
|
||||
self.label_ymax.setText("")
|
||||
self.label_ymax.setObjectName("label_ymax")
|
||||
self.horizontalLayout_4.addWidget(self.label_ymax)
|
||||
self.layoutWidget4 = QtWidgets.QWidget(self.groupBox_2)
|
||||
self.layoutWidget4.setGeometry(QtCore.QRect(208, 40, 211, 37))
|
||||
self.layoutWidget4.setObjectName("layoutWidget4")
|
||||
self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.layoutWidget4)
|
||||
self.horizontalLayout_5.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
|
||||
self.label = QtWidgets.QLabel(self.layoutWidget4)
|
||||
self.label.setObjectName("label")
|
||||
self.horizontalLayout_5.addWidget(self.label)
|
||||
self.label_nums = QtWidgets.QLabel(self.layoutWidget4)
|
||||
palette = QtGui.QPalette()
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0, 128))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.PlaceholderText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0, 128))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.PlaceholderText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(120, 120, 120))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(120, 120, 120))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 128))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.PlaceholderText, brush)
|
||||
self.label_nums.setPalette(palette)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(16)
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.label_nums.setFont(font)
|
||||
self.label_nums.setText("")
|
||||
self.label_nums.setObjectName("label_nums")
|
||||
self.horizontalLayout_5.addWidget(self.label_nums)
|
||||
self.layoutWidget5 = QtWidgets.QWidget(self.groupBox_2)
|
||||
self.layoutWidget5.setGeometry(QtCore.QRect(10, 90, 291, 38))
|
||||
self.layoutWidget5.setObjectName("layoutWidget5")
|
||||
self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.layoutWidget5)
|
||||
self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_6.setObjectName("horizontalLayout_6")
|
||||
self.label_5 = QtWidgets.QLabel(self.layoutWidget5)
|
||||
self.label_5.setObjectName("label_5")
|
||||
self.horizontalLayout_6.addWidget(self.label_5)
|
||||
self.comboBox = QtWidgets.QComboBox(self.layoutWidget5)
|
||||
self.comboBox.setObjectName("comboBox")
|
||||
self.horizontalLayout_6.addWidget(self.comboBox)
|
||||
self.layoutWidget_2 = QtWidgets.QWidget(self.groupBox_2)
|
||||
self.layoutWidget_2.setGeometry(QtCore.QRect(10, 40, 171, 37))
|
||||
self.layoutWidget_2.setObjectName("layoutWidget_2")
|
||||
self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.layoutWidget_2)
|
||||
self.horizontalLayout_7.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
|
||||
self.label_10 = QtWidgets.QLabel(self.layoutWidget_2)
|
||||
self.label_10.setObjectName("label_10")
|
||||
self.horizontalLayout_7.addWidget(self.label_10)
|
||||
self.time_lb = QtWidgets.QLabel(self.layoutWidget_2)
|
||||
palette = QtGui.QPalette()
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Text, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0, 128))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.PlaceholderText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Text, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0, 128))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.PlaceholderText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(120, 120, 120))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(120, 120, 120))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Text, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 128))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.PlaceholderText, brush)
|
||||
self.time_lb.setPalette(palette)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(16)
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.time_lb.setFont(font)
|
||||
self.time_lb.setText("")
|
||||
self.time_lb.setObjectName("time_lb")
|
||||
self.horizontalLayout_7.addWidget(self.time_lb)
|
||||
self.layoutWidget6 = QtWidgets.QWidget(self.groupBox_2)
|
||||
self.layoutWidget6.setGeometry(QtCore.QRect(210, 140, 191, 41))
|
||||
self.layoutWidget6.setObjectName("layoutWidget6")
|
||||
self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.layoutWidget6)
|
||||
self.horizontalLayout_8.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
|
||||
self.label_11 = QtWidgets.QLabel(self.layoutWidget6)
|
||||
self.label_11.setObjectName("label_11")
|
||||
self.horizontalLayout_8.addWidget(self.label_11)
|
||||
self.label_conf = QtWidgets.QLabel(self.layoutWidget6)
|
||||
palette = QtGui.QPalette()
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(120, 120, 120))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||
self.label_conf.setPalette(palette)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(16)
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.label_conf.setFont(font)
|
||||
self.label_conf.setText("")
|
||||
self.label_conf.setObjectName("label_conf")
|
||||
self.horizontalLayout_8.addWidget(self.label_conf)
|
||||
self.layoutWidget_3 = QtWidgets.QWidget(self.groupBox_2)
|
||||
self.layoutWidget_3.setGeometry(QtCore.QRect(10, 140, 191, 41))
|
||||
self.layoutWidget_3.setObjectName("layoutWidget_3")
|
||||
self.horizontalLayout_9 = QtWidgets.QHBoxLayout(self.layoutWidget_3)
|
||||
self.horizontalLayout_9.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_9.setObjectName("horizontalLayout_9")
|
||||
self.label_13 = QtWidgets.QLabel(self.layoutWidget_3)
|
||||
self.label_13.setMaximumSize(QtCore.QSize(60, 16777215))
|
||||
self.label_13.setObjectName("label_13")
|
||||
self.horizontalLayout_9.addWidget(self.label_13)
|
||||
self.type_lb = QtWidgets.QLabel(self.layoutWidget_3)
|
||||
palette = QtGui.QPalette()
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, brush)
|
||||
brush = QtGui.QBrush(QtGui.QColor(120, 120, 120))
|
||||
brush.setStyle(QtCore.Qt.SolidPattern)
|
||||
palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, brush)
|
||||
self.type_lb.setPalette(palette)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(16)
|
||||
font.setBold(True)
|
||||
font.setWeight(75)
|
||||
self.type_lb.setFont(font)
|
||||
self.type_lb.setText("")
|
||||
self.type_lb.setObjectName("type_lb")
|
||||
self.horizontalLayout_9.addWidget(self.type_lb)
|
||||
self.groupBox_4 = QtWidgets.QGroupBox(self.frame_4)
|
||||
self.groupBox_4.setGeometry(QtCore.QRect(0, 560, 431, 141))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("华文楷体")
|
||||
font.setPointSize(16)
|
||||
self.groupBox_4.setFont(font)
|
||||
self.groupBox_4.setObjectName("groupBox_4")
|
||||
self.SaveBtn = QtWidgets.QPushButton(self.groupBox_4)
|
||||
self.SaveBtn.setGeometry(QtCore.QRect(30, 50, 151, 51))
|
||||
icon1 = QtGui.QIcon()
|
||||
icon1.addPixmap(QtGui.QPixmap(":/icons/ui_imgs/icons/保存.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.SaveBtn.setIcon(icon1)
|
||||
self.SaveBtn.setIconSize(QtCore.QSize(30, 30))
|
||||
self.SaveBtn.setObjectName("SaveBtn")
|
||||
self.ExitBtn = QtWidgets.QPushButton(self.groupBox_4)
|
||||
self.ExitBtn.setGeometry(QtCore.QRect(250, 50, 151, 51))
|
||||
icon2 = QtGui.QIcon()
|
||||
icon2.addPixmap(QtGui.QPixmap(":/icons/ui_imgs/icons/退出.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.ExitBtn.setIcon(icon2)
|
||||
self.ExitBtn.setIconSize(QtCore.QSize(30, 30))
|
||||
self.ExitBtn.setObjectName("ExitBtn")
|
||||
self.frame_5 = QtWidgets.QFrame(self.centralwidget)
|
||||
self.frame_5.setGeometry(QtCore.QRect(10, 10, 1231, 91))
|
||||
self.frame_5.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||
self.frame_5.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.frame_5.setObjectName("frame_5")
|
||||
self.label_3 = QtWidgets.QLabel(self.frame_5)
|
||||
self.label_3.setGeometry(QtCore.QRect(280, 0, 811, 51))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("华文楷体")
|
||||
font.setPointSize(30)
|
||||
self.label_3.setFont(font)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.label_2 = QtWidgets.QLabel(self.frame_5)
|
||||
self.label_2.setGeometry(QtCore.QRect(20, 60, 311, 21))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("华文楷体")
|
||||
font.setPointSize(14)
|
||||
font.setUnderline(True)
|
||||
self.label_2.setFont(font)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.label_12 = QtWidgets.QLabel(self.frame_5)
|
||||
self.label_12.setGeometry(QtCore.QRect(1070, 60, 131, 21))
|
||||
font = QtGui.QFont()
|
||||
font.setFamily("华文楷体")
|
||||
font.setPointSize(14)
|
||||
font.setUnderline(True)
|
||||
self.label_12.setFont(font)
|
||||
self.label_12.setObjectName("label_12")
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
self.statusbar = QtWidgets.QStatusBar(MainWindow)
|
||||
self.statusbar.setObjectName("statusbar")
|
||||
MainWindow.setStatusBar(self.statusbar)
|
||||
|
||||
self.retranslateUi(MainWindow)
|
||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||
|
||||
def retranslateUi(self, MainWindow):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
MainWindow.setWindowTitle(_translate("MainWindow", "基于深度学习的救援过程识别系统"))
|
||||
self.groupBox_3.setTitle(_translate("MainWindow", "检测结果与位置信息"))
|
||||
item = self.tableWidget.horizontalHeaderItem(0)
|
||||
item.setText(_translate("MainWindow", "序号"))
|
||||
item = self.tableWidget.horizontalHeaderItem(1)
|
||||
item.setText(_translate("MainWindow", "文件路径"))
|
||||
item = self.tableWidget.horizontalHeaderItem(2)
|
||||
item.setText(_translate("MainWindow", "类别"))
|
||||
item = self.tableWidget.horizontalHeaderItem(3)
|
||||
item.setText(_translate("MainWindow", "置信度"))
|
||||
item = self.tableWidget.horizontalHeaderItem(4)
|
||||
item.setText(_translate("MainWindow", "坐标位置"))
|
||||
self.groupBox.setTitle(_translate("MainWindow", "文件导入"))
|
||||
self.PiclineEdit.setPlaceholderText(_translate("MainWindow", "请选择图片文件"))
|
||||
self.VideolineEdit.setPlaceholderText(_translate("MainWindow", "请选择视频文件"))
|
||||
self.CaplineEdit.setPlaceholderText(_translate("MainWindow", "摄像头未开启"))
|
||||
self.groupBox_2.setTitle(_translate("MainWindow", "检测结果"))
|
||||
self.label_4.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-weight:600;\">目标位置:</span></p></body></html>"))
|
||||
self.label_6.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-weight:600;\">xmin:</span></p></body></html>"))
|
||||
self.label_8.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-weight:600;\">ymin:</span></p></body></html>"))
|
||||
self.label_7.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-weight:600;\">xmax:</span></p></body></html>"))
|
||||
self.label_9.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-weight:600;\">ymax:</span></p></body></html>"))
|
||||
self.label.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-weight:600;\">目标数目:</span></p></body></html>"))
|
||||
self.label_5.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-weight:600;\">目标选择:</span></p></body></html>"))
|
||||
self.label_10.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-weight:600;\">用时:</span></p></body></html>"))
|
||||
self.label_11.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-weight:600;\">置信度:</span></p></body></html>"))
|
||||
self.label_13.setText(_translate("MainWindow", "<html><head/><body><p><span style=\" font-weight:600;\">类型:</span></p></body></html>"))
|
||||
self.groupBox_4.setTitle(_translate("MainWindow", "操作"))
|
||||
self.SaveBtn.setText(_translate("MainWindow", "保存"))
|
||||
self.ExitBtn.setText(_translate("MainWindow", "退出"))
|
||||
self.label_3.setText(_translate("MainWindow", "基于深度学习的救援过程识别系统"))
|
||||
self.label_2.setText(_translate("MainWindow", "公众号:救援识别技术"))
|
||||
self.label_12.setText(_translate("MainWindow", "作者:王海滨"))
|
||||
import ui_sources_rc
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# 进度条
|
||||
from PyQt5.QtWidgets import QDialog, QLabel, QProgressBar, QPushButton, QVBoxLayout, QHBoxLayout
|
||||
|
||||
|
||||
class ProgressBar(QDialog):
|
||||
def __init__(self, parent=None):
|
||||
super(ProgressBar, self).__init__(parent)
|
||||
|
||||
self.resize(350, 100)
|
||||
self.setWindowTitle(self.tr("视频保存进度信息"))
|
||||
|
||||
self.TipLabel = QLabel(self.tr("当前帧/总帧数:0/0"))
|
||||
self.FeatLabel = QLabel(self.tr("保存进度:"))
|
||||
|
||||
self.FeatProgressBar = QProgressBar(self)
|
||||
self.FeatProgressBar.setMinimum(0)
|
||||
self.FeatProgressBar.setMaximum(100) # 总进程换算为100
|
||||
self.FeatProgressBar.setValue(0) # 进度条初始值为0
|
||||
|
||||
TipLayout = QHBoxLayout()
|
||||
TipLayout.addWidget(self.TipLabel)
|
||||
|
||||
FeatLayout = QHBoxLayout()
|
||||
FeatLayout.addWidget(self.FeatLabel)
|
||||
FeatLayout.addWidget(self.FeatProgressBar)
|
||||
|
||||
self.cancelButton = QPushButton('取消保存', self)
|
||||
|
||||
buttonlayout = QHBoxLayout()
|
||||
buttonlayout.addStretch(1)
|
||||
buttonlayout.addWidget(self.cancelButton)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
layout.addLayout(FeatLayout)
|
||||
layout.addLayout(TipLayout)
|
||||
layout.addLayout(buttonlayout)
|
||||
self.setLayout(layout)
|
||||
self.cancelButton.clicked.connect(self.onCancel)
|
||||
# self.show()
|
||||
|
||||
def setValue(self, start, end, progress):
|
||||
self.TipLabel.setText(self.tr("当前帧/总帧数:" + " " + str(start) + "/" + str(end)))
|
||||
# 确保 progress 是整数类型,避免 TypeError
|
||||
self.FeatProgressBar.setValue(int(progress))
|
||||
|
||||
def onCancel(self, event):
|
||||
self.close()
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
QGroupBox {
|
||||
border: 2px solid gray;
|
||||
}
|
||||
|
||||
QPushButton#SaveBtn{color:black;
|
||||
background-color:rgb(255, 215, 0);
|
||||
border-radius:6px}
|
||||
QPushButton#ExitBtn{color:black;
|
||||
background-color:rgb(255, 215, 0);
|
||||
border-radius:6px}
|
||||
QPushButton:hover{color:red}
|
||||
QPushButton:pressed{background-color:rgb(180,180,180);border: None;}
|
||||
|
||||
|
||||
#MainWindow{border-image:url(UIProgram/ui_imgs/bg22.png)}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'ui_sources.qrc'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.9
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<RCC>
|
||||
<qresource prefix="icons">
|
||||
<file>ui_imgs/icons/目标检测.png</file>
|
||||
<file>ui_imgs/icons/保存.png</file>
|
||||
<file>ui_imgs/icons/退出.png</file>
|
||||
<file>ui_imgs/icons/camera.png</file>
|
||||
<file>ui_imgs/icons/folder.png</file>
|
||||
<file>ui_imgs/icons/img.png</file>
|
||||
<file>ui_imgs/icons/video.png</file>
|
||||
<file>ui_imgs/11.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="bgs"/>
|
||||
</RCC>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
#coding:utf-8
|
||||
import cv2
|
||||
from ultralytics import YOLO
|
||||
|
||||
# 所需加载的模型目录
|
||||
path = 'models/best.pt'
|
||||
# 需要检测的图片地址
|
||||
video_path = "TestFiles/1.mp4"
|
||||
|
||||
# Load the YOLOv8 model
|
||||
model = YOLO(path)
|
||||
cap = cv2.VideoCapture(video_path)
|
||||
# Loop through the video frames
|
||||
while cap.isOpened():
|
||||
# Read a frame from the video
|
||||
success, frame = cap.read()
|
||||
|
||||
if success:
|
||||
# Run YOLOv8 inference on the frame
|
||||
results = model(frame)
|
||||
|
||||
# Visualize the results on the frame
|
||||
annotated_frame = results[0].plot()
|
||||
# annotated_frame = cv2.resize(annotated_frame, dsize=None, fx=2, fy=2, interpolation=cv2.INTER_LINEAR)
|
||||
|
||||
# Display the annotated frame
|
||||
cv2.imshow("YOLOv8 Inference", annotated_frame)
|
||||
|
||||
# Break the loop if 'q' is pressed
|
||||
if cv2.waitKey(1) & 0xFF == ord("q"):
|
||||
break
|
||||
else:
|
||||
# Break the loop if the end of the video is reached
|
||||
break
|
||||
|
||||
# Release the video capture object and close the display window
|
||||
cap.release()
|
||||
cv2.destroyAllWindows()
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
"""
|
||||
检查并清理没有标注文件的图片
|
||||
找出 train 目录下没有对应 label 文件的图片,并删除它们
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_image_files(directory):
|
||||
"""获取目录下所有图片文件"""
|
||||
image_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.tif', '.JPG', '.JPEG', '.PNG'}
|
||||
image_files = []
|
||||
|
||||
for file in Path(directory).iterdir():
|
||||
if file.is_file() and file.suffix in image_extensions:
|
||||
image_files.append(file)
|
||||
|
||||
return image_files
|
||||
|
||||
|
||||
def get_label_files(directory):
|
||||
"""获取目录下所有标注文件"""
|
||||
label_files = []
|
||||
|
||||
for file in Path(directory).iterdir():
|
||||
if file.is_file() and file.suffix == '.txt':
|
||||
label_files.append(file)
|
||||
|
||||
return label_files
|
||||
|
||||
|
||||
def find_images_without_labels(train_dir, label_dir, dry_run=True):
|
||||
"""
|
||||
找出没有对应标注文件的图片
|
||||
|
||||
Args:
|
||||
train_dir: 图片目录
|
||||
label_dir: 标注目录
|
||||
dry_run: 如果为True,只检查不删除
|
||||
|
||||
Returns:
|
||||
list: 没有标注的图片文件列表
|
||||
"""
|
||||
train_path = Path(train_dir)
|
||||
label_path = Path(label_dir)
|
||||
|
||||
if not train_path.exists():
|
||||
print(f"错误: 图片目录不存在: {train_dir}")
|
||||
return []
|
||||
|
||||
if not label_path.exists():
|
||||
print(f"错误: 标注目录不存在: {label_dir}")
|
||||
return []
|
||||
|
||||
# 获取所有图片和标注文件
|
||||
image_files = get_image_files(train_path)
|
||||
label_files = get_label_files(label_path)
|
||||
|
||||
print(f"找到 {len(image_files)} 个图片文件")
|
||||
print(f"找到 {len(label_files)} 个标注文件")
|
||||
print("-" * 60)
|
||||
|
||||
# 创建标注文件名的集合(不含扩展名)
|
||||
label_names = {f.stem for f in label_files}
|
||||
|
||||
# 找出没有对应标注的图片
|
||||
images_without_labels = []
|
||||
|
||||
for img_file in image_files:
|
||||
img_name_without_ext = img_file.stem
|
||||
|
||||
if img_name_without_ext not in label_names:
|
||||
images_without_labels.append(img_file)
|
||||
|
||||
# 打印结果
|
||||
if images_without_labels:
|
||||
print(f"发现 {len(images_without_labels)} 个没有标注的图片:")
|
||||
print("-" * 60)
|
||||
for img in images_without_labels[:20]: # 只显示前20个
|
||||
print(f" {img.name}")
|
||||
if len(images_without_labels) > 20:
|
||||
print(f" ... 还有 {len(images_without_labels) - 20} 个文件")
|
||||
print("-" * 60)
|
||||
|
||||
if not dry_run:
|
||||
# 删除文件
|
||||
deleted_count = 0
|
||||
failed_count = 0
|
||||
|
||||
for img_file in images_without_labels:
|
||||
try:
|
||||
img_file.unlink()
|
||||
deleted_count += 1
|
||||
except Exception as e:
|
||||
print(f"删除失败: {img_file.name} - {e}")
|
||||
failed_count += 1
|
||||
|
||||
print(f"\n删除完成:")
|
||||
print(f" 成功删除: {deleted_count} 个文件")
|
||||
if failed_count > 0:
|
||||
print(f" 删除失败: {failed_count} 个文件")
|
||||
else:
|
||||
print("\n[预览模式] 未实际删除文件")
|
||||
print("要删除这些文件,请运行: python check_and_clean_images.py --delete")
|
||||
else:
|
||||
print("✓ 所有图片都有对应的标注文件!")
|
||||
|
||||
return images_without_labels
|
||||
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
import sys
|
||||
|
||||
# 默认路径
|
||||
train_dir = "datasets/handleImage/train"
|
||||
label_dir = "datasets/handleImage/label"
|
||||
|
||||
# 检查命令行参数
|
||||
dry_run = True
|
||||
force = False
|
||||
if len(sys.argv) > 1:
|
||||
if '--delete' in sys.argv or '-d' in sys.argv:
|
||||
dry_run = False
|
||||
if '--force' in sys.argv or '-f' in sys.argv:
|
||||
force = True
|
||||
if '--help' in sys.argv or '-h' in sys.argv:
|
||||
print("=" * 60)
|
||||
print("图片标注检查工具 - 使用说明")
|
||||
print("=" * 60)
|
||||
print("\n功能:")
|
||||
print(" 检查图片文件是否有对应的标注文件,并删除没有标注的图片")
|
||||
print("\n使用方法:")
|
||||
print(" python check_and_clean_images.py")
|
||||
print(" # 预览模式:检查但不删除文件(推荐先运行)")
|
||||
print("\n python check_and_clean_images.py --delete")
|
||||
print(" # 删除模式:删除没有标注的图片(需要确认)")
|
||||
print("\n python check_and_clean_images.py --delete --force")
|
||||
print(" # 强制删除:直接删除,不确认(适合脚本自动化)")
|
||||
print("\n参数说明:")
|
||||
print(" --delete, -d 启用删除模式")
|
||||
print(" --force, -f 跳过确认,直接删除")
|
||||
print(" --help, -h 显示此帮助信息")
|
||||
print("\n默认路径:")
|
||||
print(f" 图片目录: {train_dir}")
|
||||
print(f" 标注目录: {label_dir}")
|
||||
print("\n支持的图片格式:")
|
||||
print(" .jpg, .jpeg, .png, .bmp, .tiff, .tif (大小写不敏感)")
|
||||
print("\n标注文件格式:")
|
||||
print(" .txt 文件")
|
||||
print("\n文件名匹配规则:")
|
||||
print(" 通过文件名(不含扩展名)匹配,例如:")
|
||||
print(" image001.jpg ↔ image001.txt ✓")
|
||||
print(" image001.jpg ↔ image_001.txt ✗")
|
||||
print("\n注意事项:")
|
||||
print(" ⚠ 删除操作不可恢复!建议先备份数据")
|
||||
print(" ⚠ 使用 --delete 前建议先运行预览模式检查")
|
||||
print("\n详细教程:")
|
||||
print(" 查看文件: check_and_clean_images_使用教程.md")
|
||||
print("=" * 60)
|
||||
return
|
||||
|
||||
print("=" * 60)
|
||||
print("检查没有标注的图片")
|
||||
print("=" * 60)
|
||||
print(f"图片目录: {train_dir}")
|
||||
print(f"标注目录: {label_dir}")
|
||||
print()
|
||||
|
||||
if not dry_run and not force:
|
||||
try:
|
||||
response = input("⚠ 警告: 将删除没有标注的图片文件!确认继续?(yes/no): ")
|
||||
if response.lower() != 'yes':
|
||||
print("已取消")
|
||||
return
|
||||
except (EOFError, KeyboardInterrupt):
|
||||
print("\n已取消(非交互式环境,请使用 --force 参数)")
|
||||
return
|
||||
|
||||
images_to_delete = find_images_without_labels(train_dir, label_dir, dry_run=dry_run)
|
||||
|
||||
if images_to_delete and dry_run:
|
||||
print("\n提示: 使用 --delete 参数来实际删除这些文件")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
# 📋 图片标注检查工具使用教程
|
||||
|
||||
## 工具简介
|
||||
|
||||
`check_and_clean_images.py` 是一个用于检查和清理数据集的工具,可以:
|
||||
- ✅ 检查图片文件是否有对应的标注文件
|
||||
- ✅ 找出没有标注的图片
|
||||
- ✅ 删除没有标注的图片文件
|
||||
- ✅ 确保数据集完整性
|
||||
|
||||
---
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 基本用法
|
||||
|
||||
#### 1. 预览模式(推荐先运行)
|
||||
|
||||
检查哪些图片没有标注,但**不删除**文件:
|
||||
|
||||
```bash
|
||||
python check_and_clean_images.py
|
||||
```
|
||||
|
||||
**输出示例:**
|
||||
```
|
||||
============================================================
|
||||
检查没有标注的图片
|
||||
============================================================
|
||||
图片目录: datasets/handleImage/train
|
||||
标注目录: datasets/handleImage/label
|
||||
|
||||
找到 1330 个图片文件
|
||||
找到 1223 个标注文件
|
||||
------------------------------------------------------------
|
||||
发现 107 个没有标注的图片:
|
||||
------------------------------------------------------------
|
||||
订单1806953_51_7111322.jpg
|
||||
订单1805323_51_7096066.jpg
|
||||
...
|
||||
------------------------------------------------------------
|
||||
|
||||
[预览模式] 未实际删除文件
|
||||
要删除这些文件,请运行: python check_and_clean_images.py --delete
|
||||
```
|
||||
|
||||
#### 2. 删除模式(需要确认)
|
||||
|
||||
删除没有标注的图片,但会要求确认:
|
||||
|
||||
```bash
|
||||
python check_and_clean_images.py --delete
|
||||
```
|
||||
|
||||
**交互提示:**
|
||||
```
|
||||
⚠ 警告: 将删除没有标注的图片文件!确认继续?(yes/no):
|
||||
```
|
||||
|
||||
输入 `yes` 确认删除,输入 `no` 取消操作。
|
||||
|
||||
#### 3. 直接删除模式(不确认)
|
||||
|
||||
直接删除,不需要确认(适合脚本自动化):
|
||||
|
||||
```bash
|
||||
python check_and_clean_images.py --delete --force
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 详细说明
|
||||
|
||||
### 命令参数
|
||||
|
||||
| 参数 | 简写 | 说明 | 示例 |
|
||||
|------|------|------|------|
|
||||
| `--delete` | `-d` | 启用删除模式 | `--delete` |
|
||||
| `--force` | `-f` | 跳过确认,直接删除 | `--force` |
|
||||
| `--help` | `-h` | 显示帮助信息 | `--help` |
|
||||
|
||||
### 默认路径
|
||||
|
||||
工具默认检查以下路径:
|
||||
- **图片目录**: `datasets/handleImage/train`
|
||||
- **标注目录**: `datasets/handleImage/label`
|
||||
|
||||
### 支持的图片格式
|
||||
|
||||
工具会自动识别以下图片格式:
|
||||
- `.jpg` / `.JPG`
|
||||
- `.jpeg` / `.JPEG`
|
||||
- `.png` / `.PNG`
|
||||
- `.bmp`
|
||||
- `.tiff` / `.tif`
|
||||
|
||||
### 标注文件格式
|
||||
|
||||
工具查找 `.txt` 格式的标注文件。
|
||||
|
||||
---
|
||||
|
||||
## 📝 使用场景
|
||||
|
||||
### 场景 1: 检查数据集完整性
|
||||
|
||||
在训练前检查数据集是否完整:
|
||||
|
||||
```bash
|
||||
# 1. 先预览检查
|
||||
python check_and_clean_images.py
|
||||
|
||||
# 2. 如果有问题,查看具体文件
|
||||
# 3. 确认后删除
|
||||
python check_and_clean_images.py --delete
|
||||
```
|
||||
|
||||
### 场景 2: 清理导入的数据
|
||||
|
||||
从CVAT或其他工具导入数据后,清理不完整的文件:
|
||||
|
||||
```bash
|
||||
# 直接删除没有标注的图片
|
||||
python check_and_clean_images.py --delete --force
|
||||
```
|
||||
|
||||
### 场景 3: 批量处理多个数据集
|
||||
|
||||
修改脚本中的路径,处理不同数据集:
|
||||
|
||||
```python
|
||||
# 修改 check_and_clean_images.py 中的路径
|
||||
train_dir = "datasets/你的数据集/train"
|
||||
label_dir = "datasets/你的数据集/labels"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
### 1. 备份数据
|
||||
|
||||
**重要:** 删除操作不可恢复!建议在删除前备份数据:
|
||||
|
||||
```bash
|
||||
# 备份整个数据集
|
||||
cp -r datasets/handleImage datasets/handleImage_backup
|
||||
```
|
||||
|
||||
### 2. 文件名匹配规则
|
||||
|
||||
工具通过**文件名(不含扩展名)**匹配图片和标注:
|
||||
|
||||
- ✅ 匹配:`image001.jpg` ↔ `image001.txt`
|
||||
- ✅ 匹配:`订单1804264_51_7086683.jpg` ↔ `订单1804264_51_7086683.txt`
|
||||
- ❌ 不匹配:`image001.jpg` ↔ `image_001.txt`(下划线不同)
|
||||
- ❌ 不匹配:`image001.jpg` ↔ `image002.txt`(数字不同)
|
||||
|
||||
### 3. 空标注文件
|
||||
|
||||
如果标注文件存在但为空,工具**不会删除**对应的图片。如果需要处理空标注文件,需要额外检查。
|
||||
|
||||
### 4. 目录结构要求
|
||||
|
||||
确保目录结构正确:
|
||||
```
|
||||
datasets/handleImage/
|
||||
├── train/ # 图片目录
|
||||
│ ├── image1.jpg
|
||||
│ ├── image2.jpg
|
||||
│ └── ...
|
||||
└── label/ # 标注目录
|
||||
├── image1.txt
|
||||
├── image2.txt
|
||||
└── ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 输出说明
|
||||
|
||||
### 预览模式输出
|
||||
|
||||
```
|
||||
找到 1330 个图片文件 # 图片总数
|
||||
找到 1223 个标注文件 # 标注总数
|
||||
发现 107 个没有标注的图片 # 需要删除的数量
|
||||
```
|
||||
|
||||
### 删除模式输出
|
||||
|
||||
```
|
||||
删除完成:
|
||||
成功删除: 107 个文件 # 成功删除的数量
|
||||
删除失败: 0 个文件 # 删除失败的数量(如果有)
|
||||
```
|
||||
|
||||
### 完成状态输出
|
||||
|
||||
```
|
||||
✓ 所有图片都有对应的标注文件!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 使用技巧
|
||||
|
||||
### 技巧 1: 先预览再删除
|
||||
|
||||
**推荐流程:**
|
||||
```bash
|
||||
# 步骤1: 预览检查
|
||||
python check_and_clean_images.py
|
||||
|
||||
# 步骤2: 查看结果,确认要删除的文件
|
||||
# 步骤3: 确认后删除
|
||||
python check_and_clean_images.py --delete
|
||||
```
|
||||
|
||||
### 技巧 2: 批量处理多个数据集
|
||||
|
||||
创建一个批处理脚本:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# process_datasets.sh
|
||||
|
||||
datasets=("handleImage" "仪表盘" "检测仪")
|
||||
|
||||
for dataset in "${datasets[@]}"; do
|
||||
echo "处理数据集: $dataset"
|
||||
# 修改脚本中的路径或使用参数
|
||||
python check_and_clean_images.py
|
||||
done
|
||||
```
|
||||
|
||||
### 技巧 3: 检查反向问题
|
||||
|
||||
如果需要检查**有标注但没有图片**的情况,可以修改脚本或创建新工具。
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q1: 提示"目录不存在"
|
||||
|
||||
**错误信息:**
|
||||
```
|
||||
错误: 图片目录不存在: datasets/handleImage/train
|
||||
```
|
||||
|
||||
**解决方法:**
|
||||
1. 检查路径是否正确
|
||||
2. 确认目录是否存在
|
||||
3. 修改脚本中的默认路径
|
||||
|
||||
### Q2: 删除后想恢复文件
|
||||
|
||||
**解决方法:**
|
||||
- 如果之前有备份,从备份恢复
|
||||
- 如果没有备份,文件无法恢复(删除操作不可逆)
|
||||
|
||||
### Q3: 文件名不匹配
|
||||
|
||||
**问题:** 图片和标注文件名不完全一致
|
||||
|
||||
**解决方法:**
|
||||
- 检查文件名格式
|
||||
- 确保文件名(不含扩展名)完全一致
|
||||
- 可以使用重命名工具统一文件名格式
|
||||
|
||||
### Q4: 在非交互式环境运行
|
||||
|
||||
**问题:** 使用 `--delete` 时提示需要输入
|
||||
|
||||
**解决方法:**
|
||||
使用 `--force` 参数跳过确认:
|
||||
```bash
|
||||
python check_and_clean_images.py --delete --force
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 实际案例
|
||||
|
||||
### 案例 1: 清理 handleImage 数据集
|
||||
|
||||
```bash
|
||||
# 1. 检查数据集
|
||||
$ python check_and_clean_images.py
|
||||
|
||||
找到 1330 个图片文件
|
||||
找到 1223 个标注文件
|
||||
发现 107 个没有标注的图片
|
||||
|
||||
# 2. 确认后删除
|
||||
$ python check_and_clean_images.py --delete
|
||||
⚠ 警告: 将删除没有标注的图片文件!确认继续?(yes/no): yes
|
||||
|
||||
删除完成:
|
||||
成功删除: 107 个文件
|
||||
|
||||
# 3. 再次验证
|
||||
$ python check_and_clean_images.py
|
||||
|
||||
找到 1223 个图片文件
|
||||
找到 1223 个标注文件
|
||||
✓ 所有图片都有对应的标注文件!
|
||||
```
|
||||
|
||||
### 案例 2: 处理其他数据集
|
||||
|
||||
修改脚本中的路径:
|
||||
|
||||
```python
|
||||
# 在 check_and_clean_images.py 的 main() 函数中修改
|
||||
train_dir = "datasets/仪表盘/train/images"
|
||||
label_dir = "datasets/仪表盘/train/labels"
|
||||
```
|
||||
|
||||
然后运行:
|
||||
```bash
|
||||
python check_and_clean_images.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔗 相关工具
|
||||
|
||||
- `verify_seg_labels.py` - 验证分割标注格式
|
||||
- `check_label_format.py` - 检查标注格式类型
|
||||
- `convert_bbox_to_seg.py` - 转换标注格式
|
||||
|
||||
---
|
||||
|
||||
## 📞 需要帮助?
|
||||
|
||||
如果遇到问题:
|
||||
1. 查看本文档的"常见问题"部分
|
||||
2. 运行 `python check_and_clean_images.py --help` 查看帮助
|
||||
3. 检查数据集目录结构是否正确
|
||||
|
||||
---
|
||||
|
||||
## 📝 更新日志
|
||||
|
||||
- **v1.0** (2024): 初始版本
|
||||
- 支持检查图片和标注文件
|
||||
- 支持预览和删除模式
|
||||
- 支持强制删除模式
|
||||
|
||||
---
|
||||
|
||||
**提示:** 使用前建议先备份数据,删除操作不可恢复!
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import os
|
||||
|
||||
def check_dataset_match(images_dir, labels_dir):
|
||||
"""检查图片和标注文件数量是否匹配"""
|
||||
# 获取图片文件列表
|
||||
image_files = [f for f in os.listdir(images_dir) if f.lower().endswith('.jpg')]
|
||||
# 获取标注文件列表(排除classes.txt)
|
||||
label_files = [f for f in os.listdir(labels_dir)
|
||||
if f.lower().endswith('.txt') and f != 'classes.txt']
|
||||
|
||||
# 提取文件名(不带扩展名)
|
||||
image_names = {os.path.splitext(f)[0] for f in image_files}
|
||||
label_names = {os.path.splitext(f)[0] for f in label_files}
|
||||
|
||||
# 找出不匹配的文件
|
||||
missing_images = label_names - image_names
|
||||
missing_labels = image_names - label_names
|
||||
|
||||
print(f"图片数量: {len(image_files)}")
|
||||
print(f"标注数量: {len(label_files)}")
|
||||
print(f"匹配状态: {'匹配' if len(image_files) == len(label_files) else '不匹配'}")
|
||||
|
||||
if missing_images:
|
||||
print("\n缺少对应的图片文件:")
|
||||
for name in sorted(missing_images):
|
||||
print(f"- {name}.jpg")
|
||||
|
||||
if missing_labels:
|
||||
print("\n缺少对应的标注文件:")
|
||||
for name in sorted(missing_labels):
|
||||
print(f"- {name}.txt")
|
||||
|
||||
if __name__ == "__main__":
|
||||
images_dir = r'F:\myprojects\啾啾救援识别系统\JJCarDetection\datasets\猫狗\train\images'
|
||||
labels_dir = r'F:\myprojects\啾啾救援识别系统\JJCarDetection\datasets\猫狗\train\labels'
|
||||
|
||||
print("正在检查数据集匹配情况...")
|
||||
check_dataset_match(images_dir, labels_dir)
|
||||
print("\n检查完成")
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
def convert_voc_to_yolo(xml_path, output_dir):
|
||||
"""将VOC格式XML转换为YOLO格式TXT"""
|
||||
tree = ET.parse(xml_path)
|
||||
root = tree.getroot()
|
||||
|
||||
# 获取图像尺寸
|
||||
size = root.find('size')
|
||||
if size is None:
|
||||
return
|
||||
|
||||
width_elem = size.find('width')
|
||||
height_elem = size.find('height')
|
||||
if width_elem is None or height_elem is None or width_elem.text is None or height_elem.text is None:
|
||||
return
|
||||
|
||||
try:
|
||||
width = int(width_elem.text)
|
||||
height = int(height_elem.text)
|
||||
except (ValueError, TypeError):
|
||||
return
|
||||
|
||||
# 类别映射
|
||||
class_map = {'猫': 0, '狗': 1}
|
||||
|
||||
# 准备输出内容
|
||||
yolo_lines = []
|
||||
|
||||
for obj in root.findall('object'):
|
||||
name_elem = obj.find('name')
|
||||
if name_elem is None or name_elem.text is None:
|
||||
continue
|
||||
|
||||
class_name = name_elem.text
|
||||
class_id = class_map.get(class_name, -1)
|
||||
if class_id == -1:
|
||||
continue
|
||||
|
||||
bndbox = obj.find('bndbox')
|
||||
if bndbox is None:
|
||||
continue
|
||||
|
||||
try:
|
||||
xmin_elem = bndbox.find('xmin')
|
||||
xmin = int(xmin_elem.text) if xmin_elem is not None and xmin_elem.text is not None else 0
|
||||
|
||||
ymin_elem = bndbox.find('ymin')
|
||||
ymin = int(ymin_elem.text) if ymin_elem is not None and ymin_elem.text is not None else 0
|
||||
|
||||
xmax_elem = bndbox.find('xmax')
|
||||
xmax = int(xmax_elem.text) if xmax_elem is not None and xmax_elem.text is not None else 0
|
||||
|
||||
ymax_elem = bndbox.find('ymax')
|
||||
ymax = int(ymax_elem.text) if ymax_elem is not None and ymax_elem.text is not None else 0
|
||||
except (ValueError, TypeError):
|
||||
continue
|
||||
|
||||
# 转换为YOLO格式
|
||||
x_center = (xmin + xmax) / 2 / width
|
||||
y_center = (ymin + ymax) / 2 / height
|
||||
box_width = (xmax - xmin) / width
|
||||
box_height = (ymax - ymin) / height
|
||||
|
||||
yolo_lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {box_width:.6f} {box_height:.6f}")
|
||||
|
||||
# 写入TXT文件
|
||||
if yolo_lines:
|
||||
txt_filename = os.path.splitext(os.path.basename(xml_path))[0] + '.txt'
|
||||
txt_path = os.path.join(output_dir, txt_filename)
|
||||
|
||||
with open(txt_path, 'w', encoding='utf-8') as f:
|
||||
f.write('\n'.join(yolo_lines))
|
||||
|
||||
def batch_convert(input_dir, output_dir):
|
||||
"""批量转换目录中的所有XML文件"""
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
for filename in os.listdir(input_dir):
|
||||
if filename.endswith('.xml'):
|
||||
xml_path = os.path.join(input_dir, filename)
|
||||
convert_voc_to_yolo(xml_path, output_dir)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 设置输入输出目录
|
||||
input_dir = r'F:\myprojects\啾啾救援识别系统\JJCarDetection\datasets\猫狗\train\labels'
|
||||
output_dir = input_dir # 同一目录输出
|
||||
|
||||
print(f"开始转换: {input_dir}")
|
||||
batch_convert(input_dir, output_dir)
|
||||
print(f"转换完成,结果保存在: {output_dir}")
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import shutil
|
||||
import random
|
||||
|
||||
def copy_random_images(src_dir, dst_dir, num_images=20, prefix=''):
|
||||
"""
|
||||
从源目录随机复制指定数量的图像到目标目录
|
||||
:param src_dir: 源目录路径
|
||||
:param dst_dir: 目标目录路径
|
||||
:param num_images: 要复制的图像数量
|
||||
:param prefix: 文件名前缀,用于区分不同来源
|
||||
"""
|
||||
# 确保目标目录存在
|
||||
os.makedirs(dst_dir, exist_ok=True)
|
||||
|
||||
# 获取源目录中所有图像文件
|
||||
image_files = [f for f in os.listdir(src_dir) if f.lower().endswith(('.jpg', '.jpeg', '.png'))]
|
||||
|
||||
# 随机选择指定数量的图像
|
||||
selected_files = random.sample(image_files, min(num_images, len(image_files)))
|
||||
|
||||
# 复制文件
|
||||
for file in selected_files:
|
||||
src_path = os.path.join(src_dir, file)
|
||||
dst_filename = f"{prefix}{file}" if prefix else file
|
||||
dst_path = os.path.join(dst_dir, dst_filename)
|
||||
shutil.copy2(src_path, dst_path)
|
||||
print(f"已复制: {file} -> {dst_filename}")
|
||||
|
||||
print(f"已完成复制 {len(selected_files)} 张图像到 {dst_dir}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 目标目录
|
||||
destination_dir = r"F:\myprojects\啾啾救援识别系统\JJCarDetection\datasets\猫狗\train\images"
|
||||
|
||||
# 复制猫图片
|
||||
cat_source = r"F:\myprojects\cats_and_dogs_filtered\train\cats"
|
||||
print("正在复制猫图片...")
|
||||
copy_random_images(cat_source, destination_dir, 20, prefix='cat_')
|
||||
|
||||
# 复制狗图片
|
||||
dog_source = r"F:\myprojects\cats_and_dogs_filtered\train\dogs"
|
||||
print("正在复制狗图片...")
|
||||
copy_random_images(dog_source, destination_dir, 20, prefix='dog_')
|
||||
|
||||
print("所有图片复制完成!")
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
train: F:\myprojects\啾啾救援识别系统\JJCarDetection\datasets\TomatoData\train
|
||||
val: F:\myprojects\啾啾救援识别系统\JJCarDetection\datasets\TomatoData\val
|
||||
nc: 2
|
||||
names: ['Riped', 'UnRiped']
|
||||
|
After Width: | Height: | Size: 246 KiB |
|
After Width: | Height: | Size: 5.5 MiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 828 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 439 KiB |
|
After Width: | Height: | Size: 139 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 286 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 205 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 206 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 559 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 5.5 MiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 828 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 43 KiB |