QTdesigner前后端交互–结节算法实战

  • Post author:
  • Post category:其他



目录


前端界面与后台功能对接


功能1:点击button后,实现界面跳转(不卡顿)


功能2:选择文件路径按钮,并将选择后的路径显示在文本框中。


功能3:【上传】按钮,将本地的文件上传到服务器中,实现进度条显示


功能4:在lable区域读出CT图像后,用鼠标事件,添加 绘图功能,绘制十字坐标线。


功能5. 从服务器下载检测结果到本地,seeJJ.py


功能6:实现 菜单栏的各个跳转功能


功能7:python与excle表格交互:读取信息 + python读写操作


功能8:从服务器下载文件到本地


功能9:从服务器下载结节文件,列表读取本地文件


功能10 :添加【软件说明】界面,添加新界面,并将新界面的button功能实现


功能11:生成报告。python将信息写入word文档。


功能12:选中结节和取消选中 的样式改变,选中后及时保存选中文件


功能13:登录界面的跳转(project-hjq)


功能14:添加新界面,并实现其中的各个功能。


功能15:添加登录界面,账号密码登陆成功实现跳转


功能16:下拉框选中文字,实现在文本框中自动粘贴的功能。


功能17:克服桶排序。显示前24个结节。


前端界面与后台功能对接

1.前端代码

由QTdesigner生成

的ui文件,经过命令行产生,我们不妨 放在ui文件夹下,ui\seekJJ.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'SeekJJ.ui'
#
# Created by: PyQt5 UI code generator 5.15.3
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(814, 694)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("../image/icon.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        MainWindow.setWindowIcon(icon)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout_9 = QtWidgets.QHBoxLayout(self.centralwidget)
        self.horizontalLayout_9.setObjectName("horizontalLayout_9")
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setMaximumSize(QtCore.QSize(250, 16777215))
        self.groupBox.setTitle("")
        self.groupBox.setObjectName("groupBox")
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.groupBox)
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetMaximumSize)
        self.verticalLayout.setObjectName("verticalLayout")
        self.read_ct_label = QtWidgets.QLabel(self.groupBox)
        self.read_ct_label.setMinimumSize(QtCore.QSize(0, 35))
        self.read_ct_label.setMaximumSize(QtCore.QSize(16777215, 40))
        font = QtGui.QFont()
        font.setFamily("黑体")
        font.setPointSize(12)
        self.read_ct_label.setFont(font)
        self.read_ct_label.setStyleSheet("background-color:rgb(190, 217, 238)")
        self.read_ct_label.setAlignment(QtCore.Qt.AlignCenter)
        self.read_ct_label.setObjectName("read_ct_label")
        self.verticalLayout.addWidget(self.read_ct_label)
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.ct_path = QtWidgets.QLineEdit(self.groupBox)
        self.ct_path.setMinimumSize(QtCore.QSize(0, 30))
        self.ct_path.setObjectName("ct_path")
        self.horizontalLayout_6.addWidget(self.ct_path)
        self.verticalLayout.addLayout(self.horizontalLayout_6)
        self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_7.addItem(spacerItem)
        self.choose_ct_path = QtWidgets.QPushButton(self.groupBox)
        self.choose_ct_path.setMinimumSize(QtCore.QSize(0, 30))
        self.choose_ct_path.setObjectName("choose_ct_path")
        self.horizontalLayout_7.addWidget(self.choose_ct_path)
        self.upload_ct = QtWidgets.QPushButton(self.groupBox)
        self.upload_ct.setMinimumSize(QtCore.QSize(0, 30))
        self.upload_ct.setObjectName("upload_ct")
        self.horizontalLayout_7.addWidget(self.upload_ct)
        self.verticalLayout.addLayout(self.horizontalLayout_7)
        self.upload_progressBar = QtWidgets.QProgressBar(self.groupBox)
        self.upload_progressBar.setProperty("value", 0)
        self.upload_progressBar.setObjectName("upload_progressBar")
        self.verticalLayout.addWidget(self.upload_progressBar)
        self.now_layers_label = QtWidgets.QLabel(self.groupBox)
        self.now_layers_label.setObjectName("now_layers_label")
        self.verticalLayout.addWidget(self.now_layers_label)
        self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.ajust_layer_label = QtWidgets.QLabel(self.groupBox)
        self.ajust_layer_label.setMinimumSize(QtCore.QSize(0, 30))
        self.ajust_layer_label.setObjectName("ajust_layer_label")
        self.horizontalLayout_5.addWidget(self.ajust_layer_label)
        self.layer_slider = QtWidgets.QSlider(self.groupBox)
        self.layer_slider.setMinimumSize(QtCore.QSize(0, 25))
        self.layer_slider.setOrientation(QtCore.Qt.Horizontal)
        self.layer_slider.setObjectName("layer_slider")
        self.horizontalLayout_5.addWidget(self.layer_slider)
        self.verticalLayout.addLayout(self.horizontalLayout_5)
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.ajust_light_label = QtWidgets.QLabel(self.groupBox)
        self.ajust_light_label.setObjectName("ajust_light_label")
        self.horizontalLayout_4.addWidget(self.ajust_light_label)
        self.light_slider = QtWidgets.QSlider(self.groupBox)
        self.light_slider.setMinimumSize(QtCore.QSize(0, 25))
        self.light_slider.setOrientation(QtCore.Qt.Horizontal)
        self.light_slider.setObjectName("light_slider")
        self.horizontalLayout_4.addWidget(self.light_slider)
        self.verticalLayout.addLayout(self.horizontalLayout_4)
        spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem1)
        self.ct_pre_deal_label = QtWidgets.QLabel(self.groupBox)
        self.ct_pre_deal_label.setMinimumSize(QtCore.QSize(0, 35))
        self.ct_pre_deal_label.setMaximumSize(QtCore.QSize(16777215, 40))
        font = QtGui.QFont()
        font.setFamily("黑体")
        font.setPointSize(12)
        self.ct_pre_deal_label.setFont(font)
        self.ct_pre_deal_label.setStyleSheet("background-color:rgb(190, 217, 238)")
        self.ct_pre_deal_label.setAlignment(QtCore.Qt.AlignCenter)
        self.ct_pre_deal_label.setObjectName("ct_pre_deal_label")
        self.verticalLayout.addWidget(self.ct_pre_deal_label)
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.generate_mhd = QtWidgets.QPushButton(self.groupBox)
        self.generate_mhd.setMinimumSize(QtCore.QSize(0, 30))
        self.generate_mhd.setObjectName("generate_mhd")
        self.horizontalLayout_3.addWidget(self.generate_mhd)
        self.verticalLayout.addLayout(self.horizontalLayout_3)
        self.generate_clean_label = QtWidgets.QPushButton(self.groupBox)
        self.generate_clean_label.setMinimumSize(QtCore.QSize(0, 30))
        self.generate_clean_label.setObjectName("generate_clean_label")
        self.verticalLayout.addWidget(self.generate_clean_label)
        self.generate_lbb_pbb = QtWidgets.QPushButton(self.groupBox)
        self.generate_lbb_pbb.setMinimumSize(QtCore.QSize(0, 30))
        self.generate_lbb_pbb.setObjectName("generate_lbb_pbb")
        self.verticalLayout.addWidget(self.generate_lbb_pbb)
        spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem2)
        self.vessel_apart_label = QtWidgets.QLabel(self.groupBox)
        self.vessel_apart_label.setMinimumSize(QtCore.QSize(0, 35))
        self.vessel_apart_label.setMaximumSize(QtCore.QSize(16777215, 40))
        font = QtGui.QFont()
        font.setFamily("黑体")
        font.setPointSize(12)
        self.vessel_apart_label.setFont(font)
        self.vessel_apart_label.setStyleSheet("background-color:rgb(190, 217, 238)")
        self.vessel_apart_label.setAlignment(QtCore.Qt.AlignCenter)
        self.vessel_apart_label.setObjectName("vessel_apart_label")
        self.verticalLayout.addWidget(self.vessel_apart_label)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.ct_2_jpg = QtWidgets.QPushButton(self.groupBox)
        self.ct_2_jpg.setMinimumSize(QtCore.QSize(0, 30))
        self.ct_2_jpg.setObjectName("ct_2_jpg")
        self.horizontalLayout_2.addWidget(self.ct_2_jpg)
        self.verticalLayout.addLayout(self.horizontalLayout_2)
        self.vessel_line_mark = QtWidgets.QPushButton(self.groupBox)
        self.vessel_line_mark.setMinimumSize(QtCore.QSize(0, 30))
        self.vessel_line_mark.setObjectName("vessel_line_mark")
        self.verticalLayout.addWidget(self.vessel_line_mark)
        self.line_deal = QtWidgets.QPushButton(self.groupBox)
        self.line_deal.setMinimumSize(QtCore.QSize(0, 30))
        self.line_deal.setObjectName("line_deal")
        self.verticalLayout.addWidget(self.line_deal)
        spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem3)
        self.generate_jj_zb_label = QtWidgets.QLabel(self.groupBox)
        self.generate_jj_zb_label.setMinimumSize(QtCore.QSize(0, 35))
        self.generate_jj_zb_label.setMaximumSize(QtCore.QSize(16777215, 40))
        font = QtGui.QFont()
        font.setFamily("黑体")
        font.setPointSize(12)
        self.generate_jj_zb_label.setFont(font)
        self.generate_jj_zb_label.setStyleSheet("background-color:rgb(190, 217, 238)")
        self.generate_jj_zb_label.setAlignment(QtCore.Qt.AlignCenter)
        self.generate_jj_zb_label.setObjectName("generate_jj_zb_label")
        self.verticalLayout.addWidget(self.generate_jj_zb_label)
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.generate_jj_zb = QtWidgets.QPushButton(self.groupBox)
        self.generate_jj_zb.setMinimumSize(QtCore.QSize(0, 30))
        self.generate_jj_zb.setObjectName("generate_jj_zb")
        self.horizontalLayout.addWidget(self.generate_jj_zb)
        self.see_jjzb = QtWidgets.QPushButton(self.groupBox)
        self.see_jjzb.setMinimumSize(QtCore.QSize(0, 30))
        self.see_jjzb.setObjectName("see_jjzb")
        self.horizontalLayout.addWidget(self.see_jjzb)
        self.verticalLayout.addLayout(self.horizontalLayout)
        spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem4)
        self.horizontalLayout_8.addLayout(self.verticalLayout)
        self.horizontalLayout_9.addWidget(self.groupBox)
        self.ct_img = PaintArea(self.centralwidget)
        self.ct_img.setMinimumSize(QtCore.QSize(600, 600))
        self.ct_img.setText("")
        self.ct_img.setScaledContents(False)
        self.ct_img.setAlignment(QtCore.Qt.AlignCenter)
        self.ct_img.setObjectName("ct_img")
        self.horizontalLayout_9.addWidget(self.ct_img)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 814, 23))
        self.menubar.setObjectName("menubar")
        self.file_menu = QtWidgets.QMenu(self.menubar)
        self.file_menu.setObjectName("file_menu")
        self.seek_jj_menu = QtWidgets.QMenu(self.menubar)
        self.seek_jj_menu.setObjectName("seek_jj_menu")
        self.classify_jj_menu = QtWidgets.QMenu(self.menubar)
        self.classify_jj_menu.setObjectName("classify_jj_menu")
        self.setting_menu = QtWidgets.QMenu(self.menubar)
        self.setting_menu.setObjectName("setting_menu")
        self.help_menu = QtWidgets.QMenu(self.menubar)
        self.help_menu.setObjectName("help_menu")
        MainWindow.setMenuBar(self.menubar)
        self.exit_action = QtWidgets.QAction(MainWindow)
        self.exit_action.setObjectName("exit_action")
        self.seek_jj_action = QtWidgets.QAction(MainWindow)
        self.seek_jj_action.setObjectName("seek_jj_action")
        self.cut_jj_action = QtWidgets.QAction(MainWindow)
        self.cut_jj_action.setObjectName("cut_jj_action")
        self.classify_jj_action = QtWidgets.QAction(MainWindow)
        self.classify_jj_action.setObjectName("classify_jj_action")
        self.to_index_action = QtWidgets.QAction(MainWindow)
        self.to_index_action.setObjectName("to_index_action")
        self.file_menu.addAction(self.to_index_action)
        self.file_menu.addAction(self.exit_action)
        self.seek_jj_menu.addAction(self.seek_jj_action)
        self.seek_jj_menu.addAction(self.cut_jj_action)
        self.classify_jj_menu.addAction(self.classify_jj_action)
        self.menubar.addAction(self.file_menu.menuAction())
        self.menubar.addAction(self.seek_jj_menu.menuAction())
        self.menubar.addAction(self.classify_jj_menu.menuAction())
        self.menubar.addAction(self.setting_menu.menuAction())
        self.menubar.addAction(self.help_menu.menuAction())

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "肺结节多种病理类型人工智能检测系统"))
        self.read_ct_label.setText(_translate("MainWindow", "读取CT文件"))
        self.choose_ct_path.setText(_translate("MainWindow", "选择CT路径"))
        self.upload_ct.setText(_translate("MainWindow", "上传CT"))
        self.now_layers_label.setText(_translate("MainWindow", "当前层数:0/0"))
        self.ajust_layer_label.setText(_translate("MainWindow", "调整层数:"))
        self.ajust_light_label.setText(_translate("MainWindow", "调整亮度:"))
        self.ct_pre_deal_label.setText(_translate("MainWindow", "影像预处理"))
        self.generate_mhd.setText(_translate("MainWindow", "生成mhd"))
        self.generate_clean_label.setText(_translate("MainWindow", "生成clean和label"))
        self.generate_lbb_pbb.setText(_translate("MainWindow", "生成lbb和pbb"))
        self.vessel_apart_label.setText(_translate("MainWindow", "血管分割"))
        self.ct_2_jpg.setText(_translate("MainWindow", "影像生成图片"))
        self.vessel_line_mark.setText(_translate("MainWindow", "血管轮廓标记"))
        self.line_deal.setText(_translate("MainWindow", "轮廓处理"))
        self.generate_jj_zb_label.setText(_translate("MainWindow", "生成结节坐标"))
        self.generate_jj_zb.setText(_translate("MainWindow", "生成结节坐标"))
        self.see_jjzb.setText(_translate("MainWindow", "查看结节坐标"))
        self.file_menu.setTitle(_translate("MainWindow", "文件"))
        self.seek_jj_menu.setTitle(_translate("MainWindow", "肺结节检测"))
        self.classify_jj_menu.setTitle(_translate("MainWindow", "分类诊断"))
        self.setting_menu.setTitle(_translate("MainWindow", "设置"))
        self.help_menu.setTitle(_translate("MainWindow", "帮助"))
        self.exit_action.setText(_translate("MainWindow", "退出"))
        self.exit_action.setShortcut(_translate("MainWindow", "Esc"))
        self.seek_jj_action.setText(_translate("MainWindow", "肺结节检测"))
        self.cut_jj_action.setText(_translate("MainWindow", "裁剪肺结节"))
        self.classify_jj_action.setText(_translate("MainWindow", "肺结节影像良恶性诊断"))
        self.to_index_action.setText(_translate("MainWindow", "系统首页"))
from frame.myQLabel import PaintArea

2.后端代码由我们新建,frame\seekJJ.py

导入本界面

from ui.SeekJJ import Ui_MainWindow

然后对里面的button函数的书写构造。线程类和函数类。

class UploadThread(QThread):
    sigout = pyqtSignal(float)

    def __init__(self):
        super().__init__()
        self.nativePath = ''
        self.uploadPath = ''

    def run(self):
        n = 0
        fileLength = len(os.listdir(self.nativePath)) - 1
        for i in os.listdir(self.nativePath):
            print(self.nativePath+i)
            sftp.put(self.nativePath + i, self.uploadPath + i)
            self.sigout.emit((n/fileLength)*100)
            n += 1

记得这段代码:调用界面的,下面会说到。 def __init__(self, parent=None):函数初始化各个参数用的。

    def __init__(self, parent=None):
        super().__init__(parent)  # 调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  # 创建UI对象

界面
标题

界面中的相关按键的函数实现。

在新界面中的

class SeeJJ(QMainWindow):类

表示这是个新窗口类  SeekJJ.show()函数就是打开这个界面的

class SeekJJ(QMainWindow):
    def resizeEvent(self, e):
        try:
            img = QPixmap(self.ct_file)
            width = self.ui.ct_img.width()
            height = self.ui.ct_img.height()
            if img is None:
                return
            if width > height:
                small = height
            else:
                small = width
            self.ct_img_small_size = small
            img = img.scaled(small, small, Qt.KeepAspectRatio, Qt.SmoothTransformation)
            self.ui.ct_img.setPixmap(img)
            self.ui.ct_img.ct2mark()
        except Exception as e:
            print(e)

    def __init__(self, parent=None):
        super().__init__(parent)  # 调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  # 创建UI对象
        self.ui.setupUi(self)  # 构造UI界面
        self.serverWorkSpace = 'E:/LYC/lungDetection-V1/'
        self.upload_thread = UploadThread()
        self.upload_thread.uploadPath = self.serverWorkSpace + 'detection/test_mask/0006/'
        self.serverPython = 'D:/ProgramData/Anaconda3/envs/lung/python'
        self.ct_path_text = ''
        self.picSize = 0

        # self.ct_img_small_size = 512
        self.ct_file = ''
        width = self.ui.ct_img.width()
        height = self.ui.ct_img.height()
        self.ui.ct_img.slider = self.ui.layer_slider
        if width > height:
            self.ct_img_small_size = height
        else:
            self.ct_img_small_size = width

        self.function()

    def function(self):
        self.ui.choose_ct_path.clicked.connect(lambda: self._choose_ct_path())
        self.ui.upload_ct.clicked.connect(lambda: self._upload_ct())
        self.ui.generate_mhd.clicked.connect(lambda: self._generate_mhd())
        self.ui.generate_clean_label.clicked.connect(lambda: self._generate_clean_lable())
        self.ui.generate_lbb_pbb.clicked.connect(lambda: self._generate_lbb_pbb())
        self.ui.ct_2_jpg.clicked.connect(lambda: self._ct_2_jpg())
        self.ui.vessel_line_mark.clicked.connect(lambda: self._vessel_line_mark())
        self.ui.line_deal.clicked.connect(lambda: self._line_deal())
        self.ui.generate_jj_zb.clicked.connect(lambda: self._generate_jj_zb())
        self.ui.layer_slider.valueChanged.connect(self._layer_slider_changed)
        self.ui.see_jjzb.clicked.connect(lambda: self._to_see_jjzb())
        self.ui.menubar.triggered[QAction].connect(self.processtrigger)

    def _to_see_jjzb(self):
        self.seeJJ = SeeJJ()
        self.close()
        self.seeJJ.show()

    def _layer_slider_changed(self, value):
        if self.ct_path_text == '':
            return
        self.ct_file = "../picture/%d.jpg" % (value+1)
        img = QtGui.QPixmap(self.ct_file)
        img = img.scaled(self.ct_img_small_size, self.ct_img_small_size, Qt.KeepAspectRatio)
        self.ui.ct_img.setPixmap(img)
        self.ui.now_layers_label.setText('当前层数:' + str(value+1) + '/' + str(self.picSize))

    def _choose_ct_path(self):
        try:
            self.ct_path_text = QFileDialog.getExistingDirectory(None, '请选择CT文件路径')
            if self.ct_path_text != "":
                for i in os.listdir('../picture/'):
                    os.remove('../picture/' + i)
                self.picSize = len(os.listdir(self.ct_path_text))
                for i, id in enumerate(os.listdir(self.ct_path_text)):
                    RefDs = sitk.ReadImage(self.ct_path_text + '/' + id)
                    data = sitk.GetArrayFromImage(RefDs)[0]
                    ###
                    data = (np.minimum(np.maximum(data, -1000), 400) + 1000)/5.46875
                    cv2.imwrite('../picture/%s.jpg' % (self.picSize-i), data, [int(cv2.IMWRITE_JPEG_QUALITY), 100])
            else:
                return
            self.ui.ct_path.setText(self.ct_path_text)
            self.upload_thread.nativePath = self.ct_path_text + '/'
            self.ui.layer_slider.setMaximum(self.picSize-1)
            self.ui.layer_slider.setMinimum(0)
            self.ui.now_layers_label.setText('当前层数:1/' + str(self.picSize))
            self.ct_file = "../picture/1.jpg"
            img = QtGui.QPixmap(self.ct_file)
            img = img.scaled(self.ct_img_small_size, self.ct_img_small_size, Qt.KeepAspectRatio)
            self.ui.ct_img.setPixmap(img)
        except Exception as e:
            print(e)

    def _upload_ct(self):
        try:
            if self.ui.ct_path.text() == '':
                QMessageBox().information(self, '提示', '请选择CT文件路径', QMessageBox.Yes)
                # QtWidgets.QMessageBox(QMessageBox.Warning, '提示', '请选择CT文件路径').exec_()
                return

            stdin, stdout, stderr = ssh.exec_command('cd ' + self.serverWorkSpace + ';python clearCT.py')
            print(stdout.read())
            print(stderr.read())

            self.upload_thread.start()
            self.upload_thread.sigout.connect(self._change_progress)
        except Exception as e:
            print(e)

    def _change_progress(self, value):
        self.ui.upload_progressBar.setValue(value)
        print(value)
        if value == 100:
            QMessageBox().information(self, '提示', "上传完成", QMessageBox.Yes)

    def _generate_mhd(self):
        try:
            stdin, stdout, stderr = ssh.exec_command('cd ' + self.serverWorkSpace +
                                                     'detection/;' + self.serverPython + ' dcm2mhd.py')
            print(stdout.read())
            print(stderr.read())
            QMessageBox().information(self, '提示', "成功生成mhd文件", QMessageBox.Yes)
        except Exception as e:
            print(e)

    def _generate_clean_lable(self):
        try:
            print('cd ' + self.serverWorkSpace + 'detection/;' + self.serverPython + ' prepares.py')
            stdin, stdout, stderr = ssh.exec_command('cd ' + self.serverWorkSpace +
                                                     'detection/;' + self.serverPython + ' prepares.py')
            print(stdout.read())
            print(stderr.read())

            QMessageBox().information(self, '提示', "成功生成clean和label文件", QMessageBox.Yes)
        except Exception as e:
            print(e)

    def _generate_lbb_pbb(self):
        try:
            stdin, stdout, stderr = ssh.exec_command('cd ' + self.serverWorkSpace +
                                                     'detection/;' + self.serverPython + ' detections.py')
            print(stdout.read())
            print(stderr.read())
            QMessageBox().information(self, '提示', "成功生成lbb和pbb文件", QMessageBox.Yes)
        except Exception as e:
            print(e)

    def _ct_2_jpg(self):
        try:
            stdin, stdout, stderr = ssh.exec_command('cd ' + self.serverWorkSpace +
                                                     'vessel_seg/;' + self.serverPython + ' FrangiFilter2D.py')
            print(stdout.read())
            print(stderr.read())
            QMessageBox().information(self, '提示', "成功生成影像图片", QMessageBox.Yes)
        except Exception as e:
            print(e)

    def _vessel_line_mark(self):
        try:
            stdin, stdout, stderr = ssh.exec_command('cd ' + self.serverWorkSpace +
                                                     'vessel_seg/;' + self.serverPython + ' meijering.py')
            print(stdout.read())
            print(stderr.read())
            QMessageBox().information(self, '提示', "成功标记血管轮廓", QMessageBox.Yes)
        except Exception as e:
            print(e)

    def _line_deal(self):
        try:
            stdin, stdout, stderr = ssh.exec_command('cd ' + self.serverWorkSpace +
                                                     'vessel_seg/;' + self.serverPython + ' vesselMask.py')
            print(stdout.read())
            print(stderr.read())
            QMessageBox().information(self, '提示', "成功处理轮廓", QMessageBox.Yes)
        except Exception as e:
            print(e)

    def _generate_jj_zb(self):
        try:
            stdin, stdout, stderr = ssh.exec_command('cd ' + self.serverWorkSpace +
                                                     'merge/;' + self.serverPython + ' Isvessel.py')
            print(stdout.read())
            print(stderr.read())
            QMessageBox().information(self, '提示', "成功生成结节坐标", QMessageBox.Yes)
        except Exception as e:
            print(e)

    def processtrigger(self, action):
        if action.text() == '退出':
            self.close()
        elif action.text() == '系统首页':
            pass
        elif action.text() == '裁剪结节':
            pass
        elif action.text() == '肺结节影像良恶性诊断':
            pass


# ============窗体测试程序 ================================
if __name__ == "__main__":  # 用于当前窗体测试
    app = QApplication(sys.argv)  # 创建GUI应用程序
    form = SeekJJ()  # 创建窗体
    form.show()
    sys.exit(app.exec_())


功能1

:点击button后,实现界面跳转(不卡顿)

函数:

    def _to_see_jjzb(self):
# 在class SeekJJ(QMainWindow)下,需要self表示当前类
        self.seeJJ = SeeJJ() # 打开seeJJ界面
        self.close()         # 当前界面关闭
        self.seeJJ.show()    # seeJJ界面开启

点击 【查看结节坐标界面】,

self.ui.see_jjzb.clicked.connect(lambda: self._to_see_jjzb())

ui.SeekJJ.py界面的相关接口:(在做ui时自动生成的)

        self.see_jjzb = QtWidgets.QPushButton(self.groupBox)
        self.see_jjzb.setMinimumSize(QtCore.QSize(0, 30))
        self.see_jjzb.setObjectName("see_jjzb")
        self.horizontalLayout.addWidget(self.see_jjzb)

.setText函数里面的参数设置了button的名字

        self.see_jjzb.setText(_translate("MainWindow", "查看结节坐标"))

功能2:选择文件路径按钮,并将选择后的路径显示在文本框中。

功能2.

前端选择CT路径的button的触发事件函数:

    def function(self):
        self.ui.choose_ct_path.clicked.connect(lambda: self._choose_ct_path())

选择CT路径的触发函数

    def _choose_ct_path(self):
        try:
            # 弹出选择文件夹路径的标题栏title名字
            self.ct_path_text = QFileDialog.getExistingDirectory(None, '请选择CT文件路径')
            # 如果路径的文本框是空的,清空picture文件夹下的所有文件
            if self.ct_path_text != "":
                for i in os.listdir('../picture/'):
                    os.remove('../picture/' + i)
                # os.listdir()返回指定路径下的文件和文件夹列表。
                self.picSize = len(os.listdir(self.ct_path_text))
                for i, id in enumerate(os.listdir(self.ct_path_text)):
                    RefDs = sitk.ReadImage(self.ct_path_text + '/' + id)
                    data = sitk.GetArrayFromImage(RefDs)[0]
                # -1000到400,的CT影像转化为256个灰度值,1400除以256等于5.46875
                    data = (np.minimum(np.maximum(data, -1000), 400) + 1000)/5.46875
# 写入data,[int(cv2.IMWRITE_JPEG_QUALITY), 100]的意思是将画质调整为最好的100
                    cv2.imwrite('../picture/%s.jpg' % (self.picSize-i), data, [int(cv2.IMWRITE_JPEG_QUALITY), 100])
            else:
                return

# 将路径的名字读入到文本框中
            self.ui.ct_path.setText(self.ct_path_text)
# 设置多线程上传文件夹的路径
            self.upload_thread.nativePath = self.ct_path_text + '/'
# 设置【调整层数】滑动条的最大值和最小值
            self.ui.layer_slider.setMaximum(self.picSize-1)
            self.ui.layer_slider.setMinimum(0)
# 初始化当前层数,1/n
            self.ui.now_layers_label.setText('当前层数:1/' + str(self.picSize))
# 默认将1.jpg作为主界面的显示
            self.ct_file = "../picture/1.jpg"
            img = QtGui.QPixmap(self.ct_file)
# 显示图片,保持横纵比
            img = img.scaled(self.ct_img_small_size, self.ct_img_small_size, Qt.KeepAspectRatio)
            self.ui.ct_img.setPixmap(img)
# 打印报错信息
        except Exception as e:
            print(e)

初始化了主界面的滑动条是1/n,默认将第一幅图像作为显示图像,在滑动进度条的时候,动态改变进度条的层数,动态改变图片的显示。

因此这俩动态变化的功能需要在滑动条函数中写:

前端滑动条的鼠标点击触发事件:

self.ui.layer_slider.valueChanged.connect(self._layer_slider_changed)

滑动条函数:

    def _layer_slider_changed(self, value):
# 判断非空路径
        if self.ct_path_text == '':
            return
# 设置显示的图片的路径
        self.ct_file = "../picture/%d.jpg" % (value+1)
# 继续保持横纵比不变
        img = QtGui.QPixmap(self.ct_file)
        img = img.scaled(self.ct_img_small_size, self.ct_img_small_size, Qt.KeepAspectRatio)
        self.ui.ct_img.setPixmap(img)
# 动态显示当前层数
        self.ui.now_layers_label.setText('当前层数:' + str(value+1) + '/' + str(self.picSize))

功能3:【上传】按钮,将本地的文件上传到服务器中,实现进度条显示

前端upload_ctbutton组件的鼠标点击触发事件:

self.ui.upload_ct.clicked.connect(lambda: self._upload_ct())

上传函数_upload_ct的具体实现:

    def _upload_ct(self):
        try:
# 判断路径非空
            if self.ui.ct_path.text() == '':
# 路径空值时弹出提示框
                QMessageBox().information(self, '提示', '请选择CT文件路径', QMessageBox.Yes)
                return
# stdin, stdout, stderr,输入信息,命令行输出信息,输出错误信息,需要引入paramiko的ssh
            stdin, stdout, stderr = ssh.exec_command('cd ' + self.serverWorkSpace + ';python clearCT.py')
# 打印命令行产生的输出和错误信息
            print(stdout.read())
            print(stderr.read())
# upload_thread多线程上传
            self.upload_thread.start()
# 上传进度条事件
            self.upload_thread.sigout.connect(self._change_progress)
        except Exception as e:
            print(e)

关于多线程上传的,在此一并说了:


重写run函数,线程启动的时候会直接执行run()方法,我们在此处进行重写,这样线程启动的 时候会执行我们写的这个run方法。

我们使用 self.upload_thread

.start()

方法这个来启用线程,但是线程的启用会先来找run方法

class UploadThread(QThread):
# 设置多线程类
# 刚才看到的sigout在此设置的,pyqtSignal(float)是信号的传递,操作系统中的哲学家就餐问题的一个简
# 化,防止进程死锁,以float类型的参数进行传递
    sigout = pyqtSignal(float)

# 初始化,设置常参数
    def __init__(self):
# 继承 __init__ 类中的所有
        super().__init__()
# 在继承的基础上添加初始化的路径参数
        self.nativePath = ''
        self.uploadPath = ''


# 重写run函数,线程启动的时候会直接执行run()方法,我们在此处进行重写,这样线程启动的 时候会执行我# 们写的这个run方法。
# 我们使用 self.upload_thread.start()。这个来启用线程,但是线程的启用会先来找run方法
    def run(self):
        n = 0
        fileLength = len(os.listdir(self.nativePath)) - 1

        for i in os.listdir(self.nativePath):
            print(self.nativePath+i)
# 将本地文件上传到服务器nativePath + i是本地路径+i文件的意思
            sftp.put(self.nativePath + i, self.uploadPath + i)
# 发送信号
            self.sigout.emit((n/fileLength)*100)
            n += 1
self.sigout.emit((n/fileLength)*100),上传到100%

前端界面的上传进度条的进度百分比的显示功能函数的书写:

    def _change_progress(self, value):
# 进度条传入的value值
        self.ui.upload_progressBar.setValue(value)
        print(value)
        if value == 100:
# 弹出框显示上传完成
            QMessageBox().information(self, '提示', "上传完成", QMessageBox.Yes)

绘图

功能4:在lable区域读出CT图像后,用鼠标事件,添加 绘图功能,绘制十字坐标线。

from PyQt5 import QtGui, QtCore
from PyQt5.QtCore import QRect, QPoint, Qt
from PyQt5.QtGui import QPen, QBrush, QPainter, QPixmap
from PyQt5.QtWidgets import QLabel
# 导入依赖包

# 定义绘画类,这个地方注意一下,因为是(QLabel)参数,因此绘画的都是QLabel区域,坐标也是这个里面# 的区域
class PaintArea(QLabel):
    def __init__(self, parent=None):
        super().__init__(parent)
# 初始化各个参数
# 设置对其方式,居中对齐 AlignCenter
        self.setAlignment(QtCore.Qt.AlignCenter)
        self.markX = 0  # 在图像中的标记
        self.markY = 0
        self.ctX = 256  # 对应CT影像中的真实坐标
        self.ctY = 256
        self.mark = False
        self.slider = None


# 重写绘画事件
    def paintEvent(self, event):
# 继承绘画类
        super().paintEvent(event)
# 因为self.mark = False,因此初始状态不执行绘画事件,鼠标点击后将mark改为true
        if self.mark:
            painter = QPainter(self)
# setPen(self,color)方法,(0, 0, 255)设置为蓝色,1为线段的粗细程度为1
            painter.setPen(QtGui.QPen(QtGui.QColor(0, 0, 255), 1))
# .drawLine(self,l)方法画线,这都是建立在self.mark = True的基础之上的
            painter.drawLine(self.markX, 0, self.markX, self.height())
            painter.drawLine(0, self.markY, self.width(), self.markY)

    def wheelEvent(self, e):
        if e.angleDelta().y() < 0:
            # 放大图片
            if self.slider is not None:
                self.slider.setValue(self.slider.value()+1)
        elif e.angleDelta().y() > 0:
            # 缩小图片
            if self.slider is not None:
                self.slider.setValue(self.slider.value()-1)

# 重写鼠标点击事件
    def mousePressEvent(self, event):
# 获取鼠标点击的横纵坐标
        self.markX = event.x()
        self.markY = event.y()
        self.mark2ct()
        self.mark = True
# repaint方法重画界面,算是刷新
        self.repaint()

# biaoji zuobiao 
    def mark2ct(self):
        if self.width() > self.height():
# 点击鼠标事件,标记坐标
# 这个地方需要注意,CT是512*512的,所以初始化ctx应该是(256,256)位中间点的坐标
# ctX是指图片的ctx的坐标,和lable没关系
# ctx指的是坐标在长>高的时候,x的相对位置,{x-[(b-a)/2]}/a*512
            self.ctX = (self.markX - (self.width() - self.height())/2)/self.height()*512
            self.ctY = self.markY/self.height()*512
        else:
            self.ctX = self.markX/self.width()*512
            self.ctY = (self.markY-(self.height()-self.width())/2)/self.width()*512
# 如果已经有坐标,拖动窗口的大小,鼠标坐标自适应改变,不会错位
    def ct2mark(self):
        if self.width() > self.height():
            self.markX = (self.width()-self.height())/2+(self.ctX/512)*self.height()
            self.markY = (self.ctY/512)*self.height()
        else:
            self.markX = (self.ctX/512)*self.width()
            self.markY = (self.height()-self.width())/2+(self.ctY/512)*self.width()
# 自适应改完重新画坐标点
        self.repaint()

    def setCtXY(self, x, y):
        self.ctX = x
        self.ctY = y
        self.mark = True
        self.ct2mark()

功能5. 从服务器下载检测结果到本地,seeJJ.py

首先介绍界面以及初始化:

class SeeJJ(QMainWindow):
    def resizeEvent(self, e):
        try:
            img = QPixmap(self.ct_file)
            width = self.ui.ct_img.width()
            height = self.ui.ct_img.height()
            if img is None:
                return
            if width > height:
                small = height
            else:
                small = width
            self.ct_img_small_size = small

            img = img.scaled(small, small, Qt.KeepAspectRatio, Qt.SmoothTransformation)
            self.ui.ct_img.setPixmap(QPixmap(''))
            self.ui.ct_img.setPixmap(img)
            self.ui.ct_img.ct2mark()
        except Exception as e:
            print(e)


# 初始化参数
    def __init__(self, parent=None):
        super().__init__(parent)  # 调用父类构造函数,创建窗体
# Ui_MainWindow()为SeeJJ.py中的类名
        self.ui = Ui_MainWindow()  # 创建UI对象
        self.ui.setupUi(self)  # 构造UI界面
        self.serverWorkSpace_jiance = 'E:/LYC/lungDetection-V1/'
        self.serverWorkSpace_fenlei = 'E:/LYC/fenlei/'
        self.serverPython = 'D:/ProgramData/Anaconda3/envs/G_capsenv/python'
        self.zb_list = []
        self.ui.zb_listWidget.addItem('序号          x             y             z')
# 在服务器中的文件保存在'../picture/'路径下,因此要读取本路径下的文件的规模
        self.picSize = len(os.listdir('../picture/'))
# 滑动块的最大值
        self.ui.layer_ajust_slider.setMaximum(self.picSize-1)
        self.ui.layer_ajust_slider.setMinimum(0)
# 初始化滑块的值1/n
        self.ui.now_layer_label.setText('当前层数:1/' + str(self.picSize))

        # self.ct_img_small_size = 512  # ct影像尺寸标准,以宽高小者为准
# 宽度 = ct_img的宽度
        width = self.ui.ct_img.width()
        height = self.ui.ct_img.height()
# 滑块?将ui里面的滑块赋值给这个类里面的滑块
        self.ui.ct_img.slider = self.ui.layer_ajust_slider
        if width > height:
            self.ct_img_small_size = height
        else:
            self.ct_img_small_size = width
# 记录图片层数,初始化界面显示为第一层
        self.ct_file = '../picture/1.jpg'  # 记录当前ct层数的图片文件
        img = QPixmap(self.ct_file)
# img.scaled(self,width,height,aspectRatioMode,TransformMode)方法
# 最小值作为边长的正方形,保持横纵比,光滑变换
        img = img.scaled(self.ct_img_small_size, self.ct_img_small_size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
        self.ui.ct_img.setPixmap(img)
# 执行lambda函数集合
        self.function()

从服务器下载文件到本地:

# 定义组件的接口函数
    def function(self):
        self.ui.down_load.clicked.connect(lambda: self._down_load_zb())

# 对接口函数 _down_load_zb() 的实现

    def _down_load_zb(self):
        try:

# 从服务器将2020NewData.xlsx文件下载到本地的data文件夹下
            sftp.get(self.serverWorkSpace_jiance + '2020NewData.xlsx', '../data/new data.xlsx')
# 完事以后,弹出成功界面
            QMessageBox().information(self, '提示', "成功下载到本地", QMessageBox.Yes)
        except Exception as e:
            print(e)

关于 sftp 方法,用的是 paramiko 函数库进行实现,关于这个服务器功能单独写一个connect.py文件实现与服务器的连接:

import paramiko

transport = paramiko.Transport(('服务器ip', 端口号))
# 建立连接
transport.connect(username='Fizz', password='密码')
# 将sshclient的对象的transport指定为以上的transport
ssh = paramiko.SSHClient()
ssh._transport = transport
# sftp在此处赋值
sftp = paramiko.SFTPClient.from_transport(transport)

用这么一句代码 :sftp.get(self.serverWorkSpace_jiance + ‘2020NewData.xlsx’, ‘../data/new data.xlsx’)

即可以实现文件从服务器的下载。

功能6:实现 菜单栏的各个跳转功能

    def processtrigger(self, action):
        if action.text() == '退出':
            self.close()
        elif action.text() == '系统首页':
# Index.py文件中的Index()类赋值给本类的self.index
            self.index = Index.Index()
            self.index.show()
            self.close()
        elif action.text() == '裁剪肺结节':
            self.seeJJ = SeeJJ.SeeJJ()
            self.seeJJ.show()
            self.close()
        elif action.text() == '肺结节影像良恶性诊断':
# from frame import ClassifyJJ
            self.classifyJJ = ClassifyJJ.ClassifyJJ()
            self.classifyJJ.show()
            self.close()

功能7:python与excle表格交互:读取信息 + python读写操作

鼠标点击button事件:

self.ui.read_zb.clicked.connect(lambda: self._read_zb())

左侧坐标显示栏的函数实现:

    def _read_zb(self):
# 初始化清空列表
        self.ui.zb_listWidget.clear()
        self.zb_list.clear()
        self.ui.zb_listWidget.addItem('序号          x             y             z')
# from openpyxl import load_workbook;加载excle的方法,读入
        wb = load_workbook('../data/new data.xlsx')
        sheet = wb.active
        i = 2
        while True:
# 读入M列的值,空值则停
            content = sheet["M%d" % i].value
            if content is None or content == "":
                break
# 从左侧的第一个元素,到倒数第一个元素。
            content = content[1:-1]
# 逗号分隔开,这样就把坐标中的三个数取出来了
            index = content.split(",")
            x, y, z = index[0], index[1], index[2]
            self.zb_list.append((index[0], index[1], index[2]))
            self.ui.zb_listWidget.addItem(' ' + str(i-1) + '          ' + x + '          ' + y + '          ' + z)
            i += 1

Classfy.py文件。分类检测

本处附带服务器代码,关于python写入Excel的方法:

from openpyxl import Workbook
import cv2


def write_zb_excel(indexList,jjdx):
    wb = Workbook()
    sheet = wb.active
    sheet.title='Sheet1'

    sheet['A1'].value = '影像号'
    sheet['M1'].value = '坐标'
    sheet['N1'].value = '结节大小'
    sheet['O1'].value = '病理类型'
    sheet['AF1'].value = '年份'
    sheet["A2"].value = '10203040'
    img = cv2.imread('E:/LYC/lungDetection-V1/detection/savejpg2/0006/0.jpg')
    w, h = img.shape[0], img.shape[1]

    f = open(r'..\detection\extendbox.txt', 'r')
    extendbox = f.readlines()
    startX = int(extendbox[0])
    startY = int(extendbox[2])
    startZ = int(extendbox[4])
    f.close()

    f = open(r'..\detection\spacing.txt', 'r')
    space = f.readline()
    space = space.split(',')
    spaceZ = float(space[0])
    spaceXY = float(space[1])
    f.close()

    for i, index in enumerate(indexList):
        x, y, z = index[0], index[1], index[2]
        x = round((x + startX) / spaceXY)
        y = round((y + startY) / spaceXY)
        z = round((z + startZ + 1) / spaceZ)

        content = '(' + str(x) + ',' + str(y) + ',' + str(z) + ')'
        sheet["M%d" % (i + 2)].value = content
        sheet["O%d" % (i + 2)].value = 2
        sheet["AF%d" % (i + 2)].value = 2020

    for i,jj in enumerate(jjdx):
        sheet["N%d" % (i + 2)].value = jj

    wb.save('../2020NewData.xlsx')


如下,jjdx(结节大小)为一列表[1,2,3,1,1]之类似,enumerate函数的作用是一个数一个数的去拿;第二行是存在N列的每一行中。

    for i,jj in enumerate(jjdx):
        sheet["N%d" % (i + 2)].value = jj

功能8:从服务器下载文件到本地

self.ui.download_jj_file.clicked.connect(lambda: self._download_jj_file())

函数实现:

    def _download_jj_file(self):
        try:
            npyList = os.listdir('../npy')
            for npy in npyList:
                os.remove('../npy/' + npy)
            fileArray = sftp.listdir(self.serverWorkSpace + 'prework/dataset17-20_cf/test30')


            for file in fileArray:
                sftp.get(self.serverWorkSpace + 'prework/dataset17-20_cf/test30/' + file, '../npy/' + file)

            QMessageBox().information(self, '提示', "成功下载到本地", QMessageBox.Yes)
        except Exception as e:
            print(e)

功能9:从服务器下载结节文件,列表读取本地文件

点击【读取结节文件】按钮,实现列表框中读取。



    def _read_jj(self):
# 清空列表
        self.ui.jj_listWidget.clear()
        jjList = os.listdir('../npy/')
# 加载文件
        for jj in jjList:
            self.ui.jj_listWidget.addItem(jj)

鼠标点击事件,实现界面的动态变化。

    def _jj_listWidget_clicked(self, item):
        try:
            if item is None:
                return
            file = item.text()

# 本段显示结节图像
            path = '../npy/' + file
            image_data = np.load(path)
# //取整,/浮点数
            image_data = image_data[image_data.shape[0] // 2]
            ###
            image_data = (np.minimum(np.maximum(image_data, -1000), 400) + 1000)/5.46875

            img_pil = Image.fromarray(np.uint8(image_data)).resize((150, 150))
            self.ui.jj_img.setPixmap(img_pil.toqpixmap())

            # 根据文件后缀数字确定序号,获取xlsx文件中的坐标
# 正则表达式找 10203040-1.npy之类的文件,findall
            id = re.findall(r'.*?-(.*?).npy', file)[0]
            index = self.zbList[int(id)]
            index = index[1:-1]
            print(index)
            index = index.split(',')

            # 在结节部分显示坐标
            self.ui.jj_zb_label.setText('坐标: X:%s  Y:%s  Z:%s' % (index[0], index[1], index[2]))

            # 在CT中标记结节
            self.ui.ct_img.setCtXY(int(index[0]), int(index[1]))

            # ct切换到相应页面
            self.ui.layer_ajust_slider.setValue(int(index[2]))
            self.ct_file = '../picture/' + index[2] + '.jpg'
            img = QPixmap(self.ct_file)
            img = img.scaled(self.ct_img_small_size, self.ct_img_small_size, Qt.KeepAspectRatio,Qt.SmoothTransformation)
            self.ui.ct_img.setPixmap(img)

            if len(self.resList) == 0:
                return
            result = list(map(float, self.resList[int(id)]))
            result = np.exp(result)/np.sum(np.exp(result), axis=0)
# 显示百分比
            self.ui.result_lx_progressBar.setValue(float(result[0])*100)
            self.ui.result_la_progressBar.setValue(float(result[1])*100)
            self.ui.result_xa_progressBar.setValue(float(result[2])*100)
        except Exception as e:
            print(e)

功能10 :添加【软件说明】界面,添加新界面,并将新界面的button功能实现

1.在UI界面【帮助】下添加【软件使用说明】的QAction,添加方法为,先点击type here,输入wohenshuai


右侧的QAction属性栏如下:


调整frame格式:

选中要编辑的frame模块,右键stylesheet,复制里面的格式代码,到新的界面粘贴

参考里面的代码,可写更多样式。

我在【帮助】下添加的是【软件使用说明】,QAction是rjsm

    def processtrigger(self, action):
        if action.text() == '退出':
            self.close()
        elif action.text() == '系统首页':
            self.index = Index.Index()
            self.index.show()
            self.close()
        elif action.text() == '肺结节检测':
            self.seekJJ = SeekJJ.SeekJJ()
            self.seekJJ.show()
            self.close()
        elif action.text() == '肺结节影像良恶性诊断':
            self.classifyJJ = ClassifyJJ.ClassifyJJ()
            self.classifyJJ.show()
            self.close()
        elif action.text() == '软件使用说明':
            self.rjsm = gnsm.Gnsm()
            self.rjsm.show()

弹出界面不关闭

然后

from frame import gnsm



即可。self.rjsm为新命名而已,不指向其他东西;gnsm.Gnsm()指的是import的gnsm界面下的Gnsm类


添加新界面之后,如果界面中有函数,要初始化函数,并且执行之。这点十分重要,我将在下面举例说明!!!!!!!!


添加完一个软件使用说明以后,在其他界面进行添加就比较容易了。


第一步:修改ui界面,在ui界面添加【帮助】-【软件使用说明】


第二步:添加elif功能


第三步:

from frame import gnsm

功能11:生成报告。python将信息写入word文档。

关于word的操作,大概可以如下:

    def _submit(self):
# 判断信息完整性
        if self.ui.patient_name.text() == ''\
                or self.ui.patient_id.text() == ''\
                or self.ui.ct_describe_textEdit.toPlainText() == ''\
                or self.ui.doctor_advice_textEdit.toPlainText() == '':
# 弹出未完善的提示信息
            QMessageBox().information(self, '提示', '请完善信息', QMessageBox.Ok)
            return
# 选择保存路径的选择框
        save_path_text = QFileDialog.getExistingDirectory(None, '请选择报告保存路径')
# 判断保存路径非空
        if save_path_text == '':
            QMessageBox().information(self, '提示', '未选择保存路径', QMessageBox.Ok)
            return
# 读入word模板
        doc = docx.Document('../word/model.docx')  # 读取模板
# 写入信息
        doc.paragraphs[1].text = '病历号:%s             姓名:%s                 检查时间:%s' % \
                                 (self.ui.patient_id.text(), self.ui.patient_name.text(), self.ui.diagnose_date.text())

# 第三段添加图片,选中的肺结节图片
        run = doc.paragraphs[3].add_run()
        for file in os.listdir('../npy_img/'):
            run.add_picture('../npy_img/' + file)
            run = doc.paragraphs[3].add_run('  ')
# 将文档中的文字信息写入word的表格中
        doc.tables[0].rows[0].cells[0].text = self.ui.ct_describe_textEdit.toPlainText()
        doc.tables[1].rows[0].cells[0].text = self.ui.doctor_advice_textEdit.toPlainText()
# 将写好的文档保存在本地的绝对路径中,命名使用患者id命名
        doc.save(save_path_text + '/' + self.ui.patient_id.text() + '.docx')  # 要写绝对路径
        QMessageBox().information(self, '提示', '成功生成报告', QMessageBox.Ok)

功能12:选中结节和取消选中 的样式改变,选中后及时保存选中文件

点击左侧的npy文件,点击【写入检测报告】,选中结节,将结节图片文件保存起来;

点击选中的结节,点击【移除检测报告】,取消选中,并将保存的结节文件删除掉。

具体的

self.ui.put_jj_in_report.clicked.connect(lambda: self._put_jj_in_report())

的实现如下:

    def _put_jj_in_report(self):
# 我们规定选的结节个数不超过6个
        try:
            if self.put_npy_num >= 6:
                QMessageBox().information(self, '提示', '写入结节数不能超过6个', QMessageBox.Ok)
                return
# 选中结节后
            row = self.ui.jj_listWidget.currentRow()
# 设置选中时的颜色,设置选中时的icon图标
            self.ui.jj_listWidget.item(row).setBackground(QColor(190, 217, 238))
            self.ui.jj_listWidget.item(row).setIcon(QIcon('../image/t7.ico'))
# 并将本结节文件保存起来,生成报告的时候直接使用,用npy文件的名字命名jpg
            self.ui.jj_img.pixmap().save('../npy_img/%s.jpg' % self.ui.jj_listWidget.item(row).text())
            self.put_npy_num += 1
        except Exception as e:
            print(e)

移除结节文件的函数实现:

    def _remove_jj_from_report(self):
        try:
# 选中本行
            row = self.ui.jj_listWidget.currentRow()
# 设置颜色,图标设置为空值
            self.ui.jj_listWidget.item(row).setBackground(QColor(255, 255, 255))
            self.ui.jj_listWidget.item(row).setIcon(QIcon(''))
# 删除保存的文件
            os.remove('../npy_img/%s.jpg' % self.ui.jj_listWidget.item(row).text())
            self.put_npy_num -= 1
        except Exception as e:
            print(e)

这俩功能,将结果显示出来,读取坐标值。不好解释,不做解释。

    def _jj_listWidget_clicked(self, item):
        try:
            if item is None:
                return
            file = item.text()

            # 显示结节图像
            path = '../npy/' + file
            image_data = np.load(path)
            image_data = image_data[image_data.shape[0] // 2]
            ###
            image_data = (np.minimum(np.maximum(image_data, -1000), 400) + 1000)/5.46875

            img_pil = Image.fromarray(np.uint8(image_data)).resize((150, 150))
            self.ui.jj_img.setPixmap(img_pil.toqpixmap())

            # 根据文件后缀数字确定序号,获取xlsx文件中的坐标
            id = re.findall(r'.*?-(.*?).npy', file)[0]
            index = self.zbList[int(id)]
            index = index[1:-1]
            print(index)
            index = index.split(',')

            # 在结节部分显示坐标
            self.ui.zb_info_label.setText('坐标: X:%s  Y:%s  Z:%s' % (index[0], index[1], index[2]))

            if len(self.resList) == 0:
                return
            result = list(map(float, self.resList[int(id)]))
            result = np.exp(result)/np.sum(np.exp(result), axis=0)
            self.ui.res_lx_progressBar.setValue(float(result[0])*100)
            self.ui.res_la_progressBar.setValue(float(result[1])*100)
            self.ui.res_xa_progressBar.setValue(float(result[2])*100)
        except Exception as e:
            print(e)

    def _read_jj(self):
        # 读取已经下载的坐标值
        self.zbList.clear()
        wb = load_workbook('../data/new data.xlsx')
        sheet = wb.active
        i = 2
        while True:
            content = sheet["M%d" % i].value
            if content is None or content == "":
                break
            self.zbList.append(content)
            i += 1

        # 读取已经下载的识别结果
        self.resList.clear()
        resNum = len(os.listdir('../result'))
        for i in range(resNum):
            f = open('../result/tes_prob_batch' + str(i) + '.txt')
            batches = f.readlines()
            for batch in batches:
                batch = batch[0:-2]  # 去除换行符
                number = batch.split(' ')
                self.resList.append((number[1][0:8], number[2][0:8], number[3][0:8]))
            f.close()

        # 将结节文件显示在列表
        self.ui.jj_listWidget.clear()
        jjList = os.listdir('../npy/')
        for jj in jjList:
            self.ui.jj_listWidget.addItem(jj)

功能13:登录界面的跳转(project-hjq)

    def yanzheng(self):
        self.n=0
# 账号密码存放在同一级目录的11.txt下
        f=open('./11.txt')
        ma=self.username.text()+'.'+self.password.text()
        for i in f:
# 判定登陆成功
            if i[:-1]==ma:
                QMessageBox.information(self, " ", "登录成功!", QMessageBox.Yes)
# 登陆成功后打开新界面 main
                import main
                self.hide()
        # self.form.hide()  # 如果没有self.form.show()这一句,关闭Demo1界面后就会关闭程序
# main界面打开
                self.ex = main.Example()
                self.ex.show()
                self.n=1
        if self.n==0:
# 这里将三种报错信息放在了一起,报错信息弹框是一样的,不一样的地方是图标不一样。
            QMessageBox.information(self, " ", "登录成功!", QMessageBox.Yes)
            QMessageBox.critical(self, " ", "密码错误!", QMessageBox.Yes)
            QMessageBox.warning(self, " ", "查无此人!", QMessageBox.Yes)

# 记得关闭txt
        f.close()

功能14:添加新界面,并实现其中的各个功能。

第一步:制作ui界面,并且将ui界面的各个button记录好,然后用 pyuic5 -o 命令转化为py程序。这一步不在赘述

第二步:在后台程序的文件夹(frame)中新建实现本界面以及功能的py文件,

提示:ui文件和第一步生成的界面py文件在ui文件夹下;我要实现的后台程序的py文件在frame文件夹下,因此,我在frame新建的程序yjjc.py引入ui文件即可。

from ui.Yjjc import Ui_MainWindow

然后实现主方法,显示本界面:

if __name__ == "__main__":  # 用于当前窗体测试
    app = QApplication(sys.argv)  # 创建GUI应用程序
    form = Yjjc()  # 创建窗体
    form.show()
    sys.exit(app.exec_())

这段代码为避免将来忘记,在此解释一下,只需要改 form = Yjjc() 这一句即可,就是声明一个新界面为form,这个Yjjc就是本主界面的类:

这样ui界面的内容就可以显示了

第三步:实现界面中的按键的功能

首先写

def __init__(self, parent=None):

这个函数,继承父类的窗体,固定代码:

    def __init__(self, parent=None):
        super().__init__(parent)  # 调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  # 创建UI对象
        self.ui.setupUi(self)  # 构造UI界面

这说明这个界面已经继承了父类的窗体。

继承完窗体,然后找ui界面中的一键检测的按钮的名字。我命名为yjjc

于是,实现这个功能

    def function(self):
        self.ui.yjjc.clicked.connect(lambda: self._Yjjcsb())

新建一个function类,声明各个组件的对应的函数,在这里一定要注意注意再注意,


声明的function函数类必须要初始化!!!



也就是在def __init__ 中添加这么一句代码:

self.function()

这样才可以正常执行,否则不可以!如图:

将用到的初始化的 东西全都写在__init__函数中

第四步:写具体的实现函数,就是function中lambda的函数

    def _Yjjcsb(self):
        try:
            stdin, stdout, stderr = ssh.exec_command('cd ' + self.serverWorkSpace +
                                                     'detection/;' + self.serverPython + ' dcm2mhd.py')
            print(stdout.read())
            print(stderr.read())
            QMessageBox().information(self, '提示', "成功生成mhd文件", QMessageBox.Yes)
        except Exception as e:
            print(e)

这样就可以了。

以上四步实现的是按钮的功能的具体实现,下面写的是选择文件路径,并将文件上传的路基顺序:

第一步:实现选择文件路径按钮的函数

self.ui.choose_ct_path.clicked.connect(lambda: self._choose_ct_path())

第二步:实现           lambda: self._choose_ct_path() 函数

    def _choose_ct_path(self):
        try:
            self.ct_path_text = QFileDialog.getExistingDirectory(None, '请选择CT文件路径')
            if self.ct_path_text != "":
                for i in os.listdir('../picture/'):
                    os.remove('../picture/' + i)
                self.picSize = len(os.listdir(self.ct_path_text))
                for i, id in enumerate(os.listdir(self.ct_path_text)):
                    data = pydicom.dcmread(self.ct_path_text + '/' + id).pixel_array
                    data = (np.minimum(np.maximum(data, 0), 4096)) / 6
                    ###
                    plt.imsave('../picture/%s.jpg' % (self.picSize-i),
                               data, cmap='gray', vmin=0, vmax=255)
            else:
                return
            self.ui.ct_path.setText(self.ct_path_text)
            self.upload_thread.nativePath = self.ct_path_text + '/'
            self.ui.layer_slider.setMaximum(self.picSize-1)
            self.ui.layer_slider.setMinimum(0)
            self.ui.now_layers_label.setText('当前层数:1/' + str(self.picSize))
            self.ct_file = "../picture/1.jpg"
            img = QtGui.QPixmap(self.ct_file)
            img = img.scaled(self.ct_img_small_size, self.ct_img_small_size, Qt.KeepAspectRatio)
            self.ui.ct_img.setPixmap(img)
        except Exception as e:
            print(e)

这段代码下面的    self.ui….  属于初始化的参数值

self.ui.ct_path.setText(self.ct_path_text)  指的是显示路径的文本框;

下面这两句:

self.ui.layer_slider.setMaximum(self.picSize-1)

self.ui.layer_slider.setMinimum(0)

指的是滑动条的初始化的最大值最小值

ct_path.setText和layer_slider在上图已标注。

接下来要实现上传功能,首先书写上传按钮的实现方法:

    def _upload_ct(self):
        try:
            if self.ui.ct_path.text() == '' or self.ct_path_text == '':
                QMessageBox().information(self, '提示', '请选择CT文件路径', QMessageBox.Yes)
                # QtWidgets.QMessageBox(QMessageBox.Warning, '提示', '请选择CT文件路径').exec_()
                return

            stdin, stdout, stderr = ssh.exec_command('cd ' + self.serverWorkSpace + ';python clearCT.py')
            print(stdout.read())
            print(stderr.read())

            self.upload_thread.start()
            self.upload_thread.sigout.connect(self._change_progress)
        except Exception as e:
            print(e)

书写上传的 进程类

class UploadThread(QThread):
    sigout = pyqtSignal(float)

    def __init__(self):
        super().__init__()
        self.nativePath = ''
        self.uploadPath = ''

    def run(self):
        n = 0
        fileLength = len(os.listdir(self.nativePath)) - 1
        for i in os.listdir(self.nativePath):
            print(self.nativePath+i)
            sftp.put(self.nativePath + i, self.uploadPath + i)
            self.sigout.emit((n/fileLength)*100)
            n += 1

因为本处的 self.uploadPath = ” 上传路径设置为空值,因此需要在初始化里面设置好上传路径的具体指,否则程序虽然会上传但是却传不到指定路径下。

self.upload_thread.uploadPath = self.serverWorkSpace + 'detection/test_mask/0006/'

一定要记得初始化!!

self.upload_thread = UploadThread()

初始化函数里有这句话才行的。重写了run方法实现上传功能。

上传进度为百分之百的时候,弹窗提示上传完成:

    def _change_progress(self, value):
        self.ui.upload_progressBar.setValue(value)
        print(value)
        if value == 100:
            QMessageBox().information(self, '提示', "上传完成", QMessageBox.Yes)


另一个功能:实现滑块的拖动

self.ui.layer_slider.valueChanged.connect(self._layer_slider_changed)

实现本函数的方法:

    def _layer_slider_changed(self, value):
        if self.ct_path_text == '':
            return
        self.ct_file = "../picture/%d.jpg" % (value+1)
        img = QtGui.QPixmap(self.ct_file)
        img = img.scaled(self.ct_img_small_size, self.ct_img_small_size, Qt.KeepAspectRatio)
        self.ui.ct_img.setPixmap(img)
        self.ui.now_layers_label.setText('当前层数:' + str(value+1) + '/' + str(self.picSize))


鼠标的滑轮实现图片的滚动浏览等会再写


功能15:添加登录界面,账号密码登陆成功实现跳转

在之前的界面基础上,添加新界面。思路比较简单,添加login.py界面即可,使登陆成功后,跳转至index.py。

只需打包login.py即可。

具体实现方法如下:

界面添加上txt文本验证,账号密码在文本中,就登陆成功。否则失败。

至于txt的账号密码内容,可在服务器端实现修改,每次运行下载至本地。

# -*- coding: utf-8 -*-
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QFileDialog, QMessageBox
from PyQt5 import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import paramiko,os
import socket,time
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
import paramiko
transport = paramiko.Transport(('ip', 端口))
# 建立连接
transport.connect(username='服务器账号', password='密码')
# 将sshclient的对象的transport指定为以上的transport
ssh = paramiko.SSHClient()
ssh._transport = transport
sftp = paramiko.SFTPClient.from_transport(transport)
sftp.get('E:/LYC/lungDetection-V1/users.txt', '../data/users.txt')
class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.setupUi()
    def setupUi(self):
        self.resize(993, 550)
        # self.setWindowFlags(QtCore.Qt.WindowMinimizeButtonHint)
        # self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.setFixedSize(self.width(),self.height())
        s1 = '肺结节多种病理类型人工智能检测系统'
        s2 = '公司'
        s3 = '山东大学'
        self.setWindowTitle('肺结节多种病理类型人工智能检测系统-登录界面')

        self.background = QtWidgets.QLabel(self)
        self.background.setGeometry(QtCore.QRect(0, 0, 1025, 550))
        self.background.setPixmap(QtGui.QPixmap("../image/background.png"))

        self.left = QtWidgets.QLabel(self)
        self.left.setGeometry(QtCore.QRect(20, 180, 261, 211))
        self.left.setPixmap(QtGui.QPixmap("../image/pic.png"))
        self.left.setScaledContents(True)

        self.pic_1 = QtWidgets.QLabel(self)
        self.pic_1.setGeometry(QtCore.QRect(320, 170, 150, 150))
        self.pic_1.setPixmap(QtGui.QPixmap("../image/1.jpg"))
        self.pic_1.setScaledContents(True)

        self.pic_2 = QtWidgets.QLabel(self)
        self.pic_2.setGeometry(QtCore.QRect(500, 170, 150, 150))
        self.pic_2.setPixmap(QtGui.QPixmap("../image/2.jpg"))
        self.pic_2.setScaledContents(True)

        self.pic_3 = QtWidgets.QLabel(self)
        self.pic_3.setGeometry(QtCore.QRect(320, 340, 150, 150))
        self.pic_3.setPixmap(QtGui.QPixmap("../image/3.jpg"))
        self.pic_3.setScaledContents(True)

        self.pic_4 = QtWidgets.QLabel(self)
        self.pic_4.setGeometry(QtCore.QRect(500, 340, 150, 150))
        self.pic_4.setPixmap(QtGui.QPixmap("../image/4.jpg"))
        self.pic_4.setScaledContents(True)

        self.font = QtGui.QFont()
        self.font.setFamily("黑体")
        self.font.setPointSize(30)
        self.font.setItalic(True)

        self.text_1 = QtWidgets.QLabel(self)
        self.text_1.setGeometry(QtCore.QRect(300, 160, 261, 71))
        self.text_1.setFont(self.font)

        self.text_2 = QtWidgets.QLabel(self)
        self.text_2.setGeometry(QtCore.QRect(360, 290, 271, 61))
        self.text_2.setFont(self.font)

        self.text_3 = QtWidgets.QLabel(self)
        self.text_3.setGeometry(QtCore.QRect(420, 420, 261, 61))
        self.text_3.setFont(self.font)

        # self.text_1.setText("<html><head/><body><p><span style=\" color:#ff0000;\">智能数据获取</span></p></body></html>")
        # self.text_2.setText("<html><head/><body><p><span style=\" color:#ff0000;\">智能数据处理</span></p></body></html>")
        # self.text_3.setText("<html><head/><body><p><span style=\" color:#ff0000;\">智能诊断应用</span></p></body></html>")

        self.frame = QtWidgets.QFrame(self)
        self.frame.setGeometry(QtCore.QRect(690, 180, 261, 271))
        self.frame.setStyleSheet("background:rgb(240, 240, 240)")

        h2_font = QtGui.QFont()
        h2_font.setFamily("新宋体")
        h2_font.setPointSize(11)
        h2_font.setBold(True)
        h2_font.setWeight(75)

        self.h2 = QtWidgets.QLabel(self.frame)
        self.h2.setGeometry(QtCore.QRect(96, 20, 71, 21))
        self.h2.setFont(h2_font)
        self.h2.setText("账号登录")

        font = QtGui.QFont()
        font.setFamily("新宋体")
        font.setPointSize(10)

        self.zhl = QtWidgets.QLabel(self.frame)
        self.zhl.setGeometry(QtCore.QRect(20, 80, 41, 25))
        self.zhl.setFont(font)
        self.zhl.setText("账号:")

        self.mml = QtWidgets.QLabel(self.frame)
        self.mml.setGeometry(QtCore.QRect(20, 130, 41, 25))
        self.mml.setFont(font)
        self.mml.setText("密码:")

        self.checkBox = QtWidgets.QCheckBox(self.frame)
        self.checkBox.setGeometry(QtCore.QRect(170, 170, 71, 21))
        self.checkBox.setText("记住密码")

        self.login = QtWidgets.QPushButton(self.frame)
        self.login.setGeometry(QtCore.QRect(75, 210, 111, 31))
        self.login.setStyleSheet("background:rgb(255, 97, 76)")
        self.login.clicked.connect(self.yanzheng)
        self.login.setText("登  录")
        self.login.setShortcut('enter')

        self.username = QtWidgets.QLineEdit(self.frame)
        self.username.setGeometry(QtCore.QRect(70, 80, 171, 25))

        self.password = QtWidgets.QLineEdit(self.frame)
        self.password.setGeometry(QtCore.QRect(70, 130, 171, 25))
        self.password.setEchoMode(QtWidgets.QLineEdit.Password)




        self.title = QtWidgets.QLabel(self)
        self.title.setGeometry(QtCore.QRect(110, 50, 801, 51))
        title_font = QtGui.QFont()
        title_font.setFamily("黑体")
        title_font.setPointSize(32)
        self.title.setFont(title_font)
        self.title.setText(
            "<html><head/><body><p><span style=\" color:#aaffff;\">肺结节多种病理类型人工智能检测系统</span></p></body></html>")

        # self.setCentralWidget(self)
        # self.menubar = QtWidgets.QMenuBar(self)
        # self.menubar.setGeometry(QtCore.QRect(0, 0, 993, 23))
        # self.setMenuBar(self.menubar)

    def yanzheng(self):
        self.n=0
        f=open('../data/users.txt')
        ma=self.username.text()+'.'+self.password.text()
        for i in f:
            # a,b=str(i[-1]).split('.',2)
            # print(a,b)
            if i[:-1]==ma:
                QMessageBox.information(self, " ", "登录成功!", QMessageBox.Yes)
                import Index
                self.hide()
                # self.form.hide()  # 如果没有self.form.show()这一句,关闭Demo1界面后就会关闭程序
                self.ex = Index.Index()
                self.ex.show()
                self.n=1
        if self.n==0:
            # QMessageBox.information(self, " ", "登录成功!", QMessageBox.Yes)
            QMessageBox.critical(self, " ", "账号或密码错误!", QMessageBox.Yes)
            # QMessageBox.warning(self, " ", "查无此人!", QMessageBox.Yes)
        f.close()


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())

功能16:下拉框选中文字,实现在文本框中自动粘贴的功能。

      # pyqt界面的  ct_discribe和doctor_advice组件点击粘贴事件
self.ui.ct_discribe.currentTextChanged.connect(lambda :self.Clickme_ct())
self.ui.doctor_advice.currentTextChanged.connect(lambda :self.Clickme_doc())

点击将文字粘贴至下拉框中。

    def Clickme_ct(self):
        print(self.ui.ct_discribe.currentText())
        ct_dis = self.ui.ct_describe_textEdit.toPlainText()
        ct_dis += self.ui.ct_discribe.currentText()
        self.ui.ct_describe_textEdit.setText(ct_dis)
        print("文字粘贴到CT影像描述文本框")

    def Clickme_doc(self):
        print(self.ui.doctor_advice.currentText())
        doc_adv = self.ui.doctor_advice_textEdit.toPlainText()
        doc_adv += self.ui.doctor_advice.currentText()
        self.ui.doctor_advice_textEdit.setText(doc_adv)

功能17:克服桶排序。显示前24个结节。

思路是:桶排序按照字符长度排序的,同一字符同一排序,因此按照len()方法长度排序即可。

显示前24个结节也比较简单,循环到24,break即可。

    def _read_jj(self):
        # 读取已经下载的坐标值
        self.zbList.clear()
        wb = load_workbook('../data/new data.xlsx')
        sheet = wb.active
        i = 2
        while True:
            content = sheet["M%d" % i].value
            if content is None or content == "":
                break
            self.zbList.append(content)
            i += 1

        # 读取已经下载的识别结果
        self.resList.clear()
        resNum = len(os.listdir('../result'))
        for i in range(resNum):
            f = open('../result/tes_prob_batch' + str(i) + '.txt')
            batches = f.readlines()
            for batch in batches:
                batch = batch[0:-2]  # 去除换行符
                number = batch.split(' ')
                self.resList.append((number[1][0:8], number[2][0:8], number[3][0:8]))
            f.close()

        # 将结节文件显示在列表
        self.ui.jj_listWidget.clear()
        jjList = os.listdir('../npy/')
        jjList.sort(key=functools.cmp_to_key(self.jj_sort2))
        i = 0



        for jj in jjList:
            # print(jj)
            # s = jj.split("-")[-1]
            self.ui.jj_listWidget.addItem(jj)
            i += 1
            if i >= 24:
                break
            # self.ui.jj_listWidget.setSortingEnabled(True)

    def jj_sort2(self,x,y):
        return len(x)-len(y)



版权声明:本文为weixin_41569825原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。