基于OpenCV的车道线检测系统

161 篇文章 11 订阅
2 篇文章 0 订阅

收藏关注不迷路


一、项目介绍

近年来,智能驾驶技术在国内外学者中成为研究的热门领域。其中,车道线识别技术作为智能驾驶的关键技术之一,需要准确地识别各种条件下的车道线。本文提出了一种基于OpenCV图像处理的车道线识别算法。
首先,该算法对输入的图像进行色彩空间转换,这是因为不同的色彩空间对车道线的特征有不同的表现,通过转换可以提高车道线的可见性。常用的色彩空间包括灰度、HSV和RGB等。
接下来,使用大津法(OTSU)和Canny算子对图像进行分割。大津法是一种自适应阈值分割方法,可以根据图像的直方图自动确定最佳阈值,将图像分为背景和前景两部分。Canny算子则用于边缘检测,它通过计算图像中的梯度来找到边缘。
然后,设计掩膜来找出图像中的感兴趣区域。由于车道线通常位于图像的底部,通过设置一个合适的掩膜,可以限定在该区域内进行车道线的检测,减少干扰。
接着,采用渐近概率式Hough变换对直线车道线进行检测。Hough变换是一种常用的直线检测方法,可以将图像中的点映射到参数空间,并通过寻找交叉点来确定直线。渐近概率式Hough变换通过随机选择图像中的点进行检测,可以大幅度减少计算量。
最后,借助OpenCV平台对算法进行实现。OpenCV是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉功能,可以方便地实现车道线识别算法。
关键词:车道线识别;OpenCV;霍夫变换

二、开发环境

开发语言:python
技术库:OpenCV

开发工具:pycharm等均可

————————————————

三、功能介绍

车道线预处理是在进行车道线检测和跟踪之前对图像进行的一系列操作,旨在提取和增强车道线的特征,以便后续的分析和处理。以下是常见的车道线预处理步骤:

  1. 图像去噪:使用滤波器(如高斯滤波器)对图像进行平滑处理,以去除图像中的噪声和细节,减少后续处理的干扰。
  2. 图像灰度化:将彩色图像转换为灰度图像,通过去除颜色信息,简化图像处理过程,并减少计算量。
  3. 图像增强:可以应用直方图均衡化或对比度增强等技术,以增强图像的亮度和对比度,使车道线更加明显和突出。
  4. 边缘检测:使用边缘检测算法(如Canny边缘检测)来识别图像中的边缘特征,包括车道线的边缘。这有助于进一步提取车道线的位置和形状。
  5. 区域兴趣选择(ROI):根据道路的几何形状和车道线的位置,选择感兴趣的区域,通常是在图像底部周围的矩形区域。这样可以减少处理的计算量,并集中关注车道线所在的区域。
  6. 霍夫变换:应用霍夫变换来检测直线特征,以找到图像中可能表示车道线的线段。通过设置适当的参数,可以过滤掉非车道线的线段。
  7. 线段拟合:对于检测到的直线线段,可以使用线性回归或多项式拟合等方法,将其拟合为平滑的连续曲线,代表车道线的位置和方向。
  8. 车道线跟踪:根据前一帧图像中检测到的车道线位置,结合当前帧图像中的特征,进行车道线的跟踪和预测,以提高稳定性和鲁棒性。
    以上步骤是车道线预处理的一般流程,实际应用中可能会根据具体情况进行调整和优化。车道线预处理的目标是提取并增强车道线的特征,为后续的车道线检测和跟踪提供更好的输入数据。

四、核心代码

部分代码:

import sys
import time

import cv2
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

from lanedetection import LaneDetection


class Ui_MainWindow(QMainWindow):

    def __init__(self):
        QMainWindow.__init__(self)
        self.setupUi(self)

        self.format = 0                        # 0 空格式 1 图片格式 2 视频格式
        self.data = None                       # 数据

        self.lanedetection = LaneDetection()   # 车道线检测类
        
        self.timer1 = VideoTimer()             # 视频显示多线程
        self.timer1._signal.connect(self.show_input_video)

        self.timer2 = VideoTimer()             # 视频显示多线程
        self.timer2._signal.connect(self.show_output_video)

    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")

        MainWindow.resize(1000, 600)
        MainWindow.setFixedSize(1000, 600)
        self.centralwidget = QWidget(MainWindow)

        # 图片控件
        self.label_inputs = QLabel(self.centralwidget)
        self.label_inputs.setGeometry(QRect(50, 70, 400, 400))
        self.label_inputs.setFrameShape(QFrame.Box)
        self.label_inputs.setObjectName("label_inputs")

        self.label_inputsName = QLabel(self.centralwidget)
        self.label_inputsName.setGeometry(QRect(175, 25, 150, 50))
        self.label_inputsName.setObjectName("label_inputsname")
        
        self.label_outputs = QLabel(self.centralwidget)
        self.label_outputs.setGeometry(QRect(550, 70, 400, 400))
        self.label_outputs.setFrameShape(QFrame.Box)
        self.label_outputs.setObjectName("label_outputs")

        self.label_outputsName = QLabel(self.centralwidget)
        self.label_outputsName.setGeometry(QRect(685, 25, 150, 50))
        self.label_outputsName.setObjectName("label_outputsname")
        
        # 按钮控件
        # 打开图片或视频
        self.pushButton_open = QPushButton(self.centralwidget)
        self.pushButton_open.setGeometry(QRect(150, 500, 150, 50))
        self.pushButton_open.setObjectName("pushButton_open")
        self.pushButton_open.clicked.connect(self.open)
        self.pushButton_open.setEnabled(True)
        
        # 运行图片或视频
        self.pushButton_run = QPushButton(self.centralwidget)
        self.pushButton_run.setGeometry(QRect(665, 500, 150, 50))
        self.pushButton_run.setObjectName("pushButton_run")
        self.pushButton_run.clicked.connect(self.run)
        self.pushButton_run.setEnabled(False)

        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

        self.label_inputs.setText(_translate("MainWindow", "原始图片或视频"))
        self.label_inputsName.setText(_translate("MainWindow", "原始图片或视频"))
        self.label_outputs.setText(_translate("MainWindow", "处理图片或视频"))
        self.label_outputsName.setText(_translate("MainWindow", "处理图片或视频"))
        
        self.pushButton_open.setText(_translate("MainWindow", "打开图片或视频"))
        self.pushButton_run.setText(_translate("MainWindow", "处理图片或视频"))
        
    def open(self):
        # 打开图片文件
        file_name = QFileDialog.getOpenFileName(self.centralwidget, "选择图片或视频", "./assets", "ALL Files(*.*)")
        if not file_name[0]:
            result=QMessageBox.question(
                QWidget(),
                '问题提示', 
                '路径未选择', 
                QMessageBox.Yes,
                QMessageBox.Yes  # 默认关闭界面选择No
            )
            return
        
        if file_name[0].endswith('.jpg'):
            self.format = 1
            # 读取图片
            self.data = cv2.imread(file_name[0], 1)
            self.show_input_image(self.data)
            self.pushButton_open.setEnabled(False)
            self.pushButton_run.setEnabled(True)
            
        elif file_name[0].endswith('.mp4'):
            self.format = 2
            # 创建一个视频读写类
            self.data = cv2.VideoCapture(file_name[0])
            # self.outputs = cv.VideoCapture(0)
            if not self.data.isOpened():
                result=QMessageBox.question(
                QWidget(),
                '问题提示', 
                '打开mp4文件失败', 
                QMessageBox.Yes,
                QMessageBox.Yes  # 默认关闭界面选择No
            )
                return
            self.pushButton_open.setEnabled(False)
            self.timer1.start()
            self.pushButton_run.setEnabled(True)
            
        else:
            result=QMessageBox.question(
                QWidget(),
                '问题提示', 
                '文件格式不存在,请重新选择', 
                QMessageBox.Yes,
                QMessageBox.Yes  # 默认关闭界面选择No
            )
            return
                
    def run(self):
        if self.data is None:
            result=QMessageBox.question(
                QWidget(),
                '问题提示', 
                '数据未打开', 
                QMessageBox.Yes,
                QMessageBox.Yes  # 默认关闭界面选择No
            )  
            return
        
        if self.format is 1 and self.data is not None:
            res = self.lanedetection(self.data)
            self.show_output_image(res)
            
            self.pushButton_open.setEnabled(True)
            self.pushButton_run.setEnabled(False)
            
        elif self.format is 2 and self.data is not None:
            self.pushButton_run.setEnabled(False)
            self.timer2.start()
            self.pushButton_open.setEnabled(True)
            
    def show_input_video(self):
        if self.format is 2 and self.data.isOpened():
            success, frame = self.data.read()
            if success:
              self.show_input_image(frame)
            else:
                self.timer1.stop()
                # 从视频头开始
                self.data.set(cv2.cv2.CAP_PROP_POS_AVI_RATIO, 0)
                
    def show_output_video(self):
        if self.format is 2 and self.data.isOpened():
            success, frame = self.data.read()
            if success:
                res = self.lanedetection(frame)
                self.show_output_image(res)
            else:
                self.timer2.stop()
                self.data.release()
       
    def show_input_image(self, image):
        # 等比例缩放图片
        img = cv2.resize(image, (self.label_inputs.size().height(), self.label_inputs.size().width()))
        # 图片格式从BGR 转换为RGB
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # 显示图片:先从opencv转换到pyqt5种QImage格式,再通过setPixmap设置图片
        QImg = QImage(
            img.data, 
            img.shape[1], 
            img.shape[0],
            img.shape[1] * 3, 
            QImage.Format_RGB888
        )
        self.label_inputs.setPixmap(QPixmap.fromImage(QImg))

    def show_output_image(self, image):
        # 等比例缩放图片
        img = cv2.resize(image, (self.label_inputs.size().height(), self.label_inputs.size().width()))
        # 图片格式从BGR 转换为RGB
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # 显示图片:先从opencv转换到pyqt5种QImage格式,再通过setPixmap设置图片
        QImg = QImage(
            img.data, 
            img.shape[1], 
            img.shape[0],
            img.shape[1] * 3, 
            QImage.Format_RGB888
        )
        self.label_outputs.setPixmap(QPixmap.fromImage(QImg))

      
class VideoTimer(QThread):
    # refetence: https://github.com/fengtangzheng/pyqt5-opencv-video
    _signal = pyqtSignal()
    def __init__(self):
        QThread.__init__(self)
        self.stopped = False
        self.fps = 50  # 设置显示快慢
        
        self.mutex = QMutex()
        
    def run(self):
        with QMutexLocker(self.mutex):
            self.stopped = False
        while True:
            if self.stopped:
                return
            self._signal.emit()
            time.sleep(1 / self.fps)
    def stop(self):
        with QMutexLocker(self.mutex):
            self.stopped = True
            
  
if __name__ == "__main__":
    app = QApplication(sys.argv)
    ui = Ui_MainWindow()
    ui.show()
    sys.exit(app.exec_())




五、效果图

请添加图片描述

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

六、文章目录

目录

摘要 III
Abstract IV
目录 V
第1章 绪论 1
1.1 研究背景 1
2.1 国内外研究现状 1
1.2.1 国外研究现状 2
1.2.2 国内研究现状 2
3.1 论文主要内容 3
第2章 车道线的预处理 4
2.1 认识车道线 6
2.1.1 车道线的基本分类 6
2.1.2 车道线的标划区分 7
2.1.3 车道线的基本形状 7
2.2 感兴趣区域 8
2.3 平滑滤波 9
2.3.1 均值滤波 10
2.3.2 中值滤波 11
2.3.3 高斯滤波 12
2.3.4 本章总结 13
2.4 二值化 13
2.4.1 二值化的基本概念 13
2.4.2 大津法自适应阈值分割 13
2.5 边缘提取 14
2.5.1 Sobel算子 15
2.5.2 Canny算子 16
2.5.3 Sobel算子和Canny算子的比较 17
第3章 Hough变换直线和椭圆的检测 18
3.1 Hough变换直线检测的基本原理 18
3.2 Hough变换的缺陷和改进 19
第4章 车道线的识别 20
结论 24
参考文献: 25
致谢 28

  • 30
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毕业程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值