Python----计算机视觉处理(Opencv:道路检测之车道线拟合)

完整版: Python----计算机视觉处理(Opencv:道路检测完整版:透视变换,提取车道线,车道线拟合,车道线显示)

一、获取左右车道线的原始位置 

导入模块

import cv2
import numpy as np
from matplotlib import pyplot as plt

输入图像 

img = cv2.imread('img_road.png')

获取图像的高和宽 

height, width, _ = img.shape

对图像的高进行求和 

num_ax0 = np.sum(img, axis=0)

显示图像求和图 

plt.plot(num_ax0)
plt.show()

得到直方图左右两侧最高点的位置 

    img_left_argmax=np.argmax(num_ax0[:width//2])img_right_argmax=np.argmax(num_ax0[width//2:])+width//2

二、绘制小窗口

获取图像中所有非零像素的x和y的位置

nonzeroy,nonzerox=np.array(img.nonzero())

定义一些小窗口的概念参数

# 定义小窗口的个数
windows_num=10#小窗口的宽度和高度
windows_height=height//windows_num
windows_width=30#小窗口白色个数阈值
min_pix=40#初始化当前窗口的位置
left_current=img_left_argmax
right_current=img_right_argmax

创建空列表接收左侧和右侧车道线像素的索引

left_lane_inds=[]
right_lane_inds=[]

绘制小窗口一

for window in range(windows_num):# 计算当前窗口的上边界的y坐标win_y_high=height-windows_height*(window+1)# 计算当前窗口的下边界的y坐标win_y_low = height - windows_height * window# 计算左边窗口左右边界的x坐标win_x_left_left=left_current - windows_widthwin_x_left_right=left_current + windows_width# 计算右边窗口左右边界的x坐标win_x_right_left=right_current - windows_widthwin_x_right_right=right_current + windows_widthcv2.rectangle(out_img, (win_x_left_left, win_y_high), (win_x_left_right, win_y_low), (0, 255, 0), 2)cv2.rectangle(out_img, (win_x_right_left, win_y_high), (win_x_right_right, win_y_low), (0, 255, 0), 2)

 

        通过上述代码绘画出的小窗口没有随路线的弯曲程度而弯曲,需要该进 

改进小窗口,让窗口随路线的走势而走势

    for window in range(windows_num):# 计算当前窗口的上边界的y坐标win_y_high=height-windows_height*(window+1)# 计算当前窗口的下边界的y坐标win_y_low = height - windows_height * window# 计算左边窗口左右边界的x坐标win_x_left_left=left_current - windows_widthwin_x_left_right=left_current + windows_width# 计算右边窗口左右边界的x坐标win_x_right_left=right_current - windows_widthwin_x_right_right=right_current + windows_widthcv2.rectangle(out_img, (win_x_left_left, win_y_high), (win_x_left_right, win_y_low), (0, 255, 0), 2)cv2.rectangle(out_img, (win_x_right_left, win_y_high), (win_x_right_right, win_y_low), (0, 255, 0), 2)good_left_index=((nonzeroy >= win_y_high) & (nonzeroy < win_y_low)& (nonzerox >= win_x_left_left) & (nonzerox < win_x_left_right)).nonzero()[0]good_right_index=((nonzeroy >= win_y_high) & (nonzeroy < win_y_low)& (nonzerox >= win_x_right_left) & (nonzerox < win_x_right_right)).nonzero()[0]left_lane_inds.append(good_left_index)right_lane_inds.append(good_right_index)if len(good_left_index)>min_pix:left_current = int(np.mean(nonzerox[good_left_index]))else:if len(good_right_index)>min_pix:offset=int(np.mean(nonzerox[good_right_index]))-right_preleft_current=left_current+offsetif len(good_right_index)>min_pix:right_current = int(np.mean(nonzerox[good_right_index]))else:if len(good_left_index)>min_pix:offset=int(np.mean(nonzerox[good_left_index]))-left_preright_current=right_current+offsetleft_pre=left_currentright_pre=right_current

三、拟合车道线

#连接索引的列表,为了后续更方便的提取出这些像素点的和y的坐标,以便进行车道线的拟合left_lane_inds=np.concatenate(left_lane_inds)right_lane_inds=np.concatenate(right_lane_inds)# 提取左侧和右侧车道线像素的位置# left_lane_inds 是一个一维数组,它包含了左侧车道线在滑动窗口中找到的白色像素点的x坐标的索引# 通过将这些索引作为索引器应用到 nonzerox数组上,就可以得到相应的左侧车道线的x坐标# leftx 包含了左侧车道线自色像素点的华标leftx=nonzerox[left_lane_inds]lefty=nonzeroy[left_lane_inds]rightx=nonzerox[right_lane_inds]righty=nonzeroy[right_lane_inds]# 有了坐标之后,就要去对左侧和右侧车道线进行多项式拟合,从而得到拟合的车道线# np.polyfit()是numpy中用于进行多项式拟合的函数# 他接受三个参数:xy 和deg# x:自变量数组,y:因变量数组# deg:多项式的次数,如果是y=ax^2+b^x+C# left_fit里存放的就是 a、b、c的参数,left_fit=np.polyfit(lefty,leftx,2)right_fit=np.polyfit(righty, rightx, 2)# 使用np.linspace 生成一组均匀分布的数值,用于表示竖直方向上的像素坐标,方便后续的车道线的绘制# 使用多项式拟合来估计左侧和右侧车道线的x坐标# left_fitx 就是左侧拟合出来的车道线ploty=np.linspace(0,height-1,height)left_fitx=left_fit[0]*ploty**2+left_fit[1]*ploty+left_fit[2]right_fitx = right_fit[0] * ploty ** 2 + right_fit[1] * ploty +  right_fit[2]# 计算中间车道线的位置middle_fitx=(left_fitx+right_fitx)//2# 使用不同颜色将车道线标出来out_img[lefty,leftx]=[255,0,0]out_img[righty,rightx]=[0,0,255]

四、完整代码

 

import cv2  
import numpy as np  
import matplotlib.pyplot as plt  # 读取图像  
img = cv2.imread('img_road.png')  # 将图像复制到三个通道,以便于处理  
out_img = np.dstack((img, img, img))  # 计算每列像素的总和,以便找到车道线的最高点  
num_ax0 = np.sum(img, axis=0)  # 获取左右两侧最高点的位置  
img_left_argmax = np.argmax(num_ax0[:width // 2])  # 左侧最高点  
img_right_argmax = np.argmax(num_ax0[width // 2:]) + width // 2  # 右侧最高点  # 获取图像中所有非零像素的x和y的位置  
nonzeroy, nonzerox = np.array(img.nonzero())  # 定义小窗口的个数  
windows_num = 10  # 小窗口的高度和宽度  
windows_height = height // windows_num  
windows_width = 30  # 小窗口白色像素的个数阈值  
min_pix = 400  # 初始化当前窗口的位置  
left_current = img_left_argmax  
right_current = img_right_argmax  # 记录上一个窗口的位置  
left_pre = left_current  
right_pre = right_current  # 创建空列表以接收左侧和右侧车道线像素的索引  
left_lane_inds = []  
right_lane_inds = []  # 遍历每个窗口  
for window in range(windows_num):  # 计算当前窗口的上边界y坐标  win_y_high = height - windows_height * (window + 1)  # 计算当前窗口的下边界y坐标  win_y_low = height - windows_height * window  # 计算左侧窗口的左右边界x坐标  win_x_left_left = left_current - windows_width  win_x_left_right = left_current + windows_width  # 计算右侧窗口的左右边界x坐标  win_x_right_left = right_current - windows_width  win_x_right_right = right_current + windows_width  # 在图像上绘制窗口  cv2.rectangle(out_img, (win_x_left_left, win_y_high), (win_x_left_right, win_y_low), (0, 255, 0), 2)  cv2.rectangle(out_img, (win_x_right_left, win_y_high), (win_x_right_right, win_y_low), (0, 255, 0), 2)  # 找到在当前窗口内的好像素索引  good_left_index = ((nonzeroy >= win_y_high) & (nonzeroy < win_y_low)  & (nonzerox >= win_x_left_left) & (nonzerox < win_x_left_right)).nonzero()[0]  good_right_index = ((nonzeroy >= win_y_high) & (nonzeroy < win_y_low)  & (nonzerox >= win_x_right_left) & (nonzerox < win_x_right_right)).nonzero()[0]  # 将找到的索引添加到列表中  left_lane_inds.append(good_left_index)  right_lane_inds.append(good_right_index)  # 更新当前窗口位置  if len(good_left_index) > min_pix:  left_current = int(np.mean(nonzerox[good_left_index]))  # 更新左侧窗口位置  else:  if len(good_right_index) > min_pix:  offset = int(np.mean(nonzerox[good_right_index])) - right_pre  # 计算偏移量  left_current = left_current + offset  # 更新左侧窗口位置  if len(good_right_index) > min_pix:  right_current = int(np.mean(nonzerox[good_right_index]))  # 更新右侧窗口位置  else:  if len(good_left_index) > min_pix:  offset = int(np.mean(nonzerox[good_left_index])) - left_pre  # 计算偏移量  right_current = right_current + offset  # 更新右侧窗口位置  # 更新上一个窗口位置  left_pre = left_current  right_pre = right_current  # 将找到的索引合并为一个数组  
left_lane_inds = np.concatenate(left_lane_inds)  
right_lane_inds = np.concatenate(right_lane_inds)  # 获取左右车道线的x和y坐标  
leftx = nonzerox[left_lane_inds]  
lefty = nonzeroy[left_lane_inds]  rightx = nonzerox[right_lane_inds]  
righty = nonzeroy[right_lane_inds]  # 使用多项式拟合左侧和右侧车道线  
# 有了坐标之后,就要去对左侧和右侧车道线进行多项式拟合,从而得到拟合的车道线# np.polyfit()是numpy中用于进行多项式拟合的函数
# 他接受三个参数:xy 和deg
# x:自变量数组,y:因变量数组
# deg:多项式的次数,如果是2y=ax^2+b^x+C
# left_fit里存放的就是 a、b、c的参数,
left_fit = np.polyfit(lefty, leftx, 2)  # 左侧拟合  
right_fit = np.polyfit(righty, rightx, 2)  # 右侧拟合  # 创建y坐标的线性空间  
ploty = np.linspace(0, height - 1, height)  # 根据拟合的多项式计算x坐标  
left_fitx = left_fit[0] * ploty ** 2 + left_fit[1] * ploty + left_fit[2]  
right_fitx = right_fit[0] * ploty ** 2 + right_fit[1] * ploty + right_fit[2]  # 计算中间车道线的x坐标  
middle_fitx = (left_fitx + right_fitx) // 2  # 在输出图像上标记左侧和右侧车道线像素  
out_img[lefty, leftx] = [255, 0, 0]  # 左侧车道线为红色  
out_img[righty, rightx] = [0, 0, 255]  # 右侧车道线为蓝色  # 显示结果图像  
cv2.imshow('out_img', out_img)  
cv2.waitKey(0)  
  1. 图像读取和准备:读取图像并为处理做好准备。
  2. 直方图计算:计算像素值的总和,以找到车道的位置。
  3. 滑动窗口:使用滑动窗口技术识别车道像素。
  4. 车道像素索引:收集左侧和右侧车道的好像素索引。
  5. 多项式拟合:对识别出的车道点进行多项式拟合,以生成平滑的车道线。
  6. 可视化:在输出图像上绘制检测到的车道线并展示。

五、库函数

5.1、nonzero()

        返回数组中非零元素的索引

numpy.nonzero(a)

用途:它通常用来查找非零元素的位置,常用于图像处理中筛选出特定的像素。

返回值:函数返回一个元组,每个元素是一个数组,表示非零元素在每个维度上的索引。例如,对于二维数组 AA.nonzero() 返回两个数组,第一个数组表示行索引,第二个数组表示列索引。

import numpy as nparr=np.array([[0,1,2,3,4,5,6],[1,2,3,4,5,6,7],[0,0,0,0,0,0,0]]
)
print(arr.nonzero())
#(array([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]), array([1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6]))

5.2、polyfit()

        用于计算数据点的多项式拟合

numpy.polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False)
方法描述
xM 个采样点的 x 坐标。(x[i], y[i])
y采样点的 y 坐标。样本的多个数据集 共享相同 x 坐标的点可以通过以下方式一次拟合 传入一个 2D 数组,该数组每列包含一个数据集。
deg拟合多项式的次数
rcond拟合的相对条件编号。小于 this 相对于最大奇异值将被忽略。这 默认值为 len(x)*eps,其中 eps 是 float 类型,大多数情况下约为 2E-16。
fullSwitch 确定返回值的性质。当为 False 时( default) 仅返回系数,当 True diagnostic 还会返回来自奇异值分解的信息。
w权重。如果不是 None,则权重适用于未平方的 残差 。理想情况下,权重为 选中,这样产品的误差都具有 相同的方差。使用逆方差加权时,请使用 。默认值为 None。w[i]y[i] - y_hat[i]x[i]w[i]*y[i]w[i] = 1/sigma(y[i])
cov如果给定且非 False,则不仅返回估计值,还返回其 协方差矩阵。默认情况下,协方差的缩放比例为 chi2/dof,其中 dof = M - (度 + 1),即假定权重 不可靠,除非在相对意义上,并且一切都是缩放的 使得还原的 Chi2 是 Unity。如果 ,则省略此缩放,因为与权重 w = 1/sigma,其中已知 sigma 是 不确定性。cov='unscaled'
import numpy as np
x = np.array([1, 2, 3, 4])
y = np.array([2, 3, 5, 7])
# ax**2+bx+c
a,b,c = np.polyfit(x, y, 2)  # 进行二次多项式拟合
print(a,b,c)
#[0.25 0.45 1.25]

5.3、linspace()

        用于生成指定范围内的等间距数字

numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0, *, device=None)
方法描述
start序列的起始值。
stop序列的结束值,除非 endpoint 设置为 False。 在这种情况下,序列由除最后一个均匀分布的样本之外的所有样本组成,因此不包括 stop。请注意,步骤 当 endpoint 为 False 时,size 会发生变化。num + 1
num要生成的样本数。默认值为 50。必须为非负数。
endpoint如果为 True,则 stop 是最后一个样本。否则,不包括在内。 默认值为 True。
retstep如果为 True,则返回 (samples, step),其中 step 是间距 样本之间。
dtype输出数组的类型。如果未给出,则数据类型 是从 start 和 stop 推断出来的。推断的 dtype 永远不会是 整数;float 的 整数数组。
axis结果中用于存储样本的轴。仅在启动时相关 或 stop 是类似数组的。默认情况下 (0),样本将沿着 在开头插入新轴。使用 -1 在末尾获取一个轴。
device要放置创建的阵列的设备。默认值:None。 仅对于 Array-API 互作性,如果通过,则必须这样做。
import numpy as np
samples = np.linspace(0, 1, 5)  # 生成 0 到 1 之间的 5 个等间距点
print(samples)
# [0.   0.25 0.5  0.75 1.  ]

5.4、dstack()

        用于沿着深度(第三个轴)拼接数组。

numpy.dstack(tup)
方法描述
tup数组沿除第三个轴之外的所有轴必须具有相同的形状。 一维或二维数组必须具有相同的形状。
import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
c = np.dstack((a, b))  # 沿着深度轴拼接,结果形状为 (2, 2, 2)
print(c)
'''
[[[1 5][2 6]][[3 7][4 8]]]
'''

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/75757.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

优选算法的妙思之流:分治——归并专题

专栏&#xff1a;算法的魔法世界 个人主页&#xff1a;手握风云 目录 一、归并排序 二、例题讲解 2.1. 排序数组 2.2. 交易逆序对的总数 2.3. 计算右侧小于当前元素的个数 2.4. 翻转对 一、归并排序 归并排序也是采用了分治的思想&#xff0c;将数组划分为多个长度为1的子…

C语言查漏补缺:基础篇

1.原理 C语言是一门编译型计算机语言&#xff0c;要编写C代码&#xff0c;C源代码文本文件本身无法直接执行&#xff0c;必须通过编译器翻译和链接器的链接&#xff0c;生成二进制的可执行文件&#xff0c;然后才能执行。这里的二进制的可执行文件就是我们最终要形成的可执行程…

TPS入门DAY02 服务器篇

1.创建空白插件 2.导入在线子系统以及在线steam子系统库 MultiplayerSessions.uplugin MultiplayerSessions.Build.cs 3.创建游戏实例以及初始化会话创建流程 创建会话需要的函数&#xff0c;委托&#xff0c;委托绑定的回调&#xff0c;在线子系统接口绑定某一个委托的控制其…

产品经理课程

原型工具 一、土耳其机器人 这个说法来源于 1770 年出现的一个骗局&#xff0c;一个叫沃尔夫冈冯肯佩伦&#xff08;Wolfgang von Kempelen&#xff09;的人为了取悦奥地利女皇玛丽娅特蕾莎&#xff08;Maria Theresia&#xff09;&#xff0c;“制造”了一个会下国际象棋的机…

nginx中的limit_req 和 limit_conn

在 Nginx 中&#xff0c;limit_req 和 limit_conn 是两个用于限制客户端请求的指令&#xff0c;它们分别用于限制请求速率和并发连接数。 limit_req limit_req 用于限制请求速率&#xff0c;防止客户端发送过多请求影响服务器性能。它通过 limit_req_zone 指令定义一个共享内存…

基于winform的串口调试助手

目录 一、串口助手界面设计 1.1 串口配置 1.2 接收配置 1.3 发送配置 1.4 接收窗口和发送窗口 1.5 状态显示窗口 1.6 串口通讯控件 二、程序编写 2.1 端口号自动识别并显示在端口号下拉框 功能说明&#xff1a; 2.2 波特率下拉框显示 2.3 数据位下拉框显示 2.4 校…

Docker基础2

如需转载&#xff0c;标记出处 本次我们将下载一个 Docker 镜像&#xff0c;从镜像中启动容器 上一章&#xff0c;安装 Docker 时&#xff0c;获得两个主要组件&#xff1a; Docker 客户端 Docker 守护进程&#xff08;有时称为“服务器”或“引擎”&#xff09; 守护进程实…

Rocketmq2

一、生产者端防丢失 1. 发送方式选择 同步发送&#xff1a;使用 send() 方法&#xff0c;等待 Broker 确认响应&#xff08;SendResult&#xff09;&#xff0c;确保消息已成功发送。异步发送&#xff1a;使用 sendAsync() 方法并设置回调函数&#xff0c;处理发送成功 / 失败…

RabbitMQ详解,RabbitMQ是什么?架构是怎样的?

目录 一,RabbitMQ是什么? 二,RabbitMQ架构 2.1 首先我们来看下RabbitMQ里面的心概念Queue是什么? 2.2 交换器Exchange 2.3 RabbitMQ是什么? 2.4 重点看下优先级队列是什么? 三,RabbitMQ集群 3.1 普通集群模式 3.2 镜像队列集群 一,RabbitMQ是什么? 假设我们程序…

【一步步开发AI运动APP】六、运动计时计数能调用

之前我们为您分享了【一步步开发AI运动小程序】开发系列博文&#xff0c;通过该系列博文&#xff0c;很多开发者开发出了很多精美的AI健身、线上运动赛事、AI学生体测、美体、康复锻炼等应用场景的AI运动小程序&#xff1b;为了帮助开发者继续深耕AI运动领域市场&#xff0c;今…

MySQL——DQL的多表查询

一、交叉连接 标准语法&#xff1a;select * from 表1 cross join 表2 where 表1.公共列 表2.公共列; 简单语法&#xff1a;select * from 表1 , 表2 where 表1.公共列 表2.公共列; 公共列&#xff1a;两张表具有相同含义的列&#xff0c;不是列名一样。 …

【Linux内核】如何更加优雅阅读Linux内核源码(vscode)

1. 前言 因为已经习惯在Ubuntu下进行嵌入式工作开发&#xff0c;但Linux源码在Source Insight下进行阅读&#xff0c;一直很苦恼Linux/Windows来回切换的开发方式&#xff0c;当前发现可以通过 vscode clangd(扩展组件) 方式进行更好的内核源码阅读。 2. 环境 操作系统&…

21.OpenCV获取图像轮廓信息

OpenCV获取图像轮廓信息 在计算机视觉领域&#xff0c;识别和分析图像中的对象形状是一项基本任务。OpenCV 库提供了一个强大的工具——轮廓检测&#xff08;Contour Detection&#xff09;&#xff0c;它能够帮助我们精确地定位对象的边界。这篇博文将带你入门 OpenCV 的轮廓…

LETTERS(DFS)

【题目描述】 给出一个rowcolrowcol的大写字母矩阵&#xff0c;一开始的位置为左上角&#xff0c;你可以向上下左右四个方向移动&#xff0c;并且不能移向曾经经过的字母。问最多可以经过几个字母。 【输入】 第一行&#xff0c;输入字母矩阵行数RR和列数SS&#xff0c;1≤R,S≤…

Day2-2:前端项目uniapp壁纸实战

再在wallpaper新建一个目录components 在components下新建组件common-title 记得点击创建同名目录 在index加 <view class"select"><common-title></common-title></view> 图片换了下&#xff0c;原来的有点丑&#xff0c;图片可按自己喜欢…

其他 vector 操作详解(四十)

介绍 除去向 vector 添加元素&#xff08;如 push_back&#xff09;之外&#xff0c;vector 还提供了许多其他操作&#xff0c;这些操作大多与 string 的操作类似。通过掌握这些操作&#xff0c;我们可以方便地查询、修改和比较 vector 中的元素&#xff0c;从而构建灵活、高效…

【Leetcode 每日一题】368. 最大整除子集

问题背景 给你一个由 无重复 正整数组成的集合 n u m s nums nums&#xff0c;请你找出并返回其中最大的整除子集 a n s w e r answer answer&#xff0c;子集中每一元素对 ( a n s w e r [ i ] , a n s w e r [ j ] ) (answer[i], answer[j]) (answer[i],answer[j]) 都应当…

python基础-13-处理excel电子表格

文章目录 【README】【13】处理Excel电子表格【13.1】Excel文档【13.2】安装openpyxl模块【13.3】读取Excel文档【13.3.1】使用openpyxl模块打开excel文档【13.3.2】从工作簿取得工作表【13.3.3】从工作表sheet获取单元格cell【13.3.5】从表中获取行和列【13.3.6】工作簿、工作…

ABS函数c++

简介&#xff1a; abs 函数用于计算一个数的绝对值&#xff0c;在 C 中它继承自 C 语言的标准库&#xff0c;其历史可以追溯到早期的 C 语言发展历程&#xff0c;以下是详细介绍&#xff1a; 早期编程语言的需求 在计算机编程的早期阶段&#xff0c;处理数学运算就是一项基本…

闭环SOTA!北航DiffAD:基于扩散模型实现端到端自动驾驶「多任务闭环统一」

端到端自动驾驶目前是有望实现完全自动驾驶的一条有前景的途径。然而&#xff0c;现有的端到端自动驾驶系统通常采用主干网络与多任务头结合的方式&#xff0c;但是它们存在任务协调和系统复杂度高的问题。为此&#xff0c;本文提出了DiffAD&#xff0c;它统一了各种驾驶目标并…