You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

760 lines
31 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# -*- 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 sqlite3
import threading
from queue import Queue
from copy import deepcopy
from datetime import datetime
from searchHistory import Ui_Form
# 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.create_results_table()
self.signalconnect()
# 加载css渲染效果
style_file = 'UIProgram/style.css'
qssStyleSheet = QSSLoader.read_qss_file(style_file)
self.setStyleSheet(qssStyleSheet)
self.ui.SaveBtn.hide()
self.resultsSave = "./resultSave"
self.ui.lineEdit.setText(self.resultsSave)
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)
self.ui.pushButton_2.clicked.connect(self.select_folder)
self.ui.pushButton.clicked.connect(self.showHistory)
def showHistory(self):
self.second_window = QWidget() # 创建第二个窗口
self.ui_form = Ui_Form()
self.ui_form.setupUi(self.second_window) # 初始化第二个窗口界面
self.second_window.setWindowTitle("Second Page")
self.second_window.show() # 显示第二个窗口
def select_folder(self):
folder_path = QFileDialog.getExistingDirectory(None, "选择文件夹", "./") # 打开文件夹选择对话框
if folder_path:
self.ui.lineEdit.setText(folder_path)
def initMain(self):
self.image_edit = 0
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))) #预先加载推理模型
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 *.jepg *.png)")
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)[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.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.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)[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.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.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.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.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()
print(com_text)
if com_text == '全部':
cur_box = self.location_list
cur_img = self.results.plot()
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.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 *.jepg *.png)")
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 create_connection(self,data_queue, lock,db_file ="PCB_database.db"):
"""创建一个数据库连接到SQLite数据库"""
conn = None
try:
conn = sqlite3.connect(db_file)
except sqlite3.Error as e:
print(e)
self.insert_data(conn, data_queue, lock)
conn.close()
# return conn
# 插入数据的函数
def insert_data(self,conn, data_queue, lock):
"""从队列中获取数据并插入到数据库"""
while not data_queue.empty():
data_chunk = data_queue.get()
with lock: # 使用锁来同步数据库操作
cursor = conn.cursor()
try:
# 开始事务
# insert_sql = 'INSERT INTO users (name, age) VALUES (?, ?)'
insert_sql = """
INSERT INTO results (category, coordinates,confidence, image_path,date_added)
VALUES (?, ?, ?, ?, ?);
"""
cursor.executemany(insert_sql, data_chunk)
conn.commit() # 提交事务
# # 提交事务
# conn.commit()
except sqlite3.Error as e:
print(e)
# 如果发生错误,回滚事务
conn.rollback()
finally:
cursor.close()
data_queue.task_done()
def rel_insert_data(self, data_to_insert):
data_queue = Queue()
lock = threading.Lock() # 创建一个锁对象
# 使用锁来保护深拷贝和清空操作
with lock:
# 对数据进行深拷贝
data_to_insert_deepcopy = deepcopy(data_to_insert)
# 清空原始数据列表
data_to_insert.clear()
# 将深拷贝的数据分块放入队列增加chunk_size
chunk_size = 100 # 增大chunk_size
for i in range(0, len(data_to_insert_deepcopy), chunk_size):
data_queue.put(data_to_insert_deepcopy[i:i + chunk_size])
# 创建并启动线程
num_threads = 4 # 增加线程数
threads = []
for _ in range(num_threads):
# 为每个线程创建独立的数据库连接
thread = threading.Thread(target=self.create_connection, args=(data_queue, lock))
thread.start()
threads.append(thread)
# 等待所有线程完成
for thread in threads:
thread.join()
print("所有数据已成功保存到数据库。")
def open_frame(self):
ret, now_img = self.cap.read()
if ret:
# 目标检测
t1 = time.time()
results = self.model(now_img)[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()
if len(location_list) != 0:
self.ui.time_lb_2.setText("")
else:
self.ui.time_lb_2.setText("")
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))
self.image_edit+=1
if not os.path.exists(self.resultsSave):
os.makedirs(self.resultsSave)
cv2.imwrite(os.path.join(self.resultsSave,str(self.image_edit)+".jpg"),resize_cvimg)
# cv2.imwrite("./")
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.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.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()
insert_list = [(str(self.cls_list),str(self.conf_list),str(self.location_list),os.path.join(self.resultsSave,str(self.image_edit)+".jpg"),datetime.now().strftime('%Y-%m-%d'))]
self.rel_insert_data(insert_list)
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.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.split('.')
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.split('.')
save_name = name + '_detect_result.' + end_name
save_img_path = os.path.join(Config.save_path, save_name)
results = self.model(full_path)[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()
def create_results_table(self,db_file="PCB_database.db"):
"""
创建 SQLite 数据库和 results 表。
:param db_file: 数据库文件路径,默认为 PCB_database.db
"""
# 创建连接(如果文件不存在,会自动创建)
conn = sqlite3.connect(db_file)
try:
print(f"成功创建或连接到 SQLite 数据库: {db_file}")
# 创建游标
cursor = conn.cursor()
# 创建表的 SQL 语句
create_table_query = """
CREATE TABLE IF NOT EXISTS results (
id INTEGER PRIMARY KEY AUTOINCREMENT, -- 自动编号
category TEXT NOT NULL, -- 类别
confidence REAL NOT NULL, -- 置信度
coordinates TEXT NOT NULL, -- 坐标位置
image_path TEXT NOT NULL, -- 保存图片位置
date_added DATE NOT NULL -- 添加日期
);
"""
# 执行创建表的 SQL 语句
cursor.execute(create_table_query)
print("成功创建表: results")
except sqlite3.Error as e:
print(f"创建表失败: {e}")
finally:
# 关闭连接
conn.close()
class btn2Thread(QThread):
"""
进行检测后的视频保存
"""
# 声明一个信号
update_ui_signal = pyqtSignal(int,int)
def __init__(self, path, model, com_text):
super(btn2Thread, self).__init__()
self.org_path = path
self.model = model
self.com_text = com_text
# 用于绘制不同颜色矩形框
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)[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_())