LanNetSegmentation branch完成语义分割,即判断出像素属于车道or背景Embedding branch完成像素的向量表示,用于后续聚类,以完成实例分割H-Net

Segmentation branch

解决样本分布不均衡

车道线像素远小于背景像素.loss函数的设计对不同像素赋给不同权重,降低背景权重.

该分支的输出为(w,h,2).

Embedding branch

loss的设计思路为使得属于同一条车道线的像素距离尽量小,属于不同车道线的像素距离尽可能大.即Discriminative loss.

该分支的输出为(w,h,n).n为表示像素的向量的维度.

实例分割

在Segmentation branch完成语义分割,Embedding branch完成像素的向量表示后,做聚类,完成实例分割.

H-net

透视变换

to do

车道线拟合

LaneNet的输出是每条车道线的像素集合,还需要根据这些像素点回归出一条车道线。传统的做法是将图片投影到鸟瞰图中,然后使用二次或三次多项式进行拟合。在这种方法中,转换矩阵H只被计算一次,所有的图片使用的是相同的转换矩阵,这会导致坡度变化下的误差。

为了解决这个问题,论文训练了一个可以预测变换矩阵H的神经网络HNet,网络的输入是图片,输出是转置矩阵H。之前移植过Opencv逆透视变换矩阵的源码,里面转换矩阵需要8个参数,这儿只给了6个参数的自由度,一开始有些疑惑,后来仔细阅读paper,发现作者已经给出了解释,是为了对转换矩阵在水平方向上的变换进行约束。

代码分析

binary_seg_image, instance_seg_image = sess.run(            [binary_seg_ret, instance_seg_ret],            feed_dict={input_tensor: [image]}        )

输入(1,256,512,3)输出binary_seg_image:(1, 256, 512) instance_seg_image:(1, 256, 512, 4)

完成像素级别的分类和向量表示

class LaneNet的inference分为两步.

第一步提取分割的特征,包括了用于语义分割的特征和用以实例分割的特征.

class LaneNet(cnn_basenet.CNNBaseModel):    def inference(self, input_tensor, name):        """        :param input_tensor:        :param name:        :return:        """        with tf.variable_scope(name_or_scope=name, reuse=self._reuse):            # first extract image features            extract_feats_result = self._frontend.build_model(                input_tensor=input_tensor,                name='{:s}_frontend'.format(self._net_flag),                reuse=self._reuse            )            #得到一个字典,包含了用于语义分割的feature map和用于实例分割的feature map.            #binary_segment_logits (1,256,512,2) 2是类别数目.即车道/背景.            #instance_segment_logits (1,256,512,64) 用以后面再做卷积为每个像素生成一个向量表示            print('features:',extract_feats_result)            # second apply backend process            binary_seg_prediction, instance_seg_prediction = self._backend.inference(                binary_seg_logits=extract_feats_result['binary_segment_logits']['data'],                instance_seg_logits=extract_feats_result['instance_segment_logits']['data'],                name='{:s}_backend'.format(self._net_flag),                reuse=self._reuse            )            if not self._reuse:                self._reuse = True        return binary_seg_prediction, instance_seg_prediction

第一步得到的features如下:

features : OrderedDict([('encode_stage_1_share', {'data': , 'shape': [1, 256, 512, 64]}), ('encode_stage_2_share', {'data': , 'shape': [1, 128, 256, 128]}), ('encode_stage_3_share', {'data': , 'shape': [1, 64, 128, 256]}), ('encode_stage_4_share', {'data': , 'shape': [1, 32, 64, 512]}), ('encode_stage_5_binary', {'data': , 'shape': [1, 16, 32, 512]}), ('encode_stage_5_instance', {'data': , 'shape': [1, 16, 32, 512]}), ('binary_segment_logits', {'data': , 'shape': [1, 256, 512, 2]}), ('instance_segment_logits', {'data': , 'shape': [1, 256, 512, 64]})])

特征提取完毕,做后处理

class LaneNetBackEnd(cnn_basenet.CNNBaseModel):        def inference(self, binary_seg_logits, instance_seg_logits, name, reuse):            """            :param binary_seg_logits:            :param instance_seg_logits:            :param name:            :param reuse:            :return:            """            with tf.variable_scope(name_or_scope=name, reuse=reuse):                with tf.variable_scope(name_or_scope='binary_seg'):                    binary_seg_score = tf.nn.softmax(logits=binary_seg_logits)                    binary_seg_prediction = tf.argmax(binary_seg_score, axis=-1)                with tf.variable_scope(name_or_scope='instance_seg'):                    pix_bn = self.layerbn(                        inputdata=instance_seg_logits, is_training=self._is_training, name='pix_bn')                    pix_relu = self.relu(inputdata=pix_bn, name='pix_relu')                    instance_seg_prediction = self.conv2d(                        inputdata=pix_relu,                        out_channel=CFG.TRAIN.EMBEDDING_FEATS_DIMS,                        kernel_size=1,                        use_bias=False,                        name='pix_embedding_conv'                    )            return binary_seg_prediction, instance_seg_prediction

对每个像素的分类,做softmax转成概率.再argmax求概率较大值的下标.对每个像素的向量表示,用1x1卷积核做卷积,得到channel维度=CFG.TRAIN.EMBEDDING_FEATS_DIMS(配置为4).即(1,256,512,64)卷积得到(1,256,512,4)的tensor.即每个像素用一个四维向量表示.

所以,整个LaneNet的inference返回的是两个tensor.一个shape为(1,256,512) 一个为(1,256,512,4).

后处理

class LaneNetPostProcessor(object):    def postprocess(self, binary_seg_result, instance_seg_result=None,                min_area_threshold=100, source_image=None,                data_source='tusimple'):

对binary_seg_result,先通过形态学操作将小的空洞去除.参考 https://www.cnblogs.com/sdu20112013/p/11672634.html

然后做聚类.

def _get_lane_embedding_feats(binary_seg_ret, instance_seg_ret):        """        get lane embedding features according the binary seg result        :param binary_seg_ret:        :param instance_seg_ret:        :return:        """        idx = np.where(binary_seg_ret == 255) #idx (b,h,w)        lane_embedding_feats = instance_seg_ret[idx]                # idx_scale = np.vstack((idx[0] / 256.0, idx[1] / 512.0)).transpose()        # lane_embedding_feats = np.hstack((lane_embedding_feats, idx_scale))        lane_coordinate = np.vstack((idx[1], idx[0])).transpose()        assert lane_embedding_feats.shape[0] == lane_coordinate.shape[0]        ret = {            'lane_embedding_feats': lane_embedding_feats,            'lane_coordinates': lane_coordinate        }        return ret

获取到坐标及对应坐标像素对应的向量表示.

np.where(condition)

只有条件 (condition),没有x和y,则输出满足条件 (即非0) 元素的坐标 (等价于numpy.nonzero)。这里的坐标以tuple的形式给出,通常原数组有多少维,输出的tuple中就包含几个数组,分别对应符合条件元素的各维坐标。

测试结果

tensorflow-gpu 1.15.2

4张titan xp

(4, 256, 512) (4, 256, 512, 4)

I0302 17:04:31.276140 29376 test_lanenet.py:222] imgae inference cost time: 2.58794s

(32, 256, 512) (32, 256, 512, 4)

I0302 17:05:50.322593 29632 test_lanenet.py:222] imgae inference cost time: 4.31036s

类似于高吞吐量,高延迟.对单帧图片处理在1-2s,多幅图片同时处理,平均下来的处理速度在0.1s.

论文里的backbone为enet,在nvida 1080 ti上推理速度52fps.

对于这个问题的解释,作者的解释是

2.Origin paper use Enet as backbone net but I use vgg16 as backbone net so speed will not get as fast as that. 3.Gpu need a short time to warm up and you can adjust your batch size to test the speed again:)

一个是特征提取网络和论文里不一致,一个是gpu有一个短暂的warm up的时间.

我自己的测试结果是在extract image features耗时较多.换一个backbone可能会有改善.

def inference(self, input_tensor, name):        """        :param input_tensor:        :param name:        :return:        """        print("***************,input_tensor shape:",input_tensor.shape)        with tf.variable_scope(name_or_scope=name, reuse=self._reuse):            t_start = time.time()            # first extract image features            extract_feats_result = self._frontend.build_model(                input_tensor=input_tensor,                name='{:s}_frontend'.format(self._net_flag),                reuse=self._reuse            )            t_cost = time.time() - t_start            glog.info('extract image features cost time: {:.5f}s'.format(t_cost))            # second apply backend process            t_start = time.time()            binary_seg_prediction, instance_seg_prediction = self._backend.inference(                binary_seg_logits=extract_feats_result['binary_segment_logits']['data'],                instance_seg_logits=extract_feats_result['instance_segment_logits']['data'],                name='{:s}_backend'.format(self._net_flag),                reuse=self._reuse            )            t_cost = time.time() - t_start            glog.info('backend process cost time: {:.5f}s'.format(t_cost))            if not self._reuse:                self._reuse = True        return binary_seg_prediction, instance_seg_prediction

sift线特征提取代码_车道线检测LaneNet相关推荐

  1. sift线特征提取代码_Transformer 又立功了!又快(420 fps)又好的车道线检测算法

    分享一篇新出的论文 End-to-end Lane Shape Prediction with Transformers,该文为车道线检测问题建立参数模型,使用Transformer捕获道路中细长车道 ...

  2. K线形态识别_锤头线和吊颈线(绞刑线)

    写在前面: 1. 本文中提到的"K线形态查看工具"的具体使用操作请查看该博文: 2. K线形体所处背景,诸如处在上升趋势.下降趋势.盘整等,背景内容在K线形态策略代码中没有体现: ...

  3. matlab人眼疲劳检测代码_铝箔表面缺陷检测设备

    随着用户对铝材质量要求的日益严格,越来越多的生产厂家开始注重铝箔本身的表面质量问题,辊印,针孔,褶皱,凹坑,氧化,擦伤,麻点等瑕疵为表面的主要缺陷,很小的瑕疵都会影响产品的质量.目前传统的生产型企业都 ...

  4. 显著性目标检测matlab代码_显著性目标检测代码全汇总!(包含2D、3D、4D以及Video)...

    点击蓝字  关注我们 Tips◎本文为极市开发者原创投稿,转载请注明来源.◎极市「论文推荐」专栏,帮助开发者们推广分享自己的最新工作,欢迎大家投稿.联系极市小编(fengcall19)即可投稿~ 极市 ...

  5. 小杜机器人线下店_阿里线下卖车已成事实,阿里造车还会远吗?

    阿里巴巴:一个互联网行业巨无霸. 电动车:一个外行人眼中不起眼的"低端"组装产业. 殊不知,看起来毫无关联的两者正在发生激烈的化学反应,越来越多的事实表明这个互联网的巨无霸阿里巴巴 ...

  6. 小杜机器人线下店_打通线上线下渠道 九号机器人新零售模式成型

    来源:环球网 [环球网科技综合报道]日前,小米生态链企业之一的九号机器人在全国100多个城市开设的199+ "5G智慧零售门店"同期开业,标志着九号电动正式进军线下,市场版图进一步 ...

  7. 基于实例分割方法的端到端车道线检测 论文+代码解读

    Towards End-to-End Lane Detection: an Instance Segmentation Approach 论文原文 https://arxiv.org/pdf/1802 ...

  8. 基于深度强化学习的车道线检测和定位(Deep reinforcement learning based lane detection and localization) 论文解读+代码复现

    之前读过这篇论文,导师说要复现,这里记录一下.废话不多说,再重读一下论文. 注:非一字一句翻译.个人理解,一定偏颇. 基于深度强化学习的车道检测和定位 官方源码下载:https://github.co ...

  9. 空间中的语义直线检测_基于语义分割的车道线检测算法研究

    龙源期刊网 http://www.qikan.com.cn 基于语义分割的车道线检测算法研究 作者:张道芳 张儒良 来源:<科技创新与应用> 2019 年第 06 期 摘 ; 要:随着半自 ...

最新文章

  1. OCM_第十二天课程:Section6 —》数据库性能调优_ 资源管理器/执行计划
  2. Linux ifconfig指令
  3. Java并发编程实战 第4章 对象的组合
  4. Java NIO系列教程(四) Scatter/Gather
  5. redis key命名规范_redis简介
  6. 谷歌推出TensorFlow Lattice,让机器学习模型适应总体趋势
  7. DataTable 去重合并
  8. windows2003安装网络打印机的问题(原创,转载请注明)
  9. 面向对象的三大特性 - 继承、多态、封装
  10. 日期插件(jedate)
  11. 如何安装百度分享按钮
  12. 服务器虚拟机如何连接显示器,Windows 10:如何在VMware虚拟机上使用双显示器
  13. 智能灯控制页面用HTML编写,3分钟教你创建手机APP控制全彩智能灯泡应用,图形化编程!...
  14. 自动驾驶发展_自动驾驶网络及其发展
  15. 人类早期驯服野生CNN卷积神经网络的情景
  16. word里显示修订的最终状态的方法
  17. 22届电工类应届毕业生想找工作?赶快点进来看吧!
  18. 代码深度查看工具Fisheye安装破解
  19. 犀牛6.0grasshopper翻译插件_Grasshopper黏菌生长模拟
  20. 计算机桌面图标怎么改,小编教你电脑如何更改桌面图标

热门文章

  1. Oracle+BEA后的ESB
  2. 在哪里定义_创意设计学院举办设计从哪里来,到哪里去”专题讲座
  3. linux以预置密码进行验证拒绝访问,Linux重置MySQL密码
  4. [蓝桥杯][算法提高VIP]项链(dfs)
  5. Python实现中文分词--正向最大匹配和逆向最大匹配
  6. 热狗树 树形dp(中国石油大学我要变强第九场)
  7. android 消息列表,[Android]用LinearLayout 实现类微信消息列表项
  8. Android NDK各版本下载
  9. python性能分析工具_Python Profilers 分析器
  10. 操作系统--死锁避免(银行家算法)