开发和发布网站的主要流程长沙 网站设计 公司
使用 darkSCNN 和 Caffe 进行车道线检测
- 一、引言:车道线检测的重要性
- 二、darkSCNN_caffe 原理解析
- 2.1 什么是 darkSCNN?
- 2.2 模型工作原理
- 三、效果展示
- 四、详细操作步骤
- 4.1 环境准备:创建 Docker 容器
- 4.2 安装必要的依赖包
- 4.3 下载预训练模型
- 4.4 获取测试视频
- 4.5 编译推理程序
- 4.6 运行车道线检测
- 4.7 生成结果 GIF(便于展示)
- 五、代码详解
- 5.1 `caffe_inference.cpp` 核心代码解析
- 六、附加内容:从源码编译 Caffe
- 6.1 安装编译依赖
- 6.2 下载 Caffe 源码
- 6.3 配置和编译
- 七、总结
一、引言:车道线检测的重要性
车道线检测是自动驾驶和高级驾驶辅助系统(ADAS)中的关键技术之一。它能够帮助车辆识别道路上的车道标记,从而实现车道保持、偏离预警等功能。本文介绍了如何使用 darkSCNN 模型和 Caffe 框架对视频中的车道线进行检测。
二、darkSCNN_caffe 原理解析
2.1 什么是 darkSCNN?
darkSCNN 是一种基于卷积神经网络(CNN)的车道线检测模型
2.2 模型工作原理
darkSCNN 通过深度学习的方式学习车道线的特征。其基本流程如下:
- 特征提取:使用卷积层从输入图像中提取多层次的特征
- 像素级分类:对每个像素进行分类,判断它是否属于车道线以及属于哪条车道线
三、效果展示

四、详细操作步骤
4.1 环境准备:创建 Docker 容器
我们使用 Docker 容器来确保环境一致性,避免依赖问题。
# 创建项目目录
mkdir darkSCNN_caffe_DEMO
cd darkSCNN_caffe_DEMO/# 清理可能存在的旧容器
docker stop darkSCNN_caffe
docker rm darkSCNN_caffe# 创建新容器,设置文件映射和网络
docker run -it --privileged --net=host \-v $PWD:/home -w /home --name darkSCNN_caffe ubuntu:18.04 /bin/bash
4.2 安装必要的依赖包
在容器内执行以下命令安装所需软件:
# 更新软件包列表
apt update# 安装核心依赖
apt install caffe-cpu -y
apt install wget -y
apt install unzip -y
apt install python3-pip -y
apt install locales -y# 安装视频处理相关工具
apt install ffmpeg -y# 安装计算机视觉库
apt install libopencv-dev -y# 安装数学运算和深度学习依赖
apt install libopenblas-dev -y
apt install libcaffe-cpu-dev -y
apt install libboost1.62-all-dev -y# 安装日志和序列化库
apt install libgflags-dev -y
apt install libgoogle-glog-dev -y
apt install libprotobuf-dev -y# 安装视频下载工具
pip3 install you-get# 设置 locale(解决可能出现的字符编码问题)
locale-gen
locale-gen en_US.UTF-8
export LC_CTYPE=en_US.UTF-8
4.3 下载预训练模型
# 下载 darkSCNN 的预训练模型
wget https://apollo-pkg-beta.cdn.bcebos.com/perception_model/darkSCNN_caffe.zip# 解压模型文件
unzip darkSCNN_caffe.zip
4.4 获取测试视频
# 从网络下载测试视频(这里以B站视频为例)
you-get https://www.bilibili.com/video/BV19J411t7Uy/ -O test# 从视频中提取一帧作为测试图像
ffmpeg -i test.mp4 -ss 00:00:01 -vframes 1 test.jpg
4.5 编译推理程序
g++ -std=c++11 -DCPU_ONLY -o caffe_inference caffe_inference.cpp \-lcaffe -lglog -lboost_system -lopenblas `pkg-config --libs opencv`
4.6 运行车道线检测
# 设置日志级别(减少不必要的输出)
export GLOG_minloglevel=7
export GLOG_alsologtostderr=1# 运行推理程序,处理视频
./caffe_inference test.mp4 darkSCNN_caffe.mp4
4.7 生成结果 GIF(便于展示)
# 将输出的视频转换为GIF格式,便于在网页上展示
ffmpeg -i darkSCNN_caffe.mp4 -vf "fps=5,scale=640:-1:flags=lanczos,split [s0][s1];[s0] palettegen=stats_mode=diff [p];[s1][p] paletteuse=dither=none:diff_mode=rectangle" darkSCNN_caffe.gif
五、代码详解
5.1 caffe_inference.cpp 核心代码解析
#include <cblas.h>
#include <opencv2/opencv.hpp>
#include <caffe/caffe.hpp>
#include <algorithm>
#include <iosfwd>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <fstream>
#include <iostream>
#include <sstream>
#include <cmath>using namespace caffe;
using std::string;int main(int argc, char** argv) {// 设置CPU模式Caffe::set_mode(Caffe::CPU); // 模型文件路径string model_file = "darkSCNN_caffe/deploy.prototxt";string trained_file = "darkSCNN_caffe/deploy.caffemodel";// 加载网络Net<float> net(model_file, TEST);net.CopyTrainedLayersFrom(trained_file); // 获取输入blobBlob<float>* input_blob = net.input_blobs()[0];input_blob->Reshape(1, 3, 480, 640); // 根据实际情况调整形状 float* input_data_ptr = input_blob->mutable_cpu_data();// 打开视频文件cv::VideoCapture cap(argv[1]);if (!cap.isOpened()) {std::cerr << "Error: Could not open video file." << std::endl;return -1;}// 创建视频写入器,用于保存处理结果cv::VideoWriter writer;int out_width = 640;int out_height = 480*3; // 高度为3倍,用于垂直拼接三种视图writer.open(argv[2], cv::VideoWriter::fourcc('M', 'J', 'P', 'G'), 5, cv::Size(out_width, out_height));if (!writer.isOpened()) {std::cerr << "Error: Could not create video writer." << std::endl;return -1;}cv::Mat frame;int frame_count = 0; int process_count=0;// 主循环:处理视频每一帧while (true) {cap >> frame; // 读取一帧if (frame.empty()) break; frame_count++; if(frame_count%25!=0) continue; // 每25帧处理一帧,提高处理速度process_count+=1;if (process_count>25) break; // 最多处理25帧,避免处理时间过长std::cout << "Processing frame " << process_count << std::endl;// 调整图像尺寸为640x480cv::Mat resize_image;cv::resize(frame, resize_image, cv::Size(640, 480));// 将图像数据类型转换为float32cv::Mat float_image;resize_image.convertTo(float_image, CV_32FC3, 1.0);// 注意:如果输入图像实际上是BGR格式,则可以跳过此步骤cv::cvtColor(float_image, float_image, cv::COLOR_RGB2BGR);// 分离通道以便逐个处理std::vector<cv::Mat> channels;cv::split(float_image, channels);// 均值减法(均值顺序为BGR)cv::Scalar mean(95.0, 99.0, 96.0); // BGR均值channels[0] -= mean[0]; // B通道channels[1] -= mean[1]; // G通道channels[2] -= mean[2]; // R通道// 为每个通道创建新的形状 [1, height, width]for (auto& channel : channels) {channel = channel.reshape(1, 1); // 1个通道,1行,列数自动计算} // 合并通道 [channels, height, width]cv::Mat chw_image;cv::vconcat(channels, chw_image);memcpy(input_data_ptr,chw_image.data,1*3*480*640*sizeof(float)); // 前向传播net.Forward();// 获取输出Blob<float>* output_blob = net.output_blobs()[1];const float* output_data = output_blob->cpu_data();int output0_Size=1*13*480*640; int num_lanes_=13;int lane_output_height_=480;int lane_output_width_=640;float confidence_threshold_lane_=0.95;// 创建一个向量来存储每个车道的掩码std::vector<cv::Mat> masks;// 从Blob中提取每个车道的置信度图for (int i = 0; i < num_lanes_; ++i) {cv::Mat tmp(lane_output_height_, lane_output_width_, CV_32FC1); // 计算当前车道数据在Blob中的起始位置const float* channel_data = output_data +i * lane_output_height_ * lane_output_width_; // 将数据复制到OpenCV矩阵中memcpy(tmp.data, channel_data,lane_output_width_ * lane_output_height_ * sizeof(float)); masks.push_back(tmp);} // 初始化像素计数器和彩色掩码图像std::vector<int> cnt_pixels(num_lanes_, 0);cv::Mat mask_color(lane_output_height_, lane_output_width_, CV_32FC1);mask_color.setTo(cv::Scalar(0)); // 初始化为0(背景) // 遍历所有车道类别for (int c = 0; c < num_lanes_; ++c) {// 获取当前车道的置信度图cv::Mat& lane_mask = masks[c]; // 遍历每个像素for (int h = 0; h < lane_mask.rows; ++h) {for (int w = 0; w < lane_mask.cols; ++w) {// 如果置信度超过阈值if (lane_mask.at<float>(h, w) >= confidence_threshold_lane_) {// 在彩色掩码中设置对应的类别值mask_color.at<float>(h, w) = static_cast<float>(c);// 增加该类的像素计数cnt_pixels[c]++;}}}} // 将浮点型掩码转换为8位图像以便显示和保存cv::Mat mask_color_8u;mask_color.convertTo(mask_color_8u, CV_8U, 255.0 / (num_lanes_ - 1)); // 应用颜色映射使不同类别显示为不同颜色cv::Mat colored_output;cv::applyColorMap(mask_color_8u, colored_output, cv::COLORMAP_JET); cv::Mat overlay;double alpha = 0.2; // 透明度cv::addWeighted(resize_image, 1 - alpha, colored_output, alpha, 0.0, overlay);// 垂直拼接三种视图:原始图像、分割结果和叠加结果cv::Mat result0;cv::vconcat(resize_image, colored_output, result0); cv::Mat result1;cv::vconcat(result0, overlay, result1);// 写入结果帧到输出视频writer.write(result1);}// 释放资源cap.release();writer.release(); std::cout << "Video processing completed. Processed " << process_count << " frames." << std::endl;return 0;
}
六、附加内容:从源码编译 Caffe
6.1 安装编译依赖
# 安装基础编译工具和库
apt install libopenblas-dev -y
apt install git -y
apt install cmake -y
apt install protobuf-compiler -y# 安装数据库支持(可选)
apt install libhdf5-dev -y
apt install liblmdb-dev -y
apt install libleveldb-dev -y
apt install libsnappy-dev -y# 安装数学库
apt install libatlas-base-dev -y
6.2 下载 Caffe 源码
# 克隆 Caffe 官方仓库
git clone https://github.com/BVLC/caffe.git
cd caffe# 切换到稳定版本(1.0版本)
git checkout 1.0
6.3 配置和编译
# 创建配置文件
cat > Makefile.config << 'EOF'
CPU_ONLY := 1
USE_OPENCV := 0
USE_LEVELDB := 0
USE_LMDB := 0
BLAS := atlas
PYTHON_INCLUDE := /usr/include/python2.7 /usr/lib/python2.7/dist-packages/numpy/core/include
PYTHON_LIB := /usr/lib
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu/hdf5/serial
BUILD_DIR := build
DISTRIBUTE_DIR := distribute
Q ?= @
EOF# 开始编译
make
七、总结
本文介绍了如何使用 darkSCNN 模型和 Caffe 框架进行车道线检测,包括环境搭建、模型下载、代码编译和实际运行的全过程。通过这个示例,您可以了解到:
- 该模型的基本应用流程
- Caffe 框架的基本使用方法
- 计算机视觉任务中的常见预处理和后处理技术
- 如何将深度学习模型应用到视频处理中
注意:本文提供的代码和步骤在 Ubuntu 18.04 环境下测试通过,其他环境可能需要适当调整。
