斑马线检测 基于OpenCV

本文介绍了基于OpenCV的斑马线检测方法,利用梯度一致性等特征进行检测。通过预处理、Canny边缘检测和滑窗统计梯度方向来判断斑马线,有效地过滤减速带和停止线的干扰。在有磨损的斑马线上仍有不错的表现,但转弯时的斜向斑马线召回率不高。后续计划引入等间隔特征以提高精确度。
摘要由CSDN通过智能技术生成

两段程序分别测试视频和图片数据,算法参数相同(视频里没有对应改参数过滤车道线,但因为斑马线清晰所以不用过滤也无影响)
设置DEBUG变量为True时会输出每一步图像用于逐帧debug和调参(按下任意键或者按住不放下一步),设为False则只画最后结果图。
红色方框是判断为斑马线的滑窗,紫色方框是最终输出的斑马线位置(紫框计算目前默认了图内只会出现一条斑马线)

github: https://github.com/TomMao23/ZebraCrossing_Detection

基本思路

总结斑马线的四个特征:
梯度一致性
等间隔
多根线
斑马线比车道线宽
梯度一致性和等间隔是两个强分类特征,其中梯度一致性特征易召回,等间隔特征强精度。目前算法未使用等间隔特征,主要利用梯度一致,另外两个特征辅助。

转逆透视图, 中值滤波,开运算,闭运算预处理后Canny边缘检测,对边缘检测图用sobel求横纵梯度,得到梯度的模值和方向(方向归为0到90度, 即不区分正反),先过滤梯度太小的点。在滑窗内统计0:70度间隔5度的点直方图,取峰值方向的点数作为判断量,高于阈值判为斑马线。

问题及当前解决思路

  1. 过滤减速带:减速带同样具有梯度一致性,等间隔和线多的三个特征,但是有线短的特点,所以滑窗高度取得越大减速带越容易过滤,这是永远管用的。另一方面, 减速带是黄色(红+绿)黑色相间的,所以单使用蓝色通道而不是正常RGB转成的灰度图可以大大衰减减速带的梯度影响。
  2. 开运算有两个作用:能够减少噪点,可以利用斑马线比车道线更宽的特点用多iterations参数的开运算在保留斑马线的同时直接去除车道线干扰(缺点:若斑马线有磨损开运算会有一定损失,灰度图开运算可能会产生弱的虚假边缘,可以调参不检测出来)。
  3. 闭运算有两个作用:一是能够填补线磨损增强斑马线的边缘识别效果, 二是路面箭头破损时容易产生少量梯度杂乱的边缘增加误检的概率(如果斑马线无破损,阈值可以设得很高就没有这个问题)。即使无破损闭运算仍然很好地减少了其他元素的虚假边缘。
  4. 中值滤波的重要性:比起均值滤波等滤波器,同样是平滑的效果,并提升边缘检测效果,中值滤波保留了原始梯度大小更利于边缘的检出,同时可以完美地消除人行道的小砖缝纹理,所以中值滤波是必选。
  5. canny的重要性:试过直接用sobel x,y来做但是:
    1. 噪点虚假边缘较多。
    2. 一个边缘多个点,斑马线线多的特征被衰弱。
    3. 这么做只有一个梯度阈值判断过滤边缘,之后再根据梯度方向过滤,canny两个阈值并考虑连通性解决了前两个问题并且调参更方便,好效果的参数的范围也更大。所以用canny。
  6. 过滤停止线:由于当前方法利用线多特征,是在宽大于高的矩形滑窗内统计峰值梯度方向的点数(纵线斜线自然是线越多这样统计的点越多),直行时的停止线恰好在滑窗内且是横线峰值梯度方向点也会较多,所以统计时只取到0到70度(x轴方向梯度为0度),当转弯或斜行时停止线在滑窗内峰值梯度方向点不多,自然过滤。
  7. 主要干扰:停止线和减速带的干扰很小,容易调节阈值, 不成问题。路面箭头等标志是目前主要干扰,因为斑马线有缺损综合考虑召回不能把阈值调得非常高(目前阈值是1500,无缺损的清晰斑马线值会在4000到6000),当前阈值在测试图上无误检但有风险(部分箭头图最高值达到1300), 若是无缺损的清晰的斑马线可以把阈值调高解决这个问题。可能干扰:路面外边缘可能造成干扰,目前无,若出现此干扰可以调整滑窗位置大小尽可能不扫路面外解决这个问题。

结果示例

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

代码示例

//处理逆透视后的图
#coding=utf-8
import time
import os
import cv2
import numpy as np
from numpy.linalg import inv
def sliding_window(img1, img2, patch_size=(100,302), istep=50):#, jstep=1, scale=1.0):
    """
get patches and thier upper left corner coordinates
The size of the sliding window is currently fixed.
patch_size: sliding_window's size'
istep: Row stride
    """
    Ni, Nj = (int(s) for s in patch_size)
    for i in range(0, img1.shape[0] - Ni+1, istep):
        #for j in range(0, img1.shape[1] - Nj, jstep):
            #patch = (img1[i:i + Ni, j:j + Nj], img2[i:i + Ni, j:j + Nj])
        patch = (img1[i:i + Ni, 39:341], img2[i:i + Ni, 39:341])
        yield 
  • 1
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值