目录

一、图像二值化处理

1.Sobel算子+绝对值

2.Sobel算子

3.倾斜角度

4.HLS颜色空间

5.二值图结合

二、车道线分割

1.仿射变换

2.车道线直方图

3.滑动窗口寻找车道线

4.车道线拟合

5.车道线区域标注


一、图像二值化处理

主要目的是通过二值化图像,使得车道线那部分图像被尽可能多地显示出来。这里使用4中方式得到不同的二值图。

1.Sobel算子+绝对值

转为灰度图后,将求得的x,y方向上的Sobel梯度(64位浮点数)取他们的绝对值,并进行归一化后,转为8位无符号数,根据设定的阈值筛选。

原因:标准的计算梯度的方式是下面第二种,通常,为了计算方便,也会直接取绝对值。

def abs_sobel_threshold(img, orient='x', thresh_min=2, thresh_max=1000000):gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)abs_sobel = Noneif orient == 'x':abs_sobel = np.absolute(cv2.Sobel(gray, cv2.CV_64F, 1, 0))if orient == 'y':abs_sobel = np.absolute(cv2.Sobel(gray, cv2.CV_64F, 0, 1))scaled_sobel = np.uint8(255 * abs_sobel / np.max(abs_sobel))binary_output = np.zeros_like(scaled_sobel)binary_output[(scaled_sobel >= thresh_min) & (scaled_sobel <= thresh_max)] = 255return binary_output

2.Sobel算子

这里是计算的实际的xy方向上的梯度大小,公式是G = np.sqrt( G(x)**2 + G(y)**2 )。同样也是进行归一化,转为8位无符号数。

def mag_threshold(img, sobel_kernel=3, mag_threshold=(50, 1000)):gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=sobel_kernel)sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=sobel_kernel)gradmag = np.sqrt(sobel_x ** 2 + sobel_y ** 2)scale_factor = np.max(gradmag) / 255gradmag = (gradmag / scale_factor).astype(np.uint8)binary_out = np.zeros_like(gradmag)binary_out[(gradmag >= mag_threshold[0]) & (gradmag <= mag_threshold[1])] = 255return binary_out

3.倾斜角度

求出梯度后,通过arctan求得y和x之间的角度,并根据设定的角度的阈值过滤。这里设定了0.7和1.3之间,大约是45°-80°,也就是y方向梯度比x方向的梯度要大,但不能过大,如果y方向上梯度变化很大,x方向上梯度变化很小,可能是图中明暗交界非常明显的地方,以及车道线白线和车道交界的地方。根据下面第三张图可以看出来。主要保留了左边的黄色车道线。

def dir_threshold(img, sobel_kernel=5, thresh=(0.7, 1.3)):'''根据倾斜角度过滤'''gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=sobel_kernel)sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=sobel_kernel)absgraddir = np.arctan(sobel_y / (sobel_x + 1e-7))binary_out = np.zeros_like(absgraddir)binary_out[(absgraddir >= thresh[0]) & (absgraddir <= thresh[1])] = 255return binary_out

4.HLS颜色空间

将原来的RGB图像,转到HLS颜色空间,并取出S通道,根据阈值,对S通道进行筛选。

原因:车道线是白色以及黄色,训练图像是深色的路面以及其他标识,因此将颜色转换到HLS色域,该颜色空间的三种表示方式分别是:Hue(色相)、Saturation(饱和度)、Lightness(亮度)。饱和度越低,颜色越偏向于灰色。亮度越高,颜色越偏向于白色。色相越高,颜色越鲜艳。因此,由于训练图整体是偏灰色的,把饱和度高的这一部分的提取出来,会更容易取出车道线。

def hls_thresh(img, thresh=(100, 255)):hls = cv2.cvtColor(img, cv2.COLOR_RGB2HLS)_, _, s_channel = cv2.split(hls)binary_output = np.zeros_like(s_channel)binary_output[(s_channel >= thresh[0]) & (s_channel <= thresh[1])] = 255return binary_output

5.二值图结合

以上四种方式,根据调整的阈值不同,可能有不同的效果,我们根据四个输出,对其进行融合,得到最终的二值图。

def combined_threshold(img):abs_bin = abs_sobel_threshold(img, orient='x', thresh_min=50, thresh_max=255)mag_bin = mag_threshold(img, mag_threshold=(50, 255))dir_bin = dir_threshold(img, sobel_kernel=5, thresh=(0.7, 1.3))hls_bin = hls_thresh(img, thresh=(170, 255))combined = np.zeros_like(dir_bin)combined[(abs_bin == 255) & (mag_bin == 255) & (dir_bin == 255) | (hls_bin == 255)] = 255return combined, abs_bin, mag_bin, dir_bin, hls_bin

以上四种以及二值图结合后效果如下:

二、车道线分割

1.仿射变换

SRC是实际图像的车道线所在的位置四点坐标,原图是1280*720,选出了一个梯形的车道线。DST是目标图像四点坐标,是一个矩形,要把车道线映射到这个矩形上。也就是说我们要把原图中,有畸变的车道线,变成一个俯视图的车道线。因此这里先获取到变换矩阵m以及逆变换矩阵m_inv。

import cv2
import numpy as np
import matplotlib.pyplot as pltsrc = np.float32([[200, 720], [1100, 720], [595, 450], [685, 450]])
dst = np.float32([[300, 720], [980, 720], [300, 0], [980, 0]])
m_inv = cv2.getPerspectiveTransform(dst, src)
m = cv2.getPerspectiveTransform(src, dst)

2.车道线直方图

(这里首先把原图的1280*720转为了720*1280,也就是行和列的表示方式,以方便矩阵运算。)

由于已经转为了二值图,车道线在图的下半部分,于是我们直接把下半部分,沿着高的方向求和,就可以得到直方图了。从1280/2=640也就是图的中心位置,左右两侧分别从100开始,找到峰值,峰值所在的地方,就是车道线的地方。

    histogram = np.sum(binary_warped[int(binary_warped.shape[0] / 2):, :], axis=0)midpoint = np.int(histogram.shape[0] / 2)leftx_base = np.argmax(histogram[100:midpoint]) + 100rightx_base = np.argmax(histogram[midpoint:binary_warped.shape[1] - 100]) + midpoint

3.滑动窗口寻找车道线

首先选出图像中的非零点,并返回非零点的x和y坐标,这张图里面有23819个非零点,那么x和y就全都是23819维的向量。注意:矩阵的行,是坐标中的y,矩阵的列,是坐标中的x。

滑动窗口的方式是由上到下,窗口的起始位置,就是峰值所在的像素点的位置。窗口宽度这里设定为200,因此需要中心点左边-100,右边+100。高度就是根据窗口数量,用总高度除以数量所得。

有了窗口之后,只需要判断非零点的xy坐标全都在窗口内即可,在的话,就记录他的索引,用这个索引可以在23819那么多的非零点里面,取得对应的点的坐标。对于左右车道线都进行同样的操作。当出现了车道线之后,根据索引,取得其像素坐标,根据均值作为新的窗口中心点,继续往下移动。

最后把两侧车道线的xy坐标都合并起来。

总结:这种滑动的方式寻找的车道线,只适合车道线比较清晰的路面,如果路面上很多车道线都磨没了,这种方式很可能就找不到车道线了,但是深度学习的方式可以自动脑补出来车道线。

# 滑动窗口查找车道线nwindows = 9window_height = np.int(binary_warped.shape[0] / nwindows)nonzero = binary_warped.nonzero()nonzeroy = np.array(nonzero[0])nonzerox = np.array(nonzero[1])leftx_current = leftx_baserightx_current = rightx_basemargin = 100minpix = 10left_lane_inds = []right_lane_inds = []for window in range(nwindows):win_y_low = binary_warped.shape[0] - (window + 1) * window_heightwin_y_high = binary_warped.shape[0] - window * window_heightwin_xleft_low = leftx_current - marginwin_xleft_high = leftx_current + marginwin_xright_low = rightx_current - marginwin_xright_high = rightx_current + margin# 非零y的索引在窗口内,非零x的索引也在窗口内,只记录行索引即可,后面通过索引寻找good_left_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & (nonzerox > win_xleft_low) & (nonzerox < win_xleft_high)).nonzero()[0]good_right_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & (nonzerox >= win_xright_low) & (nonzerox < win_xright_high)).nonzero()[0]left_lane_inds.append(good_left_inds)right_lane_inds.append(good_right_inds)if len(good_left_inds) > minpix:leftx_current = np.int(np.mean(nonzerox[good_left_inds]))if len(good_right_inds) > minpix:rightx_current = np.int(np.mean(nonzerox[good_right_inds]))left_lane_inds = np.concatenate(left_lane_inds)right_lane_inds = np.concatenate(right_lane_inds)leftx = nonzerox[left_lane_inds]lefty = nonzeroy[left_lane_inds]rightx = nonzerox[right_lane_inds]righty = nonzeroy[right_lane_inds]

4.车道线拟合

通过np.polyfit,对车道线进行拟合,根据多项式函数的特性,如果变量的幂比较高,是可以出现曲线的,因此这里设为最高3次幂,基本上就足够用来拟合了。返回的是四个值,分别是三次项参数、二次项参数、一次项参数、以及偏置。由于我们是通过x来计算y,因此方法中传入的是y和x。

有了参数,就可以创建y坐标了,这里的undist就是原图,读出来后是720*1280,因此y坐标就是0到719。根据得到的多项式参数,就可以算出左侧车道线以及右侧车道线的x坐标了。

    para_l = np.polyfit(lefty, leftx, deg=3)para_r = np.polyfit(righty, rightx, deg=3)ploty = np.linspace(0, undist.shape[0] - 1, undist.shape[0])left_fitx = para_l[0] * ploty ** 3 + para_l[1] * ploty ** 2 + para_l[2] * ploty + para_l[3]right_fitx = para_r[0] * ploty ** 3 + para_r[1] * ploty ** 2 + para_r[2] * ploty + para_r[3]

5.车道线区域标注

这里用一张黑色的图,把车道线的区域标出来。

    # 生成一张黑图,做mask,将车道线区域标注出来color_warp = np.zeros((720, 1280, 3), dtype='uint8')pts_left = np.array([np.transpose(np.vstack([left_fitx, ploty]))])pts_right = np.array([np.flipud(np.transpose(np.vstack([right_fitx, ploty])))])pts = np.hstack((pts_left, pts_right))cv2.fillPoly(color_warp, np.int_([pts]), (0, 255, 0))

对于左侧车道线,y是从0到719,也就是从上到下,因此,左侧车道线是从右到左的x坐标,由大到小排列,坐标顺序就是下图中的从上到下。

对于右侧也是一样,但是对于cv2.fillPoly来说,需要提供的是轮廓点,如果想生成下面左图这样的填充好的图的话,顺序应当是左上,左下,右下,右上,这样才是一个完整的轮廓,因此需要把右侧的坐标上下反转,用来在画图时,和左侧进行连接。

填充完毕,就可以逆变换了,使用前面已经准备好的矩阵进行逆变换。最后通过addWeighted方法,把变换好的mask和原图融合在一起,得到结果。

newwarp = cv2.warpPerspective(color_warp, m_inv, imgOut_size, flags=cv2.INTER_LINEAR)
result = cv2.addWeighted(img, 0.5, newwarp, 0.5, 0)

 

传统方法车道线标注及相关知识相关推荐

  1. 第二代支付系统及电票线上清算相关知识

    二代支付系统 国家处理中心(NPC):NPC是人民银行连接支付系统所有城市节点和特许参与者的中枢节点,负责接收.转发各CCPC和接收.处理特许参与者的支付指令,以及资金清算的一组硬件和软件系统的总称. ...

  2. 自动驾驶——车道线检测相关数据集整理

    自动驾驶视觉方向的分支车道线检测需要的相关数据集 暂时没有好好整理,先作个记录: 1.KITTI KITTI数据集由德国卡尔斯鲁厄理工学院和丰田美国技术研究院联合创办,主要于算法评测. KITTI数据 ...

  3. 2023最新车道线综述!近五年文章全面盘点(几何建模/机器学习/深度学习)

    点击下方卡片,关注"自动驾驶之心"公众号 ADAS巨卷干货,即可获取 点击进入→自动驾驶之心[车道线检测]技术交流群 后台回复[车道线综述]获取基于检测.分割.分类.曲线拟合等近几 ...

  4. 速度精度双SOTA! TPAMI2022最新车道线检测算法(Ultra-Fast-Lane-Detection-V2)

    点击下方卡片,关注"自动驾驶之心"公众号 ADAS巨卷干货,即可获取 点击进入→自动驾驶之心技术交流群 后台回复[车道线综述]获取基于检测.分割.分类.曲线拟合等近几十篇学习论文! ...

  5. 计算机视觉——车道线(路沿)检测

    目录 系列文章目录 一.实验内容与方法 二.视频的导入.拆分.合成 1.视频时长读取 2.视频的拆分 3.视频的合成 三.图像处理/边缘检测 0.尝试 1.图像处理->边缘检测(原理) 2.Ca ...

  6. 3.1.1 车道线检测

    更多内容,请关注: github:Autopilot-Updating-Notes gitee: Autopilot-Updating-Notes 车道线检测是一种环境感知应用,其目的是通过车载相机或 ...

  7. VIL-100: 一个新的车道线检测数据集和基线模型(ICCV2021)

    作者丨StrongerTang@知乎 来源丨https://zhuanlan.zhihu.com/p/411156533 编辑丨3D视觉工坊 之前写过一篇车道线检测的综述,得到了一些朋友的认可,也因此 ...

  8. 一个3D车道线检测方法PersFormer及其开源OpenLane数据集

    来源丨计算机视觉深度学习和自动驾驶 arXiv上2022年3月论文"PersFormer: 3D Lane Detection via Perspective Transformer and ...

  9. 3D车道线单目检测方法ONCE-3DLanes

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 作者丨黄浴 来源丨计算机视觉深度学习和自动驾驶 3D车道线检测论文"ONCE-3DLanes ...

  10. 车道线检测在AR导航中的应用与挑战

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 1. 导读 现代社会中,随着车辆的普及,人的活动范围在逐步扩大,单单依靠人类记忆引导行驶到达目的地已经 ...

最新文章

  1. dev编译器:c++如何让其输出小数16.84,浮点数类型数据!
  2. c语言表达式用法,C语言开发之运算符、表达式用法
  3. MySQL 索引 :哈希索引、B+树索引、最左前缀匹配规则、全文索引
  4. linux文本工具总结,Linux 文本工具
  5. Valhalla项目的价值
  6. 用python做采集时相对路径转换成绝对路径
  7. 【转】请让孩子输在起跑线上
  8. 【251】◀▶IEW-Unit16
  9. HTML设置单边圆角,如何在html中做圆角矩形和 只有右边的分隔线
  10. Jenkins的配置(rpm red hat方式)
  11. Gstreamer之No package ‘gstreamer-1.0‘ found解决(十一)
  12. 两本关于sharepoint 2010的书值得参考
  13. php 数组任意位置插入值
  14. 在Win7中IIS配置Asp.Net虚拟文件夹的方法及错误总结!
  15. 怎么在Linux中安装gcc编译器使用,如何在linux中安装gcc编译器?
  16. 如何获取和发现用户需求
  17. Python学习推荐
  18. Android Palette 提取图片的主色调
  19. 开正式发票到底谁交税
  20. decimal与decimal?的区别

热门文章

  1. Linux系统下如何复制粘贴文件(待更新)
  2. 萤石开放平台-摄像头画面如何在小程序上播放?
  3. 微信小程序微信登录-云端登录模板
  4. 图片放大后模糊怎么变清晰?
  5. 图片放大后不清晰怎么处理?
  6. 【20220912】电商业务的核心流程
  7. comsol matlab script,comsol script
  8. 网络工程师(软考中级-华为认证)
  9. 【Go语言】动态库和静态库详解
  10. 代码合规性:开发人员使用Helix QAC的5大原因