热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python图像识别马路_OpenCVPython:车道检测

任务:一共要完成两项任务:1.在所提供的公路图片上检测出车道线并标记2.在所提供的公路视频上检测出车道线并标记方案:要检测出当前车道&#x

任务:

一共要完成两项任务:

1. 在所提供的公路图片上检测出车道线并标记

2. 在所提供的公路视频上检测出车道线并标记

方案:

要检测出当前车道,就是要检测出左右两条车道直线。由于无人车一直保持在当前车道,那么无人车上的相机拍摄视频中,车道线的位置应该基本固定在某一个范围内:

如果我们手动把这部分ROI区域抠出来,就会排除大部分干扰。接下来检测直线肯定用霍夫变换,但ROI区域内的边缘直线信息还是很多,考虑到只有左右两条车道,一条斜率为正、一条斜率为负,可将所有的线分为两组,每组再通过均值或最小二乘法拟合的方式确定唯一一条线就可以完成检测。具体步骤如下:

1. 灰度化

2. 高斯模糊

3. Canny边缘检测

4. 不规则ROI区域截取

5. 霍夫直线检测

6. 车道计算

对于视频来说,只要能检测出一幅图,后面将图像合成一下即可。

图像预处理

灰度化和滤波操作是大部分图像处理的必要步骤。灰度化是因为不需要色彩信息,可以减少计算量。而滤波会削弱图像噪点,排除干扰信息。另外,边缘提取是基于图像梯度的,梯度对噪声很敏感,所以平滑操作必不可少。

这里我们用分模块来写,方便调用:

import cv2

import numpyasnp

# 高斯滤波核大小

blur_ksize= 5# Canny边缘检测高低阈值

canny_lth= 50canny_hth= 150def process_an_image(img):

#1. 灰度化、滤波和Canny

gray=cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)

blur_gray= cv2.GaussianBlur(gray, (blur_ksize, blur_ksize), 1)

edges=cv2.Canny(blur_gray, canny_lth, canny_hth)if __name__ == "__main__":

img= cv2.imread('test_pictures/lane.jpg')

result=process_an_image(img)

cv2.imshow("lane", np.hstack((img, result)))

cv2.waitKey(0)

边缘检测结果图

ROI截取

按前面方案中提到的,只需保留边缘图中红线部分区域用于后续的霍夫直线检测,其余的都是无用的信息:

我们可以穿件一个梯形的掩膜,然后与边缘检测结果图混合运算,掩膜中白色部分保留,黑色部分舍弃。梯形的四个坐标需要手动标记:

def process_an_image(img):

#1. 灰度化、滤波和Canny

#2. 标记四个坐标点用于ROI截取

rows, cols=edges.shape

points= np.array([[(0, rows), (460, 325), (520, 325), (cols, rows)]])

# [[[0 540], [460 325], [520 325], [960 540]]]

roi_edges=roi_mask(edges, points)

def roi_mask(img, corner_points):

# 创建掩膜

mask=np.zeros_like(img)

cv2.fillPoly(mask, corner_points,255)

masked_img=cv2.bitwise_and(img, mask)return masked_img

结果图 roi_edges如下:

只保留关键区域的边缘检测图

霍夫直线提取

为了方便后续计算直线的斜率,我们使用统计概率霍夫直线变换(因为它能得到直线的起点和终点坐标):

# 霍夫变换参数

rho= 1theta= np.pi / 180threshold= 15min_line_len= 40max_line_gap= 20def process_an_image(img):

#1. 灰度化、滤波和Canny

#2. 标记四个坐标点用于ROI截取

#3. 霍夫直线提取

drawing, lines=hough_lines(roi_edges, rho, theta, threshold, min_line_len, max_line_gap)

def hough_lines(img, rho, theta, threshold, min_line_len, max_line_gap):

# 统计概率霍夫直线变换

lines= cv2.HoughLinesP(img, rho, theta, threshold, minLineLength=min_line_len, maxLineGap=max_line_gap)

# 新建一副空白画布

drawing= np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8)

# draw_lines(drawing, lines) # 画出直线检测结果returndrawing, lines

def draw_lines(img, lines, color=[0, 0, 255], thickness=1):for line inlines:for x1, y1, x2, y2 inline:

cv2.line(img, (x1, y1), (x2, y2), color, thickness)

draw_lines()用来画直线检测的结果,后面我们会接着处理直线,所以这里注释掉了。可以取消注释看看效果:

霍夫变换结果图

对本例的这张测试图来说,如果打印出直线的条数print(len(lines)),应该是16条

车道计算

前面通过霍夫变换得到了多条直线的地点和终点,我们的目的是通过某种算法只得到左右两条车道线

第一步、 根据斜率正负划分某条线是左车道还是右车道。

其中左车道(斜率 <0)&#xff0c;右车道(斜率 > 0)。原因如下图所示&#xff1a;

左车道与图像坐标系成钝角&#xff0c;斜率为负&#xff0c;右车道与图像坐标系成锐角&#xff0c;斜率为正。

第二步、迭代计算各直线斜率与斜率均值的差&#xff0c;排除掉差值过大的异常数据

第一次计算完斜率均值并排除掉异常值后&#xff0c;再在剩余的斜率中取均值&#xff0c;继续排除。一直迭代下去。

第三步、最小二乘法拟合左右车道线

经过第二步的筛选&#xff0c;就只剩下可能的左右车道线了。我们需要从多条直线中拟合出一条。使用最小二乘法&#xff0c;它通过最小化误差的平方和来寻找数据的最佳匹配函数。

假设目前可能的左车道线有6条&#xff0c;也就是12个坐标点。

我们的目标是拟合出这样一条直线&#xff1a;

使得误差平方和最小&#xff1a;

Python中可以直接使用 np.polyfit() 进行最小二乘法拟合

def process_an_image(img):

#1. 灰度化、滤波和Canny

#2. 标记四个坐标点用于ROI截取

#3. 霍夫直线提取

#4. 车道拟合计算

draw_lanes(drawing, lines)

#5. 最终将结果合在原图上

result&#61; cv2.addWeighted(img, 0.9, drawing, 0.2, 0)returnresult

def draw_lanes(img, lines, color&#61;[255, 0, 0], thickness&#61;8):

# a. 划分左右车道

left_lines, right_lines&#61;[], []for line inlines:for x1, y1, x2, y2 inline:

k&#61; (y2 - y1) / (x2 -x1)if k <0:

left_lines.append(line)else:

right_lines.append(line)if (len(left_lines) <&#61; 0 or len(right_lines) <&#61; 0):return# b. 清理异常数据

clean_lines(left_lines,0.1)

clean_lines(right_lines,0.1)

# c. 得到左右车道线点的集合&#xff0c;拟合直线

left_points&#61; [(x1, y1) for line in left_lines for x1, y1, x2, y2 inline]

left_points&#61; left_points &#43; [(x2, y2) for line in left_lines for x1, y1, x2, y2 inline]

right_points&#61; [(x1, y1) for line in right_lines for x1, y1, x2, y2 inline]

right_points&#61; right_points &#43; [(x2, y2) for line in right_lines for x1, y1, x2, y2 inline]

left_results&#61; least_squares_fit(left_points, 325, img.shape[0])

right_results&#61; least_squares_fit(right_points, 325, img.shape[0])

# 注意这里点的顺序

vtxs&#61; np.array([[left_results[1], left_results[0], right_results[0], right_results[1]]])

# d. 填充车道区域

cv2.fillPoly(img, vtxs, (0, 255, 0))

# 或者只画车道线

# cv2.line(img, left_results[0], left_results[1], (0, 0, 255), thickness)

# cv2.line(img, right_results[0], right_results[1], (0, 0, 255), thickness)

def clean_lines(lines, threshold):

# 迭代计算斜率均值&#xff0c;排除掉与差值差异较大的数据

slope&#61; [(y2 - y1) / (x2 - x1) for line in lines for x1, y1, x2, y2 inline]while len(lines) > 0:

mean&#61;np.mean(slope)

diff&#61; [abs(s - mean) for s inslope]

idx&#61;np.argmax(diff)if diff[idx] >threshold:

slope.pop(idx)

lines.pop(idx)else:breakdef least_squares_fit(point_list, ymin, ymax):

# 最小二乘法拟合

x&#61; [p[0] for p inpoint_list]

y&#61; [p[1] for p inpoint_list]

# polyfit第三个参数为拟合多项式的阶数&#xff0c;所以1代表线性

fit&#61; np.polyfit(y, x, 1)

fit_fn&#61;np.poly1d(fit) # 获取拟合的结果

xmin&#61; int(fit_fn(ymin))

xmax&#61; int(fit_fn(ymax))return [(xmin, ymin), (xmax, ymax)]

最后得到的是左右两条车道线的起点和终点坐标。可以选择画出车道线&#xff0c;也可以填充整个区域&#xff1a;

画出车道线的效果不是很好&#xff0c;还是选用填充比较直观。

视频处理

搞定了一张图&#xff0c;视频的话也就没什么难度了。关键是视频帧的提取和合成&#xff0c;为此我们需要用到Python的视频编辑包 moviepy&#xff1a;

pip install moviepy

另外还需要 ffmpeg&#xff0c;首次运行moviepy时会自动下载。也可手动下载。建议手动下载&#xff0c;不知为什么&#xff0c;博主自动下载老是失败。ffmpeg-win32-v3.2.4.exe

只需要在开头导入 moviepy&#xff0c;然后主函数改掉就可以了&#xff0c;其余代码不需要修改&#xff1a;

# 开头导入moviepyfrommoviepy.editor import VideoFileClip

# 主函数更改为&#xff1a;if __name__ &#61;&#61; "__main__":

output&#61; &#39;test_videos/output.mp4&#39;clip&#61; VideoFileClip("test_videos/cv2_white_lane.mp4")

out_clip&#61;clip.fl_image(process_an_image)

out_clip.write_videofile(output, audio&#61;False)



推荐阅读
  • Python实现变声器功能(萝莉音御姐音)的方法及步骤
    本文介绍了使用Python实现变声器功能(萝莉音御姐音)的方法及步骤。首先登录百度AL开发平台,选择语音合成,创建应用并填写应用信息,获取Appid、API Key和Secret Key。然后安装pythonsdk,可以通过pip install baidu-aip或python setup.py install进行安装。最后,书写代码实现变声器功能,使用AipSpeech库进行语音合成,可以设置音量等参数。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了九度OnlineJudge中的1002题目“Grading”的解决方法。该题目要求设计一个公平的评分过程,将每个考题分配给3个独立的专家,如果他们的评分不一致,则需要请一位裁判做出最终决定。文章详细描述了评分规则,并给出了解决该问题的程序。 ... [详细]
  • Python如何调用类里面的方法
    本文介绍了在Python中调用同一个类中的方法需要加上self参数,并且规范写法要求每个函数的第一个参数都为self。同时还介绍了如何调用另一个类中的方法。详细内容请阅读剩余部分。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 本文介绍了在mac环境下使用nginx配置nodejs代理服务器的步骤,包括安装nginx、创建目录和文件、配置代理的域名和日志记录等。 ... [详细]
author-avatar
罗丝012
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有