赞
踩
【原创文章】欢迎正常授权转载(联系作者)
【反对恶意复制粘贴,如有发现必维权】
【微信公众号原文传送门】
上篇详细介绍实现利用PyQt给SSD加界面的三种方案(没学的赶快点进来学呀,哈哈)。这篇将详细介绍方案1的实现代码(代码获取见文章末尾)。
下载好的代码中项目文件构成如下:
其中 “ssd” 文件夹中是SSD检测的关键文件,关于这部分之前写文章了,里面详细介绍了如何训练一个属于自己的SSD300,有代码、有预训练的权值文件,不清楚的请移步这里。
接下来详细介绍实现,先看看流程图,实现的关键在于 检测循环 和 显示。
这里推荐一个非常方便的PyQt开发IDE—— eric,整体开发过程有点像MFC的感觉,可以直观看见控件的动作信号,并直接创建对应的槽函数,开发非常有效率,可以节省大把时间。
创建一个对话框窗口或者主窗口,拖拽一个QLabel在主窗口中用于显示,两个QPushButton用于控制开始/停止,一个QTextEdit用于显示检测结果。当然添加什么控件还是按照自己的需求来。为了讲解下面的代码,这里我把用到的控件和名称列在下面。界面的布置如下图。
控件类型 | ObjectName | 作用 |
---|---|---|
QLabel | label_imgshow | 画面显示 |
QPushButton | pushButton_start | 开始 |
QPushButton | pushButton_end | 结束 |
QTextEdit | textEdit | 显示检测结果 |
绘制好ui文件(对应文件:MainWindow.ui)后将其转为.py文件(Ui_MainWindow.py)。eric 可以十分方便的完成转化,唯一麻烦的是,每次ui文件改变了都需要重新再“转化更新”一次。
界面显示主要是要将opencv的图像数据(numpy.array)显示在界面的QLabel(label_imgshow)中,项目中构建了一个类成员函数实现。
def show_img(self, img):
showImg = QImage(img.data, img.shape[1], img.shape[0],
img.shape[1] * 3, # 每行数据个数,3通道 所以width*3
QImage.Format_RGB888)
self.label_imgshow.setPixmap(QPixmap.fromImage(showImg)) # 展示图片
代码非常简单,就是先将numpy.array的数据转为QImage,再通过Qlabel控件的setPixmap将图像显示出来。每次更新显示时将opencv的图像数据作为参数,调用一次函数就行。
接下来就是最复杂(其实超简单)的帧循环了。在窗口实例化时,将SSD300模型建立并导入训练好的权值,点击‘开始’后时开始帧循环检测(循环在点击‘开始’的槽函数中),点击‘结束’后结束帧循环(通过控制循环条件实现)。
下面详细介绍构造函数及“开始/结束”按钮点击的槽函数。
功能:主要完成SSD的初始化以及一些依赖变量的初始化。
这里建议那些利用该方案来给自己搭建的网络添加界面的同学,建议将网络单独封装成类,界面类中使用时会非常便利。
def __init__(self, parent=None): super(MainWindow, self).__init__(parent) # 父类初始化 self.setupUi(self) # 窗口‘穿衣服’,变成我们设计的样子 # 初始化界面 # 设置图片自适应显示 self.label_imgshow.setScaledContents(True) # 创建一幅白色图片,在停止的时候显示 self.img_none = np.ones((420, 720, 3), dtype=np.uint8)*255 self.show_img(self.img_none) # 初始化SSD # 目标名称,按顺序 self.obj_names = ['Aeroplane', 'Bicycle', 'Bird', 'Boat', 'Bottle', 'Bus', 'Car', 'Cat', 'Chair', 'Cow', 'Diningtable', 'Dog', 'Horse', 'Motorbike', 'Person', 'Pottedplant', 'Sheep', 'Sofa', 'Train', 'Tvmonitor'] # 需要显示的目标list, 用于过滤 self.include_class = self.obj_names # 导入权值文件,关联检测目标类别名 self.ssd = SSD_test(weight_path='./ssd/weights/weights_SSD300.hdf5', class_nam_list=self.obj_names) # 摄像头索引号或者视频文件路径 self.camera_index = 0 # 电脑连接的摄像头默认为0 # opencv 支持 ip摄像头 # self.camera_index = './Voc_test.avi' # 主循环flg,控制循环, False时循环停止 self.video_flg = True
功能:获取图像数据流,之后开始帧循环检测
帧循环基本流程:读入图片–>预处理–>SSD检测–>处理检测结果–>结果绘制在图像上–>更新显示
@pyqtSlot() def on_pushButton_start_clicked(self): # 获取图像数据流 self.cap = cv2.VideoCapture(self.camera_index) # 判断数据流是否打开 if self.cap.isOpened(): # ‘开始’按钮设置为不可用 # 以免二次误点造成错误 self.pushButton_start.setEnabled(False) # 开始帧循环 self.video_flg = True while self.video_flg: # 按帧读取图像 ret, self.img_scr = self.cap.read() # opencv中图像为BGR,这里转为RGB # 因为我的SSD训练时用的是RGB图像,顺序错误会影响检测准确性 self.img_scr = cv2.cvtColor(self.img_scr, cv2.COLOR_BGR2RGB) # SSD检测 self.preds = self.ssd.Predict(self.img_scr) # 对检测结果过滤 self.preds = self.filter(self.preds, inclued_class=self.include_class) # 将检测结果绘制到图像 self.img_scr = self.draw_img(self.img_scr, self.preds) # 将检测结果显示在QTextEdit控件上 h, w = self.img_scr.shape[:2] self.text = self.decode_preds(self.preds, w=w, h=h) self.textEdit.setText(self.text) # 更新显示图像 self.show_img(self.img_scr) # 强制更新UI # 如果没有,界面就‘假死’了,因为一直处于循环里 QApplication.processEvents() else: self.textEdit.setText('摄像头未打开!!!\n请检查')
功能:改变帧循环条件停止循环;为下一次开始做准备
@pyqtSlot() def on_pushButton_end_clicked(self): # 改变循环条件,停止循环 self.video_flg = False # 显示空白图片 self.show_img(self.img_none) # 清除TextEdit中的显示 self.textEdit.clear() # 释放摄像头/数据流 # 先判断是不是当前实例是不是有‘cap’成员 # 防止摄像头已经释放完了,再次点击时报错 if hasattr(self, 'cap'): # 释放摄像头 self.cap.release() # 删除成员变量 del self.cap # 将‘开始’设置为可以点击,为再开始做准备 self.pushButton_start.setEnabled(True)
方案1源代码下载:
回复“SSD界面1”获取。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。