基于语义分割的矸石充填捣实机构防碰撞系统

对研一时候做的一个项目进行简短的总结~
背景:为某煤矿公司智能研究中心做一个智能检测:矸(gān)石充填防碰撞的检测和预警。矸石充填就是捣实机不断把传动带送过来的细碎矸石给往后捣实。以往都是矿工手动操控捣实机,由于矿工经常误操作,会把捣实机抬得过高,撞断传送带。现在使用计算机视觉的方法,借助海康威视的ip摄像头,实现一个智能的防碰撞系统,降低人力成本和撞击的概率。
总共包括:读取视频流,语义分割及图像处理,设计I/O接口,程序加密,多线程设计,程序封装
Demo:视频

在这里插入图片描述
在这里插入图片描述

语义分割识别模块

在讨论设计方案的时候,提出两种方案:
1.目标检测(Object Detection):如YOLO,Faster R-CNN…
2.语义分割(Semantic Segmentation):如AlexNet,Bisenet…
区别在于前者是物体的分类及定位,后者是像素级别的分类。根据实际需求,最终是需要计算捣实机构和传送带之间的视觉距离。目标检测的优点:计算距离的时候比较方便,只要预测是准确的,距离的计算即是上下两个bounding_box的坐标相减,但是目标检测一旦没有检测出来,一个检测物体就会”消失‘了,整个系统就失效了,即是一个非0即1的过程。语义分割的优点:像素级分割,会比目标检测的识别更加准确且细致。测距的实现,可以通过算法来进行弥补。所以最终选择的语义分割的方法。

1.神经网络的选择

基于工程有一定的实时性要求,所以网络需要尽可能的快速轻量。
通过我的实测和论文作者提供的FPS、iou等数据,bisenet是相对满足本项目的一个网络。所以最终选择该语义分割网络。实验环境:NVIDIA 2080TI+CUDA10.1
reference:https://github.com/CoinCheung/BiSeNet
paper: https://arxiv.org/abs/1808.00897
网络的运行和测试可以参考原作者的github

2.读取视频流

使用python-opencv拉流,读取实时视频通过ip地址+端口 以及用户名密码等。

import cv2
# user: admin
# pwd: 12345
# main: 主码流
# ip: 192.168.1.64
# Channels: 实时数据
# 1: 通道
cap = cv2.VideoCapture("rtsp://admin:12345@192.168.1.64/main/Channels/1")
print (cap.isOpened())
while cap.isOpened():
	 success,frame = cap.read()
	 cv2.imshow("frame",frame)
	 cv2.waitKey(1)

相当于视频的输入直接从ip摄像头中读取并直接输入神经网络。

3.画轮廓+去噪

轮廓的目的:①为了后续能够锁定捣实机和传送带,为后面测距做准备②不受到其他因素产生的误检所干扰。
利用cv2.findContours()函数来查找检测物体的轮廓,需要注意的是cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),所以读取的图像要先转成灰度的,再转成二值图,具体操作为下面的代码(注释)。

out_vis_image = helpers.colour_code_segmentation(output_image, label_values)
img = cv2.resize(cv2.cvtColor(np.uint8(out_vis_image), cv2.COLOR_RGB2BGR), (1024, 1024),interpolation=cv2.INTER_AREA)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换颜色空间
ret, thresh = cv2.threshold(gray, 5, 100, 0) #检测轮廓
image, contours, hier = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(img, contours, i, (0, 0, 0), cv2.FILLED)#绘制轮廓

需要注意的是:opencv2返回两个值:contours:hierarchy。opencv3会返回三个值,分别是img, countours, hierarchy,我这里使用opencv3所以会返回三个参数。contours返回的是所有轮廓的像素点坐标(x,y)。
这里还涉及到一个opencv返回轮廓的坑:一个python的np.ndarray(n维数组),假设轮廓有50个点,OpenCV返回的ndarray的维数是(50, 1, 2),而不是我们认为的(100, 2)。所以需要特殊对数据处理一下才能利用轮廓点的坐标。在numpy的数组中,用逗号分隔的是轴的索引。举个例子,假设有如下的数组:

a = np.array([[[3,4]], [[1,2]],[[5,7]],[[3,7]],[[1,8]]]) 

这里的shape是 (5, 1, 2),想要取出轮廓坐标需要 a[:,0]。
由于矿下环境复杂,捣实的过程环境很差,有煤渣覆盖和水汽等,一开始的预测效果有点差强人意,后期通过扩充数据集训练更拟合损失函数,精度有较大的提升。除此之外,借助opencv来对误检的噪点进行去除,只选中中间捣实机构的有效区域。
去噪
有了轮廓点的坐标就可以利用opencv的库函数contourArea求出轮廓的面积,,剔除小面积误检的轮廓,锁定中间区域的倒是机构和传送带,并使用高斯去噪操作,去噪之后的效果可以基本锁定倒是机构和传送带。

4.测算距离

利用轮廓处理后的坐标,由于区别于目标检测,语义分割没有规整的矩形框,所以需要进行坐标选点。
捣实机构和传送带两者,传送带如果不受到撞击是相对静止的,而捣实机构是会动态变化的,所以确定捣实机构的点坐标更加的关键。
依次在轮廓上选取四个点,并且取y坐标的最小值(相对人眼视角的最大值),将最小值(x1,y1)的向上延长,使用这个点的很坐标x得到在传动带内轮廓的对应坐标(x2,y2),然后x1-x2就可得到像素距离(需要注意的是:这里opencv的矩阵和我们所理解的横纵坐标是相反的,垂直方向是x,水平方向是y,左上角是(0,0))。
这块在后期测试的时候,遇到一个问题:在捣实机构向前推的时候,由于捣实机构上面会附带碎的矸石,所以会遮挡住传送带,这个时候是无法识别传送带的。
解决方案:一旦捣实机构的坐标小于传送带的下沿坐标,把传动带的坐标给保存下来,也就是上一时刻的传送带坐标。

输入/输出

因为需求的变化,需要同时对四个相机(总共有81个相机,81选4)下的捣实环境同时进行防碰撞检测。主程序在主目录的main.py,
为了减小程序的耦合,更好的并行运行,将输入视频流和图像处理分割成了两个子函数,分别为readframe和ca()分别有四个逻辑相同的子函数。
因为所有的处理(包括语义分割、图像处理、视频流读入、黑屏检测、程序加密)都需要在后台处理,所以前端需要留一个输入供用户选择控制的四个相机,以及检测系统需要随时输出每台相机下捣实机构与传送带的距离,输出给后面的PLC端控制。分别为in.txt,out.txt。所以主要涉及到怎么实时的修改输入输出文件。python有一个对文本的读写功能,可以满足需求。

f = open('in.txt')
urlgl = f.read().strip().split(',')

这里urlgl 设置的就是ip地址尾部的每个相机的区别。

def savetxt_compact(fname, x, fmt="%d", delimiter=','):
    with open(fname, 'w+') as fh:
        for row in x:
            line = delimiter.join("0" if value == 0 else fmt % value for value in row)
            fh.write(line + '\n')

保存输出的像素距离。

程序加密

使用的是tkinter设计的一个GUI,功能就是程序可以被指定运行指定时间,计时器到期后需要输入密码才能获得重新启动。相当于输入密码,又加了一段程序使用的时间周期。通过一个外部文件读取剩余时间,程序内部设计了一个类似于密码本的字典,外部显示的话是一个乱码,但是输入正确密码之后就会怎么指定的时间。一个数字对应一个字母,在外部显示的就是打乱的英文码。过程就类似于加密传输中的编码和解码。

dict1 = {'0': 'H', '1': '*', '2': 'q', '3': 'M', '4': '&', '5': 'd', '6': 'W', '7': 'K', '8': 'x', '9': '#'}
dict2 = {'0': 'n', '1': 'B', '2': 'c', '3': 'k', '4': 'F', '5': 'j', '6': '^', '7': 'L', '8': 's', '9': '%'}
dict3 = {'0': 'R', '1': 'r', '2': 'S', '3': '$', '4': 'Y', '5': 'Z', '6': 'A', '7': 'a', '8': 'U', '9': 'i'}

程序封装

因为企业的电脑是windows平台,且没有python和深度学习的环境,并且要求需要有可移植性,所以程序要整个封装成一个可执行文件。
使用的是外置的Pyinstaller模块,可以直接pip安装。

pip install pyinstaller

基本语法:

PyInstaller -F -w -i  xxx.ico dev.py --hidden-import=pandas._libs.tslibs.timedeltas

-F 指只生成一个exe文件,不生成其他dll文件
-w 不弹出交互窗口,如果你想程序运行的时候,与程序进行交互,则不加该参数
-i 设定程序图标 ,其后面的xxx.ico文件就是程序小图标
dev.py 要打包的程序,如果你不是在dev.py同一级目录下执行的打包命令,这里得写上dev.py的路径地址
–hidden-import=pandas._libs.tslibs.timedeltas 隐藏相关模块的引用

你在哪个目录下执行的命令,默认打包完成的文件或者文件夹就在该目录,需要特别注意的是如果程序是在虚拟环境下开发的,封装也需要在虚拟环境下执行,毕竟封装包括一些依赖库的封装。
py文件运行没问题,不代表你打包后的文件运行就没问题,在windows下测试时,可以使用windows下的powershell来运行,这样就不会闪退了。封装真的是一个很痛苦,很折腾的事情!!CUDA版本也需要匹配,包括一些细小的版本区别。

后记

本项目目前已经申请专利《一种基于深度学习的矸石充填捣实机构防碰撞应用方法》
请勿转载~
这个项目的github部分实现代码放在了我的个人https://github.com/hm7455/Anti-collision_Semantic-segmentation_,之前一直把项目的过程记录在本地文件里,一直学习别人的博客,现在也体验一下自己写博客的的感觉~

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值