1 Star 4 Fork 0

davidhu / 基于YOLOv5+PyQt5+Python的AI视觉检测系统

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
myMainWindow.py 40.64 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
from myCommunicationDialog import QmyCommunicationDialog
from utils.torch_utils import select_device, time_sync
from utils.plots import Annotator, colors
from utils.general import (
LOGGER, check_img_size, check_imshow, non_max_suppression, scale_coords, xyxy2xywh)
from utils.datasets import LoadImages, LoadStreams
from models.common import DetectMultiBackend
import json
import datetime
import time
import os
import sys
import cv2
import time
import shutil
import os.path as osp
from pathlib import Path
import threading
import modbus_tk.modbus_tcp as modbus_tcp
import modbus_tk.defines as cst
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QFileDialog, QMessageBox)
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from ui_MainWindow import Ui_MainWindow
from myDetectModelConfigDialog import QmyDetectModelConfigDialog
# 导入yolov5模型需要库
import torch
import torch.backends.cudnn as cudnn
FILE = Path(__file__).resolve()
ROOT = FILE.parents[0] # YOLOv5 root directory
if str(ROOT) not in sys.path:
sys.path.append(str(ROOT)) # add ROOT to PATH
ROOT = Path(os.path.relpath(ROOT, Path.cwd())) # relative
# 获取配置文件信息类
class Get_json_config():
def get_communication_json_config(self):
print("获取通讯配置文件信息")
self.config_file = 'config/communication.json'
self.config = json.load(open(self.config_file, 'r', encoding='utf-8'))
self.plc_ip = self.config["plc_ip"]
self.plc_start_point = self.config["plc_start_point"]
self.plc_finish_point = self.config["plc_finish_point"]
self.plc_result_point = self.config["plc_result_point"]
self.database_ip = self.config["database_ip"]
self.database_port = self.config['database_port']
self.database_user = self.config['database_user']
self.database_password = self.config['database_password']
self.database_name = self.config['database_name']
# 给PLC写入信号线程类
class Write_To_PLC_Thread(QThread):
pop_up_Message_box_signal = pyqtSignal(str)
# 定义写入PLC信号过程状态监控信号,改变主界面拍照按钮点击状态
status_write_to_plc_signal = pyqtSignal(bool)
# 发送状态信息给主界面状态栏显示的信号
send_status_signal = pyqtSignal(str)
def __init__(self):
super(Write_To_PLC_Thread, self).__init__()
def get_plc_point(self, start_point, finish_point, result_point):
self.start_point = start_point
self.finish_point = finish_point
self.result_point = result_point
self.start()
def run(self):
self.get_communication_json_config = Get_json_config()
self.get_communication_json_config.get_communication_json_config()
try:
self.master = modbus_tcp.TcpMaster(
host=self.get_communication_json_config.plc_ip)
self.master.set_timeout(2500)
print("PLC连接成功!")
print(str(self.get_communication_json_config.plc_ip))
print(str(self.get_communication_json_config.plc_start_point))
print(str(self.get_communication_json_config.plc_finish_point))
print(str(self.get_communication_json_config.plc_result_point))
except Exception as e:
print(e)
print("主线程发送信号"+str(self.start_point) +
str(self.finish_point)+str(self.result_point))
try:
self.status_write_to_plc_signal.emit(False)
self.master.execute(1, cst.WRITE_SINGLE_COIL, int(self.get_communication_json_config.plc_start_point),
output_value=self.start_point)
print("重置PLC拍照启动信号成功!")
self.send_status_signal.emit("重置PLC拍照启动信号成功!")
self.master.execute(1, cst.WRITE_SINGLE_COIL, int(self.get_communication_json_config.plc_finish_point),
output_value=self.finish_point)
print("写入PLC拍照完成信号成功!")
self.send_status_signal.emit("写入PLC拍照完成信号成功!")
self.master.execute(1, cst.WRITE_SINGLE_COIL, int(self.get_communication_json_config.plc_result_point),
output_value=self.result_point)
print("写入PLC拍照结果信号成功!")
self.send_status_signal.emit("写入PLC拍照结果信号成功!")
self.status_write_to_plc_signal.emit(True)
except Exception as e2:
print(e2)
self.pop_up_Message_box_signal.emit(
str(e2)+"<br>PLC连接错误,请检查PLC连接!")
self.status_write_to_plc_signal.emit(True)
# PLC触发拍照按钮线程类
class PLC_Tigger_TakePicture_Thread(QThread):
start_take_picture_signal = pyqtSignal(bool)
pop_up_Message_box_signal = pyqtSignal(str)
def __init__(self):
super(PLC_Tigger_TakePicture_Thread, self).__init__()
self._isPause = False
# 控制PLC自动控制拍照线程启动函数
def start_auto_take_picture(self):
self._isPause = True
self.get_communication_json_config = Get_json_config()
self.get_communication_json_config.get_communication_json_config()
self.start()
self.master = modbus_tcp.TcpMaster(
host=self.get_communication_json_config.plc_ip)
self.master.set_timeout(2500)
# 控制PLC自动控制拍照线程停止函数
def stop_thread(self):
self._isPause = False
self.quit()
# 重写run函数,定义线程运行逻辑
def run(self):
while self._isPause:
try:
plc_start_point = self.master.execute(
1, cst.READ_COILS, int(self.get_communication_json_config.plc_start_point), 1) # 读取PLC初始启动拍照信号
if plc_start_point[0] == 1:
print("启动拍照!")
print(plc_start_point[0])
# 当启动信号为1时,复位拍照完成信号为0
self.master.execute(1, cst.WRITE_SINGLE_COIL, int(self.get_communication_json_config.plc_finish_point),
output_value=0) # 复位拍照完成信号
print("复位PLC拍照完成信号点")
self.start_take_picture_signal.emit(True)
time.sleep(10)
except Exception as e:
message_str = str(e)
print(message_str)
self.pop_up_Message_box_signal.emit(message_str)
continue
# 显示信息类
class DisplayContentToUi():
def get_now_timeinfo(self):
i = datetime.datetime.now()
year = str(i.year).zfill(4)
month = str(i.month).zfill(2)
day = str(i.day).zfill(2)
hour = str(i.hour).zfill(2)
minute = str(i.minute).zfill(2)
second = str(i.second).zfill(2)
# print("今天是%s年%s月%s日%s时%s分%s秒" %
# (year, month, day, hour, minute, second))
time_info = ("%s%s%s-%s%s%s" %
(year, month, day, hour, minute, second))
datetime_info = ("今天是%s年%s月%s日%s时%s分%s秒" %
(year, month, day, hour, minute, second))
# print(time_info)
return_info = {'time_info': time_info, 'datetime_info': datetime_info}
return return_info
# 捕获图片
@pyqtSlot()
def _queryFrame(self):
'''
循环捕获图片
'''
try:
ret, self.frame = self.camera.read()
if ret:
self.capheight, self.capwidth, bytesPerComponent = self.frame.shape
self.bytesPerLine = bytesPerComponent*self.capwidth
self.frame = cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR)
QImg = QImage(self.frame.data, self.capwidth,
self.capheight, self.bytesPerLine, QImage.Format_RGB888)
pixmap = QPixmap.fromImage(QImg).scaled(
self.ui.realtimePic.size())
self.ui.realtimePic.setPixmap(pixmap)
self.frame_count += 1
self.show_now_frame(
"循环捕获图像帧中....当前第"+str(self.frame_count)+"帧")
else:
print("捕获图像失败!")
self.statusBar_show_msg("捕获图像失败!")
self.show_now_frame("捕获图像失败!")
if self.frame_count == 1:
self.statusBar_show_msg("摄像头已打开!")
else:
return None
except Exception as e:
print(e)
# 状态栏显示信息
def statusBar_show_msg(self, msg, stayshow: bool = False):
if stayshow == False:
self.ui.statusBar.showMessage(msg, 5000)
else:
self.ui.statusBar.showMessage(msg)
def statusBar_show_msg2(self):
self.ui.statusBar.showMessage("摄像头初始化中...")
# 往界面上的显示帧label显示当前帧数
def show_now_frame(self, msg):
self.ui.now_frame_label.setText(str(msg))
def printSomething(msg):
print(str(msg))
# 相机调用类
class CameraUse():
# 初始化计时器
# 初始化摄像头
def init_camera_config(self):
self.timer_camera = QTimer()
self.timer_camera.timeout.connect(self._queryFrame)
self.camera = cv2.VideoCapture()
print("相机初始化中...")
print("使用的"+str(self.CAM_NUM)+"号摄像头!")
QMessageBox.information(
self, "提示!", "相机初始化中,请耐心等待....(受相机型号影响,初始化时间或长或短...)")
flag = self.camera.open(self.CAM_NUM)
if flag == False:
msg = QMessageBox.Warning(self, u'Warning', u'请检测相机与电脑是否连接正确',
buttons=QMessageBox.Ok,
defaultButton=QMessageBox.Ok)
else:
self.camera.set(3, 3840)
self.camera.set(4, 2160)
self.camera.set(15, 0.1)
print("摄像头连接正常!")
self.statusBar_show_msg("摄像头连接正常!", True)
# 打开摄像头(此处的打开以及后边的关闭摄像头均是开启关闭计时器,
# 从而实现开启和暂停刷新摄像头画面,而不是释放release摄像头,从而提高再次打开摄像头的速度感受!)
def open_camera_button_clicked(self):
# 如果是摄像头开启的则返回
if self.is_camera_opened:
self.statusBar_show_msg("摄像头已开启!请勿重复点击!")
QMessageBox.warning(self, "提示!", "摄像头已开启!请勿重复点击!")
else:
self.timer_camera.start(30)
self.ui.open_camera.setStyleSheet(
"background-color:green;border: 1px solid;border-radius: 10px;width: 80px;height: 25px;padding: 5px")
self.is_camera_opened = True
self.statusBar_show_msg("摄像头已打开!", True)
# 关闭摄像头
def close_camera_button_clicked(self):
if not self.is_camera_opened:
self.statusBar_show_msg("摄像头已关闭!请勿重复点击!")
QMessageBox.warning(self, "提示!", "摄像头已关闭!请勿重复点击!")
else:
self.timer_camera.stop()
self.is_camera_opened = False
self.frame_count = 0 # 关闭后帧计数清零
self.ui.realtimePic.setText("摄像头已关闭")
self.ui.now_frame_label.setText("摄像头已关闭")
self.statusBar_show_msg("摄像头已关闭")
self.ui.open_camera.setStyleSheet(
"background-color:rgb(123, 170, 156);border: 1px solid;border-radius: 10px;width: 80px;height: 25px;padding: 5px")
# 主窗体类
class QmyMainWindow(QMainWindow, DisplayContentToUi, CameraUse):
reset_plc_point_signal = pyqtSignal(int, int, int)
# reset_plc_finish_point_signal = pyqtSignal(bool)
# write_result_signal = pyqtSignal(bool)
def __init__(self, parent=None):
super().__init__(parent) # 调用父类构造函数
self.ui = Ui_MainWindow() # 创建UI对象
self.ui.setupUi(self) # 构造UI界面
# self.load_model_toComboBox() # 加载模型到模型选项框
self.show_datetime_label() # 显示时间到时间显示Lable
# 初始化帧计数
self.frame_count = 0
# 输出图片相关参数
self.output_size = 400
self.output_width = 1920
self.output_height = 1080
# 上传和拍照检测将要的处理图片
self.img2predict = ""
self.device = 'cpu'
# 模型相关参数
self.imgsz = [640, 640] # inference size (pixels)
self.conf_thres = 0.35 # confidence threshold
self.iou_thres = 0.45 # NMS IOU threshold
self.max_det = 100
# 摄像头ID
self.CAM_NUM = 0
# 初始化加载配置文件
self.load_setting()
self.fold_config = self.load_config_folder()
# 初始化计时器
# 初始化摄像头
self.init_camera_config()
# 摄像头未打开标记
self.is_camera_opened = False
# 判断结束输出结果给PLC(1代表合格,0代表不合格,初始为0)
self.final_send_signal = 0
# 手动关联自定义功能函数
self.connect_signal_slot()
self.stopEvent = threading.Event()
self.webcam = True
self.stopEvent.clear()
self.now_model = "pt/yolov5l.pt"
self.model = ""
# 初始化加载默认模型
# self.loadmodel()
self.ui.show_model_label.setText(self.now_model)
# self.init_final_results()
self.open_camera_button_clicked()
def loadmodel(self):
self.model = self.model_load(weights=self.now_model,
device=self.device) # todo 指明模型加载的位置的设备
self.statusBar_show_msg(self.now_model+"模型加载完成!!!")
QMessageBox.information(
self, "提示!", self.now_model+"模型加载完成!!!")
@torch.no_grad()
def model_load(self, weights="", # model.pt path(s)
device='', # cuda device, i.e. 0 or 0,1,2,3 or cpu
half=False, # use FP16 half-precision inference
dnn=False, # use OpenCV DNN for ONNX inference
):
device = select_device(device)
half &= device.type != 'cpu' # half precision only supported on CUDA
device = select_device(device)
model = DetectMultiBackend(weights, device=device, dnn=dnn)
stride, names, pt, jit, onnx = model.stride, model.names, model.pt, model.jit, model.onnx
# Half
# half precision only supported by PyTorch on CUDA
half &= pt and device.type != 'cpu'
if pt:
model.model.half() if half else model.model.float()
print(str(weights)+"模型加载完成!")
return model
# =================自定义功能函数================================
def show_datetime_label(self):
self.show_datetimeTimer = QTimer()
self.show_datetimeTimer.timeout.connect(
self.setText_for_show_datetime_label)
self.show_datetimeTimer.start(30)
def setText_for_show_datetime_label(self):
self.ui.datetimeshow_label.setText(
self.get_now_timeinfo()['datetime_info']) # 初始化时间显示
# 手动关联自定义功能函数
def connect_signal_slot(self):
self.ui.upload_img.clicked.connect(self.upload_img)
self.ui.loadmodel.clicked.connect(self.loadmodel)
self.ui.IoU_doubleSpinBox.valueChanged.connect(
self.IoU_doubleSpinBox_valueChanged)
self.ui.conf_thres_doubleSpinBox.valueChanged.connect(
self.conf_thres_doubleSpinBox_valueChanged)
# self.ui.save_photo.triggered.connect(self.save_pic)
self.ui.open_capturedPic_dir.triggered.connect(
self.open_captured_pictures_folder)
self.ui.open_resultPic_dir.triggered.connect(
self.open_result_pictures_folder)
self.ui.open_camera.clicked.connect(self.open_camera_button_clicked)
self.ui.close_camera.clicked.connect(self.close_camera_button_clicked)
# 打开并选择文件
def open_file(self):
# source = QFileDialog.getOpenFileName(self, '选取视频或图片', os.getcwd(), "Pic File(*.mp4 *.mkv *.avi *.flv "
# "*.jpg *.png)")
config_file = 'config/fold.json'
# config = json.load(open(config_file, 'r', encoding='utf-8'))
config = json.load(open(config_file, 'r', encoding='utf-8'))
open_fold = config['open_fold']
open_fold_absolutely = os.getcwd() + "/"+open_fold
if not os.path.exists(open_fold_absolutely):
open_fold_absolutely = os.getcwd()
name, _ = QFileDialog.getOpenFileName(self, '选取视频或图片', open_fold_absolutely, "Pic File(*.mp4 *.mkv *.avi *.flv "
"*.jpg *.png)")
self.statusBar_show_msg("打开文件...")
# 打开拍照存储文件夹
def open_captured_pictures_folder(self, Form):
captured_pictures_folder = self.fold_config['captured_pictures_folder']
'''打开系统文件资源管理器的对应文件夹'''
# 方法1:通过start explorer
# os.system("start explorer %s" % folder)
# 方法2:通过startfile
# os.startfile(captured_pictures_folder)
# print(os.getcwd() + "/"+captured_pictures_folder)
os.startfile(os.getcwd() + "/"+captured_pictures_folder)
# 打开拍照处理结果文件夹
def open_result_pictures_folder(self):
result_pictures_folder = self.fold_config['result_pictures_folder']
os.startfile(os.getcwd() + "/"+result_pictures_folder)
def upload_img(self):
# 选择录像文件进行读取
fileName, fileType = QFileDialog.getOpenFileName(
self, 'Choose file', '', '*.jpg *.png *.tif *.jpeg')
if fileName:
suffix = fileName.split(".")[-1]
save_path = osp.join("images/tmp", "tmp_upload." + suffix)
shutil.copy(fileName, save_path)
# 应该调整一下图片的大小,然后统一防在一起
im0 = cv2.imread(save_path)
resultPic_width = self.ui.resultPic.size().width()
resultPic_height = self.ui.resultPic.size().height()
dim = (self.output_width, self.output_height)
im0 = cv2.resize(im0, dim, interpolation=cv2.INTER_AREA)
cv2.imwrite("images/tmp/upload_show_result.jpg", im0)
# self.right_img.setPixmap(QPixmap("images/tmp/single_result.jpg"))
# 将绝对路径转换为相对路径
fileName2 = Path(fileName)
print(fileName2.parts)
fileName3 = Path(
fileName2.parts[-3], fileName2.parts[-2], fileName2.parts[-1]).joinpath()
self.img2predict = fileName3
print("self.img2predict: "+str(self.img2predict))
self.ui.capturePic.setPixmap(
QPixmap(
"images/tmp/upload_show_result.jpg").scaled(self.ui.capturePic.size()))
# todo 上传图片之后右侧的图片重置,
self.ui.resultPic.setPixmap(
QPixmap("images/UI/up.jpeg").scaled(self.ui.resultPic.size()))
self.statusBar_show_msg("上传图片检测...")
def detect_img(self):
if self.final_send_signal == 1:
# 如果合格,设置合格颜色为绿色,并显示合格信息
self.ui.finalResult.setText("合格!")
self.ui.finalResult.setStyleSheet(
"background-color:green;color:white")
else:
# 如果不合格,设置不合格颜色为绿色,并显示不合格信息
self.ui.finalResult.setText("不合格!")
self.ui.finalResult.setStyleSheet(
"background-color:red;color:white")
# 图像检测
def detect_img2(self):
if self.model == '':
QMessageBox.warning(self, "提示!", "请先加载模型再进行检测")
return
model = self.model
output_width = self.output_width
output_height = self.output_height
dim = (output_width, output_height)
source = self.img2predict # file/dir/URL/glob, 0 for webcam
imgsz = self.imgsz # inference size (pixels)
conf_thres = self.conf_thres # confidence threshold
iou_thres = self.iou_thres # NMS IOU threshold
max_det = self.max_det # maximum detections per image
device = self.device # cuda device, i.e. 0 or 0,1,2,3 or cpu
print("在detect_img2运行时的参数值:"+"conf_thres:"+str(conf_thres) + ";" +
"iou_thres:"+str(iou_thres)+";"+"max_det:"+str(max_det))
view_img = False # show results
save_txt = False # save results to *.txt
save_conf = False # save confidences in --save-txt labels
save_crop = False # save cropped prediction boxes
nosave = False # do not save images/videos
classes = None # filter by class: --class 0, or --class 0 2 3
agnostic_nms = False # class-agnostic NMS
augment = False # ugmented inference
visualize = False # visualize features
line_thickness = 6 # bounding box thickness (pixels)
hide_labels = False # hide labels
hide_conf = False # hide confidences
half = False # use FP16 half-precision inference
dnn = False # use OpenCV DNN for ONNX inference
print(source)
if source == "":
QMessageBox.warning(self, "提示!", "请先上传图片再进行检测")
else:
source = str(source)
device = select_device(self.device)
webcam = False
stride, names, pt, jit, onnx = model.stride, model.names, model.pt, model.jit, model.onnx
imgsz = check_img_size(imgsz, s=stride) # check image size
save_img = not nosave and not source.endswith(
'.txt') # save inference images
# Dataloader
if webcam:
view_img = check_imshow()
cudnn.benchmark = True # set True to speed up constant image size inference
dataset = LoadStreams(
source, img_size=imgsz, stride=stride, auto=pt and not jit)
bs = len(dataset) # batch_size
else:
print("source: "+str(source))
dataset = LoadImages(source, img_size=imgsz,
stride=stride, auto=pt and not jit)
print("dateset: "+str(dataset))
print("dateset_type: "+str(type(dataset)))
bs = 1 # batch_size
vid_path, vid_writer = [None] * bs, [None] * bs
# Run inference
if pt and device.type != 'cpu':
model(torch.zeros(
1, 3, *imgsz).to(device).type_as(next(model.model.parameters()))) # warmup
dt, seen = [0.0, 0.0, 0.0], 0
for path, im, im0s, vid_cap, s in dataset:
t1 = time_sync()
im = torch.from_numpy(im).to(device)
im = im.half() if half else im.float() # uint8 to fp16/32
im /= 255 # 0 - 255 to 0.0 - 1.0
if len(im.shape) == 3:
im = im[None] # expand for batch dim
t2 = time_sync()
dt[0] += t2 - t1
# Inference
# visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False
pred = model(im, augment=augment, visualize=visualize)
t3 = time_sync()
dt[1] += t3 - t2
# NMS
pred = non_max_suppression(
pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)
dt[2] += time_sync() - t3
# Second-stage classifier (optional)
# pred = utils.general.apply_classifier(pred, classifier_model, im, im0s)
# Process predictions
for i, det in enumerate(pred): # per image
seen += 1
if webcam: # batch_size >= 1
p, im0, frame = path[i], im0s[i].copy(), dataset.count
s += f'{i}: '
else:
p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0)
p = Path(p) # to Path
s += '%gx%g ' % im.shape[2:] # print string
# normalization gain whwh
gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]
imc = im0.copy() if save_crop else im0 # for save_crop
annotator = Annotator(
im0, line_width=line_thickness, example=str(names))
if len(det):
# Rescale boxes from img_size to im0 size
det[:, :4] = scale_coords(
im.shape[2:], det[:, :4], im0.shape).round()
# Print results
for c in det[:, -1].unique():
n = (det[:, -1] == c).sum() # detections per class
# add to string
s += f"{n} {names[int(c)]}{'s' * (n > 1)}, "
# Write results
for *xyxy, conf, cls in reversed(det):
if save_txt: # Write to file
xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(
-1).tolist() # normalized xywh
# label format
line = (
cls, *xywh, conf) if save_conf else (cls, *xywh)
# with open(txt_path + '.txt', 'a') as f:
# f.write(('%g ' * len(line)).rstrip() % line + '\n')
if save_img or save_crop or view_img: # Add bbox to image
c = int(cls) # integer class
label = None if hide_labels else (
names[c] if hide_conf else f'{names[c]} {conf:.2f}')
annotator.box_label(
xyxy, label, color=colors(c, True))
# if save_crop:
# save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg',
# BGR=True)
# Print time (inference-only)
LOGGER.info(f'{s}Done. ({t3 - t2:.3f}s)')
# 对输出结果进行处理,并显示在界面上
print("s: "+str(s))
self.out_put_list = s.split(':')[1].strip(' ,').split(" ")
print("self.out_put_list: "+str(self.out_put_list))
self.out_put_list.pop(0)
print(self.out_put_list)
self.out_put_list2 = '-'.join(
self.out_put_list).replace(',-', ';')
print(self.out_put_list2)
self.ui.detect_result_info.setText(s)
self.ui.detect_result_info_label.setText(
self.out_put_list2)
if self.out_put_list2.split("-")[-1] == '3IR':
self.final_send_signal = 1
print("合格!")
# 重置PLC信号点,分别是PLC启动信号,拍照完成信号,拍照结果信号
self.reset_plc_point_signal.emit(0, 1, 1)
elif self.out_put_list2.split("-")[-1] == '3IL':
self.final_send_signal = 0
print('不合格!')
# 重置PLC信号点,分别是PLC启动信号,拍照完成信号,拍照结果信号
self.reset_plc_point_signal.emit(0, 1, 0)
else:
self.final_send_signal = 0
print("不在当前检测结果判断范围内")
# 重置PLC信号点,分别是PLC启动信号,拍照完成信号,拍照结果信号
self.reset_plc_point_signal.emit(0, 1, 0)
self.detect_img()
# Stream results
im0 = annotator.result()
# if view_img:
# cv2.imshow(str(p), im0)
# cv2.waitKey(1) # 1 millisecond
# Save results (image with detections)
im0 = cv2.resize(
im0, dim, interpolation=cv2.INTER_AREA)
# 设置照片存放目录
save_picname = self.get_now_timeinfo()['time_info']
config_file = 'config/fold.json'
config = json.load(
open(config_file, 'r', encoding='utf-8'))
result_pictures_folder = config['result_pictures_folder']
cv2.imwrite(result_pictures_folder +
'\\'+save_picname+".jpg", im0)
# 目前的情况来看,应该只是ubuntu下会出问题,但是在windows下是完整的,所以继续
self.ui.resultPic.setPixmap(
QPixmap(result_pictures_folder + '\\'+save_picname+".jpg").scaled(self.ui.resultPic.size()))
# 检测完成后,清空img2predict
self.img2predict = ""
# 加载配置文件
def load_setting(self):
config_file = 'config/setting.json'
if not os.path.exists(config_file):
iou = 0.26
conf = 0.33
exposure = 200
max_det = 300
main_title = "装配线凸轮轴承盖方向识别系统"
cam_num = 0
new_config = {"iou": iou,
"conf": conf,
"exposure": exposure,
"max_det": max_det,
"main_title": main_title,
"cam_num": cam_num
}
new_json = json.dumps(new_config, ensure_ascii=False, indent=2)
with open(config_file, 'w', encoding='utf-8') as f:
f.write(new_json)
else:
config = json.load(open(config_file, 'r', encoding='utf-8'))
iou = config['iou']
conf = config['conf']
exposure = config['exposure']
max_det = config['max_det']
main_title = config['main_title']
cam_num = config['cam_num']
self.ui.main_title.setText(main_title)
self.ui.main_title_edit.setText(main_title)
self.ui.IoU_doubleSpinBox.setValue(iou)
self.ui.conf_thres_doubleSpinBox.setValue(conf)
self.ui.exposure_horizontalSlider.setValue(exposure)
self.ui.max_det_horizontalSlider.setValue(max_det)
self.ui.cam_num_spinBox.setValue(cam_num)
self.iou_thres = iou
self.max_det = max_det
self.conf_thres = conf
self.CAM_NUM = cam_num
print("配置文件加载完成!")
self.statusBar_show_msg("配置文件加载完成!")
def load_config_folder(self):
config_fold_file = 'config/fold.json'
fold_config = json.load(open(config_fold_file, 'r', encoding='utf-8'))
return fold_config
# ===========connectSlotsByName() 自动连接的槽函数=================
@pyqtSlot()
def on_start_detect_clicked(self):
try:
self.reset_plc_point_signal.disconnect(
self.write_plc_thread.get_plc_point, type=Qt.QueuedConnection)
except Exception as e:
print(e)
self.detect_img2()
@pyqtSlot()
def on_auto_run_btn_clicked(self):
print("点击了自动运行按钮")
self.ui.auto_run_btn.setStyleSheet(
"background-color:green;border: 1px solid;border-radius: 10px;width: 40px;height: 25px;padding: 5px")
self.ui.stop_run_btn.setStyleSheet(
"background-color:gray;border: 1px solid;border-radius: 10px;width: 40px;height: 25px;padding: 5px")
self.statusBar_show_msg("新建自动拍照线程,启动自动拍照线程!!!")
self.plc_thread = PLC_Tigger_TakePicture_Thread()
# 将线程信号连接至主界面类的槽函数
self.plc_thread.start_take_picture_signal.connect(
self.on_takePicButton_released)
self.plc_thread.pop_up_Message_box_signal.connect(
self.show_signal_message)
self.plc_thread.start_auto_take_picture()
@pyqtSlot()
def on_stop_run_btn_clicked(self):
print("点击了停止自动运行按钮")
self.ui.auto_run_btn.setStyleSheet(
"background-color:gray;border: 1px solid;border-radius: 10px;width: 40px;height: 25px;padding: 5px")
self.ui.stop_run_btn.setStyleSheet(
"background-color:green;border: 1px solid;border-radius: 10px;width: 40px;height: 25px;padding: 5px")
self.plc_thread.stop_thread()
self.statusBar_show_msg("退出自动拍照线程!!!")
@ pyqtSlot()
def on_detect_model_config_triggered(self):
print("点击了检测模型配置按钮")
DetectModelConfigDialog = QmyDetectModelConfigDialog(self)
DetectModelConfigDialog.setInitial()
DetectModelConfigDialog.setAttribute(Qt.WA_DeleteOnClose) # 对话框关闭自动删除
DetectModelConfigDialog.detect_model_configActionEnable.connect(
self.do_detect_model_configActionEnable)
DetectModelConfigDialog.change_model_config.connect(self.setComboxText)
DetectModelConfigDialog.show()
# ret = DetectModelConfigDialog.exec() # 以模态方式运行对话框
# if (ret == QDialog.Accepted):
# print(DetectModelConfigDialog.sendConfigToMainWindow())
@ pyqtSlot()
def on_communication_config_triggered(self):
print("点击了通讯配置按钮")
CommunicationConfigDialog = QmyCommunicationDialog(self)
CommunicationConfigDialog.setInitial()
# CommunicationConfigDialog.show() 以非模态方式运行对话框
ret = CommunicationConfigDialog.exec()
def do_detect_model_configActionEnable(self, enable):
self.ui.detect_model_config.setEnabled(enable)
@ pyqtSlot(str)
def setComboxText(self, setModel):
self.now_model = "pt/"+setModel
self.ui.show_model_label.setText(self.now_model)
self.loadmodel()
print("setmodel")
print(setModel)
def on_takePicButton_released(self):
# 捕获图片
# 摄像头未打开,不执行任何操作
if not self.is_camera_opened:
self.statusBar_show_msg("摄像头未打开,请先打开摄像头!")
QMessageBox.warning(self, "提示!", "摄像头未打开,请先打开摄像头!")
return
self.save_pic()
self.img2predict = self.img_save_fold + \
'\\'+self.save_picname+".jpg"
self.ui.capturePic.setPixmap(QPixmap(self.img2predict).scaled(
self.ui.capturePic.size()))
self.write_plc_thread = Write_To_PLC_Thread()
# 检测结果信号关联子进程槽函数
self.reset_plc_point_signal.connect(
self.write_plc_thread.get_plc_point, type=Qt.QueuedConnection)
# 报错信号关联子进程槽函数
self.write_plc_thread.pop_up_Message_box_signal.connect(
self.show_signal_message)
self.write_plc_thread.status_write_to_plc_signal.connect(
self.change_take_pic_btn_status)
self.write_plc_thread.send_status_signal.connect(
self.statusBar_show_msg)
self.detect_img2()
def save_pic(self):
config_file = 'config/fold.json'
config = json.load(open(config_file, 'r', encoding='utf-8'))
self.img_save_fold = config['captured_pictures_folder']
if not os.path.exists(self.img_save_fold):
self.img_save_fold = os.getcwd()
self.save_picname = self.get_now_timeinfo()['time_info']
ret, self.save_frame = self.camera.read()
# self.save_frame = cv2.cvtColor(self.save_frame, cv2.COLOR_BGR2GRAY)
print(self.save_frame.shape)
cv2.imwrite(self.img_save_fold+'\\' +
self.save_picname+".jpg", self.save_frame)
self.statusBar_show_msg(
"照片保存成功!保存路径:"+self.img_save_fold+'\\'+self.save_picname+".jpg")
# 设置界面拍照日期时间
curDateTime = QDateTime.currentDateTime()
self.ui.take_picture_date.setDate(curDateTime.date())
self.ui.take_picture_time.setTime(curDateTime.time())
def on_exposure_horizontalSlider_valueChanged(self, value):
print("on_exposure_horizontalSlider_valueChanged")
self.statusBar_show_msg("曝光值变化为:"+str(value))
def on_max_det_horizontalSlider_valueChanged(self, value):
print("on_max_det_horizontalSlider_valueChanged")
self.statusBar_show_msg("最大检测数量变化为:"+str(value))
def on_parameter_config_triggered(self):
self.load_setting()
def on_comboBox_currentTextChanged(self, value):
self.statusBar_show_msg("检测模型变更为:"+str(value))
@ pyqtSlot()
def on_save_to_config_pressed(self):
config_file = 'config/setting.json'
if not os.path.exists(config_file):
iou = 0.26
conf = 0.33
exposure = 200
max_det = 300
main_title = "装配线凸轮轴承盖方向识别系统"
cam_num = 0
new_config = {"iou": iou,
"conf": conf,
"exposure": exposure,
"max_det": max_det,
"main_title": main_title,
"cam_num": cam_num
}
new_json = json.dumps(new_config, ensure_ascii=False, indent=2)
with open(config_file, 'w', encoding='utf-8') as f:
f.write(new_json)
else:
iou = self.ui.IoU_doubleSpinBox.value()
conf = self.ui.conf_thres_doubleSpinBox.value()
exposure = self.ui.exposure_horizontalSlider.value()
max_det = self.ui.max_det_horizontalSlider.value()
main_title = self.ui.main_title_edit.text()
cam_num = self.ui.cam_num_spinBox.value()
new_config = {"iou": iou,
"conf": conf,
"exposure": exposure,
"max_det": max_det,
"main_title": main_title,
"cam_num": cam_num
}
new_json = json.dumps(new_config, ensure_ascii=False, indent=2)
with open(config_file, 'w', encoding='utf-8') as f:
f.write(new_json)
print("保存到配置文件成功!")
self.statusBar_show_msg("保存到配置文件成功!")
# ============自定义槽函数================================
def change_take_pic_btn_status(self, status):
self.ui.takePicButton.setEnabled(status)
if status == False:
self.ui.takePicButton.setStyleSheet(
"background-color:gray;border: 1px solid;border-radius: 10px;width: 40px;height: 25px;padding: 5px;color:white")
self.ui.takePicButton.setText("等待信号写入完成")
else:
self.ui.takePicButton.setStyleSheet(
"background-color:rgb(146, 189, 108);border: 1px solid;border-radius: 10px;width: 40px;height: 25px;padding: 5px")
self.ui.takePicButton.setText("拍照")
def show_signal_message(self, message):
QMessageBox.information(
self, "提示!", message)
def IoU_doubleSpinBox_valueChanged(self):
print("IoU_doubleSpinBox_valueChanged")
self.statusBar_show_msg(str(float(self.ui.IoU_doubleSpinBox.value())))
def conf_thres_doubleSpinBox_valueChanged(self):
print("conf_thres_doubleSpinBox_valueChanged")
self.statusBar_show_msg(
str(float(self.ui.conf_thres_doubleSpinBox.value())))
# ===========窗体测试程序=================================
if __name__ == "__main__": # 用于当前窗体测试
app = QApplication(sys.argv) # 创建GUI应用程序
form = QmyMainWindow() # 创建窗体
form.show()
sys.exit(app.exec_())
Python
1
https://gitee.com/davidhu1/AI_Vision_DetectSys.git
git@gitee.com:davidhu1/AI_Vision_DetectSys.git
davidhu1
AI_Vision_DetectSys
基于YOLOv5+PyQt5+Python的AI视觉检测系统
master

搜索帮助