【搞事情】利用PyQt为目标检测SSD300添加界面(一)

【原创文章】欢迎正常授权转载(联系作者)
【反对恶意复制粘贴,如有发现必维权】
【微信公众号原文传送门


SSD界面
CSDN上好多人留言想要我上面程序的源码,但是真的抱歉,由于种种原因我不能直接将这个代码给大家。但我会利用大概几节教程中详细介绍如何实现视频流的采集–实时检测–显示界面,并重新写一个项目,并将代码分享。

本节教程主要从思想上给大家分享项目是如何实现的。
在下一教程中,我将结合之前发过的教程《基于Keras搭建的SSD300目标检测神经网络》(没学的赶快点进去学呀,哈哈)详细介绍代码实现,并将源代码分享给大家。


1. 需求描述

项目要实现视频流采集图像,然后将图像送入SSD300检测,再将检测结果绘制在采集到的图像,最后将图像在界面上显示出来,同时界面要控制上述流程。
做之前需要了解的几点注意事项

(1) opencv中图像保存在numpy.array类型的数组中,PyQt显示控件无法直接使用,显示opencv的图像是需要转换一下。
(2) 不同进程在内存上是隔离的,变量不能在进程间直接调用(也可以实现共享内存)。
(3) PyQt界面自己有一套信号传递处理循环机制来处理人机交互的命令,并且在一个GUI线程中完成。
(4) 基于keras+TensorFlow的模型预测需要在进程中执行,不能在线程中。

简单的思考后我们可以画出一个关系图。
关系流程图
从上面看是不是太简单了?真的这样吗?简单实现一张图片的检测并显示在界面里是挺简单的,但是我们的目标是不断采集视频流、检测并在界面上显示出来,因此重要的是上面红线,如何通过界面控制采集检测显示出来(人机交互嘛,最基本的要可以点击按钮来控制检测显示开始结束吧?要不要界面干什么?)


2. 解决方案1

熟悉使用opencv + 帧循环的同学简单思考一下就可以获得一个最简单的解决方案(如下图):点击“开始”后直接创建帧循环获取视频图像,再检测,然后在显示界面上,之后继续进入下一循环,直到点击“结束”改变条件跳出循环就行了呀。
解决方案1流程
简直完美有没有?但是实际这么做的时候你就会发现如果把帧循环放在“开始”按钮的响应函数里,你的界面什么也不会有,鼠标点击后还在出现“程序无响应”,这是为什么呢?代码搞错了?并不是,这是界面“假死”了,现在回过头去看看上面的注意事项(3),这是因为PyQt里的“更新”机制是在执行你按钮响应函数后,由它自己的机制去显示你对控件外观的改变(就是显示你的图片),而你的响应函数下有个循环呀~它在一直跑呀,所有这个按钮响应函数根本没有执行完呀,它怎么会去执行更新显示呢?

通常我们遇到这种需要长时间run的循环是单独把它放在线程里,这样就不影响界面的GUI线程了,但是注意事项(4)怎么说的?不行了吧?

那我放在进程里,这个是可以了,但是需要把图像采集的过程也放在这个进程里,因为注意事项(2)说进程之间的内存不共享。如果放在同一进程下,那对这个进程的控制会变得很复杂,新手(作者就是)有好多问题处理不好的,会越来越麻烦;如果放在不同的进程,那大量图片数据通过进程通信是没办法的,虽然Python下也有进程共享内存处理方法,但涉及数据转换,经测试耗时严重,不能实时,而且也很复杂。

我的处理方法是意外发现了这个函数

QApplication.processEvents()

这个函数可以实现强制GUI线程“立刻更新”你对界面控件作出的改变,只要在帧循环里执行显示后加上这一句就可以完美完成上面的需求。

进一步思考:上面的方案对于摄像头现采集的视频流进行检测时,没有什么大的问题,只要你的计算机算力足够,那么实时显示没有问题(在英伟达750M上测试过基本流畅检测显示),但对于视频文件而言问题就来了,如果你的电脑太快,画面就是“加速播放”,因为没有控制帧率。


3. 解决方案2

强调:该方法尚未测试不知道是否可行。

这个方法主要就是为了解决文件视频流出现加速播放的问题(作者是穷鬼没有好设备,没遇到速度太快的问题,所以没测试,嘤嘤嘤~)

基本想法就是用QTimer(计时器)来解决,计时器可以设置一个计时,只要时间到了就会给对应的槽函数发送一个信号来执行槽函数,然后重新计时,一直重复这个过程,直到计时器被停止,我们可以利用计时器来代替帧循环。

基本流程如下图,点击“开始”后,启动计时器开始计时,时间(1/FPS 单位:s)一到就执行计时器槽函数(采集图像–检测–显示);结束时关闭计时器就好。

解决方案2流程
进一步思考:上面的方案如果可行就能解决检测视频时播放速度不对的问题,当然计时器的时间设计要考虑到预测耗时。对应算力有限的同学来说,无论是解决方案1还是解决方案2,基本面临的情况是:画面一帧一帧的卡过(简直要把穷人逼疯),有些时候其实也不用每帧图像都检测呀~能不能隔一段时间检测一下,实现流畅的播放视频呢?毕竟咱没泰坦呀。请阅读解决方案3


4. 解决方案3

强调:该方法已测试确认可行,放心操作。

这个方法主要就是“抽帧”检测,跳过检测时在播放显示的那些帧,做到播放视频与检测并行运行。显然这种方法要是将检测结果显示出来,那目标框就会在视频中一闪而过,所以这个方法适合将检测结果独立显示出来。
基本实现就是利用多进程+进程共享内存。基本流程如下图所示。
解决方案3流程
软件初始化时单独建立SSD进程及共享内存,图像采集及播放显示由定时器完成,采集到的图像复制到共享内存,SSD进程获得图片后进行检测,检测结束后通知计时器可以向共享内存写入图片了,然后一直循环往复进行下去。

多进程及共享内存:

# 多进程及进程通讯
from multiprocessing import Process, Queue
# 共享内存
from multiprocessing.sharedctypes import RawArray, RawValue
# RawArray :共享数组变量
# RawValue :共享值变量,具体什么类型可设置

最近在赶毕业论文,没时间更新了,下一节详细介绍代码的估计要一周后更新了。
需要的请关注公众号,第一时间获取更新

如果你读后有收获,欢迎关注我的微信公众号
上面有更多完全免费教程,我也会不定期更新
ღ ღ ღ 打开微信扫描下方二维码关注 ღ ღ ღ

在这里插入图片描述

发布了13 篇原创文章 · 获赞 24 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章