MaskRCNN可视化界面开发(PyQt5)

Mask RCNN系列文章目录

Mask RCNN笔记:环境安装篇(Win10+tensrflow-gpu) 不需要另行安装cuda cudnn
MaskRCNN可视化界面开发(PyQt5)


文章目录

  • Mask RCNN系列文章目录
  • 前言
  • 一、PyQt5及Designer、Pyuic插件安装
  • 二、设计UI界面
    • 1.使用Qt Designer来设计界面
    • 2.按钮事件
    • 3.ui文件转py代码
  • 三、编写逻辑代码
  • 四、补充
    • 1.界面样式美化
    • 2.pyinstaller打包成独立exe文件
    • 打包调试:
      • 1.`pyinstaller`重新安装后不是内部或外部命令,也不是可运行的程序 或批处理文件
      • 2.图片加载问题


笔者因毕设要求,需要对maskRCNN进行封装,制作一个可视化界面。

先来展示下效果图:
MaskRCNN可视化界面开发(PyQt5)_第1张图片

文章目录

  • Mask RCNN系列文章目录
  • 前言
  • 一、PyQt5及Designer、Pyuic插件安装
  • 二、设计UI界面
    • 1.使用Qt Designer来设计界面
    • 2.按钮事件
    • 3.ui文件转py代码
  • 三、编写逻辑代码
  • 四、补充
    • 1.界面样式美化
    • 2.pyinstaller打包成独立exe文件
    • 打包调试:
      • 1.`pyinstaller`重新安装后不是内部或外部命令,也不是可运行的程序 或批处理文件
      • 2.图片加载问题


前言

本文默认已经实现了MaskRCNN的训练和测试,现在测试的基础上加一个UI界面。 本文使用PyQt5进行界面开发。

提示:以下是本篇文章正文内容,下面案例可供参考

一、PyQt5及Designer、Pyuic插件安装

1.激活maskRCNN虚拟环境,安装PyQt5:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package PyQt5

清华的镜像地址,加速下载,推荐使用

PyQt5 测试

import sys
from PyQt5 import QtWidgets

app = QtWidgets.QApplication(sys.argv)
widget = QtWidgets.QWidget()
widget.resize(360, 360)
widget.setWindowTitle("Hello, PyQt5")
widget.show()
sys.exit(app.exec_())

MaskRCNN可视化界面开发(PyQt5)_第2张图片
2.安装Qt的工具包

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package PyQt5-tools 

安装成功打开python的安装目录的Lib目录下,site-packages里面会有 PyQt5pyqt5-tools 两个目录

配置PyChram,安装QtDesigner:
2.1打开PyCharm,File > Settings > Tools > External Tools
MaskRCNN可视化界面开发(PyQt5)_第3张图片
2.2点击 + 号创建
Name: Designer
Group: Qt
Program: designer.exe所在目录
Working directory: $ProjectFileDir$
MaskRCNN可视化界面开发(PyQt5)_第4张图片
2.3安装Pyuic
打开PyCharm,File > Settings > Tools > External Tools
点击 + 号创建
Name: Pyuic
Group: Qt
Program: python.exe所在目录
Arguments: -m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py
Working directory: $FileDir$

MaskRCNN可视化界面开发(PyQt5)_第5张图片

二、设计UI界面

1.使用Qt Designer来设计界面

注意本过程需在maskRCNN源码的同一目录下进行。

按照我们之前的界面构思
MaskRCNN可视化界面开发(PyQt5)_第6张图片
我们需要从3个PushButton按键,2个label用于展示和1个textBrowser用于状态显示。
控件上显示的文字 text 属性和控件的名字 objectName 属性需要修改,便于显示和代码调用。可以按照下面我推荐的命名:

控件 显示内容text 控件名objectName
PushButton 导入图片 btnInput
PushButton 检测 btnTest
PushButton 保存 btnSave
Label 输入图片 labelinput
Label 结果图片 labelresult
TextBrowser textBrowser

2.按钮事件

我们知道GUI是通过事件驱动的,什么意思呢?比如前面我们已经设计好了界面,接下来就需要实现”导入图片”到”保存”这3个按钮的功能,也就是给每个按钮指定一个”函数”,逻辑代码写在这个函数里面。这种函数就称为事件,Qt中称为槽连接。
点击Designer工具栏的”Edit Signals/Slots”按钮,进入槽函数编辑界面,点击旁边的”Edit Widgets”可以恢复正常视图:
MaskRCNN可视化界面开发(PyQt5)_第7张图片
进入槽函数编辑界面后,然后点击按钮并拖动,当产生类似于电路中的接地符号时释放鼠标,参看下图:
MaskRCNN可视化界面开发(PyQt5)_第8张图片
到此,我们就完成了界面设计的所有工作,按下Ctrl+S保存当前窗口为.ui文件。

3.ui文件转py代码

MaskRCNN可视化界面开发(PyQt5)_第9张图片
运行PyUIC后,会生成UI个.py文件,打开.py就是我们需要的界面模板。注意不要直接在.py文件里编码,因为每一次运行PyUIC,生成的.py文件都会更新,添加的代码不会保存。

三、编写逻辑代码

在同一工作目录下新建一个”UI_main.py”的文件,存放逻辑代码。代码中的每部分我都写得比较独立,没有封装成函数,便于理解。代码看上去很长,但很简单,可以每个模块单独看。

我整体的思路比较简单:
1.当按下导入图片按键时,要导入的图片显示在待显示的label区域;
2.当按下导入检测按键时,运行原来的maskRCNN的测试部分的代码,并将测试部分的结果图片保存为temp.png,并显示在结果显示的label区域;
3.当按下导入保存按键时,读取temp.png图片,保存到指定位置。
4.以上三部步都会产生反馈状态,将反馈状态显示在textBrowser区域。
下面直接上代码:

import sys
import cv2 as cv

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
# from PyQt5.QtWidgets import QFileDialog, QMainWindow
from PyQt5.QtWidgets import QFileDialog, QMainWindow, QApplication

from untitled import Ui_MainWindow


class PyQtMainEntry(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle("路面缺陷检测软件V1.0")

        self.labelinput.setAlignment(Qt.AlignCenter)
        self.labelinput.setStyleSheet("QLabel{background:gray;}"
                                      "QLabel{color:rgba(255,255,255,150);"
                                      "font-size:20px;"
                                      "font-weight:bold;"
                                      "font-family:Roman times;}")

        self.labelresult.setAlignment(Qt.AlignCenter)
        self.labelresult.setStyleSheet("QLabel{background:gray;}"
                                       "QLabel{color:rgba(255,255,255,150);"
                                       "font-size:20px;"
                                       "font-weight:bold;"
                                       "font-family:Roman times;}")

    def btnTest_Pressed(self):
        if not hasattr(self, "captured"):
            # print("没有输入图像")
            # self.textBrowser.setPlainText("没有输入图像")
            return
        self.textBrowser.append("图像检测中...")



    def btnInput_Clicked(self):
        '''
        从本地读取图片
        '''
        global fname
        # 打开文件选取对话框
        filename, _ = QFileDialog.getOpenFileName(self, '打开图片', "", "*.jpg;;*.png;;All Files(*)")
        if filename:
            self.captured = cv.imread(str(filename))
            # OpenCV图像以BGR通道存储,显示时需要从BGR转到RGB
            self.captured = cv.cvtColor(self.captured, cv.COLOR_BGR2RGB)

            rows, cols, channels = self.captured.shape
            bytesPerLine = channels * cols
            QImg = QImage(self.captured.data, cols, rows, bytesPerLine, QImage.Format_RGB888)
            self.labelinput.setPixmap(QPixmap.fromImage(QImg).scaled(
                self.labelinput.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
        fname = filename
        print(fname)
        self.textBrowser.setPlainText("成功打开图片")

    def btnTest_Clicked(self):
        '''
        test
        '''
        global fname
        # 如果没有捕获图片,则不执行操作
        if not hasattr(self, "captured"):
            print("没有输入图像")
            self.textBrowser.setPlainText("没有输入图像")
            return
        print("start")
        print(fname.split("/")[-1])
        # -*- coding: utf-8 -*-
        import os
        import sys
        import skimage.io
        import matplotlib
        matplotlib.rcParams['font.sans-serif'] = ['KaiTi']
        matplotlib.rcParams['font.serif'] = ['KaiTi']
        from mrcnn.config import Config
        from datetime import datetime

        # Root directory of the project
        ROOT_DIR = os.getcwd()

        # Import Mask RCNN
        sys.path.append(ROOT_DIR)  # To find local version of the library
        from mrcnn import utils
        import mrcnn.model as modellib
        from mrcnn import visualize

        # Import COCO config
        # sys.path.append(os.path.join(ROOT_DIR, "samples/coco/"))  # To find local version
        # from samples.coco import coco

        # Directory to save logs and trained model
        MODEL_DIR = os.path.join(ROOT_DIR, "logs")

        # Local path to trained weights file
        # todo:模型位置
        COCO_MODEL_PATH = "E:\\maskrcnn_pycharm\\Mask_RCNN\\logs\\mask_rcnn_shapes_1000.h5"  # 模型保存目录
        # Download COCO trained weights from Releases if needed
        if not os.path.exists(COCO_MODEL_PATH):
            utils.download_trained_weights(COCO_MODEL_PATH)
            print("cuiwei***********************")

        # Directory of images to run detection on
        # todo:测试图片位置
        # IMAGE_DIR = os.path.join(ROOT_DIR, "picRGB")
        IMAGE_DIR = fname

        print(IMAGE_DIR)

        class ShapesConfig(Config):
            """Configuration for training on the toy shapes dataset.
            Derives from the base Config class and overrides values specific
            to the toy shapes dataset.
            """
            # Give the configuration a recognizable name
            NAME = "shapes"

            # Train on 1 GPU and 8 images per GPU. We can put multiple images on each
            # GPU because the images are small. Batch size is 8 (GPUs * images/GPU).
            GPU_COUNT = 1
            IMAGES_PER_GPU = 1

            # Number of classes (including background)
            NUM_CLASSES = 1 + 6  # background + 3 shapes

            # Use small images for faster training. Set the limits of the small side
            # the large side, and that determines the image shape.
            IMAGE_MIN_DIM = 320
            IMAGE_MAX_DIM = 512

            # Use smaller anchors because our image and objects are small
            RPN_ANCHOR_SCALES = (8 * 6, 16 * 6, 32 * 6, 64 * 6, 128 * 6)  # anchor side in pixels

            # Reduce training ROIs per image because the images are small and have
            # few objects. Aim to allow ROI sampling to pick 33% positive ROIs.
            TRAIN_ROIS_PER_IMAGE = 100

            # Use a small epoch since the data is simple
            STEPS_PER_EPOCH = 100

            # use small validation steps since the epoch is small
            VALIDATION_STEPS = 50

        # import train_tongue
        # class InferenceConfig(coco.CocoConfig):
        class InferenceConfig(ShapesConfig):
            # Set batch size to 1 since we'll be running inference on
            # one image at a time. Batch size = GPU_COUNT * IMAGES_PER_GPU
            GPU_COUNT = 1
            IMAGES_PER_GPU = 1

        config = InferenceConfig()

        # Create model object in inference mode.
        model = modellib.MaskRCNN(mode="inference", model_dir=MODEL_DIR, config=config)

        # Load weights trained on MS-COCO
        model.load_weights(COCO_MODEL_PATH, by_name=True)

        # COCO Class names
        # Index of the class in the list is its ID. For example, to get ID of
        # the teddy bear class, use: class_names.index('teddy bear')
        # class_names = ['BG', '隐裂']  # 注意修改类别名称
        class_names = ['BG', '灌缝修补', '横向裂缝', '块状裂缝', '块状修补', '纵向裂缝', '坑槽']
        # Load a random image from the images folder
        # file_names = next(os.walk(IMAGE_DIR))[2]
        # image = skimage.io.imread("E:\\maskrcnn_pycharm\\Mask_RCNN\\picRGB\\62.png")  # 你想要测试的图片
        image = skimage.io.imread(fname)  # 你想要测试的图片

        a = datetime.now()
        # Run detection
        results = model.detect([image], verbose=1)
        # print("result:",results)
        b = datetime.now()
        # Visualize results
        # print("检测用时", (b - a).seconds)
        time = (b - a).seconds
        self.textBrowser.append("检测用时:" + str(time) + "s")
        r = results[0]
        visualize.display_instances(image, r['rois'], r['masks'], r['class_ids'],
                                    class_names, r['scores'])

        class_ids = r['class_ids']

        class_dict = {
     }
        for index, i in enumerate(class_ids):
            if i in class_dict:
                class_dict[i] += 1
            else:
                class_dict[i] = 1

        output_dict = {
     }

        for key, value in class_dict.items():
            label = class_names[key]
            output_dict[label] = value
        print(output_dict)
        self.textBrowser.append("本张路面图片包含:" )
        for key, value in output_dict.items():
            self.textBrowser.append(str(value)+"处"+str(key))

        self.captured = cv.imread(r"temp.png")
        # OpenCV图像以BGR通道存储,显示时需要从BGR转到RGB
        self.captured = cv.cvtColor(self.captured, cv.COLOR_BGR2RGB)

        rows, cols, channels = self.captured.shape
        bytesPerLine = channels * cols
        QImg = QImage(self.captured.data, cols, rows, bytesPerLine, QImage.Format_RGB888)
        self.labelresult.setPixmap(QPixmap.fromImage(QImg).scaled(
            self.labelresult.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))

        self.textBrowser.append("检测完成")

    def btnSave_Clicked(self):
        '''
        保存
        '''
        global fname
        if not hasattr(self, "captured"):
            print("没有输入图像")
            self.textBrowser.setPlainText("没有输入图像")
            return
        tmp = fname.split('/')[-1]
        img = cv.imread("temp.png")
        fd, type = QFileDialog.getSaveFileName(self,
                                               "保存图片", tmp)
        print(fd)
        cv.imwrite(fd, img)
        # self.textBrowser.setPlainText("保存成功")
        self.textBrowser.append("保存成功")  # textedit是文本框的名称

        print("保存成功")


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = PyQtMainEntry()
    window.show()
    sys.exit(app.exec_())

今天就先写到这边,后续有想法再补充!
2020年12月8日15:32:30

四、补充

1.界面样式美化

原来的界面有比较朴实无华(丑),这两天在原来的基础上做了一些布局修改和样式效果,下面先看下美化后的效果(简单的美化,哈哈哈!!!)。
MaskRCNN可视化界面开发(PyQt5)_第10张图片

总的来说就是,加了一些图标、按键样式和背景。
实现这些只需要在之前代码的def __init__(self)初始化函数中加入以下代码:

        self.setWindowIcon(QIcon('E:\\maskRCNN\\Mask_RCNN\\icon\\head.png'))

        # 设置背景图片
        palette1 = QPalette()
        palette1.setBrush(self.backgroundRole(), QBrush(QPixmap('E:\\maskRCNN\\Mask_RCNN\\icon\\bg.jpg')))
        self.setPalette(palette1)

        self.setStyleSheet(
            'QPushButton{font-weight: bold; background: skyblue; border-radius: 14px;'  # 为按钮设置通用样式
            'width: 64px; height: 28px; font-size: 20px; text-align: center;}'
            'QPushButton:hover{background: rgb(50, 150, 255);}'  # 鼠标划到按钮上的样式
            'QLabel{font-weight: bold; font-size: 20px; color: orange}'  # QLabel通用样式
            'QLineEdit{width: 100px; font: 微软雅黑}'  # QlineEdit通用样式
        )

        # self.btnInput.setIcon(QIcon(r'icon/open_img.png'))
        self.btnInput.setStyleSheet("QPushButton{color:black}"
                                      "QPushButton:hover{color:red}"
                                      "QPushButton{background-color:lightgreen}"
                                      "QPushButton{border:2px}"
                                      "QPushButton{border-radius:10px}"
                                      "QPushButton{padding:2px 4px}")

        # self.btnTest.setIcon(QIcon(r'icon/start.png'))
        self.btnTest.setStyleSheet("QPushButton{color:black}"
                                    "QPushButton:hover{color:red}"
                                    "QPushButton{background-color:lightgreen}"
                                    "QPushButton{border:2px}"
                                    "QPushButton{border-radius:10px}"
                                    "QPushButton{padding:2px 4px}")

        # self.btnSave.setIcon(QIcon(r'icon/save.png'))
        self.btnSave.setStyleSheet("QPushButton{color:black}"
                                   "QPushButton:hover{color:red}"
                                   "QPushButton{background-color:lightgreen}"
                                   "QPushButton{border:2px}"
                                   "QPushButton{border-radius:10px}"
                                   "QPushButton{padding:2px 4px}")

这次的补充就先到这,下次预计更新pyinstaller打包成独立exe文件。
第一次更新:2020年12月10日21:10:12

2.pyinstaller打包成独立exe文件

现在maskRCNN环境中安装pyinstaller

pip install pyinstaller

cmd到文件夹下运行pyinstaller -w -F UI_main.py

MaskRCNN可视化界面开发(PyQt5)_第11张图片
出现上图后,说明打包成功。
在同级目录下就会出现一个dist文件夹,里面就有一个我们打包好的exe文件。
在这里插入图片描述

打包调试:

1.pyinstaller重新安装后不是内部或外部命令,也不是可运行的程序 或批处理文件

一般安装完pyinstaller 会默认在 python 的 Scripts 目录下,需要你配置好环境变量。
接着把pyinstaller.exe从(C:\Users…\AppData\Roaming\Python\Python36\Scripts)复制一份到cmd检索的路径中(C:\Program Files\Python36\Scripts),此处需要根据自己的路径稍作修改。

2.图片加载问题

我在最初打包的时候没有将图片的路径写为绝对路径,导致打包后的程序打开后不能够显示图片,解决办法就是将程序中的路径,全部写为绝对路径,这样打包后的程序打开后就直接可以看到图片了!

好了,到这里本文应该差不多写完了!
如果阅读本文对你有用,欢迎点赞评论收藏呀!!!
第二次更新:2020年12月11日17:07:14

你可能感兴趣的:(深度学习,python,深度学习,图像识别,qt,目标检测)