opencv识别车道线(霍夫线变换)
目录
- 1、前言
- 2、霍夫线变换
- 2.1、霍夫线变换是什么?
- 2.2、在opencv中的基本用法
- 2.2.1、HoughLinesP函数定义
- 2.2.2、用法
- 3、识别车道
- 3.1、优化
- 3.1.1、降噪
- 3.1.2、过滤方向
- 3.1.3、截选区域
- 3.1.4、测试其它图片
- 图片1
- 图片2
- 图片3
1、前言
最近学习opencv学到了霍夫线变换,霍夫线变换是一个查找图像中直线的算法,它的其中一种应用场景就是识别车道,本文以识别车道为例,介绍霍夫线的简单用法。
2、霍夫线变换
2.1、霍夫线变换是什么?
下面是chatGPT给出的说明:
霍夫线变换(Hough Line Transform)是一种图像处理技术,可以用于检测图像中的直线。它的基本思想是,将直线转换为参数空间,并在参数空间中寻找与图像中的边缘相对应的点,从而找到这些直线。霍夫线变换常用于计算机视觉领域,例如在车道线检测、图像拼接、人脸识别等方面应用广泛。
原理性的东西这里不讲,因为有点复杂,我看得也有点懵。
2.2、在opencv中的基本用法
2.2.1、HoughLinesP函数定义
opencv实现霍夫线变换的函数是HoughLinesP,它的定义如下。
void HoughLinesP( InputArray image, OutputArray lines,double rho, double theta, int threshold,double minLineLength = 0, double maxLineGap = 0 );
它的参数的含义如下:
image:8位、单通道二进制源图像。
lines:输出线的矢量。每条线由一个4元素矢量表示,可以传入vector< cv::Vec4i>类型。
控制精度:
rho:累加器的距离分辨率(以像素为单位)。
theta:累加器的角度分辨率(弧度)。
过滤:
threshold:累加器阈值参数。
minLineLength:最小行长度。小于该长度的线段将被拒绝。
maxLineGap:同一条线上链接点的最大允许间隙。
2.2.2、用法
因为HoughLinesP传入的图像必须是8位、单通道二进制源图像,所以在传入图像之前,需要做转灰度图-》转二进制图的操作。
opencv提供了一些转二进制图的方法,因为HoughLinesP的目的是找到直线,而直线其实也是轮廓的一部分,所以一般我们采用Canny算法来把灰度图转为二进制图。
例程:
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>using namespace cv;int main() {Mat src = imread("road.png");imshow("src", src);Mat gray;cvtColor(src, gray, COLOR_BGR2GRAY);imshow("gray", gray);// Apply Canny edge detectionMat edges;Canny(gray, edges, 50, 150);imshow("canny", edges);// Perform Hough transform to find linesstd::vector<Vec4i> lines;HoughLinesP(gray, lines, 1, CV_PI / 180, 50, 50, 10);// Draw lines on output imageMat dst = src.clone();for (size_t i = 0; i < lines.size(); i++) {Vec4i vline = lines[i];line(dst, Point(vline[0], vline[1]), Point(vline[2], vline[3]), Scalar(0, 0, 255), 2);}imshow("dst", dst);waitKey(0);}
3、识别车道
首先准备一张图片,如下图所示,要识别出它的白色车道线。

我们直接使用上一节的例程,效果如下。

发现虽然车道是识别出来了,但是环境中的纹理也被误认为车道,所以要做进一步优化。
3.1、优化
3.1.1、降噪
从上面的Canny图可以看到,环境中的树木形成了密密麻麻的纹理,这些就是影响效果的因素之一。
经过测试,我选用了“二值化 - 》腐蚀 - 》膨胀”的方式来完成降噪,经过优化后的代码如下:
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>using namespace cv;int main() {Mat src = imread("/road.png");imshow("src", src);Mat gray;cvtColor(src, gray, COLOR_BGR2GRAY);imshow("gray", gray);//二值化Mat thr;threshold(gray, thr, 100, 255, THRESH_BINARY);imshow("threshold", thr);// 腐蚀Mat eroded;Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));erode(thr, eroded, element);// 膨胀Mat dilated;dilate(eroded, dilated, element);imshow("dilated", dilated);// Apply Canny edge detectionMat edges;Canny(dilated, edges, 50, 150);imshow("canny", edges);// Perform Hough transform to find linesstd::vector<Vec4i> lines;HoughLinesP(edges, lines, 1, CV_PI / 180, 50, 50, 10);// Draw lines on output imageMat dst = src.clone();for (size_t i = 0; i < lines.size(); i++) {Vec4i vline = lines[i];line(dst, Point(vline[0], vline[1]), Point(vline[2], vline[3]), Scalar(0, 0, 255), 2);}imshow("dst", dst);waitKey(0);
}
优化后的效果如下:

从Canny中明显可以看到环境纹理少了很多。
3.1.2、过滤方向
在上图中,可以看到还有一些横向的纹理影响了效果,我们可以通过直线的方向来做进一步过滤。
在车的视角下,车道是朝中间斜的,两边车道成八字型,如图所示。

也就是说,车道的线在图像上倾斜角度不会小,所以我们可以在得出最终结果时,添加一个过滤条件:倾斜角度小于20度的直线不满足条件。
修改代码如下:
.....// Perform Hough transform to find linesstd::vector<Vec4i> lines;HoughLinesP(edges, lines, 1, CV_PI / 180, 50, 50, 10);// Draw lines on output imageMat dst = src.clone();for (size_t i = 0; i < lines.size(); i++) {Vec4i vline = lines[i];/* 过滤倾斜45度及以下的斜线 */float tanVal = (float)(vline[3] - vline[1]) / (vline[2] - vline[0]);if (abs(tanVal) < tan(CV_PI / 18)) continue;line(dst, Point(vline[0], vline[1]), Point(vline[2], vline[3]), Scalar(0, 0, 255), 2);}
.......
效果:

3.1.3、截选区域
在识别车道时,因为车道是在车的脚下,需要识别的图像只有相机拍下的下半截,所以这里还可以加多一层优化:把上半截图像砍掉,只处理下半截图像。
修改代码:
int main() {Mat src = imread("road.png");Rect vaildRect(0, src.rows / 2, src.cols, src.rows / 2);Mat src = src(vaildRect);imshow("src", src);
......
效果:

3.1.4、测试其它图片
图片1
因为拍照时的亮度不一,所以需要根据亮度来调整二值化时的阀值,此例用的是
threshold(gray, thr, 170, 255, THRESH_BINARY);

图片2

图片3
threshold(gray, gray, 150, 255, THRESH_BINARY);

相关文章:
opencv识别车道线(霍夫线变换)
目录1、前言2、霍夫线变换2.1、霍夫线变换是什么?2.2、在opencv中的基本用法2.2.1、HoughLinesP函数定义2.2.2、用法3、识别车道3.1、优化3.1.1、降噪3.1.2、过滤方向3.1.3、截选区域3.1.4、测试其它图片图片1图片2图片31、前言 最近学习opencv学到了霍夫线变换&am…...
MySQL的同步数据Replication功能
MySQL提供了Replication功能,可以实现将一个数据库的数据同步到多台其他数据库。前者通常称之为主库(master),后者则被称从库(slave)。MySQL复制过程采用异步方式,但延时非常小,秒级…...
2023年全国最新高校辅导员精选真题及答案17
百分百题库提供高校辅导员考试试题、辅导员考试预测题、高校辅导员考试真题、辅导员证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 21.完善大学生的自我意识,我们可以采取的措施是()。 …...
中文代码92
PK 嘚釦 docProps/PK 嘚釦諿hl | docProps/app.xml漅Mo?糤?皘幅H??Q州濾mじ沜咅K宩Z5~q矹阶浇?灭貄}鰜>hk?i灐Q墩娲蝊毲b檊!J邮?\鏶 鵉苻牢[?j Y?a漺1簕B傟p悺L睮恃鶤?龎劂Q|瓣} A??苷0???5m?髤咄佶?\/#姧1N_??熹 冟.琽僠糧固Pw襅…...
Python SEO采集海量文本标题,用倒排索引找出“类似的标题“代码实现
Python SEO采集海量文本标题,用倒排索引找出“类似的标题“代码实现 作者:虚坏叔叔 博客:https://xuhss.com 早餐店不会开到晚上,想吃的人早就来了!😄 一、说明 假设这个是采集到的海量文本标题: 现在要判断找到的这个标题 title = "拜登称特朗普拒绝承认选举…...
模型杂谈:快速上手元宇宙大厂 Meta “开源泄露”的大模型(LLaMA)
本篇文章聊聊如何低成本快速上手使用 Meta(Facebook)的开源模型 LLaMA。 写在前面 在积累点赞,兑现朋友提供的显卡算力之前,我们先来玩玩“小号的”大模型吧。我相信 2023 年了,应该不需要再赘述如何使用 Docker 干净…...
RedisCluster集群模式下master宕机主从切换期间Lettuce连接Redis无法使用报错Redis command timed out的问题
背景springboot使用redisTemplate访问redis cluster(三主三从),底层是Lettuce,当其中一个master挂掉后,slave正常升为master,程序报错 Redis commond timed out after 6 seconds。解决手动连接集群…...
Xuetr杀毒工具使用实验(28)
实验目的 (1)学习Xuetr的基本功能; (2)掌握Xuetr的基本使用方法。预备知识 windows操作系统的基本知识如:进程、网络、服务和文件等的了解。 XueTr是近年推出的一款广受好评的ARK工具。ARK工具全称为Anti R…...
fastapi(https)+openssl+测试(双向校验)
第一步生成根证书 # Generate CA private key openssl genrsa -out ca.key 2048 # Generate CSR openssl req -new -key ca.key -out ca.csr # Generate Self Signed certificate(CA 根证书) openssl x509 -req -days 365 -in ca.csr -signkey ca.key -o…...
TiDB Server
文章目录TiDB Server架构TiDB Server作用TiDB Server的进程SQL语句的解析和编译SQL读写相关模块在线DDL相关模块GC机制与相关模块TiDB Server的缓存热点小表缓存TiDB Server架构 Protocol Layer、Parse、Compile负责sql语句的解析编译和优化,然后生成sql语句执行计划…...
S3C2440移植Linux4.19.275内核以及过程中遇到的问题
目录 1 问题一:内核移植时MTD分区问题 2 问题二:uboot的MTDPARTS_DEFAULT定义的MTD分区,bootargs中的文件系统分区,内核的mtd_partition smdk_default_nand_part定义的分区,三者要对应起来 3 问题三:ubo…...
解忧杂货铺(二):UML时序图
目录 1、概述 2、UML时序图 2.1、什么是时序图 2.2、时序图的元素 2.2.1 角色(Actor) 2.2.2 对象(Object) 2.2.3 生命线(LifeLine) 2.2.4 控制焦点(Activation) 2.2.5 消息(Message) 2.2.6 自关联消息 2.2.7 组合片段 1、概述 在看AUTOSAR规范的时候发现时序图里面的…...
微信小程序的代码由哪些结构组成?
小程序官方建议把所有小程序的页面,都存放在pages 目录中,以单独的文件夹存在,如图所示: 其中,每个页面由4 个基本文件组成,它们分别是:js文件(页面的脚本文件,存放页面的数据、事件…...
Cloud Kernel SIG月度动态:发布 ANCK 新版本及 Plugsched v1.2.0
Cloud Kernel SIG(Special Interest Group):支撑龙蜥内核版本的研发、发布和服务,提供生产可用的高性价比内核产品。 01 2 月 SIG 整体进展 发布 ANCK 4.19.91-27.1 版本。 发布 ANCK 5.10.134-13.1 版本。 调度器热升级相关事…...
Jedis 使用详解(官方原版)
一、配置 Maven 依赖项Jedis也通过Sonatype作为Maven Dependency 分发。要配置它,只需将以下 XML 代码段添加到您的 pom.xml 文件中。<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.…...
关于Pytorch中的张量学习
关于Pytorch中的张量学习 张量的概念和创建 张量的概念 Tensor是pytorch中非常重要且常见的数据结构,相较于numpy数组,Tensor能加载到GPU中,从而有效地利用GPU进行加速计算。但是普通的Tensor对于构建神经网络还远远不够,我们需…...
基于Transformer的目标检测算法学习记录
前言 本文主要通过阅读相关论文了解当前Transformer在目标检测领域的应用与发展。 谷歌在 ICLR2020 上提出的 ViT(Vision Transformer)是将 Transformer 应用在视觉领域的先驱。从此,打开了Transformer进入CV领域的桥梁,NLP与CV几…...
嵌入式学习笔记——使用寄存器编程实现按键输入功能
文章目录前言模块介绍原理图编程思路前言 昨天,通过配置通用输出模式,实现了LED灯的点亮、熄灭以及流水等操作,解决了通用输出的问题,今天我们再借用最常见的输入模块,按键来实现一个按键控制LED的功能,重…...
打卡小达人之路:Spring Boot与Redis GEO实现商户附近查询
在当今社会,定位服务已经成为了各种应用的重要组成部分,比如地图、打车、美食等应用。如何在应用中实现高效的附近商户搜索功能呢?传统的做法是将商户的经纬度信息存储在关系型数据库中,然后使用SQL查询语句实现附近商户搜索功能。…...
Apache HTTP Server <2.4.56 mod_proxy_uwsgi 模块存在请求走私漏洞(CVE-2023-27522)
漏洞描述 Apache HTTP Server 是一个Web服务器软件。 该项目受影响版本存在请求走私漏洞。由于mod_proxy_uwsgi.c 中uwsgi_response方法对于源响应头缺少检查,当apache启用mod_proxy_uwsgi后,攻击者可利用过长的源响应头等迫使应转发到客户端的响应被截…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
