SLAM从入门到精通(车道线检测)

news2024/11/25 13:00:53

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        对于slam而言,大家一般想到的就是去通过传感器找特征点,进而借助于特征点去定位机器人的位置。但是对于用户或者厂家来说,他们很多时候对机器人在道路上的精度不做要求,但对工位上的对接要求很高。所以,对于供应商来说,是不是整个定位和导航都需要借助于传感器或者反光柱,这就两说了。

        此外,相比较室外而言,工厂内部的光源一般会好一点。就算条件不是很好,我们自己也可以通过补充光源的形式加以修正。所以,对于机器人来说,一种不错的导航方法就是借助于路面来机器人的自我定位,相信也是可以考虑的一个选择。

        网上关于车道线检测的代码不少,我们不妨找一个来学习和参考下,之前文章的地址如下,

https://www.cnblogs.com/wojianxin/p/12624096.html

1、图像灰化,提取边缘信息

    # 1. 灰度化、滤波和Canny
    gray = cv.cvtColor(img, cv.COLOR_RGB2GRAY)
    blur_gray = cv.GaussianBlur(gray, (blur_ksize, blur_ksize), 1)
    edges = cv.Canny(blur_gray, canny_lth, canny_hth)

2、兴趣区域截取

    # 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)

3、利用HoughLinesP函数提取直线

    # 3. 霍夫直线提取
    drawing, lines = hough_lines(roi_edges, rho, theta,
                                 threshold, min_line_len, max_line_gap)

4、车道线拟合

        生成的车道线很多,这个步骤主要是将多个车道线拟合成左右各两条直线。其中左边直线的斜率大于等于0,右边直线的斜率小于等于0。整个拟合的过程中使用到了最小二乘法。

    # 4. 车道拟合计算
    draw_lanes(drawing, lines)

5、绘制车道线

        拟合出来的车道线,最终需要放到原来的图片上,验证一下实现的效果。

    # 5. 最终将结果合在原图上
    result = cv.addWeighted(img, 0.9, drawing, 0.2, 0)

6、完整的代码

import cv2 as cv
import numpy as np

# 高斯滤波核大小
blur_ksize = 5

# Canny边缘检测高低阈值
canny_lth = 50
canny_hth = 150

# 霍夫变换参数
rho = 1
theta = np.pi / 180
threshold = 15
min_line_len = 40
max_line_gap = 20


def process_an_image(img):
    # 1. 灰度化、滤波和Canny
    gray = cv.cvtColor(img, cv.COLOR_RGB2GRAY)
    blur_gray = cv.GaussianBlur(gray, (blur_ksize, blur_ksize), 1)
    edges = cv.Canny(blur_gray, canny_lth, canny_hth)

    # 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)

    # 3. 霍夫直线提取
    drawing, lines = hough_lines(roi_edges, rho, theta,
                                 threshold, min_line_len, max_line_gap)

    # 4. 车道拟合计算
    draw_lanes(drawing, lines)

    # 5. 最终将结果合在原图上
    result = cv.addWeighted(img, 0.9, drawing, 0.2, 0)

    return result


def roi_mask(img, corner_points):
    # 创建掩膜
    mask = np.zeros_like(img)
    cv.fillPoly(mask, corner_points, 255)

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


def hough_lines(img, rho, theta, threshold, min_line_len, max_line_gap):
    # 统计概率霍夫直线变换
    lines = cv.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)
    # print(len(lines))

    return drawing, lines


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


def draw_lanes(img, lines, color=[255, 0, 0], thickness=8):
    # a. 划分左右车道
    left_lines, right_lines = [], []
    for line in lines:
        for x1, y1, x2, y2 in line:
            k = (y2 - y1) / (x2 - x1)
            if k < 0:
                left_lines.append(line)
            else:
                right_lines.append(line)

    if (len(left_lines) <= 0 or len(right_lines) <= 0):
        return

    # b. 清理异常数据
    clean_lines(left_lines, 0.1)
    clean_lines(right_lines, 0.1)

    # c. 得到左右车道线点的集合,拟合直线
    left_points = [(x1, y1) for line in left_lines for x1, y1, x2, y2 in line]
    left_points = left_points + [(x2, y2)
                                 for line in left_lines for x1, y1, x2, y2 in line]

    right_points = [(x1, y1)
                    for line in right_lines for x1, y1, x2, y2 in line]
    right_points = right_points + \
        [(x2, y2) for line in right_lines for x1, y1, x2, y2 in line]

    left_results = least_squares_fit(left_points, 325, img.shape[0])
    right_results = least_squares_fit(right_points, 325, img.shape[0])

    # 注意这里点的顺序
    vtxs = np.array(
        [[left_results[1], left_results[0], right_results[0], right_results[1]]])
    # d.填充车道区域
    cv.fillPoly(img, vtxs, (0, 255, 0))

    # 或者只画车道线
    # cv.line(img, left_results[0], left_results[1], (0, 255, 0), thickness)
    # cv.line(img, right_results[0], right_results[1], (0, 255, 0), thickness)


def clean_lines(lines, threshold):
    # 迭代计算斜率均值,排除掉与差值差异较大的数据
    slope = [(y2 - y1) / (x2 - x1)
             for line in lines for x1, y1, x2, y2 in line]
    while len(lines) > 0:
        mean = np.mean(slope)
        diff = [abs(s - mean) for s in slope]
        idx = np.argmax(diff)
        if diff[idx] > threshold:
            slope.pop(idx)
            lines.pop(idx)
        else:
            break


def least_squares_fit(point_list, ymin, ymax):
    # 最小二乘法拟合
    x = [p[0] for p in point_list]
    y = [p[1] for p in point_list]

    # polyfit第三个参数为拟合多项式的阶数,所以1代表线性
    fit = np.polyfit(y, x, 1)
    fit_fn = np.poly1d(fit)  # 获取拟合的结果

    xmin = int(fit_fn(ymin))
    xmax = int(fit_fn(ymax))

    return [(xmin, ymin), (xmax, ymax)]


if __name__ == "__main__":
    img = cv.imread('img02.jpg')
    result = process_an_image(img)
    cv.imshow("lane", np.hstack((img, result)))
    cv.waitKey(0)

        执行方法也非常简单,直接输入python3 checkplane.py即可。注意,这里测试的图片是img02.jpg,大家可以换成自己的测试图片。最后,非常感谢原作者给出的参考代码。

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

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

相关文章

Linux常用命令——cd命令

在线Linux命令查询工具 cd 切换用户当前工作目录 补充说明 cd命令用来切换工作目录至dirname。 其中dirName表示法可为绝对路径或相对路径。若目录名称省略&#xff0c;则变换至使用者的home directory(也就是刚login时所在的目录)。另外&#xff0c;~也表示为home directo…

LabVIEW开发多速率实时混合仿真

LabVIEW开发多速率实时混合仿真 混合仿真是一种子结构技术&#xff0c;通过将数值建模的优点与实验测试的优点相结合来模拟感兴趣的结构。模拟结构的其余部分特别令人感兴趣&#xff0c;因此可以进行物理复制&#xff0c;以揭示粘弹性、屈曲、速率相关特性或其他非线性效应的影…

微信小程序文件上传wx.uploadFile

网页版查看了一下负载要求是这样 wx.uploadFile({url: ${wx.getStorageSync(apiUrl)}//sysFileInfo/upload?token${wx.getStorageSync(token)}, // 仅为示例&#xff0c;非真实的接口地址filePath: files[0].url,name: file,formData: {secretFlag: Y },success: (res) > {…

Android 11.0 framework层实现app默认全屏显示

1.前言 在11.0的系统rom定制化开发中,在对于第三方app全屏显示的功能需求开发中,需要默认app全屏显示,针对这一个要求,就需要在系统启动app 的过程中,在绘制app阶段就设置全屏属性,接下来就实现这个功能 效果图如下: 2.framework层实现app默认全屏显示的核心类 framewo…

数据跨领域应用实例—公路数据应用场景(一)

2023年10月25日&#xff0c;国家数据局正式揭牌。标志着我国数据基础制度正在不断完善&#xff0c;数据资源使用水平稳额步提升&#xff0c;数据要素市场将进入发展快车道。当前&#xff0c;数字经济已成为我国经济高质量发展的新动能&#xff0c;国家数据局的成立&#xff0c;…

数量关系(蒙题技巧)

选中间2项 选三的倍数 数学中很少无法确定 难题 质数很难消掉

Leetcode Daily Challenge 1845. Seat Reservation Manager

1845. Seat Reservation Manager 题目要求&#xff1a;初始化一个SeatManager类包括默认构造函数和类函数&#xff0c;所有的seat初始化为true。reverse函数返回最小的true&#xff0c;然后把这个编号的椅子赋值为false。unreverse(seatNumber)函数把编号为seatNumber的椅子恢…

OpenAI 发布会总结-图片版

关于OpenAI发布会的总结&#xff0c;这里开一个帖子 汇总精华的展示图&#xff0c;以便大家理解&#xff1a; 2 产品 3、价格分析

volatile-日常使用场景

6.4 如何正确使用volatile 单一赋值可以&#xff0c;但是含复合运算赋值不可以&#xff08;i之类的&#xff09; volatile int a 10; volatile boolean flag true; 状态标志&#xff0c;判断业务是否结束 作为一个布尔状态标志&#xff0c;用于指示发生了一个重要的一次…

001、Nvidia Jetson Nano Developer KIT(b01)

之——镜像烧录 杂谈 Nvidia Jetson Nano Developer KIT&#xff08;b01&#xff0c;4G&#xff09;&#xff0c;系统配置全纪录&#xff0c;镜像烧录、系统安装、远程桌面安装、cuda与torch安装、pycharm、pycuda、tensorrt等等。 正文 1.开发板系统安装 1.1 开发板简介 Jet…

【框架篇】统一数据格式返回

✅作者简介&#xff1a;大家好&#xff0c;我是小杨 &#x1f4c3;个人主页&#xff1a;「小杨」的csdn博客 &#x1f433;希望大家多多支持&#x1f970;一起进步呀&#xff01; 1&#xff0c;统一数据格式返回的介绍 统一数据返回是指在进行接口开发时对返回数据进行规范和统…

【MogDB/openGauss的三种函数稳定性关键字】

一、ORACLE中的类似的函数稳定性关键字&#xff08;DETERMINISTIC&#xff09; 在ORACLE里&#xff0c;function有着一个DETERMINISTIC参数&#xff0c;它表示一个函数在输入不变的情况下输出是否确定&#xff0c;只要输入的参数一样&#xff0c;返回的结果一定一样的&#xf…

Android Mvp案例解析

目录 后端数据接口数据格式 App客户端布局逻辑主界面布局 M&#xff08;Model&#xff09;V&#xff08;View&#xff09;P&#xff08;Presenter&#xff09;OkhttpRetrofitRxJava网络http请求 Mvp架构-初学者MVP架构的契约者 后端数据接口 接口地址&#xff1a;https://apis.…

APP埋点:页面统计与事件统计

我们平时所说的埋点&#xff0c;可以大致分为两部分&#xff0c;一部分是统计APP页面访问情况&#xff0c;即页面统计&#xff1b;另外一部分是统计APP内的操作行为&#xff0c;及自定义事件统计。 一、页面统计 页面统计&#xff0c;可以统计应用内各个页面的访问次数&#x…

fiddler抓包拦截请求转发到其他地址

使用Fiddler拦截请求转发到指定地址方便于本地调试&#xff0c;不需要进行打包切换地址&#xff0c;可以加快问题的确定修复效果 内容&#xff1a; 1&#xff1a;首先给app进行设置代理抓包内容&#xff0c;给进行 https://blog.csdn.net/qq_43717814/article/details/84317038…

精读《算法题 - 二叉树中的最大路径和》

今天我们看一道 leetcode hard 难度题目&#xff1a;二叉树中的最大路径和。 题目 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点&#xff0c;且不一定经过根节点…

Si4010 一款带有MCU SoC RF发射机芯片 无线遥控器

Si4010是一款完全集成的SoC RF发射机&#xff0c;带有嵌入式CIP-51 8051 MCU&#xff0c;专为1GHz以下ISM频带设计。该芯片针对电池供电的应用进行了优化&#xff0c;工作电压为1.8至3.6 V&#xff0c;待机电流小于10 nA的超低电流消耗。高功率放大器可提供高达10 dBm的输出功率…

服务器数据库中了elbie勒索病毒怎么办,elbie勒索病毒解密,数据恢复

网络技术的不断成熟&#xff0c;为企业的生产运营提供了强有力的支撑&#xff0c;但是&#xff0c;随之而来的网络安全威胁也不断增加。云天数据恢复中心陆陆续续接到很多企业的求助&#xff0c;企业的服务器数据库e遭到了elbie勒索病毒攻击&#xff0c;导致企业计算机系统瘫痪…

基于PHP语言的会员系统搭建(Docker版)

1、操作系统 ubuntu22 2、安装Docker # Add Dockers official GPG key: sudo apt-get update sudo apt-get install ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -…

【UART】UART QA

UART常见知识点整理 定义&#xff1a;Universal Asynchronous Receiver/Transmitter - 通用异步收发传输器。 特点&#xff1a;速率不快、可全双工、结构上一般由波特率产生器、UART发送器、UART接收器组成&#xff0c;硬件2-3线。 线&#xff1a;RXD&#xff0c;TXD&#xff0…