Advanced Lane Detection源码解读(一)

2024-02-12 04:32

本文主要是介绍Advanced Lane Detection源码解读(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 源码解读

1.1 文件目录结构

源码文件下载自GitHub:advanced_lane_detection-master

  • advanced_lane_detection-master
    • camera_cal 存放用于相机标定棋盘格照片
      • *.jpg
    • output_images
      • *.png
    • test_images
      • *.jpg
    • calibrate_camera.p

      pickle文件,由calibrate_camera.py生成并存盘,包含键为mtx和dist的字典,存储了相机校正矩阵。

    • calibrate_camera.py
      def calibrate_camera():

      读取camera_cal/*.jpg照片,调用cv2.findChessboardCorners函数找到棋盘格的角点,再调用cv2.calibrateCamera的得到相机校正矩阵,并返回。

    • combined_thresh.py
      包含以下函数:
      • abs_sobel_thresh(img, orient='x', thresh_min=20, thresh_max=100)

        输入img为RGB图像,在该函数内部会被转为灰度图像。计算其在x或y方向的梯度。
        返回一个0-1的二值图像,选出了x或y梯度在最大、最小范围之间的像素点。

      • mag_thresh(img, sobel_kernel=3, mag_thresh=(30, 100))

        输入img为RGB图像,在该函数内部会被转为灰度图像。计算其梯度值。
        返回一个0-1的二值图像,选出了x或y梯度在最大、最小范围之间的像素点。

      • dir_threshold(img, sobel_kernel=3, thresh=(0, np.pi/2))

        输入img为RGB图像,在该函数内部会被转为灰度图像。计算其梯度方向角。
        返回一个0-1的二值图像,选出了梯度方向角在最大、最小范围之间的像素点。

      • hls_thresh(img, thresh=(100, 255))

        输入img为RGB图像,在该函数内部会被转为HLS图像。提取S通道,选出S通道值在最大、最小范围之间的像素点。

      • combined_thresh(img)

        输入img为RGB图像,分别调用以上的x方向梯度、梯度值、梯度方向角、HLS的S阈值及同时满足这几个阈值范围的五个二值图像。
        return combined, abs_bin, mag_bin, dir_bin, hls_bin

    • gen_example_images.py
    1. 读取test_images文件夹下的jpg文件,调用img = cv2.undistort(img, mtx, dist, None, mtx)函数进行畸变校正,使用matplot进行显示,并将显示结果存为undistort_*.png文件。
    2. 调用img, abs_bin, mag_bin, dir_bin, hls_bin = combined_thresh(img)函数,生成相对应的二值图。使用matplot进行显示,并将显示结果存为binary_*.png文件。
    3. 调用img, binary_unwarped, m, m_inv = perspective_transform(img)生成鸟瞰视图,使用matplot进行显示,并将显示结果存为warped_*.png文件。
    4. 调用ret = line_fit(img)得到曲线拟合后的参数,调用viz2(img, ret, save_file=save_file)进行可视化,并将可视化的结果存为polyfit_*.png文件。
    5. 读取文件,调用undist = cv2.undistort(orig, mtx, dist, None, mtx)进行畸变校正。
    6. 调用left_curve, right_curve = calc_curve(left_lane_inds, right_lane_inds, nonzerox, nonzeroy),计算得到左右车道线曲线参数。
    7. 计算得到vehicle_offset *= xm_per_pix,车辆相对车道线的偏移值。
    8. 调用img = final_viz(undist, left_fit, right_fit, m_inv, left_curve, right_curve, vehicle_offset)将左右车道线和车道的偏移叠加到原图像,并进行显示。
    • Line.py
      • 定义类class Line():
        • 包含的属性:
          n: 移动平均的窗口大小
          detected:
          二次曲线的系数 x = A ∗ y 2 + B ∗ y + C x = A*y^2 + B*y + C x=Ay2+By+C
          二次曲线系数的平均值:A_avg,B_avg,C_avg
        • 包含的方法:
          get_fit(self):返回系数平均值
          def add_fit(self, fit_coeffs):增加一组A,B,C,返回A_avg,B_avg,C_avg
    • line_fit.py
      • 定义函数def line_fit(binary_warped)
        • 输入二值图像。
        • 返回一字典,包含左右车道线的参数。
          	ret = {}ret['left_fit'] = left_fit # left_fit = np.polyfit(lefty, leftx, 2)ret['right_fit'] = right_fitret['nonzerox'] = nonzeroxret['nonzeroy'] = nonzeroyret['out_img'] = out_imgret['left_lane_inds'] = left_lane_indsret['right_lane_inds'] = right_lane_inds
          
        • gen_example_images.py中被调用。img, binary_unwarped, m, m_inv = perspective_transform(img)ret = line_fit(img)
        • line_fit_video.py中被调用。ret = line_fit(binary_warped)
      • 定义函数def tune_fit(binary_warped, left_fit, right_fit)
      • 定义函数def viz1(binary_warped, ret, save_file=None)
      • 定义函数def viz2(binary_warped, ret, save_file=None)
      • 定义函数def calc_curve(left_lane_inds, right_lane_inds, nonzerox, nonzeroy)
        • gen_example_images.py中被调用,left_curve, right_curve = calc_curve(left_lane_inds, right_lane_inds, nonzerox, nonzeroy)
      • 定义函数def calc_vehicle_offset(undist, left_fit, right_fit)
      • 定义函数def final_viz(undist, left_fit, right_fit, m_inv, left_curve, right_curve, vehicle_offset)
    • line_fit_video.py 主程序运行入口
    • perspective_transform.py
      • 定义函数def perspective_transform(img):
      • return warped, unwarped, m, m_inv 返回透视变换后的图像、再反透视变换后的图像、透视变换和反透视变换矩阵。

1.2 源码解析

1.2.1 主程序line_fit_video.py

  • 运行方法。命令行输入python line_fit_video.py,程序会读取project_video.mp4,并且输出标注后的视频out.mp4。
  • 源码如下
  • 相关变量的读取、初始化
# Global variables (just to make the moviepy video annotation work)
with open('calibrate_camera.p', 'rb') as f:save_dict = pickle.load(f)
mtx = save_dict['mtx']
dist = save_dict['dist']
window_size = 5  # how many frames for line smoothing
left_line = Line(n=window_size)
right_line = Line(n=window_size)
detected = False  # did the fast line fit detect the lines?
left_curve, right_curve = 0., 0.  # radius of curvature for left and right lanes
left_lane_inds, right_lane_inds = None, None  # for calculating curvature
  • 定义单帧图像的注释函数
# MoviePy video annotation will call this function
def annotate_image(img_in):"""Annotate the input image with lane line markingsReturns annotated image"""# 使用global函数声明全局变量(只是声明,而不是定义)global mtx, dist, left_line, right_line, detectedglobal left_curve, right_curve, left_lane_inds, right_lane_inds# Undistort, threshold, perspective transformundist = cv2.undistort(img_in, mtx, dist, None, mtx)img, abs_bin, mag_bin, dir_bin, hls_bin = combined_thresh(undist)binary_warped, binary_unwarped, m, m_inv = perspective_transform(img)# Perform polynomial fitif not detected: # 如果不是检测目的,即为第一帧图像。运行彻底拟合。# Slow line fitret = line_fit(binary_warped) # 将阈值分割和透视变换后的图像送入line_fit()函数,返回车道检测后的参数,这里是最重要的一个函数left_fit = ret['left_fit']right_fit = ret['right_fit']nonzerox = ret['nonzerox']nonzeroy = ret['nonzeroy']left_lane_inds = ret['left_lane_inds']right_lane_inds = ret['right_lane_inds']# Get moving average of line fit coefficients # 使用移动平均法得到曲线拟合的参数left_fit = left_line.add_fit(left_fit)right_fit = right_line.add_fit(right_fit)# Calculate curvatureleft_curve, right_curve = calc_curve(left_lane_inds, right_lane_inds, nonzerox, nonzeroy)detected = True  # slow line fit always detects the lineelse:  # implies detected == True# Fast line fitleft_fit = left_line.get_fit()right_fit = right_line.get_fit()ret = tune_fit(binary_warped, left_fit, right_fit) # 如果不是第一帧,则调用tune_fit()函数进行拟合left_fit = ret['left_fit']right_fit = ret['right_fit']nonzerox = ret['nonzerox']nonzeroy = ret['nonzeroy']left_lane_inds = ret['left_lane_inds']right_lane_inds = ret['right_lane_inds']# Only make updates if we detected lines in current frameif ret is not None:left_fit = ret['left_fit']right_fit = ret['right_fit']nonzerox = ret['nonzerox']nonzeroy = ret['nonzeroy']left_lane_inds = ret['left_lane_inds']right_lane_inds = ret['right_lane_inds']left_fit = left_line.add_fit(left_fit)right_fit = right_line.add_fit(right_fit)left_curve, right_curve = calc_curve(left_lane_inds, right_lane_inds, nonzerox, nonzeroy)else:detected = Falsevehicle_offset = calc_vehicle_offset(undist, left_fit, right_fit)# Perform final visualization on top of original undistorted imageresult = final_viz(undist, left_fit, right_fit, m_inv, left_curve, right_curve, vehicle_offset)return result
  • 定义视频标注函数
def annotate_video(input_file, output_file):""" Given input_file video, save annotated video to output_file """video = VideoFileClip(input_file)annotated_video = video.fl_image(annotate_image)annotated_video.write_videofile(output_file, audio=False)
  • 调用以上函数进行测试
if __name__ == '__main__':# Annotate the videoannotate_video('project_video.mp4', 'out.mp4')# Show example annotated image on screen for sanity checkimg_file = 'test_images/test2.jpg'img = mpimg.imread(img_file)result = annotate_image(img)result = annotate_image(img)result = annotate_image(img)plt.imshow(result)plt.show()

这篇关于Advanced Lane Detection源码解读(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/701669

相关文章

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟 开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚 第一站:海量资源,应有尽有 走进“智听

MCU7.keil中build产生的hex文件解读

1.hex文件大致解读 闲来无事,查看了MCU6.用keil新建项目的hex文件 用FlexHex打开 给我的第一印象是:经过软件的解释之后,发现这些数据排列地十分整齐 :02000F0080FE71:03000000020003F8:0C000300787FE4F6D8FD75810702000F3D:00000001FF 把解释后的数据当作十六进制来观察 1.每一行数据

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

GPT系列之:GPT-1,GPT-2,GPT-3详细解读

一、GPT1 论文:Improving Language Understanding by Generative Pre-Training 链接:https://cdn.openai.com/research-covers/languageunsupervised/language_understanding_paper.pdf 启发点:生成loss和微调loss同时作用,让下游任务来适应预训

red5-server源码

red5-server源码:https://github.com/Red5/red5-server