多进程 传递数据、运行时卡顿、退出时卡顿的简单案例

Python学习之旅:高级阶段(四)多进程编程multiprocessing模块 进程可以理解为一个正在运行的程序实例。在单进程程序中,一次只能执行一个任务,就像一个人一次只能做一件事。而多进程编程允许同时运行多个进程,就像多个人同时做不同的事情,大大提高了工作效率。比如,你可以一边下载文件,一边编辑文档,这两个任务可以由不同的进程来完成。模块是 Python 标准库中用于多进程编程的模块,它提供了创建和管理进程的各种功能,包括进程的启动、停止、通信等。 阅读详情

多进程

多进程(简单程序)

from multiprocessing import Process, Queue

class MyProcess(Process):
    def __init__(self, q, i):
        super().__init__()
        self.q = q
        self.i = i

    def run(self):
        print('子进程%s 开始put数据' % self.i)
        self.q.put('我是%s 通过Queue通信' % self.i)
        self.q.put('我是%s 通过Queue通信' % 2)

if __name__ == '__main__':
    q = Queue()

    process_list = []
    p = MyProcess(q, 0)
    p.start()

    p.join()

    print('主进程获取Queue数据')
    print(q.get())
    print(q.get())

    print('结束测试')

主进程向子进程传递数据(简单程序)

from multiprocessing import Process, Queue

class MyProcess(Process):
    def __init__(self, q, i, data):
        super().__init__()
        self.q = q
        self.i = i
        self.data = data

    def run(self):
        print('子进程%s 开始put数据' % self.i)
        self.q.put(self.data[0]+1)
        self.q.put(self.data[1]+1)
        self.q.put(self.data[2]+1)


if __name__ == '__main__':
    q = Queue()
    data = [1, 2, 3]  # 要传递的列表

    process_list = []

    p = MyProcess(q, 0, data)
    p.start()

    p.join()

    print('主进程获取Queue数据')
    print(q.get())
    print(q.get())
    print(q.get())
    print('结束测试')

解决卡顿问题

解决运行时卡顿的简单可执行代码

在这段代码中,主进程在启动子进程后使用了p.join()方法等待子进程完成。这会导致主进程在等待子进程期间被阻塞,导致GUI界面出现卡顿和未响应的情况。

为了解决这个问题,可以将子进程的启动和等待放在一个单独的线程中执行,而不是在主线程中执行。这样可以确保主线程不会被阻塞,保持GUI界面的响应性。

以下是修改后的代码示例:

from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
from multiprocessing import Process, Queue
import threading
import time

class MyProcess(Process):
    def __init__(self, q, data):
        super().__init__()
        self.q = q
        self.data = data

    def run(self):
        time.sleep(20)
        print('子进程开始put数据')
        self.data.append('123')
        self.q.put(self.data)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.q = Queue()
        self.data = ['111', '222', '333']  # 要传递的列表

        self.button = QPushButton('启动子进程', self)
        self.button.clicked.connect(self.start_child_process)

    def start_child_process(self):
        def run_child_process():
            p = MyProcess(self.q, self.data)
            p.start()
            p.join()

            # 子进程完成后的逻辑
            result = self.q.get()
            print('主进程获取Queue数据:', result)

        thread = threading.Thread(target=run_child_process)
        thread.start()

if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

在修改后的代码中,start_child_process方法创建了一个新的线程,并将子进程的启动和等待放在该线程中执行。这样,主线程不再阻塞,GUI界面可以保持响应性。

在本次系统的代码中,预测推理部分采用了多进程的技术,生成pdf的时候使用的是多线程的技术但是有时候程序会突然出现闪退。原因是GUI程序在推出的时候,执行耗时时间任务的进程仍然在活动,导致第二次打开GUI假面然后启动耗时时间任务的时候,产生了进程之间的冲突。

为了避免这种情况的发生,我们只需要在退出GUI程序的时候同时销毁执行耗时任务的子进程。

解决退出卡顿的简单程序

在退出GUI界面后,是否需要销毁进程取决于具体情况。下面是两种常见的情况:

  1. 进程执行的任务与GUI界面无关:如果子进程执行的任务与GUI界面无关,并且在退出界面后仍然需要继续执行,那么你可以选择不销毁进程。在这种情况下,子进程可以继续在后台执行,直到任务完成或手动终止。

  2. 进程执行的任务与GUI界面相关:如果子进程执行的任务与GUI界面相关,并且在退出界面后不再需要执行,那么最好在退出界面时销毁进程。这样可以确保资源被正确释放,避免潜在的问题。你可以在关闭主窗口时添加一些代码来终止子进程,例如使用p.terminate()方法来强制终止进程。

以下是修改后的代码示例,演示了如何在关闭主窗口时终止子进程:

from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
from multiprocessing import Process, Queue
import threading
import time

class MyProcess(Process):
    def __init__(self, q, data):
        super().__init__()
        self.q = q
        self.data = data

    def run(self):
        time.sleep(20)
        print('子进程开始put数据')
        self.data.append('123')
        self.q.put(self.data)

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.q = Queue()
        self.data = ['111', '222', '333']  # 要传递的列表

        self.button = QPushButton('启动子进程', self)
        self.button.clicked.connect(self.start_child_process)

    def start_child_process(self):
        def run_child_process():
            p = MyProcess(self.q, self.data)
            p.start()
            p.join()

            # 子进程完成后的逻辑
            result = self.q.get()
            print('主进程获取Queue数据:', result)

        self.thread = threading.Thread(target=run_child_process)
        self.thread.start()

    def closeEvent(self, event):
        if self.thread.is_alive():
            self.thread.join()  # 等待子线程完成
        event.accept()

if __name__ == '__main__':
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

最后的代码test2

# -*- coding: utf-8 -*-
 
# Form implementation generated from reading ui file 'test2.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# 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.
'''
这个文件用于显示PyQt,无需输入正确的账号和密码就可以登录进去
选择图片的时候只能选择28*28像素的图片,也就是TestDigitImgs的第一张图片
'''
'''PyQt'''
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QFileDialog
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import  QApplication, QFileDialog, QMessageBox
from PyQt5.Qt import Qt, QIcon
from PyQt5 import QtCore, QtGui, QtWidgets
'''调用类'''
import os
from multiprocessing import Process
from multiprocessing import Process, Queue
import threading
# from Docx import GenerateDocx
# import cv2
# import math
# import utils
# import numpy as np
# from docx2pdf import convert
# from multiprocessing import Process
# from mmdeploy_runtime import Detector, Classifier
# from datetime import datetime
# 获取当前日期和时间

INFER_WINDOW_SIZE = [1024, 1024]
INFER_WINDOW_STRIDES = (960, 960)
OVERLAP_NMS_THRESHOLD = 0.5
BBOX_DISPLAY_CONFIDENCE = 0.5
 
CATEGORY_COLOR = {   
    'papule':(140,240,255),
    'nevus':(162,247,223),
    'nodule':(152,192,250),
    'open_comedo':(86,143,128),
    'closed_comedo':(60,57,166),
    'atrophic_scar':(103,49,132),
    'hypertrophic_scar':(249,233,160),
    'melasma':(164,93,222),
    'pustule':(235,177,161),
    'other':(233,222,252)
    }
 
CATEGORY_INDEX = {0:'papule',
                  1:'nevus',
                  2:'nodule',
                  3:'open_comedo',
                  4:'closed_comedo',
                  5:'atrophic_scar',
                  6:'hypertrophic_scar',
                  7:'melasma',
                  8:'pustule',
                  9:'other'}
 
CLASSIFICATION_DRUG = {
    1:"无需治疗",
    2:"BPO或弱效维A酸类外用",
    3:"BPO联合维A酸类外用",
    4:"BPO联合维A酸,考虑口服抗生素",
    5:"BPO联合维A酸,口服抗生素",
    6:"BPO联合维A酸,口服抗生素,并开始考虑异维A酸",
    7:"BPO联合维A酸,口服抗生素,推荐异维A酸",
    8:"异维A酸"
}
 
 
QApplication.processEvents()
 
 
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1410, 902)
        MainWindow.setWindowIcon(QIcon('./icon/main.ico'))
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.groupBox_main = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox_main.setTitle("")
        self.groupBox_main.setObjectName("groupBox_main")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox_main)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.horizontalLayout_largest = QtWidgets.QHBoxLayout()
        self.horizontalLayout_largest.setObjectName("horizontalLayout_largest")
        self.groupBox_left = QtWidgets.QGroupBox(self.groupBox_main)
        self.groupBox_left.setMinimumSize(QtCore.QSize(320, 0))
        self.groupBox_left.setMaximumSize(QtCore.QSize(320, 16777215))
        self.groupBox_left.setTitle("")
        self.groupBox_left.setObjectName("groupBox_left")
        self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.groupBox_left)
        self.verticalLayout_8.setObjectName("verticalLayout_8")
        self.groupBox_menu = QtWidgets.QGroupBox(self.groupBox_left)
        self.groupBox_menu.setMinimumSize(QtCore.QSize(300, 40))
        self.groupBox_menu.setMaximumSize(QtCore.QSize(16777215, 40))
        self.groupBox_menu.setTitle("")
        self.groupBox_menu.setObjectName("groupBox_menu")
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.groupBox_menu)
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.label_menu = QtWidgets.QLabel(self.groupBox_menu)
        self.label_menu.setStyleSheet("font-size: 22px;")
        self.label_menu.setObjectName("label_menu")
        self.horizontalLayout_6.addWidget(self.label_menu)
        spacerItem = QtWidgets.QSpacerItem(205, 17, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_6.addItem(spacerItem)
        self.verticalLayout_8.addWidget(self.groupBox_menu)
        self.groupBox_startAction = QtWidgets.QGroupBox(self.groupBox_left)
        self.groupBox_startAction.setMaximumSize(QtCore.QSize(16777215, 130))
        self.groupBox_startAction.setTitle("")
        self.groupBox_startAction.setObjectName("groupBox_startAction")
        self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.groupBox_startAction)
        self.verticalLayout_4.setObjectName("verticalLayout_4")
        self.horizontalLayout_imgAndDir = QtWidgets.QHBoxLayout()
        self.horizontalLayout_imgAndDir.setObjectName("horizontalLayout_imgAndDir")
        self.pushButton_selectImg = QtWidgets.QPushButton(self.groupBox_startAction)
        self.pushButton_selectImg.setMinimumSize(QtCore.QSize(20, 40))
        self.pushButton_selectImg.setStyleSheet("font-size: 18px;")
        self.pushButton_selectImg.setObjectName("pushButton_selectImg")
        self.horizontalLayout_imgAndDir.addWidget(self.pushButton_selectImg)
        self.pushButton_selectDir = QtWidgets.QPushButton(self.groupBox_startAction)
        self.pushButton_selectDir.setMinimumSize(QtCore.QSize(0, 40))
        self.pushButton_selectDir.setStyleSheet("font-size: 18px;")
        self.pushButton_selectDir.setObjectName("pushButton_selectDir")
        self.horizontalLayout_imgAndDir.addWidget(self.pushButton_selectDir)
        self.verticalLayout_4.addLayout(self.horizontalLayout_imgAndDir)
        self.pushButton_startAction = QtWidgets.QPushButton(self.groupBox_startAction)
        self.pushButton_startAction.setMinimumSize(QtCore.QSize(50, 40))
        self.pushButton_startAction.setStyleSheet("font-size: 18px;")

        self.pushButton_startAction.setObjectName("pushButton_startAction")
        self.verticalLayout_4.addWidget(self.pushButton_startAction)
        self.verticalLayout_8.addWidget(self.groupBox_startAction)
        self.groupBox = QtWidgets.QGroupBox(self.groupBox_left)
        self.groupBox.setMinimumSize(QtCore.QSize(0, 62))
        self.groupBox.setTitle("")
        self.groupBox.setObjectName("groupBox")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.groupBox)
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.pushButton_save = QtWidgets.QPushButton(self.groupBox)
        self.pushButton_save.setMinimumSize(QtCore.QSize(0, 40))
        self.pushButton_save.setStyleSheet("font-size: 18px;")
        self.pushButton_save.setObjectName("pushButton_save")
        self.horizontalLayout.addWidget(self.pushButton_save)
        self.lineEdit_savePath = QtWidgets.QLineEdit(self.groupBox)
        self.lineEdit_savePath.setMinimumSize(QtCore.QSize(0, 40))
        self.lineEdit_savePath.setObjectName("lineEdit_savePath")
        self.horizontalLayout.addWidget(self.lineEdit_savePath)
        self.horizontalLayout_3.addLayout(self.horizontalLayout)
        self.verticalLayout_8.addWidget(self.groupBox)
        self.groupBox_showDir = QtWidgets.QGroupBox(self.groupBox_left)
        self.groupBox_showDir.setMinimumSize(QtCore.QSize(0, 50))
        self.groupBox_showDir.setMaximumSize(QtCore.QSize(16777215, 55))
        self.groupBox_showDir.setTitle("")
        self.groupBox_showDir.setObjectName("groupBox_showDir")
        self.horizontalLayout_10 = QtWidgets.QHBoxLayout(self.groupBox_showDir)
        self.horizontalLayout_10.setObjectName("horizontalLayout_10")
        self.pushButton_showPDF = QtWidgets.QPushButton(self.groupBox_showDir)
        self.pushButton_showPDF.setMinimumSize(QtCore.QSize(0, 40))
        self.pushButton_showPDF.setStyleSheet("font-size: 18px;")
        self.pushButton_showPDF.setObjectName("pushButton_showPDF")
        self.horizontalLayout_10.addWidget(self.pushButton_showPDF)
        self.verticalLayout_8.addWidget(self.groupBox_showDir)
        self.verticalLayout_result = QtWidgets.QVBoxLayout()
        self.verticalLayout_result.setObjectName("verticalLayout_result")
        self.groupBox_resultTitle = QtWidgets.QGroupBox(self.groupBox_left)
        self.groupBox_resultTitle.setMinimumSize(QtCore.QSize(0, 50))
        self.groupBox_resultTitle.setMaximumSize(QtCore.QSize(16777215, 50))
        self.groupBox_resultTitle.setTitle("")
        self.groupBox_resultTitle.setObjectName("groupBox_resultTitle")
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.groupBox_resultTitle)
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.label_resultTitle = QtWidgets.QLabel(self.groupBox_resultTitle)
        self.label_resultTitle.setStyleSheet("font-size: 22px;")
        self.label_resultTitle.setObjectName("label_resultTitle")
        self.horizontalLayout_8.addWidget(self.label_resultTitle)
        spacerItem1 = QtWidgets.QSpacerItem(181, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_8.addItem(spacerItem1)
        self.verticalLayout_result.addWidget(self.groupBox_resultTitle)
        self.groupBox_resultContent = QtWidgets.QGroupBox(self.groupBox_left)
        self.groupBox_resultContent.setMinimumSize(QtCore.QSize(0, 50))
        self.groupBox_resultContent.setTitle("")
        self.groupBox_resultContent.setObjectName("groupBox_resultContent")
        self.horizontalLayout_9 = QtWidgets.QHBoxLayout(self.groupBox_resultContent)
        self.horizontalLayout_9.setObjectName("horizontalLayout_9")
        self.listWidget = QtWidgets.QListWidget(self.groupBox_resultContent)
        self.listWidget.setLayoutDirection(QtCore.Qt.LeftToRight)
        self.listWidget.setStyleSheet("font-size: 14px;")
        self.listWidget.setIconSize(QtCore.QSize(7, 7))
        self.listWidget.setObjectName("listWidget")
        item = QtWidgets.QListWidgetItem()
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("./icon/closed_comedo.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        item.setIcon(icon)
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap("./icon/opend_comedo.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        item.setIcon(icon1)
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        icon2 = QtGui.QIcon()
        icon2.addPixmap(QtGui.QPixmap("./icon/papule.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        item.setIcon(icon2)
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        icon3 = QtGui.QIcon()
        icon3.addPixmap(QtGui.QPixmap("./icon/pustule.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        item.setIcon(icon3)
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        icon4 = QtGui.QIcon()
        icon4.addPixmap(QtGui.QPixmap("./icon/nodule.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        item.setIcon(icon4)
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        icon5 = QtGui.QIcon()
        icon5.addPixmap(QtGui.QPixmap("./icon/atrophic_scar.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        item.setIcon(icon5)
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        icon6 = QtGui.QIcon()
        icon6.addPixmap(QtGui.QPixmap("./icon/hypertrophic_scar.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        item.setIcon(icon6)
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        icon7 = QtGui.QIcon()
        icon7.addPixmap(QtGui.QPixmap("./icon/melasma.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        item.setIcon(icon7)
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        icon8 = QtGui.QIcon()
        icon8.addPixmap(QtGui.QPixmap("./icon/nevus.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        item.setIcon(icon8)
        self.listWidget.addItem(item)
        item = QtWidgets.QListWidgetItem()
        icon9 = QtGui.QIcon()
        icon9.addPixmap(QtGui.QPixmap("./icon/other.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        item.setIcon(icon9)
        self.listWidget.addItem(item)
        self.horizontalLayout_9.addWidget(self.listWidget)
        self.verticalLayout_result.addWidget(self.groupBox_resultContent)
        self.verticalLayout_8.addLayout(self.verticalLayout_result)
        self.verticalLayout_advice = QtWidgets.QVBoxLayout()
        self.verticalLayout_advice.setObjectName("verticalLayout_advice")
        self.groupBox_10 = QtWidgets.QGroupBox(self.groupBox_left)
        self.groupBox_10.setMinimumSize(QtCore.QSize(0, 50))
        self.groupBox_10.setMaximumSize(QtCore.QSize(16777215, 50))
        self.groupBox_10.setTitle("")
        self.groupBox_10.setObjectName("groupBox_10")
        self.horizontalLayout_12 = QtWidgets.QHBoxLayout(self.groupBox_10)
        self.horizontalLayout_12.setObjectName("horizontalLayout_12")
        self.label_adviceTitle = QtWidgets.QLabel(self.groupBox_10)
        self.label_adviceTitle.setMinimumSize(QtCore.QSize(0, 30))
        self.label_adviceTitle.setStyleSheet("font-size: 22px;")
        self.label_adviceTitle.setObjectName("label_adviceTitle")
        self.horizontalLayout_12.addWidget(self.label_adviceTitle)
        spacerItem2 = QtWidgets.QSpacerItem(137, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_12.addItem(spacerItem2)
        self.verticalLayout_advice.addWidget(self.groupBox_10)
        self.groupBox_12 = QtWidgets.QGroupBox(self.groupBox_left)
        self.groupBox_12.setMinimumSize(QtCore.QSize(0, 70))
        self.groupBox_12.setMaximumSize(QtCore.QSize(16777215, 120))
        self.groupBox_12.setTitle("")
        self.groupBox_12.setObjectName("groupBox_12")
        self.horizontalLayout_13 = QtWidgets.QHBoxLayout(self.groupBox_12)
        self.horizontalLayout_13.setObjectName("horizontalLayout_13")
        self.label_adviceResult = QtWidgets.QLabel(self.groupBox_12)
        self.label_adviceResult.setMinimumSize(QtCore.QSize(0, 50))
        self.label_adviceResult.setMaximumSize(QtCore.QSize(16777215, 120))
        self.label_adviceResult.setStyleSheet("font-size: 16px;")
        self.label_adviceResult.setAlignment(QtCore.Qt.AlignCenter)
        self.label_adviceResult.setObjectName("label_adviceResult")
        self.horizontalLayout_13.addWidget(self.label_adviceResult)
        self.verticalLayout_advice.addWidget(self.groupBox_12)
        self.verticalLayout_8.addLayout(self.verticalLayout_advice)
        self.horizontalLayout_largest.addWidget(self.groupBox_left)
        self.groupBox_right = QtWidgets.QGroupBox(self.groupBox_main)
        self.groupBox_right.setTitle("")
        self.groupBox_right.setObjectName("groupBox_right")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox_right)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.groupBox_selectImg = QtWidgets.QGroupBox(self.groupBox_right)
        self.groupBox_selectImg.setMinimumSize(QtCore.QSize(0, 40))
        self.groupBox_selectImg.setMaximumSize(QtCore.QSize(16777215, 40))
        self.groupBox_selectImg.setTitle("")
        self.groupBox_selectImg.setObjectName("groupBox_selectImg")
        self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.groupBox_selectImg)
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.label_imgTitle = QtWidgets.QLabel(self.groupBox_selectImg)
        self.label_imgTitle.setMinimumSize(QtCore.QSize(0, 20))
        self.label_imgTitle.setStyleSheet("font-size: 20px;")
        self.label_imgTitle.setObjectName("label_imgTitle")
        self.horizontalLayout_5.addWidget(self.label_imgTitle)
        self.lineEdit_imgPath = QtWidgets.QLineEdit(self.groupBox_selectImg)
        self.lineEdit_imgPath.setMinimumSize(QtCore.QSize(0, 25))
        self.lineEdit_imgPath.setMaximumSize(QtCore.QSize(300, 16777215))
        self.lineEdit_imgPath.setObjectName("lineEdit_imgPath")
        self.horizontalLayout_5.addWidget(self.lineEdit_imgPath)
        spacerItem3 = QtWidgets.QSpacerItem(287, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_5.addItem(spacerItem3)
        self.label_5 = QtWidgets.QLabel(self.groupBox_selectImg)
        self.label_5.setText("")
        self.label_5.setObjectName("label_5")
        self.horizontalLayout_5.addWidget(self.label_5)
        self.verticalLayout_3.addWidget(self.groupBox_selectImg)
        self.horizontalLayout_imgs = QtWidgets.QHBoxLayout()
        self.horizontalLayout_imgs.setObjectName("horizontalLayout_imgs")
        self.label_showImg = QtWidgets.QLabel(self.groupBox_right)
        self.label_showImg.setMinimumSize(QtCore.QSize(500, 0))
        self.label_showImg.setText("")
        self.label_showImg.setAlignment(QtCore.Qt.AlignCenter)
        self.label_showImg.setObjectName("label_showImg")
        self.horizontalLayout_imgs.addWidget(self.label_showImg)
        spacerItem4 = QtWidgets.QSpacerItem(10, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.horizontalLayout_imgs.addItem(spacerItem4)
        self.label_showImg2 = QtWidgets.QLabel(self.groupBox_right)
        self.label_showImg2.setMinimumSize(QtCore.QSize(500, 0))
        self.label_showImg2.setText("")
        self.label_showImg2.setAlignment(QtCore.Qt.AlignCenter)
        self.label_showImg2.setObjectName("label_showImg2")
        self.horizontalLayout_imgs.addWidget(self.label_showImg2)
        self.verticalLayout_3.addLayout(self.horizontalLayout_imgs)
        self.horizontalLayout_pageTurning = QtWidgets.QHBoxLayout()
        self.horizontalLayout_pageTurning.setObjectName("horizontalLayout_pageTurning")
        self.prev_image_button = QtWidgets.QPushButton(self.groupBox_right)
        self.prev_image_button.setMinimumSize(QtCore.QSize(0, 30))
        self.prev_image_button.setObjectName("prev_image_button")
        self.horizontalLayout_pageTurning.addWidget(self.prev_image_button)
        self.label_pageNum = QtWidgets.QLabel(self.groupBox_right)
        self.label_pageNum.setMinimumSize(QtCore.QSize(80, 0))
        self.label_pageNum.setMaximumSize(QtCore.QSize(50, 16777215))
        self.label_pageNum.setAlignment(QtCore.Qt.AlignCenter)
        self.label_pageNum.setObjectName("label_pageNum")
        self.horizontalLayout_pageTurning.addWidget(self.label_pageNum)
        self.next_image_button = QtWidgets.QPushButton(self.groupBox_right)
        self.next_image_button.setMinimumSize(QtCore.QSize(0, 30))
        self.next_image_button.setObjectName("next_image_button")
        self.horizontalLayout_pageTurning.addWidget(self.next_image_button)
        self.verticalLayout_3.addLayout(self.horizontalLayout_pageTurning)
        self.horizontalLayout_largest.addWidget(self.groupBox_right)
        self.verticalLayout_2.addLayout(self.horizontalLayout_largest)
        self.groupBox_botton = QtWidgets.QGroupBox(self.groupBox_main)
        self.groupBox_botton.setMinimumSize(QtCore.QSize(0, 32))
        self.groupBox_botton.setTitle("")
        self.groupBox_botton.setObjectName("groupBox_botton")
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.groupBox_botton)
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.label_condition = QtWidgets.QLabel(self.groupBox_botton)
        self.label_condition.setMinimumSize(QtCore.QSize(0, 12))
        self.label_condition.setObjectName("label_condition")
        self.horizontalLayout_2.addWidget(self.label_condition)
        self.verticalLayout_2.addWidget(self.groupBox_botton)
        self.verticalLayout.addWidget(self.groupBox_main)
        MainWindow.setCentralWidget(self.centralwidget)
 
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
 
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "痤疮检测"))
        self.label_menu.setText(_translate("MainWindow", "菜单栏"))
        self.pushButton_selectImg.setText(_translate("MainWindow", "选择图片"))
        self.pushButton_selectDir.setText(_translate("MainWindow", "选择文件夹"))
        self.pushButton_startAction.setText(_translate("MainWindow", "开始检测"))
        self.pushButton_save.setText(_translate("MainWindow", "保存报告"))
        self.pushButton_showPDF.setText(_translate("MainWindow", "显示输出文件夹"))
        self.label_resultTitle.setText(_translate("MainWindow", "检测结果"))
        __sortingEnabled = self.listWidget.isSortingEnabled()
        self.listWidget.setSortingEnabled(False)
        item = self.listWidget.item(0)
        item.setText(_translate("MainWindow", "痤疮分级结果:待检测"))
        item = self.listWidget.item(2)
        item.setText(_translate("MainWindow", "各类别痤疮检测数量:"))
        item = self.listWidget.item(4)
        item.setText(_translate("MainWindow", "  闭口粉刺:待检测"))
        item = self.listWidget.item(5)
        item.setText(_translate("MainWindow", "  开口粉刺:待检测"))
        item = self.listWidget.item(6)
        item.setText(_translate("MainWindow", "  丘疹:待检测"))
        item = self.listWidget.item(7)
        item.setText(_translate("MainWindow", "  脓疱:待检测"))
        item = self.listWidget.item(8)
        item.setText(_translate("MainWindow", "  结节:待检测"))
        item = self.listWidget.item(9)
        item.setText(_translate("MainWindow", "  萎缩性瘢痕:待检测"))
        item = self.listWidget.item(10)
        item.setText(_translate("MainWindow", "  增生性瘢痕刺:待检测"))
        item = self.listWidget.item(11)
        item.setText(_translate("MainWindow", "  斑:待检测"))
        item = self.listWidget.item(12)
        item.setText(_translate("MainWindow", "  色素痣:待检测"))
        item = self.listWidget.item(13)
        item.setText(_translate("MainWindow", "  其他:待检测"))
        self.listWidget.setSortingEnabled(__sortingEnabled)
        self.label_adviceTitle.setText(_translate("MainWindow", "推荐治疗方案"))
        self.label_adviceResult.setText(_translate("MainWindow", "用药指南"))
        self.label_imgTitle.setText(_translate("MainWindow", "所选图片"))
        self.prev_image_button.setText(_translate("MainWindow", "上一页"))
        self.label_pageNum.setText(_translate("MainWindow", "共 0 页"))
        self.next_image_button.setText(_translate("MainWindow", "下一页"))
        self.label_condition.setText(_translate("MainWindow", "系统运行情况"))
 
        # 按钮关联函数
        self.pushButton_selectDir.clicked.connect(self.openImageFolder)
        # self.pushButton_startAction.clicked.connect(self.startAction)
        self.pushButton_selectImg.clicked.connect(self.openImage)
 
        self.pushButton_startAction.clicked.connect(self.start_work)
        # self.worker_thread.finished.connect(self.on_worker_finished)
 
        self.pushButton_save.clicked.connect(self.start_work_pdf)
        # self.worker_thread_pdf.finished.connect(self.on_worker_finished_pdf)
 
        self.pushButton_showPDF.clicked.connect(self.button_show_dir)
 
        self.prev_image_button.clicked.connect(self.showPrevImage)
        self.next_image_button.clicked.connect(self.showNextImage)
        
        QApplication.processEvents()
 
    def start_work(self):
        def run_child_process():
            QApplication.processEvents()
 
            self.pushButton_startAction.setEnabled(False)  # 禁用按钮
            self.pushButton_selectImg.setEnabled(False)  # 禁用按钮
            self.pushButton_save.setEnabled(False)  # 禁用按钮
            self.pushButton_showPDF.setEnabled(False)  # 禁用按钮
            self.pushButton_selectDir.setEnabled(False)  # 禁用按钮
            self.prev_image_button.setEnabled(False)
            self.next_image_button.setEnabled(False)
            self.label_condition.setText('正在检测,请耐心等待')
 
            print("启动进程")
            p = Worker(self.q, self.selected_imgPaths,self.now)
            p.start()
            p.join()


            self.generated_image_paths = self.q.get()
            self.generated_docxFilePath_List = self.q.get()
            self.text = self.q.get()
            print("我得到啦")
            self.label_condition.setText('检测完毕,请点击保存图片')
 
            self.pushButton_startAction.setEnabled(True)  # 启动之前被禁用的按钮
            self.pushButton_selectImg.setEnabled(True)
            self.pushButton_save.setEnabled(True)  
            self.pushButton_showPDF.setEnabled(True)  
            self.pushButton_selectDir.setEnabled(True)
            self.prev_image_button.setEnabled(True)
            self.next_image_button.setEnabled(True)
            img_path = self.selected_imgPaths[0]
            img_name = os.path.splitext(os.path.basename(img_path))[0]
 
            grading_result = self.text[img_name]["grading_result"]
            item = self.listWidget.item(0)
            item.setText(f"痤疮分级结果:{grading_result}") 
            item = self.listWidget.item(2)
            item.setText("各类别痤疮检测数量:")
            item = self.listWidget.item(4)
            closed_comedo_count = self.text[img_name]["category_count"]["closed_comedo"]
            item.setText(f"  闭口粉刺:{closed_comedo_count}")
            item = self.listWidget.item(5)
            open_comedo_count = self.text[img_name]["category_count"]["open_comedo"]
            item.setText(f"  开口粉刺:{open_comedo_count}")
            item = self.listWidget.item(6)
            papule_count = self.text[img_name]["category_count"]["papule"]
            item.setText(f"  丘疹:{papule_count}")
            item = self.listWidget.item(7)
            pustule_count = self.text[img_name]["category_count"]["pustule"]
            item.setText(f"  脓疱:{pustule_count}")
            item = self.listWidget.item(8)
            nodule_count = self.text[img_name]["category_count"]["nodule"]
            item.setText(f"  结节:{nodule_count}")
            item = self.listWidget.item(9)
            atrophic_scar_count = self.text[img_name]["category_count"]["atrophic_scar"]
            item.setText(f"  萎缩性瘢痕:{atrophic_scar_count}")
            item = self.listWidget.item(10)
            hypertrophic_scar_count = self.text[img_name]["category_count"]["hypertrophic_scar"]
            item.setText(f"  增生性瘢痕刺:{hypertrophic_scar_count}")
            item = self.listWidget.item(11)
            melasma_count = self.text[img_name]["category_count"]["melasma"]
            item.setText(f"  斑:{melasma_count}")
            item = self.listWidget.item(12)
            nevus_count = self.text[img_name]["category_count"]["nevus"]
            item.setText(f"  色素痣:{nevus_count}")
            item = self.listWidget.item(13)
            other_count = self.text[img_name]["category_count"]["other"]
            item.setText(f"  其他:{other_count}")
 
 
            img_path = self.generated_image_paths[0]
            # 通过文件路径获取图片文件,并设置图片长宽为label控件的长、宽
            img = QtGui.QPixmap(img_path).scaled(self.label_showImg2.width(), self.label_showImg2.height(), Qt.KeepAspectRatio,Qt.SmoothTransformation)
            # 在label控件上显示选择的图片
            self.label_showImg2.setPixmap(img)
            #显示用药指南
            self.label_adviceResult.setText(CLASSIFICATION_DRUG[grading_result])
            # if self.thread.is_alive():
            #     self.thread.join()  # 等待子线程完成

        
        self.thread = threading.Thread(target=run_child_process)
        
        self.thread.start()
        # self.thread.join()
        # print("ok")
 
 
    def start_work_pdf(self):
        if len(self.generated_image_paths) == 0:
            return
        self.dir_choose = QFileDialog.getExistingDirectory(self.centralwidget, "选取文件夹", "./report_pdf")
        if self.dir_choose == '':
            print("未生成报告,保存无效")
            self.label_condition.setText('未生成报告,保存无效')
            return
        else:
            # f=open(fd,'w')
            import queue
            for i in range(len(self.generated_image_paths)):
                QApplication.processEvents()
                img_name = os.path.splitext(os.path.basename(self.generated_docxFilePath_List[i]))[0]
                self.label_condition.setText(f"正在生成{img_name}.pdf报告")

                # 创建队列对象
                data_queue = queue.Queue()
                data_queue.put(self.generated_docxFilePath_List[i])
                data_queue.put(self.dir_choose)
                # 启动工作线程
                self.worker_pdf = threading.Thread(target=self.my_thread_pdf,args=(data_queue,))
 
                self.worker_pdf.start()
 
 
    
    def my_thread_pdf(self,data_queue_in):
        from docx2pdf import convert
        # 执行耗时的任务
        generated_docxFilePath = data_queue_in.get()
        dir_choose = data_queue_in.get()

        img_name = os.path.splitext(os.path.basename(generated_docxFilePath))[0]
        convert(generated_docxFilePath, dir_choose+f"/{img_name}.pdf")

        print("pdf报告全部转换完毕")
        self.label_condition.setText(f"pdf报告生成完毕")
        self.lineEdit_savePath.setText(self.dir_choose)
        self.label_condition.setText('已保存所有报告')
 
    
    def showNextImage(self):
        if len(self.selected_imgPaths) == 0:
            return
        self.current_image_index += 1
        if self.current_image_index >= len(self.selected_imgPaths):
            self.current_image_index = 0
 
        img_path = self.selected_imgPaths[self.current_image_index]
 
        img = QtGui.QPixmap(img_path).scaled(self.label_showImg.width(), self.label_showImg.height(), Qt.KeepAspectRatio,Qt.SmoothTransformation)
        self.label_showImg.setPixmap(img)
        self.lineEdit_imgPath.setText(img_path)
        pageNum = len(self.selected_imgPaths)
        current_image_index_fact = self.current_image_index + 1
        self.label_pageNum.setText(f"{current_image_index_fact} / {pageNum} ")
 
 
        if len(self.text) == len(self.selected_imgPaths):
            img_name = os.path.splitext(os.path.basename(img_path))[0]
            # self.label_showResult.setText(self.text[img_name])
            # print(self.text[img_name])
            grading_result = self.text[img_name]["grading_result"]
            self.label_adviceResult.setText(CLASSIFICATION_DRUG[grading_result])
            item = self.listWidget.item(0)
            item.setText(f"痤疮分级结果:{grading_result}")
            item = self.listWidget.item(2)
            item.setText("各类别痤疮检测数量:")
            item = self.listWidget.item(4)
            closed_comedo_count = self.text[img_name]["category_count"]["closed_comedo"]
            item.setText(f"  闭口粉刺:{closed_comedo_count}")
            item = self.listWidget.item(5)
            open_comedo_count = self.text[img_name]["category_count"]["open_comedo"]
            item.setText(f"  开口粉刺:{open_comedo_count}")
            item = self.listWidget.item(6)
            papule_count = self.text[img_name]["category_count"]["papule"]
            item.setText(f"  丘疹:{papule_count}")
            item = self.listWidget.item(7)
            pustule_count = self.text[img_name]["category_count"]["pustule"]
            item.setText(f"  脓疱:{pustule_count}")
            item = self.listWidget.item(8)
            nodule_count = self.text[img_name]["category_count"]["nodule"]
            item.setText(f"  结节:{nodule_count}")
            item = self.listWidget.item(9)
            atrophic_scar_count = self.text[img_name]["category_count"]["atrophic_scar"]
            item.setText(f"  萎缩性瘢痕:{atrophic_scar_count}")
            item = self.listWidget.item(10)
            hypertrophic_scar_count = self.text[img_name]["category_count"]["hypertrophic_scar"]
            item.setText(f"  增生性瘢痕刺:{hypertrophic_scar_count}")
            item = self.listWidget.item(11)
            melasma_count = self.text[img_name]["category_count"]["melasma"]
            item.setText(f"  斑:{melasma_count}")
            item = self.listWidget.item(12)
            nevus_count = self.text[img_name]["category_count"]["nevus"]
            item.setText(f"  色素痣:{nevus_count}")
            item = self.listWidget.item(13)
            other_count = self.text[img_name]["category_count"]["other"]
            item.setText(f"  其他:{other_count}")
 
            img_path2 = self.generated_image_paths[self.current_image_index]
            img2 = QtGui.QPixmap(img_path2).scaled(self.label_showImg2.width(), self.label_showImg2.height(), Qt.KeepAspectRatio,Qt.SmoothTransformation)
            self.label_showImg2.setPixmap(img2)
 
    def showPrevImage(self):
        if len(self.selected_imgPaths) == 0:
            return
        self.current_image_index -= 1
        if self.current_image_index < 0:
            self.current_image_index = len(self.selected_imgPaths) - 1
 
        img_path = self.selected_imgPaths[self.current_image_index]
        img = QtGui.QPixmap(img_path).scaled(self.label_showImg.width(), self.label_showImg.height(), Qt.KeepAspectRatio,Qt.SmoothTransformation)
        self.label_showImg.setPixmap(img)
        self.lineEdit_imgPath.setText(img_path)
        pageNum = len(self.selected_imgPaths)
        current_image_index_fact = self.current_image_index + 1
        self.label_pageNum.setText(f"{current_image_index_fact} / {pageNum} ")
 
        img_path = self.selected_imgPaths[self.current_image_index]
        img_name = os.path.splitext(os.path.basename(img_path))[0]
        grading_result = self.text[img_name]["grading_result"]
        
 
        if len(self.text) == len(self.selected_imgPaths):
            img_name = os.path.splitext(os.path.basename(img_path))[0]
            # self.label_showResult.setText(self.text[img_name])
            # print(self.text[img_name])
            grading_result = self.text[img_name]["grading_result"]
            self.label_adviceResult.setText(CLASSIFICATION_DRUG[grading_result])
            item = self.listWidget.item(0)
            item.setText(f"痤疮分级结果:{grading_result}")
            item = self.listWidget.item(2)
            item.setText("各类别痤疮检测数量:")
            item = self.listWidget.item(4)
            closed_comedo_count = self.text[img_name]["category_count"]["closed_comedo"]
            item.setText(f"  闭口粉刺:{closed_comedo_count}")
            item = self.listWidget.item(5)
            open_comedo_count = self.text[img_name]["category_count"]["open_comedo"]
            item.setText(f"  开口粉刺:{open_comedo_count}")
            item = self.listWidget.item(6)
            papule_count = self.text[img_name]["category_count"]["papule"]
            item.setText(f"  丘疹:{papule_count}")
            item = self.listWidget.item(7)
            pustule_count = self.text[img_name]["category_count"]["pustule"]
            item.setText(f"  脓疱:{pustule_count}")
            item = self.listWidget.item(8)
            nodule_count = self.text[img_name]["category_count"]["nodule"]
            item.setText(f"  结节:{nodule_count}")
            item = self.listWidget.item(9)
            atrophic_scar_count = self.text[img_name]["category_count"]["atrophic_scar"]
            item.setText(f"  萎缩性瘢痕:{atrophic_scar_count}")
            item = self.listWidget.item(10)
            hypertrophic_scar_count = self.text[img_name]["category_count"]["hypertrophic_scar"]
            item.setText(f"  增生性瘢痕刺:{hypertrophic_scar_count}")
            item = self.listWidget.item(11)
            melasma_count = self.text[img_name]["category_count"]["melasma"]
            item.setText(f"  斑:{melasma_count}")
            item = self.listWidget.item(12)
            nevus_count = self.text[img_name]["category_count"]["nevus"]
            item.setText(f"  色素痣:{nevus_count}")
            item = self.listWidget.item(13)
            other_count = self.text[img_name]["category_count"]["other"]
            item.setText(f"  其他:{other_count}")
 
            img_path2 = self.generated_image_paths[self.current_image_index]
            img2 = QtGui.QPixmap(img_path2).scaled(self.label_showImg2.width(), self.label_showImg2.height(), Qt.KeepAspectRatio,Qt.SmoothTransformation)
            self.label_showImg2.setPixmap(img2)
 
    def button_show_dir(self):
        default_dir = "./report_pdf"
        show_dirPath = 0
        if self.dir_choose == '':
            show_dirPath = default_dir
        else:
            show_dirPath = self.dir_choose
 
        url = QUrl.fromLocalFile(show_dirPath)
        if url:
            print("选择的文件夹路径:", show_dirPath)
        else:
            print("未选择文件夹")
        QDesktopServices.openUrl(url)
 
 
    # 选择本地图片上传
    def openImage(self):
        self.selected_imgPaths = [] # 清空之前选择的所有图片
        self.generated_image_paths = [] # 清空之前推理生成的所有图片
        empty_pixmap = QPixmap()
        self.label_showImg.setPixmap(empty_pixmap)
        self.label_showImg2.setPixmap(empty_pixmap)
        # 弹出一个文件选择框,第一个返回值imgName记录选中的文件路径+文件名,第二个返回值imgType记录文件的类型
        # QFileDialog就是系统对话框的那个类第一个参数是上下文,第二个参数是弹框的名字,第三个参数是默认打开的路径,第四个参数是需要的格式
        self.selected_imgPaths, _ = QtWidgets.QFileDialog.getOpenFileNames(
            self, "打开图片", "./pending_images", "*.jpg;;*.JPG;;*.png;;*.png;;All Files(*)")
        if len(self.selected_imgPaths) == 0:
            print('没有选择图片!')
            self.label_condition.setText("没有选择图片!") # 点击选择图片按钮后不选择图片会将存放图片路径的列表置为空
            # 创建一个空的QPixmap对象
            empty_pixmap = QPixmap()
            self.label_showImg.setPixmap(empty_pixmap)
            pageNum = 0
            self.label_pageNum.setText(f"共 {pageNum} 页")
            return
        
        # 通过文件路径获取图片文件,并设置图片长宽为label控件的长、宽
        img = QtGui.QPixmap(self.selected_imgPaths[0]).scaled(self.label_showImg.width(), self.label_showImg.height(), Qt.KeepAspectRatio,Qt.SmoothTransformation)
        # 提示点击生成
        self.label_condition.setText("请点击 开始检测")
        # 在label控件上显示选择的图片
        self.label_showImg.setPixmap(img)
        # 显示所选图片的路径
        self.lineEdit_imgPath.setText(self.selected_imgPaths[0])
        pageNum = len(self.selected_imgPaths)
        self.label_pageNum.setText(f"共 {pageNum} 页")
 
 
 
    # 选择图片文件夹上传
    def openImageFolder(self):
        self.selected_imgPaths = [] # 清空之前选择的所有图片
        self.generated_image_paths = [] # 清空之前推理生成的所有图片
        empty_pixmap = QPixmap()
        self.label_showImg.setPixmap(empty_pixmap)
        self.label_showImg2.setPixmap(empty_pixmap)
        # 弹出一个文件夹选择框,返回选中的文件夹路径
        selected_folder = QtWidgets.QFileDialog.getExistingDirectory(self, "选择文件夹", "./pending_images")
 
        if selected_folder:
            # 获取文件夹中的所有图片文件路径
            for file_name in os.listdir(selected_folder):
                if file_name.lower().endswith((".jpg", ".png")):
                    self.selected_imgPaths.append(os.path.join(selected_folder, file_name))
 
            # 通过第一个图片文件路径获取图片,并设置图片长宽为label控件的长、宽
            img = QtGui.QPixmap(self.selected_imgPaths[0]).scaled(self.label_showImg.width(), self.label_showImg.height(), Qt.KeepAspectRatio,Qt.SmoothTransformation)
            # 提示点击开始检测
            self.label_condition.setText("请点击 开始检测")
            # 在label控件上显示第一张图片
            self.label_showImg.setPixmap(img)
            # 显示所选图片的路径
            self.lineEdit_imgPath.setText(self.selected_imgPaths[0])
            pageNum = len(self.selected_imgPaths)
            self.label_pageNum.setText(f"共 {pageNum} 页")
        else:
            print('没有选择图片!')
            self.label_condition.setText("没有选择图片!")
            empty_pixmap = QPixmap()
            self.label_showImg.setPixmap(empty_pixmap)
            pageNum = 0
            self.label_pageNum.setText(f"共 {pageNum} 页")
            return
 
        
    def closeEvent(self, event):
        # 在这里执行你的函数
        self.delete_files_in_current_folder()
        if self.thread.is_alive():
            self.thread.join()  # 等待子线程完成
        # self.p.terminate()
        event.accept()
        
    # 删除中途产生的图片和docx文件
    def delete_files_in_current_folder(self):
    # 获取当前文件夹路径
        # current_folder = os.path.dirname(self.generated_docxFilePath)
        current_folder = "./result"
        # 获取当前文件夹中的所有文件
        if len(current_folder) == 0:
            print('没有报告生成')
            return
        file_list = os.listdir(current_folder)
 
        # 遍历文件列表
        for file_name in file_list:
            # 构建文件的绝对路径
            file_path = os.path.join(current_folder, file_name)
 
            # 判断是否是文件
            if os.path.isfile(file_path):
                # 删除文件
                os.remove(file_path)
 
# 自定义的工作线程类
class Worker(Process):
    # 生成对应预测的数字
    # 定义一个信号,用于在工作完成后发送通知
    # on_result = pyqtSignal(object,object,object)
    QApplication.processEvents()
    def __init__(self, q, selected_imgPaths,now):
        super().__init__()
        self.q = q
        self.selected_imgPaths = selected_imgPaths
        self.generated_image_paths = []
        self.text = {}
        self.generated_docxFilePath_List = []
        self.now = now
        # self.detector, self.classifier = self.create_acne_inference(acne_infer_config)
 
 
    
    def run(self):
        from Docx import GenerateDocx
        import os
        import cv2
        import math
        import utils
        import numpy as np
        from docx2pdf import convert
        from mmdeploy_runtime import Detector, Classifier
        from infer_config import acne_infer_config
        def create_acne_inference(cfg):
            QApplication.processEvents()
            self.detector = Detector(model_path=cfg['detector']['model_path'],
                                device_name=cfg['detector']['device_name'],
                                device_id=cfg['detector']['device_id'])
            QApplication.processEvents()
            self.classifier = Classifier(model_path=cfg['classifier']['model_path'],
                                    device_name=cfg['classifier']['device_name'],
                                    device_id=cfg['classifier']['device_id'])
            QApplication.processEvents()
            return self.detector, self.classifier
 
        def acne_instance_seg(img: np.ndarray, detector: Detector):
            QApplication.processEvents()
            win_gen = utils.WindowGenerator(img.shape[0], img.shape[1],
                                            INFER_WINDOW_SIZE[0], INFER_WINDOW_SIZE[1],
                                            INFER_WINDOW_STRIDES[0], INFER_WINDOW_STRIDES[1])
            QApplication.processEvents()
            p_bboxes, p_labels, p_masks = [], [], []
            for h_slice, w_slice in win_gen:
                QApplication.processEvents()
                img_patch = img[h_slice, w_slice, :]
                offset_x, offset_y = w_slice.start, h_slice.start
 
                b, l, m = detector(img_patch)
                b[:, [0, 2]] += offset_x
                b[:, [1, 3]] += offset_y
 
                p_bboxes.append(b)
                p_labels.append(l)
                p_masks.extend(m)
            p_bboxes = np.concatenate(p_bboxes, axis=0)
            p_labels = np.concatenate(p_labels, axis=0)
            p_masks = np.array(p_masks, dtype=object)
 
            bboxes, labels, masks = [], [], []
            cls = np.unique(p_labels)
            for c in cls:
                QApplication.processEvents()
                idx = p_labels == c
                b = p_bboxes[idx]
                l = p_labels[idx]
                m = p_masks[idx]
                keep = utils.nms(b, OVERLAP_NMS_THRESHOLD)
                bboxes.append(b[keep])
                labels.append(l[keep])
                masks.append(m[keep])
            bboxes = np.concatenate(bboxes, axis=0)
            labels = np.concatenate(labels, axis=0)
            masks = np.concatenate(masks, axis=0)
            return bboxes, labels, masks
 
 
        def acne_severity_grading(img: np.ndarray, classifier: Classifier):
            result = classifier(img)
            return result
        from infer_config import acne_infer_config
        detector, classifier = create_acne_inference(acne_infer_config)
        # 执行耗时的任务
        print("开始处理图片")
        QApplication.processEvents()
 
        # 模拟耗时的任务
    #    '''人脸严重程度分级'''
        grading_result = 0 # 从1开始的痤疮等级
        # count = 0
        # 判断是否选择了图片
        if len(self.selected_imgPaths)== 0:
            print("未选择图片")
            return
        
        for i in range(len(self.selected_imgPaths)):
            QApplication.processEvents()
            # count = i+1
            # self.label_showResult.setText(f'正在检测第{count}张图片')
            # self.label_condition.setText(f'请耐心等待,正在检测第{count}张图片')
            image = cv2.imread(self.selected_imgPaths[i])
            QApplication.processEvents()
            # self.detector, self.classifier = self.create_acne_inference(acne_infer_config)
            QApplication.processEvents()
            bboxes, labels, masks = acne_instance_seg(image, detector)
            QApplication.processEvents()
            cls_result = acne_severity_grading(image, classifier)
            QApplication.processEvents()
 
            grading_result = cls_result[0][0]+1
 
            indices = [i for i in range(len(bboxes))]
            QApplication.processEvents()
 
            category_count = {   
            'papule':0,
            'nevus':0,
            'nodule':0,
            'open_comedo':0,
            'closed_comedo':0,
            'atrophic_scar':0,
            'hypertrophic_scar':0,
            'melasma':0,
            'pustule':0,
            'other':0
            }
            
            for index, bbox, label_id in zip(indices, bboxes, labels):
                QApplication.processEvents()
                # print(count,index,bbox,label_id)
                [left, top, right, bottom], score = bbox[0:4].astype(int), bbox[4]
                if score < BBOX_DISPLAY_CONFIDENCE:
                    continue
                color = CATEGORY_COLOR[CATEGORY_INDEX[label_id]]
                cv2.rectangle(image, (left, top), (right, bottom), color)
 
                label_text = f"{CATEGORY_INDEX[label_id]} | {int(100 * score)}%"  # 使用痤疮的标签作为标注信息
                cv2.putText(image, label_text, (left, top - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1)  # 添加标注信息
 
                if masks[index].size:
                    mask = masks[index]
                    if mask.shape == image.shape[:2]:  # rtmdet-inst
                        mask_img = image.copy()
                    else:  # maskrcnn
                        x0 = int(max(math.floor(bbox[0]) - 1, 0))
                        y0 = int(max(math.floor(bbox[1]) - 1, 0))
                        mask_img = image[y0:y0 + mask.shape[0], x0:x0 + mask.shape[1]]
                    mask_img[mask.astype(bool)] = color
 
                category_count[CATEGORY_INDEX[label_id]] += 1
                
 
            text = f'Prediction: {cls_result[0][0]}, {cls_result[0][1]:.4f} ' \
                f'({acne_infer_config["classifier"]["classes"][cls_result[0][0]]})'
            
            cv2.putText(image, text, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 2)
 
            img_name = os.path.splitext(os.path.basename(self.selected_imgPaths[i]))[0]
            # from datetime import datetime
            # # 获取当前日期和时间
            # now = datetime.now()
            # 提取年、月和日
            year = self.now.year
            month = self.now.month
            day = self.now.day
            generated_image_path = f"./result/{img_name}_report_{year}_{month}_{day}.jpg"
        
            cv2.imwrite(generated_image_path , image)
            self.generated_image_paths.append(generated_image_path)
 
        
            closed_comedo_count = category_count['closed_comedo']
            open_comedo_count = category_count['open_comedo']
            papule_count = category_count['papule']
            pustule_count = category_count['pustule']
            nodule_count = category_count['nodule']
            atrophic_scar_count = category_count['atrophic_scar']
            hypertrophic_scar_count = category_count['hypertrophic_scar']
            melasma_count = category_count['melasma']
            nevus_count = category_count['nevus']
            other_count = category_count['other']
 
            self.text[img_name] = {
                "grading_result":grading_result,
                "category_count":{
                    "closed_comedo":closed_comedo_count,
                    "open_comedo":open_comedo_count,
                    "papule":papule_count,
                    "pustule":pustule_count,
                    "nodule":nodule_count,
                    "atrophic_scar":atrophic_scar_count,
                    "hypertrophic_scar":hypertrophic_scar_count,
                    "melasma":melasma_count,
                    "nevus":nevus_count,
                    "other":other_count
                }
            }
 
            '''生成报告'''
            #必须先生成docx文件再生成pdf文件,我的docx文件和产生的结果图片保存在同一个位置的
            grading_result = self.text[img_name]["grading_result"]
            category_count = self.text[img_name]["category_count"]
            docx_generate = GenerateDocx(generated_image_path,'./result',grading_result,category_count)
            generated_docxFilePath = docx_generate.predict()
            self.generated_docxFilePath_List.append(generated_docxFilePath)
        self.q.put(self.generated_image_paths)
        self.q.put(self.generated_docxFilePath_List)
        self.q.put(self.text)
        
 

进一步改进

主程序的退出位置:

改为

sys.exit(app.exec_())用于确保在退出应用程序时,所有的线程和进程都能被正确地终止。

与关闭事件关联的函数位置:

QApplication.quit()

Pyradiomics 医学影像提取放射组学特征(下) 阅读详情

相关推荐

PX4二次开发实战:从零构建自定义飞控模块

本文详细介绍了PX4二次开发的实战指南,从环境搭建到自定义飞控模块的创建,涵盖了uORB消息定义、外部传感器驱动集成、控制算法实现等关键步骤。通过具体代码示例和调试技巧,帮助开发者快速入门PX4二次开发,构建高效稳定的无人机飞控系统。

weixin_29175469的博客 339

Thread.join()用法

  python3内threading库引入了Thread类,包含了一系列方法,其中,对于join()方法一直不太理解。 文章目录**1.join()函数无参数时****2.join(x)内传递了变量x**,**总结:** 1.join()函数无参数时 主线程在所有引用join的线程结束后结束。 import _thread,time,threading from threading import Thread exitFlag = 0 class myThread (Thread)

ice123muxin的博客 2569

多孔材料吸附性质模拟程序RASPA的离线和在线安装方法

RASPA-2.0是今年美国西北大学教授Randall Q. Snurr等人开发的针对于MC,MD,分子力学优化等用途的程序,相比于之前开发的MUSIC软件,RASPA的功能更加齐全,操作更加简便,可以在MC的吸附过程中考虑骨架的柔性,也可以想MUSIC一样先制作积分格点(music中的map)。 A、离线安装(centos为例): (1)、安装之前要检查一下是否装了automake,

youyno的博客 1万+

Python多线程的理解和使用(一)Threading中join()函数的理解

转载自 https://blog.csdn.net/zhuzuwei/article/details/80927554 多线程的概念 多线程类似于同时执行多个不同程序,多线程运行有如下优点: 使用线程可以把占据长时间的程序中的任务放到后台去处理。 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度 程序的运行速度可能加快 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等

qq_42501075的博客 394

NPP/VIIRS夜间灯光数据下载和介绍

夜间灯光数据作为当前比较火热的研究数据,与其他遥感数据不同,它是通过DN值来体现所携带的信息,最常用的使用月度数据。 该数据数据量大,下载慢,相对来说较难快速获取。 一、数据下载 美国国家海洋大气管理局NOAA下属的NCEI国家环境信息中心Earth Observation Group。 二、月度数据文件介绍 从网站上下载的逐月的灯光数据文件是压缩包的形式,每月的数据包括vcm, vcmsl两个版本的压缩包,其中vcm版本排除了受杂散光影响的数据,vcmsl版本为辐射值经过杂散光校正程序后的数

端木宛白的博客家园 7376

Python Opencv cv2提取图像中某种特定颜色区域(例如黑字白纸背景下的红色公章提取),并将纯色背景透明化

拜拜PHOTOSHOP- 领导突然让我帮他把公章从图片中抠出来,在确保了不是要做坏事的情况下,我打开了PHOTOSHOP,用魔棒工具一点一点抠,但由于魔棒工具的原理是对比临近区域像素差值,导致封闭字体中的区域无法剔除,而且一点一点抠非常麻烦,愤而PYTHON,使用CV2完美解决。 效果如下(马赛克是我添加的): 任务就是把蓝色的公章抠出来。 效果如上。 代码如下: import cv2 import numpy as np src = cv2.imread(r"imagepath")#这里填你的原图像路

qq_43670549的博客 1万+

python线程join()方法使用

所以运行流程为:main线程启动-->thread1启动--->thread2启动--->thread1与2均阻塞main线程运行-->thread1与2并行运行-->thread1与2运行完毕--->main线程运行结束。时,target=get_target_html(), target=get_target_url()会自动实例化并。可以看出主线程在两个子线程运行完成之前就结束了,两个子线程继续执行直至完成。笔者在第一次写程序时,在调用两个子线程方法时。,类不带括号---赋值,带括号---实例化。

nairuozi的博客 3955

Redhawk: 为什么STA CHECK中switch cell覆盖率为0(STA file中switch control pin没有timing window)?

如题,做dynamic analysis时,不需要switch cell的timing window信息,但是做low power analysis需要做上电时switch cell的timing window就是必须的了,本文对switch cell control pin没有timing window (STA CHECK覆盖率为零)的这种现象做分析。

m0_61544122的博客 1197

Python多线程(四)——join属性

Python多线程之join()属性

重邮皮皮尛的博客 1782

【图像分类】卷积神经网络之VGGNet网络模型实现花卉图像识别(附代码和数据集,PyTorch框架)

卷积神经网络之VGGNet网络模型实现花卉图像识别(附代码和数据集,PyTorch框架)

学无止境、积少成多、厚积薄发 2431

R语言中如何获取前向选择(forward selection)选出的变量

前向选择是一种常用的特征选择方法,可以在给定一个预测模型的情况下,逐步添加变量来确定最佳的预测模型。在R语言中,可以使用适当的函数和库来执行前向选择,并获取选出的变量。以下是一个详细的步骤,展示了如何使用R语言执行前向选择并获得选出的变量。通过按照上述步骤,你可以使用R语言执行前向选择,并获取选出的变量。记住,前向选择是一种特征选择方法,可以根据不同的评估指标选择最佳的预测模型。接下来,准备用于前向选择的数据。使用"summary"函数查看前向选择的摘要,并使用"which"函数获取被选中的变量。

WangWEel的博客 924

【PyQt】multiprocessing.Queue进程退出问题

弃用multiprocessing.Queue,改用multiprocessing.Manager().Queue.子进程中使用了multiprocessing.Queue,主页面退出时无法完全退出,留有僵尸进程。查资料multiprocessing.Manager().Queue表现更稳定,以后尽量使用这个。

不吃鱼的小时喵 633

基于Simulink的光伏+储能家庭能源管理系统仿真

本文通过Simulink建模,分析了家庭光伏+储能系统的优化调度问题。针对光伏发电与用电高峰不匹配导致电费节省有限的问题,构建了包含5kW光伏、10kWh电池和6kW负荷的完整模型,设计了无控、规则控制和24小时经济优化三种策略。仿真结果显示,经济优化策略可使日电费降低32%,光伏自用率从45%提升至89%,尤其在晚高峰时段能显著减少高价购电。文章详细介绍了物理层建模、分时电价实现和控制策略设计方法,并探讨了天气预测、V2H等高级扩展功能,为家庭能源智能管理提供了实用解决方案。

xiaoheshang_123的博客 188

Android进程相关资料

android中进程的分级: 1.前台进程:如ireader程序就是前台就是前台进程,这些进程是不会被系统优先结束的,当我们把它切到后台时,那么它就变成了后台进程 2.可见进程:如输入法等程序,一般这些程序的显示界面都是隐藏起来的,但当我们开始输入文字时,它很快就会弹出来 3.主要服务:如电话、短信等,这些主要服务平时也不会被系统自动结束的,除非你自己关闭它,但是关闭了之后它自己也会重新加载...

huang_wei_cai的专栏 124

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

命名管道FIFO与进程池:打造多进程任务分发系统实战

进程间通信(IPC)是Linux多进程编程的基石,它决定了进程间如何安全、高效地交换数据。在众多IPC方式中,命名管道(FIFO)通过文件系统提供通信入口,打破了匿名管道必须依赖父子进程血缘关系的限制,让任意进程都能按路径读写,实现解耦协作。然而,实际工程中仅理解API远不够,阻塞语义、粘包、僵尸进程等问题常让任务分发系统崩溃。将命名管道与进程池架构结合,既能复用预启动的worker进程避免频繁fork的开销,又能通过消息协议和有序的open流程保障双向通信稳定。这种设计广泛适用于任务队列、调度器、轻量级分

weixin_30431445的博客 281

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Dask 共享内存调度器(Shared Memory Scheduler)完全指南:异步调度策略、性能开销与多进程/多线程选型

本文深入讲解 Dask 的共享内存异步调度器(asynchronous shared-memory scheduler),这是 Dask 在**单机多核**场景下执行任务图的核心引擎,也是 `dask.threaded.get`、`dask.multiprocessing.get` 与 `dask.get` 三个入口的共同底座。读完本文,你将掌握该调度器基于 `concurrent.futures

gitblog_00300的博客 927

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

python标准库、threading、multiprocessing、aiomultiprocess、进程/线程 同步、queue(队列)

multiprocessing 包提供了本地和远程并发操作,通过使用子进程而非线程有效地绕过了全局解释器锁。 因此,multiprocessing 模块允许程序员充分利用给定机器上的多个处理器。

freeking101的博客 2万+

QT系列(五)

在进行桌面应用程序开发的时候, 假设应用程序在某些情况下需要处理比较复杂的逻辑如果只有一个线程去处理,就会导致窗口卡顿无法处理用户的相关操作。这种情况下就需要使用多线程,其中一个线程处理窗口事件其他线程进行逻辑运算,多个线程各司其职,不仅可以提高用户体验还可以提升程序的执行效率。默认的线程在Qt中称之为窗口线程,也叫主线程,有时候也称之ui线程负责窗口事件处理或者窗口控件数据的更新子线程负责后台的业务逻辑处理,子线程中不能对窗口对象做任何操作,这些事情需要交给窗口线程处理。

m0_57794197的博客 1187

Godot引擎集成CEF:实现游戏与Web混合渲染的完整指南

在现代应用开发中,跨平台渲染与交互技术是连接不同生态系统的关键。其核心原理在于通过进程间通信与图形API共享,将独立的渲染管线进行桥接,实现视觉与逻辑的统一。这项技术的价值在于能够突破单一框架的限制,让高性能的本地应用与动态、丰富的Web内容无缝融合。典型的应用场景包括游戏内嵌复杂UI、工具软件集成Web编辑器、以及数字孪生系统中的实时数据可视化仪表盘。本文聚焦于通过Chromium Embedded Framework(CEF)为Godot游戏引擎注入完整的Web能力,深入剖析了其**分层架构设计**与*

weixin_30326515的博客 682

五年Android开发,让我“刻骨铭心”的那些坑

&nbsp;前言&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这篇文章是本人对在开发过程中踩坑经历的一次总结;分为系统API的坑、使用不当导致的坑、开源项目中的坑等几个方面,知识面有限,认知难免会有偏颇,如发现有问题还请指正。1&amp

贵公子丶笔记 791

Linux进程控制实战:从D状态排障到fork、僵尸进程与cgroup

在Linux系统运维中,进程控制是排查性能问题的核心技能。当服务器负载飙升但CPU空闲时,往往意味着大量进程陷入D状态(不可中断睡眠),正等待IO完成。理解进程的创建与回收机制,如fork的写时复制、僵尸进程的产生与治理,以及通过nice、cgroup限制资源使用,是保障系统稳定性的基础。同时,掌握进程间通信(管道、信号、共享内存)和ps、top、strace等排查工具,能帮助定位进程卡住的根因。本文从实际排障案例出发,系统梳理进程生命周期、状态切换、优先级、资源限额及工程防治方案,帮助运维和开发人员构建完

weixin_31309419的博客 265

Python线程实战指南:GIL约束、ThreadPoolExecutor与线程安全通信

线程是实现并发编程的基础机制,其核心在于操作系统级的抢占式调度与共享内存模型;在Python中,受CPython解释器GIL(全局解释器锁)限制,线程仅对I/O密集型任务有效,而无法加速CPU密集型计算;理解GIL的本质约束与`threading`模块的设计边界,是规避性能陷阱的关键;技术价值体现在资源复用、异步等待解耦与轻量级并发控制上;典型应用场景包括Web请求批量采集、日志轮询监控、GUI响应保活及阻塞式第三方库调用;本文聚焦真实工程问题,深入解析`ThreadPoolExecutor`替代裸`Thr

weixin_33755557的博客 330

Python循环绘图实战:从实时监控到性能优化

在数据分析和算法开发中,实时可视化是理解动态过程的关键技术。其核心原理是通过程序循环迭代,将计算过程中的数据变化实时映射到图形界面,实现从静态图表到动态监控的转变。这项技术的价值在于能够打破传统“黑盒”计算的局限,让开发者能够直观观察模型训练、物理模拟或优化算法的收敛趋势,及时发现问题并调整参数。从应用场景来看,循环绘图广泛应用于机器学习模型训练监控、长时间运行的数值模拟、实时数据流分析等领域。本文聚焦于Python生态下的实现方案,深入探讨了Matplotlib和Plotly等工具在构建实时监控系统时的核

weixin_34185512的博客 397

Python网络数据安全分析毕设:从抓包到机器学习检测的完整实现

网络数据安全分析是网络安全领域的核心实践,其原理在于通过对网络流量进行深度解析与模式识别,发现潜在威胁。从技术价值看,它不仅是防火墙、入侵检测系统等传统安全措施的补充,更是实现主动防御和态势感知的关键。在应用场景上,广泛用于企业安全运营中心、云平台威胁监控以及物联网设备防护。本文聚焦使用Python实现网络数据安全分析毕设项目,详细讲解如何利用Scapy进行数据采集,结合pandas进行特征工程,并集成机器学习模型构建实时检测引擎,最终通过Flask搭建可视化防御仪表盘,为构建微型SOC系统提供完整解决方案

weixin_30765505的博客 400

Python多线程实战:解决AI助手排队问题,提升I/O密集型任务并发性能

在软件开发中,并发编程是提升程序性能的核心技术之一,尤其对于需要处理多个任务的应用程序。其基本原理在于允许程序同时执行多个操作,而非顺序执行,从而更高效地利用系统资源。对于I/O密集型任务,如网络请求、文件读写等,多线程技术能显著减少等待时间,提升整体吞吐量。在Python生态中,通过 threading 模块和 concurrent.futures 模块提供的 ThreadPoolExecutor,开发者可以便捷地实现线程池,管理并发任务。这项技术的核心价值在于优化响应速度与资源利用率,广泛应用于Web服

weixin_33827731的博客 375

昇腾Atlas 300V 24G推理卡部署YOLO全流程解析

在AI推理场景中,算力硬件与模型部署路径的选型至关重要。华为昇腾平台的Atlas 300V 24G作为一款专用的神经网络推理加速卡,凭借NPU架构与24GB大容量内存,为高吞吐低延迟的推理任务提供了新的选择。不同于传统GPU,它将训练好的模型通过ATC工具转换为OM离线格式,并基于CANN软件栈与AscendCL接口高效调度。这种预编译的部署模式不仅降低了运行时的框架依赖,也提升了稳定性与能效比。在智慧安防、工业质检、视频分析等实时目标检测场景中,将YOLO模型部署到Atlas 300V是算法工程师关注的热

weixin_29047919的博客 323
上一篇: 服务器 Linux常见指令
下一篇: 多进程传递数据的简单案例
pythonSuperman
博客等级 码龄6年 7764粉丝 499原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值