通过语义分割的道路识别

在上一个系列中,我对家用储罐的自动运动进行了实验。 使用滤色器识别道路,然后将得到的遮罩转到经过专门训练的分类器神经网络的入口,该神经网络选择向右,向左或向右行驶。

弱点是由于色调的可变性而对道路本身的认识,因此决策神经网络产生了奇怪的结果。 该文章的评论建议注意语义分割。 事实证明该主题很有希望,而分段神经网络的使用带来了它的优点,但也带来了它的缺点,如果没有它们的话。

但是首先要注意的是设备。

细分


分割是突出显示图像某些部分的过程。 最简单和最明显的细分类型是颜色。 但是,使用这种方法无法理解图片中所描绘的内容和位置。

这是一篇描述原始方法的好文章

语义分割


语义分割-通过确定这些对象的类型将图像拆分为对象。

看起来像这样:



结果令人印象深刻,让我们看看将其转化为现实生活是值得的。

网络


最著名的神经网络,最初是为医学而开发的。
主要来源

人们很快意识到该方法可用于所有场合。

互联网上有许多文章如何准备数据和训练U-net网络:


但是,我没有找到可以快速使用和试验的现成的U-net网络。

网络


一个鲜为人知的网络。 专为识别城市街道而设计。


资料


最受欢迎的街道细分数据集(最初教过E-net):


在相同的数据集上,U-net现在正在接受训练。

实施选择


关于细分的新信息泛滥成灾。 本能地,我想坚持一些简单的方法。 我没有内心的禅意来理解网络的架构并花时间学习。 但是,在PyImageSearch的文章中, 还有一个现成的,经过训练的神经网络,其格式与OpenCV-DNN兼容。

因此,选择了最小的阻力。

使用非常简单:
(最令人担忧的是,网络是在1024x512的图片上训练的-首先,这比摄像机在Raspberry上所提供的要多,其次,处理此数据量所需的性能有些令人困惑。结果,主要问题就是这样。)

我们从文件中读取神经网络(一种是模型本身,另一种是类名,第三种是颜色)。

def load_segment_model(): try: classes = None with open(PiConf.SEGMENT_CLASSES) as f: classes = f.read().strip().split("\n") colors = None with open(PiConf.SEGMENT_COLORS) as f: colors= f.read().strip().split("\n") colors = [np.array(c.split(",")).astype("int") for c in colors] colors = np.array(colors, dtype="uint8") print("[INFO] loading model...") net = cv2.dnn.readNet(PiConf.SEGMENT_MODEL) return net, classes, colors except Exception as e: logging.exception("Cannot load segment model") return None, None, None 

我们对图像进行分割,同时在原始图像上方标记片段
(在我的情况下,除道路以外的所有类都是不可见的)。

 def segment_image(image_path, seg_net, seg_classes, seg_colors): image0 = cv2.imread(image_path) image = cv2.resize(image0, (1024, 512),interpolation=cv2.INTER_NEAREST) blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (1024, 512), 0, swapRB=True, crop=False) seg_net.setInput(blob) start = time.time() output = seg_net.forward() end = time.time() print("[INFO] inference took {:.4f} seconds".format(end - start)) (numClasses, height, width) = output.shape[1:4] classMap = np.argmax(output[0], axis=0) mask = seg_colors[classMap] mask = cv2.resize(mask, (image0.shape[1], image0.shape[0]),interpolation=cv2.INTER_NEAREST) classMap = cv2.resize(classMap, (image0.shape[1], image0.shape[0]), interpolation=cv2.INTER_NEAREST) gmask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY) gmask = cv2.resize(gmask, (128, 64), interpolation=cv2.INTER_NEAREST) gmask = gmask[0:64,32:96] output = ((0.6 * image0) + (0.4 * mask)).astype("uint8") return output, gmask 

检查一下


我们从战车上拍摄现成的照片,并在其上设置分段的神经网络。

1个



仅人行道的左侧被认为是昂贵的。

我们压缩图片并从中获取64x64的中心尺寸:
(此大小是神经网络所期望的,它决定改变方向)



方向的神经网络(实际上是分类器)命令向左移动。 不是很正确,但是可以忍受。

2



同样,再次丢失了右下角(也有沥青湿)。
但是,大多数道路仍被认可。



分类器建议直接进行。

3

机器人在人行道中央的情况。



这条路几乎被公认。



分类器命令向右移动(下次找到道路的边缘)。

申请书


在对储罐固件进行了一些修改之后,我用分段神经网络替换了色路检测器。

在Raspberry Pi上启动所有这些功能时,首先出现的就是降低性能。
分割一幅图像需要6秒钟-在这段时间内,坦克通过强劲的小跑成功滑过所有转弯。

在实际测试中,尽管对人行道几乎完全识别并且来自控制神经网络发出了正确的命令,但还是发生了这种情况,在处理图像的过程中,水箱设法搁置了。



通常,无法在Raspberry上消化此大小的图像。
看来您仍然必须进行专门的神经网络训练。

参考文献


Source: https://habr.com/ru/post/zh-CN452088/


All Articles