ultra fast lane detection读后感及使用情况(附训练好的模型及libtorch端代码)

ultra fast lane detection提供了很好的源码,根据演示视频来看,效果似乎不赖,很有必要试一试该算法。
一、基本情况
作者知乎:https://zhuanlan.zhihu.com/p/157530787
简单来说,作者认为卷积层形式的输出,导致局部感受野小,很明显车道线识别需要结合全局特征来分析。而全连接层形式的输出,运用了全局特征,也就没有感受野的问题。
另外,作者把这个问题转化为了分类问题。也就是如下图所示。
C是车道线数目,h和w则是图像长宽相关的cell,类似于锚点。w方向上的通道是w+1个,最后一位输出的是有无该通道。
大概意思,就是用h和w预测第c个车道的大概位置,然后按照下面的公式,算具体位置:
损失函数还考量到相邻的位置附近,因此有了,后两个损失函数就是邻近位置的二阶差分,邻近概率的差分。
二、使用情况
作者在github上已经给出了开源库。要求先设置configs下的py,我选了culane数据集(比较大,大概50多个G),因此修改了culane.py。
需要注意的是,culane数据集有黑夜的数据集,但貌似没有特殊天气的数据。
之后就在pycharm进行了训练。
以下是笔者使用的libtorch C++端的代码,另外需要提醒一点(如果对数据的存储与运算不熟悉的话)
CPU类型下大多数函数都可以使用,但是推理速度比较慢。CUDA类型下并行速度快,但是有些函数不能用,遍历计算速度很慢,需要转为CPU类型。

#include <torch/script.h>
#include <torch/torch.h>
#include<ATen/ATen.h>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <windows.h>
using namespace torch::indexing;
using namespace std;


int tusimple_row_anchor[56] = {64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112,
116, 120, 124, 128, 132, 136, 140, 144, 148, 152, 156, 160, 164,
168, 172, 176, 180, 184, 188, 192, 196, 200, 204, 208, 212, 216,
220, 224, 228, 232, 236, 240, 244, 248, 252, 256, 260, 264, 268,
272, 276, 280, 284};
int culane_row_anchor[18] = {121, 131, 141, 150, 160, 170, 180, 189, 199, 209, 219, 228, 238, 248, 258, 267, 277, 287};


void tusimple_lane(at::Tensor& input, cv::Mat& img)
{

	int lane_num = 4;
	int length_cell = 56;
	int width = 100;
	int topk_n = 3;

	double w_scale = img.cols / (double)width;
	double h_scale = img.rows / (double)(length_cell*2);
	input = input.to(torch::kCPU);//CPU for Ergodic computation,CUDA for Parallel computation

	for (int i = 0; i < length_cell; i++)
		for (int j = 0; j < lane_num; j++)
		{

			double lane_loc = 0;
			double sum_w = 0;
			double sum = 0;




			auto cut = input.index({ Slice(torch::indexing::None),Slice(torch::indexing::None), Slice(i,i + 1), Slice(j,j + 1) });
			cut = torch::softmax(cut, 1).view(-1);

			if (cut[width].item<float>() > 0.5)
			{
				continue;
			}

			std::vector<float> tesnor2vec(cut.data_ptr<float>(), cut.data_ptr<float>() + cut.numel());
			for (int s = 0; s < width; s++)
			{
				sum += tesnor2vec[s];
				sum_w += tesnor2vec[s] * s;
			}

			lane_loc = (sum_w / sum) * w_scale;

			//std::tuple<torch::Tensor, torch::Tensor> result = cut.topk(2, -1);
			//auto top_scores = std::get<0>(result).view(-1);//{1,10} 变成 {10}
			//auto top_idxs = std::get<1>(result).view(-1);
			/*if (cut[width].item<float>() > 0.5)
			{
				continue;
			}
			if(top_idxs[0].item().toInt()!=width)
			{
				lane_loc = top_idxs[0].item().toInt() * w_scale;
			}
			else
			{
				lane_loc= top_idxs[1].item().toInt() * w_scale;
			}*/



			cv::Scalar temp;
			switch (j)
			{
			case 0:
				temp = cv::Scalar(0, 0, 0);
				break;
			case 1:
				temp = cv::Scalar(255, 0, 0);
				break;
			case 2:
				temp = cv::Scalar(0, 255, 0);
				break;
			case 3:
				temp = cv::Scalar(0, 0, 255);
				break;
			}
			cv::circle(img, cv::Point(lane_loc, tusimple_row_anchor[i]), 5, temp, -1);

		}

}
//
void culane_lane(at::Tensor& input, cv::Mat& img)
{
	
	int lane_num = 4;
	int length_cell = 18;
	int width = 200;
	int topk_n =3;

	double w_scale = img.cols/(double)width;
	double h_scale = img.rows/(double)length_cell;
	input = input.to(torch::kCPU);//CPU for Ergodic computation,CUDA for Parallel computation

	for(int i=0;i<length_cell;i++)
		for (int j = 0; j < lane_num; j++)
		{

			double lane_loc = 0;
			double sum_w = 0;
			double sum = 0;




			auto cut = input.index({ Slice(torch::indexing::None),Slice(torch::indexing::None), Slice(i,i + 1), Slice(j,j + 1) });
			cut = torch::softmax(cut, 1).view(-1);


			if (cut[width].item<float>() > 0.5)
			{
				continue;
			}

			std::vector<float> tesnor2vec(cut.data_ptr<float>(), cut.data_ptr<float>() + cut.numel());
			for (int s = 0; s < width; s++)
			{
				sum += tesnor2vec[s];
				sum_w += tesnor2vec[s] * s;
			}

			lane_loc = (sum_w / sum )* w_scale;
			cv::Scalar temp;
			switch (j)
			{
			case 0:
				temp = cv::Scalar(0, 0, 0);
				break;
			case 1:
				temp = cv::Scalar(255, 0, 0);
				break;
			case 2:
				temp = cv::Scalar(0, 255, 0);
				break;
			case 3:
				temp = cv::Scalar(0, 0, 255);
				break;
			}
			cv::circle(img, cv::Point(lane_loc, culane_row_anchor[i]), 5, temp, -1);

		}
		
}

int main()
{
	torch::jit::script::Module module = torch::jit::load("C:\\Users\\lvdon\\source\\repos\\C_test\\lane_det\\lane.torchscript_gpu.pt");
	torch::DeviceType device_type = torch::kCUDA;
	module.to(device_type);
	module.eval();
	cv::VideoCapture cap("G:\\视频\\弯道\\cv2_curve.mp4");

	//cv::VideoWriter vw;
	//vw.open("C:\\Users\\lvdon\\source\\repos\\C_test\\test.mp4", //路径
	//	CV_FOURCC('m', 'p', '4', 'v'), //编码格式
	//	30, //帧率
	//	cv::Size(800,
	//		288));//尺寸

	cv::Mat img;
	cv::Mat ori;
	cap.read(img);
	int width = img.size().width;
	int height = img.size().height;
	int count = 0;
	while (true)
	{
		clock_t start = clock();
		count++;
		cap >> img;
		if (img.empty())
		{
			cout << "play end" << endl;
			break;
		}
		else if (count % 1 != 0)
		{
			continue;
		}
		//img = cv::imread("E:\\train_lane\\driver_182_30frame\\05312333_0003.MP4\\00000.jpg");
		cv::resize(img, img, cv::Size(600, 288));
		cv::copyMakeBorder(img, img,0, 0, 100, 100, cv::BORDER_CONSTANT, cv::Scalar(0, 0,0));
		cv::cvtColor(img, img, cv::COLOR_BGR2RGB);  // BGR -> RGB
		img.convertTo(img, CV_32FC3, 1.0f / 255.0f);  // normalization 1/255

		
		auto tensor_img = torch::from_blob(img.data, { 1, img.rows, img.cols, img.channels() },torch::kFloat).to(device_type);
		tensor_img = tensor_img.permute({ 0, 3, 1, 2 }).contiguous();  // BHWC -> BCHW (Batch, Channel, Height, Width)
		std::vector<torch::jit::IValue> inputs;

	
		inputs.emplace_back(tensor_img);
		auto output = module.forward(inputs).toTensor();
		culane_lane(output,img);
		cout << "cost time:" << clock() - start << endl;
		//cv::imshow("result", img);

		img.convertTo(img, CV_8UC3,255);//need to convert to CV_8UC3 for save the video
		cv::imshow("result", img);
		//vw << img;
	
		//cv::imshow("result", img);
		cv::waitKey(1);
	}
	return NULL;
}

模型链接: https://pan.baidu.com/s/1MZhkt87aWFb771gwUBxH6A?pwd=LDHL 提取码: LDHL
转载前,请注明来源。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值