feat: initial HSAP platform

Huaxu Sentinel Active Safety Platform with embedded algorithm code,
Docker Compose setup, and vendored dataset scaffolds for clone-and-run.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-25 16:59:59 +08:00
commit 7c43b44c57
1619 changed files with 373355 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
import os
from importmagician import import_from
with import_from('./'):
from configs.semantic_segmentation.common.datasets._utils import CITYSCAPES_ROOT as base
def traverse(images_dir, data_list):
for city in sorted(os.listdir(images_dir)):
city_path = os.path.join(images_dir, city)
for image in sorted(os.listdir(city_path)):
temp = city + '/' + image.split('_leftImg8bit')[0] + '\n'
data_list.append(temp)
# Traverse images
train_list = []
val_list = []
test_list = []
traverse(os.path.join(base, "leftImg8bit/train"), train_list)
traverse(os.path.join(base, "leftImg8bit/val"), val_list)
traverse(os.path.join(base, "leftImg8bit/test"), test_list)
print('Whole training set size: ' + str(len(train_list)))
print('Whole validation set size: ' + str(len(val_list)))
print('Whole test set size: ' + str(len(test_list)))
# Save training list
lists_dir = os.path.join(base, "data_lists")
if not os.path.exists(lists_dir):
os.makedirs(lists_dir)
with open(os.path.join(lists_dir, "train.txt"), "w") as f:
f.writelines(train_list)
with open(os.path.join(lists_dir, "val.txt"), "w") as f:
f.writelines(val_list)
with open(os.path.join(lists_dir, "test.txt"), "w") as f:
f.writelines(test_list)
print("Complete.")

View File

@@ -0,0 +1,49 @@
PROJECT_NAME:= evaluate
# config ----------------------------------
INCLUDE_DIRS := include
LIBRARY_DIRS := lib
COMMON_FLAGS := -DCPU_ONLY
CXXFLAGS := -std=c++11 -fopenmp
LDFLAGS := -fopenmp -Wl,-rpath,./lib
BUILD_DIR := build
# make rules -------------------------------
CXX ?= g++
BUILD_DIR ?= ./build
LIBRARIES += opencv_core opencv_highgui opencv_imgproc
# Comment Line 21 if using opencv2
LIBRARIES += opencv_imgcodecs
CXXFLAGS += $(COMMON_FLAGS) $(foreach includedir,$(INCLUDE_DIRS),-I$(includedir))
LDFLAGS += $(COMMON_FLAGS) $(foreach includedir,$(LIBRARY_DIRS),-L$(includedir)) $(foreach library,$(LIBRARIES),-l$(library))
SRC_DIRS += $(shell find * -type d -exec bash -c "find {} -maxdepth 1 \( -name '*.cpp' -o -name '*.proto' \) | grep -q ." \; -print)
CXX_SRCS += $(shell find src/ -name "*.cpp")
CXX_TARGETS:=$(patsubst %.cpp, $(BUILD_DIR)/%.o, $(CXX_SRCS))
ALL_BUILD_DIRS := $(sort $(BUILD_DIR) $(addprefix $(BUILD_DIR)/, $(SRC_DIRS)))
.PHONY: all
all: $(PROJECT_NAME)
.PHONY: $(ALL_BUILD_DIRS)
$(ALL_BUILD_DIRS):
@mkdir -p $@
$(BUILD_DIR)/%.o: %.cpp | $(ALL_BUILD_DIRS)
@echo "CXX" $<
@$(CXX) $(CXXFLAGS) -c -o $@ $<
$(PROJECT_NAME): $(CXX_TARGETS)
@echo "CXX/LD" $@
@$(CXX) -o $@ $^ $(LDFLAGS)
.PHONY: clean
clean:
@rm -rf $(CXX_TARGETS)
@rm -rf $(PROJECT_NAME)
@rm -rf $(BUILD_DIR)

View File

@@ -0,0 +1,46 @@
# Accumulate and calculate whole F1 score on CULane
import argparse
import fcntl
if __name__ == '__main__':
# Settings
parser = argparse.ArgumentParser(description='PyTorch 1.6.0')
parser.add_argument('--exp-name', type=str, default='',
help='Name of experiment')
parser.add_argument('--save-dir', type=str, help='Path prefix to save full res.')
args = parser.parse_args()
filename = 'output/' + args.exp_name + '_iou0.5_split.txt'
with open(filename, 'r') as f:
temp = f.readlines()
# Count
tp = 0
fp = 0
fn = 0
for i in range(9):
line = temp[i * 6 + 1].replace('\n', '').split(' ')
tp += int(line[1])
fp += int(line[3])
fn += int(line[5])
# Calculate
precision = tp / (tp + fp)
recall = tp / (tp + fn)
f1 = 2 * precision * recall / (precision + recall) * 100
# Log
res_str = '\nF1 score: {}\nPrecision: {}\nRecall: {}\n'.format(f1, precision * 100, recall * 100)
print(res_str)
with open('../../log.txt', 'a') as f:
fcntl.flock(f, fcntl.LOCK_EX)
f.write(args.exp_name + ': ' + str(f1) + '\n')
fcntl.flock(f, fcntl.LOCK_UN)
if args.save_dir is not None:
import os
save_dir = os.path.join('../../', args.save_dir, args.exp_name)
os.makedirs(save_dir, exist_ok=True)
with open(os.path.join(save_dir, 'test_result.txt'), 'a') as f:
f.write('Total:' + res_str)

View File

@@ -0,0 +1,46 @@
#!/bin/bash
root=../../
data_dir=../../../../dataset/culane/
exp=$1
detect_dir=../../output/
# These can not be changed
w_lane=30;
iou=0.5; # Set iou to 0.3 or 0.5
im_w=1640
im_h=590
frame=1
list0=${data_dir}list/test_split/test0_normal.txt
list1=${data_dir}list/test_split/test1_crowd.txt
list2=${data_dir}list/test_split/test2_hlight.txt
list3=${data_dir}list/test_split/test3_shadow.txt
list4=${data_dir}list/test_split/test4_noline.txt
list5=${data_dir}list/test_split/test5_arrow.txt
list6=${data_dir}list/test_split/test6_curve.txt
list7=${data_dir}list/test_split/test7_cross.txt
list8=${data_dir}list/test_split/test8_night.txt
out0=./output/out0_normal.txt
out1=./output/out1_crowd.txt
out2=./output/out2_hlight.txt
out3=./output/out3_shadow.txt
out4=./output/out4_noline.txt
out5=./output/out5_arrow.txt
out6=./output/out6_curve.txt
out7=./output/out7_cross.txt
out8=./output/out8_night.txt
./evaluate -a $data_dir -d $detect_dir -i $data_dir -l $list0 -w $w_lane -t $iou -c $im_w -r $im_h -f $frame -o $out0
./evaluate -a $data_dir -d $detect_dir -i $data_dir -l $list1 -w $w_lane -t $iou -c $im_w -r $im_h -f $frame -o $out1
./evaluate -a $data_dir -d $detect_dir -i $data_dir -l $list2 -w $w_lane -t $iou -c $im_w -r $im_h -f $frame -o $out2
./evaluate -a $data_dir -d $detect_dir -i $data_dir -l $list3 -w $w_lane -t $iou -c $im_w -r $im_h -f $frame -o $out3
./evaluate -a $data_dir -d $detect_dir -i $data_dir -l $list4 -w $w_lane -t $iou -c $im_w -r $im_h -f $frame -o $out4
./evaluate -a $data_dir -d $detect_dir -i $data_dir -l $list5 -w $w_lane -t $iou -c $im_w -r $im_h -f $frame -o $out5
./evaluate -a $data_dir -d $detect_dir -i $data_dir -l $list6 -w $w_lane -t $iou -c $im_w -r $im_h -f $frame -o $out6
./evaluate -a $data_dir -d $detect_dir -i $data_dir -l $list7 -w $w_lane -t $iou -c $im_w -r $im_h -f $frame -o $out7
./evaluate -a $data_dir -d $detect_dir -i $data_dir -l $list8 -w $w_lane -t $iou -c $im_w -r $im_h -f $frame -o $out8
cat ./output/out*.txt>./output/${exp}_iou${iou}_split.txt
if ! [ -z "$2" ]
then
mkdir -p ../../${2}/${1}
cp ./output/${exp}_iou${iou}_split.txt ../../${2}/${1}/test_result.txt
fi

View File

@@ -0,0 +1,21 @@
#!/bin/bash
root=../../
data_dir=../../../../dataset/culane/
exp=$1
detect_dir=../../output/
# These can not be changed
w_lane=30;
iou=0.5; # Set iou to 0.3 or 0.5
im_w=1640
im_h=590
frame=1
list=${data_dir}list/val.txt
out=./output/${exp}_iou${iou}_validation.txt
./evaluate -a $data_dir -d $detect_dir -i $data_dir -l $list -w $w_lane -t $iou -c $im_w -r $im_h -f $frame -o $out
if ! [ -z "$2" ]
then
mkdir -p ../../${2}/${1}
cp ${out} ../../${2}/${1}/val_result.txt
fi

View File

@@ -0,0 +1,47 @@
#ifndef COUNTER_HPP
#define COUNTER_HPP
#include "lane_compare.hpp"
#include "hungarianGraph.hpp"
#include <iostream>
#include <algorithm>
#include <tuple>
#include <vector>
#include <opencv2/core/core.hpp>
using namespace std;
using namespace cv;
// before coming to use functions of this class, the lanes should resize to im_width and im_height using resize_lane() in lane_compare.hpp
class Counter
{
public:
Counter(int _im_width, int _im_height, double _iou_threshold=0.4, int _lane_width=10):tp(0),fp(0),fn(0){
im_width = _im_width;
im_height = _im_height;
sim_threshold = _iou_threshold;
lane_compare = new LaneCompare(_im_width, _im_height, _lane_width, LaneCompare::IOU);
};
double get_precision(void);
double get_recall(void);
long getTP(void);
long getFP(void);
long getFN(void);
void setTP(long);
void setFP(long);
void setFN(long);
// direct add tp, fp, tn and fn
// first match with hungarian
tuple<vector<int>, long, long, long, long> count_im_pair(const vector<vector<Point2f> > &anno_lanes, const vector<vector<Point2f> > &detect_lanes);
void makeMatch(const vector<vector<double> > &similarity, vector<int> &match1, vector<int> &match2);
private:
double sim_threshold;
int im_width;
int im_height;
long tp;
long fp;
long fn;
LaneCompare *lane_compare;
};
#endif

View File

@@ -0,0 +1,71 @@
#ifndef HUNGARIAN_GRAPH_HPP
#define HUNGARIAN_GRAPH_HPP
#include <vector>
using namespace std;
struct pipartiteGraph {
vector<vector<double> > mat;
vector<bool> leftUsed, rightUsed;
vector<double> leftWeight, rightWeight;
vector<int>rightMatch, leftMatch;
int leftNum, rightNum;
bool matchDfs(int u) {
leftUsed[u] = true;
for (int v = 0; v < rightNum; v++) {
if (!rightUsed[v] && fabs(leftWeight[u] + rightWeight[v] - mat[u][v]) < 1e-2) {
rightUsed[v] = true;
if (rightMatch[v] == -1 || matchDfs(rightMatch[v])) {
rightMatch[v] = u;
leftMatch[u] = v;
return true;
}
}
}
return false;
}
void resize(int leftNum, int rightNum) {
this->leftNum = leftNum;
this->rightNum = rightNum;
leftMatch.resize(leftNum);
rightMatch.resize(rightNum);
leftUsed.resize(leftNum);
rightUsed.resize(rightNum);
leftWeight.resize(leftNum);
rightWeight.resize(rightNum);
mat.resize(leftNum);
for (int i = 0; i < leftNum; i++) mat[i].resize(rightNum);
}
void match() {
for (int i = 0; i < leftNum; i++) leftMatch[i] = -1;
for (int i = 0; i < rightNum; i++) rightMatch[i] = -1;
for (int i = 0; i < rightNum; i++) rightWeight[i] = 0;
for (int i = 0; i < leftNum; i++) {
leftWeight[i] = -1e5;
for (int j = 0; j < rightNum; j++) {
if (leftWeight[i] < mat[i][j]) leftWeight[i] = mat[i][j];
}
}
for (int u = 0; u < leftNum; u++) {
while (1) {
for (int i = 0; i < leftNum; i++) leftUsed[i] = false;
for (int i = 0; i < rightNum; i++) rightUsed[i] = false;
if (matchDfs(u)) break;
double d = 1e10;
for (int i = 0; i < leftNum; i++) {
if (leftUsed[i] ) {
for (int j = 0; j < rightNum; j++) {
if (!rightUsed[j]) d = min(d, leftWeight[i] + rightWeight[j] - mat[i][j]);
}
}
}
if (d == 1e10) return ;
for (int i = 0; i < leftNum; i++) if (leftUsed[i]) leftWeight[i] -= d;
for (int i = 0; i < rightNum; i++) if (rightUsed[i]) rightWeight[i] += d;
}
}
}
};
#endif // HUNGARIAN_GRAPH_HPP

View File

@@ -0,0 +1,37 @@
#ifndef LANE_COMPARE_HPP
#define LANE_COMPARE_HPP
#include "spline.hpp"
#include <vector>
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
class LaneCompare{
public:
enum CompareMode{
IOU,
Caltech
};
LaneCompare(int _im_width, int _im_height, int _lane_width = 10, CompareMode _compare_mode = IOU){
im_width = _im_width;
im_height = _im_height;
compare_mode = _compare_mode;
lane_width = _lane_width;
}
double get_lane_similarity(const vector<Point2f> &lane1, const vector<Point2f> &lane2);
void resize_lane(vector<Point2f> &curr_lane, int curr_width, int curr_height);
private:
CompareMode compare_mode;
int im_width;
int im_height;
int lane_width;
Spline splineSolver;
};
#endif

View File

@@ -0,0 +1,28 @@
#ifndef SPLINE_HPP
#define SPLINE_HPP
#include <vector>
#include <cstdio>
#include <math.h>
#include <opencv2/core/core.hpp>
using namespace cv;
using namespace std;
struct Func {
double a_x;
double b_x;
double c_x;
double d_x;
double a_y;
double b_y;
double c_y;
double d_y;
double h;
};
class Spline {
public:
vector<Point2f> splineInterpTimes(const vector<Point2f> &tmp_line, int times);
vector<Point2f> splineInterpStep(vector<Point2f> tmp_line, double step);
vector<Func> cal_fun(const vector<Point2f> &point_v);
};
#endif

View File

@@ -0,0 +1,134 @@
/*************************************************************************
> File Name: counter.cpp
> Author: Xingang Pan, Jun Li
> Mail: px117@ie.cuhk.edu.hk
> Created Time: Thu Jul 14 20:23:08 2016
************************************************************************/
#include "counter.hpp"
double Counter::get_precision(void)
{
cerr<<"tp: "<<tp<<" fp: "<<fp<<" fn: "<<fn<<endl;
if(tp+fp == 0)
{
cerr<<"no positive detection"<<endl;
return -1;
}
return tp/double(tp + fp);
}
double Counter::get_recall(void)
{
if(tp+fn == 0)
{
cerr<<"no ground truth positive"<<endl;
return -1;
}
return tp/double(tp + fn);
}
long Counter::getTP(void)
{
return tp;
}
long Counter::getFP(void)
{
return fp;
}
long Counter::getFN(void)
{
return fn;
}
void Counter::setTP(long value)
{
tp = value;
}
void Counter::setFP(long value)
{
fp = value;
}
void Counter::setFN(long value)
{
fn = value;
}
tuple<vector<int>, long, long, long, long> Counter::count_im_pair(const vector<vector<Point2f> > &anno_lanes, const vector<vector<Point2f> > &detect_lanes)
{
vector<int> anno_match(anno_lanes.size(), -1);
vector<int> detect_match;
if(anno_lanes.empty())
{
return make_tuple(anno_match, 0, detect_lanes.size(), 0, 0);
}
if(detect_lanes.empty())
{
return make_tuple(anno_match, 0, 0, 0, anno_lanes.size());
}
// hungarian match first
// first calc similarity matrix
vector<vector<double> > similarity(anno_lanes.size(), vector<double>(detect_lanes.size(), 0));
for(int i=0; i<anno_lanes.size(); i++)
{
const vector<Point2f> &curr_anno_lane = anno_lanes[i];
for(int j=0; j<detect_lanes.size(); j++)
{
const vector<Point2f> &curr_detect_lane = detect_lanes[j];
similarity[i][j] = lane_compare->get_lane_similarity(curr_anno_lane, curr_detect_lane);
}
}
makeMatch(similarity, anno_match, detect_match);
int curr_tp = 0;
// count and add
for(int i=0; i<anno_lanes.size(); i++)
{
if(anno_match[i]>=0 && similarity[i][anno_match[i]] > sim_threshold)
{
curr_tp++;
}
else
{
anno_match[i] = -1;
}
}
int curr_fn = anno_lanes.size() - curr_tp;
int curr_fp = detect_lanes.size() - curr_tp;
return make_tuple(anno_match, curr_tp, curr_fp, 0, curr_fn);
}
void Counter::makeMatch(const vector<vector<double> > &similarity, vector<int> &match1, vector<int> &match2) {
int m = similarity.size();
int n = similarity[0].size();
pipartiteGraph gra;
bool have_exchange = false;
if (m > n) {
have_exchange = true;
swap(m, n);
}
gra.resize(m, n);
for (int i = 0; i < gra.leftNum; i++) {
for (int j = 0; j < gra.rightNum; j++) {
if(have_exchange)
gra.mat[i][j] = similarity[j][i];
else
gra.mat[i][j] = similarity[i][j];
}
}
gra.match();
match1 = gra.leftMatch;
match2 = gra.rightMatch;
if (have_exchange) swap(match1, match2);
}

View File

@@ -0,0 +1,298 @@
/*************************************************************************
> File Name: evaluate.cpp
> Author: Xingang Pan, Jun Li
> Mail: px117@ie.cuhk.edu.hk
> Created Time: 2016年07月14日 星期四 18时28分45秒
************************************************************************/
#include "counter.hpp"
#include "spline.hpp"
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <string>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
void help(void)
{
cout<<"./evaluate [OPTIONS]"<<endl;
cout<<"-h : print usage help"<<endl;
cout<<"-a : directory for annotation files (default: /data/driving/eval_data/anno_label/)"<<endl;
cout<<"-d : directory for detection files (default: /data/driving/eval_data/predict_label/)"<<endl;
cout<<"-i : directory for image files (default: /data/driving/eval_data/img/)"<<endl;
cout<<"-l : list of images used for evaluation (default: /data/driving/eval_data/img/all.txt)"<<endl;
cout<<"-w : width of the lanes (default: 10)"<<endl;
cout<<"-t : threshold of iou (default: 0.4)"<<endl;
cout<<"-c : cols (max image width) (default: 1920)"<<endl;
cout<<"-r : rows (max image height) (default: 1080)"<<endl;
cout<<"-s : show visualization"<<endl;
cout<<"-f : start frame in the test set (default: 1)"<<endl;
}
void read_lane_file(const string &file_name, vector<vector<Point2f> > &lanes);
void visualize(string &full_im_name, vector<vector<Point2f> > &anno_lanes, vector<vector<Point2f> > &detect_lanes, vector<int> anno_match, int width_lane);
int main(int argc, char **argv)
{
// process params
string anno_dir = "/data/driving/eval_data/anno_label/";
string detect_dir = "/data/driving/eval_data/predict_label/";
string im_dir = "/data/driving/eval_data/img/";
string list_im_file = "/data/driving/eval_data/img/all.txt";
string output_file = "./output.txt";
int width_lane = 10;
double iou_threshold = 0.4;
int im_width = 1920;
int im_height = 1080;
int oc;
bool show = false;
int frame = 1;
while((oc = getopt(argc, argv, "ha:d:i:l:w:t:c:r:sf:o:")) != -1)
{
switch(oc)
{
case 'h':
help();
return 0;
case 'a':
anno_dir = optarg;
break;
case 'd':
detect_dir = optarg;
break;
case 'i':
im_dir = optarg;
break;
case 'l':
list_im_file = optarg;
break;
case 'w':
width_lane = atoi(optarg);
break;
case 't':
iou_threshold = atof(optarg);
break;
case 'c':
im_width = atoi(optarg);
break;
case 'r':
im_height = atoi(optarg);
break;
case 's':
show = true;
break;
case 'f':
frame = atoi(optarg);
break;
case 'o':
output_file = optarg;
break;
}
}
cout<<"------------Configuration---------"<<endl;
cout<<"anno_dir: "<<anno_dir<<endl;
cout<<"detect_dir: "<<detect_dir<<endl;
cout<<"im_dir: "<<im_dir<<endl;
cout<<"list_im_file: "<<list_im_file<<endl;
cout<<"width_lane: "<<width_lane<<endl;
cout<<"iou_threshold: "<<iou_threshold<<endl;
cout<<"im_width: "<<im_width<<endl;
cout<<"im_height: "<<im_height<<endl;
cout<<"-----------------------------------"<<endl;
cout<<"Evaluating the results..."<<endl;
// this is the max_width and max_height
if(width_lane<1)
{
cerr<<"width_lane must be positive"<<endl;
help();
return 1;
}
ifstream ifs_im_list(list_im_file, ios::in);
if(ifs_im_list.fail())
{
cerr<<"Error: file "<<list_im_file<<" not exist!"<<endl;
return 1;
}
Counter counter(im_width, im_height, iou_threshold, width_lane);
vector<int> anno_match;
string sub_im_name;
// pre-load filelist
vector<string> filelists;
while (getline(ifs_im_list, sub_im_name)) {
filelists.push_back(sub_im_name);
}
ifs_im_list.close();
vector<tuple<vector<int>, long, long, long, long>> tuple_lists;
tuple_lists.resize(filelists.size());
#pragma omp parallel for
for (size_t i = 0; i < filelists.size(); i++)
{
auto sub_im_name = filelists[i];
string full_im_name = im_dir + sub_im_name;
string sub_txt_name = sub_im_name.substr(0, sub_im_name.find_last_of(".")) + ".lines.txt";
string anno_file_name = anno_dir + sub_txt_name;
string detect_file_name = detect_dir + sub_txt_name;
vector<vector<Point2f> > anno_lanes;
vector<vector<Point2f> > detect_lanes;
read_lane_file(anno_file_name, anno_lanes);
read_lane_file(detect_file_name, detect_lanes);
//cerr<<count<<": "<<full_im_name<<endl;
tuple_lists[i] = counter.count_im_pair(anno_lanes, detect_lanes);
if (show)
{
auto anno_match = get<0>(tuple_lists[i]);
visualize(full_im_name, anno_lanes, detect_lanes, anno_match, width_lane);
waitKey(0);
}
}
long tp = 0, fp = 0, tn = 0, fn = 0;
for (auto result: tuple_lists) {
tp += get<1>(result);
fp += get<2>(result);
// tn = get<3>(result);
fn += get<4>(result);
}
counter.setTP(tp);
counter.setFP(fp);
counter.setFN(fn);
double precision = counter.get_precision();
double recall = counter.get_recall();
double F = 2 * precision * recall / (precision + recall);
cerr<<"finished process file"<<endl;
cout<<"precision: "<<precision<<endl;
cout<<"recall: "<<recall<<endl;
cout<<"Fmeasure: "<<F<<endl;
cout<<"----------------------------------"<<endl;
ofstream ofs_out_file;
ofs_out_file.open(output_file, ios::out);
ofs_out_file<<"file: "<<output_file<<endl;
ofs_out_file<<"tp: "<<counter.getTP()<<" fp: "<<counter.getFP()<<" fn: "<<counter.getFN()<<endl;
ofs_out_file<<"precision: "<<precision<<endl;
ofs_out_file<<"recall: "<<recall<<endl;
ofs_out_file<<"Fmeasure: "<<F<<endl<<endl;
ofs_out_file.close();
return 0;
}
void read_lane_file(const string &file_name, vector<vector<Point2f> > &lanes)
{
lanes.clear();
ifstream ifs_lane(file_name, ios::in);
if(ifs_lane.fail())
{
return;
}
string str_line;
while(getline(ifs_lane, str_line))
{
vector<Point2f> curr_lane;
stringstream ss;
ss<<str_line;
double x,y;
while(ss>>x>>y)
{
curr_lane.push_back(Point2f(x, y));
}
lanes.push_back(curr_lane);
}
ifs_lane.close();
}
void visualize(string &full_im_name, vector<vector<Point2f> > &anno_lanes, vector<vector<Point2f> > &detect_lanes, vector<int> anno_match, int width_lane)
{
Mat img = imread(full_im_name, 1);
Mat img2 = imread(full_im_name, 1);
vector<Point2f> curr_lane;
vector<Point2f> p_interp;
Spline splineSolver;
Scalar color_B = Scalar(255, 0, 0);
Scalar color_G = Scalar(0, 255, 0);
Scalar color_R = Scalar(0, 0, 255);
Scalar color_P = Scalar(255, 0, 255);
Scalar color;
for (int i=0; i<anno_lanes.size(); i++)
{
curr_lane = anno_lanes[i];
if(curr_lane.size() == 2)
{
p_interp = curr_lane;
}
else
{
p_interp = splineSolver.splineInterpTimes(curr_lane, 50);
}
if (anno_match[i] >= 0)
{
color = color_G;
}
else
{
color = color_G;
}
for (int n=0; n<p_interp.size()-1; n++)
{
line(img, p_interp[n], p_interp[n+1], color, width_lane);
line(img2, p_interp[n], p_interp[n+1], color, 2);
}
}
bool detected;
for (int i=0; i<detect_lanes.size(); i++)
{
detected = false;
curr_lane = detect_lanes[i];
if(curr_lane.size() == 2)
{
p_interp = curr_lane;
}
else
{
p_interp = splineSolver.splineInterpTimes(curr_lane, 50);
}
for (int n=0; n<anno_lanes.size(); n++)
{
if (anno_match[n] == i)
{
detected = true;
break;
}
}
if (detected == true)
{
color = color_B;
}
else
{
color = color_R;
}
for (int n=0; n<p_interp.size()-1; n++)
{
line(img, p_interp[n], p_interp[n+1], color, width_lane);
line(img2, p_interp[n], p_interp[n+1], color, 2);
}
}
namedWindow("visualize", 1);
imshow("visualize", img);
namedWindow("visualize2", 1);
imshow("visualize2", img2);
}

View File

@@ -0,0 +1,73 @@
/*************************************************************************
> File Name: lane_compare.cpp
> Author: Xingang Pan, Jun Li
> Mail: px117@ie.cuhk.edu.hk
> Created Time: Fri Jul 15 10:26:32 2016
************************************************************************/
#include "lane_compare.hpp"
double LaneCompare::get_lane_similarity(const vector<Point2f> &lane1, const vector<Point2f> &lane2)
{
if(lane1.size()<2 || lane2.size()<2)
{
cerr<<"lane size must be greater or equal to 2"<<endl;
return 0;
}
Mat im1 = Mat::zeros(im_height, im_width, CV_8UC1);
Mat im2 = Mat::zeros(im_height, im_width, CV_8UC1);
// draw lines on im1 and im2
vector<Point2f> p_interp1;
vector<Point2f> p_interp2;
if(lane1.size() == 2)
{
p_interp1 = lane1;
}
else
{
p_interp1 = splineSolver.splineInterpTimes(lane1, 50);
}
if(lane2.size() == 2)
{
p_interp2 = lane2;
}
else
{
p_interp2 = splineSolver.splineInterpTimes(lane2, 50);
}
Scalar color_white = Scalar(1);
for(int n=0; n<p_interp1.size()-1; n++)
{
line(im1, p_interp1[n], p_interp1[n+1], color_white, lane_width);
}
for(int n=0; n<p_interp2.size()-1; n++)
{
line(im2, p_interp2[n], p_interp2[n+1], color_white, lane_width);
}
double sum_1 = cv::sum(im1).val[0];
double sum_2 = cv::sum(im2).val[0];
double inter_sum = cv::sum(im1.mul(im2)).val[0];
double union_sum = sum_1 + sum_2 - inter_sum;
double iou = inter_sum / union_sum;
return iou;
}
// resize the lane from Size(curr_width, curr_height) to Size(im_width, im_height)
void LaneCompare::resize_lane(vector<Point2f> &curr_lane, int curr_width, int curr_height)
{
if(curr_width == im_width && curr_height == im_height)
{
return;
}
double x_scale = im_width/(double)curr_width;
double y_scale = im_height/(double)curr_height;
for(int n=0; n<curr_lane.size(); n++)
{
curr_lane[n] = Point2f(curr_lane[n].x*x_scale, curr_lane[n].y*y_scale);
}
}

View File

@@ -0,0 +1,178 @@
#include <vector>
#include <iostream>
#include "spline.hpp"
using namespace std;
using namespace cv;
vector<Point2f> Spline::splineInterpTimes(const vector<Point2f>& tmp_line, int times) {
vector<Point2f> res;
if(tmp_line.size() == 2) {
double x1 = tmp_line[0].x;
double y1 = tmp_line[0].y;
double x2 = tmp_line[1].x;
double y2 = tmp_line[1].y;
for (int k = 0; k <= times; k++) {
double xi = x1 + double((x2 - x1) * k) / times;
double yi = y1 + double((y2 - y1) * k) / times;
res.push_back(Point2f(xi, yi));
}
}
else if(tmp_line.size() > 2)
{
vector<Func> tmp_func;
tmp_func = this->cal_fun(tmp_line);
if (tmp_func.empty()) {
cout << "in splineInterpTimes: cal_fun failed" << endl;
return res;
}
for(int j = 0; j < tmp_func.size(); j++)
{
double delta = tmp_func[j].h / times;
for(int k = 0; k < times; k++)
{
double t1 = delta*k;
double x1 = tmp_func[j].a_x + tmp_func[j].b_x*t1 + tmp_func[j].c_x*pow(t1,2) + tmp_func[j].d_x*pow(t1,3);
double y1 = tmp_func[j].a_y + tmp_func[j].b_y*t1 + tmp_func[j].c_y*pow(t1,2) + tmp_func[j].d_y*pow(t1,3);
res.push_back(Point2f(x1, y1));
}
}
res.push_back(tmp_line[tmp_line.size() - 1]);
}
else {
cerr << "in splineInterpTimes: not enough points" << endl;
}
return res;
}
vector<Point2f> Spline::splineInterpStep(vector<Point2f> tmp_line, double step) {
vector<Point2f> res;
/*
if (tmp_line.size() == 2) {
double x1 = tmp_line[0].x;
double y1 = tmp_line[0].y;
double x2 = tmp_line[1].x;
double y2 = tmp_line[1].y;
for (double yi = std::min(y1, y2); yi < std::max(y1, y2); yi += step) {
double xi;
if (yi == y1) xi = x1;
else xi = (x2 - x1) / (y2 - y1) * (yi - y1) + x1;
res.push_back(Point2f(xi, yi));
}
}*/
if (tmp_line.size() == 2) {
double x1 = tmp_line[0].x;
double y1 = tmp_line[0].y;
double x2 = tmp_line[1].x;
double y2 = tmp_line[1].y;
tmp_line[1].x = (x1 + x2) / 2;
tmp_line[1].y = (y1 + y2) / 2;
tmp_line.push_back(Point2f(x2, y2));
}
if (tmp_line.size() > 2) {
vector<Func> tmp_func;
tmp_func = this->cal_fun(tmp_line);
double ystart = tmp_line[0].y;
double yend = tmp_line[tmp_line.size() - 1].y;
bool down;
if (ystart < yend) down = 1;
else down = 0;
if (tmp_func.empty()) {
cerr << "in splineInterpStep: cal_fun failed" << endl;
}
for(int j = 0; j < tmp_func.size(); j++)
{
for(double t1 = 0; t1 < tmp_func[j].h; t1 += step)
{
double x1 = tmp_func[j].a_x + tmp_func[j].b_x*t1 + tmp_func[j].c_x*pow(t1,2) + tmp_func[j].d_x*pow(t1,3);
double y1 = tmp_func[j].a_y + tmp_func[j].b_y*t1 + tmp_func[j].c_y*pow(t1,2) + tmp_func[j].d_y*pow(t1,3);
res.push_back(Point2f(x1, y1));
}
}
res.push_back(tmp_line[tmp_line.size() - 1]);
}
else {
cerr << "in splineInterpStep: not enough points" << endl;
}
return res;
}
vector<Func> Spline::cal_fun(const vector<Point2f> &point_v)
{
vector<Func> func_v;
int n = point_v.size();
if(n<=2) {
cout << "in cal_fun: point number less than 3" << endl;
return func_v;
}
func_v.resize(point_v.size()-1);
vector<double> Mx(n);
vector<double> My(n);
vector<double> A(n-2);
vector<double> B(n-2);
vector<double> C(n-2);
vector<double> Dx(n-2);
vector<double> Dy(n-2);
vector<double> h(n-1);
//vector<func> func_v(n-1);
for(int i = 0; i < n-1; i++)
{
h[i] = sqrt(pow(point_v[i+1].x - point_v[i].x, 2) + pow(point_v[i+1].y - point_v[i].y, 2));
}
for(int i = 0; i < n-2; i++)
{
A[i] = h[i];
B[i] = 2*(h[i]+h[i+1]);
C[i] = h[i+1];
Dx[i] = 6*( (point_v[i+2].x - point_v[i+1].x)/h[i+1] - (point_v[i+1].x - point_v[i].x)/h[i] );
Dy[i] = 6*( (point_v[i+2].y - point_v[i+1].y)/h[i+1] - (point_v[i+1].y - point_v[i].y)/h[i] );
}
//TDMA
C[0] = C[0] / B[0];
Dx[0] = Dx[0] / B[0];
Dy[0] = Dy[0] / B[0];
for(int i = 1; i < n-2; i++)
{
double tmp = B[i] - A[i]*C[i-1];
C[i] = C[i] / tmp;
Dx[i] = (Dx[i] - A[i]*Dx[i-1]) / tmp;
Dy[i] = (Dy[i] - A[i]*Dy[i-1]) / tmp;
}
Mx[n-2] = Dx[n-3];
My[n-2] = Dy[n-3];
for(int i = n-4; i >= 0; i--)
{
Mx[i+1] = Dx[i] - C[i]*Mx[i+2];
My[i+1] = Dy[i] - C[i]*My[i+2];
}
Mx[0] = 0;
Mx[n-1] = 0;
My[0] = 0;
My[n-1] = 0;
for(int i = 0; i < n-1; i++)
{
func_v[i].a_x = point_v[i].x;
func_v[i].b_x = (point_v[i+1].x - point_v[i].x)/h[i] - (2*h[i]*Mx[i] + h[i]*Mx[i+1]) / 6;
func_v[i].c_x = Mx[i]/2;
func_v[i].d_x = (Mx[i+1] - Mx[i]) / (6*h[i]);
func_v[i].a_y = point_v[i].y;
func_v[i].b_y = (point_v[i+1].y - point_v[i].y)/h[i] - (2*h[i]*My[i] + h[i]*My[i+1]) / 6;
func_v[i].c_y = My[i]/2;
func_v[i].d_y = (My[i+1] - My[i]) / (6*h[i]);
func_v[i].h = h[i];
}
return func_v;
}

View File

@@ -0,0 +1,46 @@
# Accumulate and calculate whole F1 score on CULane
import argparse
import fcntl
if __name__ == '__main__':
# Settings
parser = argparse.ArgumentParser(description='PyTorch 1.6.0')
parser.add_argument('--exp-name', type=str, default='',
help='Name of experiment')
parser.add_argument('--save-dir', type=str, help='Path prefix to save full res.')
args = parser.parse_args()
filename = 'output/' + args.exp_name + '_iou0.5_split.txt'
with open(filename, 'r') as f:
temp = f.readlines()
# Count
tp = 0
fp = 0
fn = 0
for i in range(9):
line = temp[i * 6 + 1].replace('\n', '').split(' ')
tp += int(line[1])
fp += int(line[3])
fn += int(line[5])
# Calculate
precision = tp / (tp + fp)
recall = tp / (tp + fn)
f1 = 2 * precision * recall / (precision + recall) * 100
# Log
res_str = '\nF1 score: {}\nPrecision: {}\nRecall: {}\n'.format(f1, precision * 100, recall * 100)
print(res_str)
with open('../../log.txt', 'a') as f:
fcntl.flock(f, fcntl.LOCK_EX)
f.write(args.exp_name + ': ' + str(f1) + '\n')
fcntl.flock(f, fcntl.LOCK_UN)
if args.save_dir is not None:
import os
save_dir = os.path.join('../../', args.save_dir, args.exp_name)
os.makedirs(save_dir, exist_ok=True)
with open(os.path.join(save_dir, 'test_result.txt'), 'a') as f:
f.write('Total:' + res_str)

View File

@@ -0,0 +1,96 @@
# Copied from Turoad/lanedet
# Slightly differs from official metric, recommend using this only for visualization
import cv2
import numpy as np
from scipy.interpolate import splprep, splev
from scipy.optimize import linear_sum_assignment
from shapely.geometry import LineString, Polygon
try:
from utils.common import warnings
except ImportError:
import warnings
def draw_lane(lane, img=None, img_shape=None, width=30):
if img is None:
img = np.zeros(img_shape, dtype=np.uint8)
lane = lane.astype(np.int32)
for p1, p2 in zip(lane[:-1], lane[1:]):
cv2.line(img, tuple(p1), tuple(p2), color=1, thickness=width)
return img
def discrete_cross_iou(xs, ys, width=30, img_shape=(590, 1640, 3)):
xs = [draw_lane(lane, img_shape=img_shape[:2], width=width) for lane in xs]
ys = [draw_lane(lane, img_shape=img_shape[:2], width=width) for lane in ys]
ious = np.zeros((len(xs), len(ys)))
for i, x in enumerate(xs):
for j, y in enumerate(ys):
inter = (x * y).sum()
ious[i, j] = inter / (x.sum() + y.sum() - inter)
return ious
def continuous_cross_iou(xs, ys, width=30, img_shape=(590, 1640, 3)):
h, w, _ = img_shape
image = Polygon([(0, 0), (0, h - 1), (w - 1, h - 1), (w - 1, 0)])
xs = [LineString(lane).buffer(distance=width / 2., cap_style=1, join_style=2).intersection(image) for lane in xs]
ys = [LineString(lane).buffer(distance=width / 2., cap_style=1, join_style=2).intersection(image) for lane in ys]
ious = np.zeros((len(xs), len(ys)))
for i, x in enumerate(xs):
for j, y in enumerate(ys):
ious[i, j] = x.intersection(y).area / x.union(y).area
return ious
def remove_consecutive_duplicates(x):
"""Remove consecutive duplicates"""
y = []
for t in x:
if len(y) > 0 and y[-1] == t:
warnings.warn('Removed consecutive duplicate point ({}, {})!'.format(t[0], t[1]))
continue
y.append(t)
return y
def interp(points, n=50):
if len(points) == 2:
return np.array(points)
# Consecutive duplicates (can happen with parametric curves)
# cause internal error for scipy's splprep:
# https://stackoverflow.com/a/47949170/15449902
points = remove_consecutive_duplicates(points)
x = [x for x, _ in points]
y = [y for _, y in points]
tck, u = splprep([x, y], s=0, t=n, k=min(3, len(points) - 1))
u = np.linspace(0., 1., num=(len(u) - 1) * n + 1)
return np.array(splev(u, tck)).T
def culane_metric(pred, anno, width=30, iou_threshold=0.5, official=True, img_shape=(590, 1640, 3)):
if len(pred) == 0:
return 0, 0, len(anno), np.zeros(len(pred)), np.zeros(len(pred), dtype=bool)
if len(anno) == 0:
return 0, len(pred), 0, np.zeros(len(pred)), np.zeros(len(pred), dtype=bool)
interp_pred = [interp(pred_lane) for pred_lane in pred] # (4, 50, 2)
interp_anno = [interp(anno_lane) for anno_lane in anno] # (4, 50, 2)
if official:
ious = discrete_cross_iou(interp_pred, interp_anno, width=width, img_shape=img_shape)
else:
ious = continuous_cross_iou(interp_pred, interp_anno, width=width, img_shape=img_shape)
row_ind, col_ind = linear_sum_assignment(1 - ious)
tp = int((ious[row_ind, col_ind] > iou_threshold).sum())
fp = len(pred) - tp
fn = len(anno) - tp
pred_ious = np.zeros(len(pred))
pred_ious[row_ind] = ious[row_ind, col_ind]
return tp, fp, fn, pred_ious, pred_ious > iou_threshold

View File

@@ -0,0 +1,45 @@
#!/bin/bash
root=../../
data_dir=../../../../dataset/culane/
exp=$1
detect_dir=../../output/
# These can not be changed
w_lane=30;
iou=0.5; # Set iou to 0.3 or 0.5
im_w=1640
im_h=590
list0=${data_dir}list/test_split/test0_normal.txt
list1=${data_dir}list/test_split/test1_crowd.txt
list2=${data_dir}list/test_split/test2_hlight.txt
list3=${data_dir}list/test_split/test3_shadow.txt
list4=${data_dir}list/test_split/test4_noline.txt
list5=${data_dir}list/test_split/test5_arrow.txt
list6=${data_dir}list/test_split/test6_curve.txt
list7=${data_dir}list/test_split/test7_cross.txt
list8=${data_dir}list/test_split/test8_night.txt
out0=./output/out0_normal.txt
out1=./output/out1_crowd.txt
out2=./output/out2_hlight.txt
out3=./output/out3_shadow.txt
out4=./output/out4_noline.txt
out5=./output/out5_arrow.txt
out6=./output/out6_curve.txt
out7=./output/out7_cross.txt
out8=./output/out8_night.txt
python evaluate.py -a $data_dir -d $detect_dir -l $list0 -w $w_lane -t $iou -c $im_w -r $im_h -o $out0
python evaluate.py -a $data_dir -d $detect_dir -l $list1 -w $w_lane -t $iou -c $im_w -r $im_h -o $out1
python evaluate.py -a $data_dir -d $detect_dir -l $list2 -w $w_lane -t $iou -c $im_w -r $im_h -o $out2
python evaluate.py -a $data_dir -d $detect_dir -l $list3 -w $w_lane -t $iou -c $im_w -r $im_h -o $out3
python evaluate.py -a $data_dir -d $detect_dir -l $list4 -w $w_lane -t $iou -c $im_w -r $im_h -o $out4
python evaluate.py -a $data_dir -d $detect_dir -l $list5 -w $w_lane -t $iou -c $im_w -r $im_h -o $out5
python evaluate.py -a $data_dir -d $detect_dir -l $list6 -w $w_lane -t $iou -c $im_w -r $im_h -o $out6
python evaluate.py -a $data_dir -d $detect_dir -l $list7 -w $w_lane -t $iou -c $im_w -r $im_h -o $out7
python evaluate.py -a $data_dir -d $detect_dir -l $list8 -w $w_lane -t $iou -c $im_w -r $im_h -o $out8
cat ./output/out*.txt>./output/${exp}_iou${iou}_split.txt
if ! [ -z "$2" ]
then
mkdir -p ../../${2}/${1}
cp ./output/${exp}_iou${iou}_split.txt ../../${2}/${1}/test_result.txt
fi

View File

@@ -0,0 +1,20 @@
#!/bin/bash
root=../../
data_dir=../../../../dataset/culane/
exp=$1
detect_dir=../../output/
# These can not be changed
w_lane=30;
iou=0.5; # Set iou to 0.3 or 0.5
im_w=1640
im_h=590
list=${data_dir}list/val.txt
out=./output/${exp}_iou${iou}_validation.txt
python evaluate.py -a $data_dir -d $detect_dir -l $list -w $w_lane -t $iou -c $im_w -r $im_h -o $out
if ! [ -z "$2" ]
then
mkdir -p ../../${2}/${1}
cp ${out} ../../${2}/${1}/val_result.txt
fi

View File

@@ -0,0 +1,88 @@
# modified from Turoad/lanedet to align with original Cpp scripts
import os
import argparse
from functools import partial
from p_tqdm import p_map
from culane_metric import culane_metric
def load_culane_data_one(path):
with open(path, 'r') as data_file:
t = data_file.readlines()
t = [line.split() for line in t]
t = [list(map(float, lane)) for lane in t]
t = [[(lane[i], lane[i + 1]) for i in range(0, len(lane), 2)] for lane in t]
t = [lane for lane in t if len(lane) >= 2]
return t
def load_culane_data(data_dir, file_list_path):
with open(file_list_path, 'r') as file_list:
filepaths = [
os.path.join(data_dir, line[1 if line[0] == '/' else 0:].rstrip().replace('.jpg', '.lines.txt'))
for line in file_list.readlines()
]
data = []
for path in filepaths:
img_data = load_culane_data_one(path)
data.append(img_data)
return data
def eval_predictions(args, official=True):
print('List file: {}'.format(args.list_path))
print('Width lane: {}'.format(args.width))
print('IoU threshold: {}'.format(args.threshold))
print('Image height: {}'.format(args.img_height))
print('Image width: {}'.format(args.img_width))
print('Loading prediction data...')
predictions = load_culane_data(args.pred_dir, args.list_path)
print('Loading annotation data...')
annotations = load_culane_data(args.anno_dir, args.list_path)
print('Calculating metric in parallel...')
img_shape = (args.img_height, args.img_width, 3)
results = p_map(partial(culane_metric, width=args.width, iou_threshold=args.threshold, official=official, img_shape=img_shape),
predictions, annotations)
total_tp = sum(tp for tp, _, _, _, _ in results)
total_fp = sum(fp for _, fp, _, _, _ in results)
total_fn = sum(fn for _, _, fn, _, _ in results)
if total_tp == 0:
precision = 0.0
recall = 0.0
f1 = 0.0
else:
precision = float(total_tp) / (total_tp + total_fp)
recall = float(total_tp) / (total_tp + total_fn)
f1 = 2 * precision * recall / (precision + recall)
return {'TP': total_tp, 'FP': total_fp, 'FN': total_fn, 'Precision': precision, 'Recall': recall, 'F1': f1}
if __name__ == '__main__':
# Settings
# retain original defaults
# remove unused/not needed: -i -f -s
parser = argparse.ArgumentParser(description='CULane test')
parser.add_argument('-a', '--anno-dir', type=str, help='directory for annotation files', default='/data/driving/eval_data/anno_label/')
parser.add_argument('-d', '--pred-dir', type=str, help='directory for detection files', default='/data/driving/eval_data/predict_label/')
parser.add_argument('-l', '--list-path', type=str, help='directory for image files', default='/data/driving/eval_data/img/')
parser.add_argument('-w', '--width', type=int, help='width of the lanes', default=10)
parser.add_argument('-t', '--threshold', type=float, help='threshold of iou', default=0.4)
parser.add_argument('-c', '--img-width', type=int, help='cols (max image width)', default=1920)
parser.add_argument('-r', '--img-height', type=int, help='rows (max image height)', default=1080)
parser.add_argument('-o', '--output-path', type=str, help='result txt output path', default='./output.txt')
_args = parser.parse_args()
res = eval_predictions(_args)
for k, v in res.items():
print('{}: {:.6f}'.format(k, v) if type(v) == float else '{}: {}'.format(k, v))
with open(_args.output_path, 'w') as f:
f.write('file: {}\n'.format(_args.output_path))
f.write('tp: {} fp: {} fn: {}\n'.format(res['TP'], res['FP'], res['FN']))
f.write('precision: {:.6f}\n'.format(res['Precision']))
f.write('recall: {:.6f}\n'.format(res['Recall']))
f.write('Fmeasure: {:.6f}\n\n'.format(res['F1']))

View File

@@ -0,0 +1,25 @@
# CULane (official lists)
# /driver_23_30frame/05151649_0422.MP4/00000.jpg /laneseg_label_w16/driver_23_30frame/05151649_0422.MP4/00000.png 1 1 1 1 =>
# /driver_23_30frame/05151649_0422.MP4/00000 1 1 1 1
import os
from importmagician import import_from
with import_from('./'):
from configs.lane_detection.common.datasets._utils import CULANE_ROOT as base
root = os.path.join(base, 'lists')
old_file_names = ['train_gt.txt', 'val_gt.txt', 'val.txt', 'test.txt']
new_file_names = ['train.txt', 'valfast.txt', 'val.txt', 'test.txt']
for i in range(len(old_file_names)):
file_name = os.path.join(root, old_file_names[i])
with open(file_name, 'r') as f:
temp = f.readlines()
for x in range(len(temp)):
if new_file_names[i] == 'test.txt' or new_file_names[i] == 'val.txt':
temp[x] = temp[x].replace('.jpg', '')[1:]
else:
temp[x] = temp[x][1: temp[x].find('.jpg')] + temp[x][temp[x].find('.png') + 4:]
file_name = os.path.join(root, new_file_names[i])
with open(file_name, 'w') as f:
f.writelines(temp)

View File

@@ -0,0 +1,16 @@
from importmagician import import_from
with import_from('./'):
from configs.lane_detection.common.datasets._utils import TUSIMPLE_ROOT, CULANE_ROOT, LLAMAS_ROOT
root_map = {
'tusimple': TUSIMPLE_ROOT,
'culane': CULANE_ROOT,
'llamas': LLAMAS_ROOT
}
size_map = {
'tusimple': (720, 1280),
'culane': (590, 1640),
'llamas': (717, 1276)
}

View File

@@ -0,0 +1,50 @@
import argparse
import json
import os
from tqdm import tqdm
from loader import SimpleKPLoader
from _utils import root_map, size_map
from importmagician import import_from
with import_from('./'):
from utils.curve_utils import BezierCurve as Bezier
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='PytorchAutoDrive Bezier curve GT generation')
parser.add_argument('--dataset', type=str, default='culane')
parser.add_argument('--image-set', type=str, default='train', help='train.txt/test.txt/val.txt/valfast.txt')
parser.add_argument('--order', type=int, default=3, help='the order of curve')
parser.add_argument('--norm', action='store_true', default=False, help='normalize coordinates')
args = parser.parse_args()
root = root_map[args.dataset]
image_size = size_map[args.dataset]
order = args.order
lane_interpolate = True if args.dataset == 'curvelanes' else False
lkp = SimpleKPLoader(root=root, image_set=args.image_set, data_set=args.dataset, image_size=image_size, norm=False)
keypoints = lkp.load_annotations()
all_lanes_kps = []
for kps in tqdm(keypoints.keys()):
temp = []
for kp in keypoints[kps]:
if kp.shape[0] == 0:
continue
fcns = Bezier(order=order)
fcns.get_control_points(kp[:, 0], kp[:, 1], interpolate=lane_interpolate)
matrix = fcns.save_control_points()
flatten = [round(p, 3) for sub_m in matrix for p in sub_m]
temp.append(flatten)
formatted = {
"raw_file": kps,
"bezier_control_points": temp
}
all_lanes_kps.append(json.dumps(formatted))
dir_name = os.path.join(root, 'bezier_labels')
if not os.path.exists(dir_name):
os.makedirs(dir_name)
save_path = os.path.join(dir_name, args.image_set + "_" + str(args.order) + ".json")
with open(save_path, 'w') as f:
for lane in all_lanes_kps:
print(lane, end="\n", file=f)

View File

@@ -0,0 +1,130 @@
import os
import numpy as np
from tqdm import tqdm
import json
from collections import OrderedDict
class SimpleKPLoader(object):
def __init__(self, root, image_size, image_set='test', data_set='tusimple', norm=False):
self.image_set = image_set
self.data_set = data_set
self.root = root
self.norm = norm
self.image_height = image_size[0]
self.image_width = image_size[-1]
if self.image_set == 'test' and data_set == 'llamas':
raise ValueError
if data_set == 'tusimple':
self.image_dir = root
elif data_set == 'culane':
self.image_dir = root
self.annotations_suffix = '.lines.txt'
elif data_set == 'curvelanes':
self.image_dir = root
self.annotations_suffix = '.lines.txt'
elif data_set == 'llamas':
self.image_dir = os.path.join(root, 'color_images')
self.annotations_suffix = '.lines.txt'
else:
raise ValueError
self.splits_dir = os.path.join(root, 'lists')
def load_txt_path(self, dataset):
split_f = os.path.join(self.splits_dir, self.image_set + '.txt')
with open(split_f, "r") as f:
contents = [x.strip() for x in f.readlines()]
if self.image_set in ['test', 'val']:
path_lists = [os.path.join(self.image_dir, x + self.annotations_suffix) for x in contents]
elif self.image_set == 'train':
if dataset == 'curvelanes':
path_lists = [os.path.join(self.image_dir, x + self.annotations_suffix) for x in contents]
else:
path_lists = [os.path.join(self.image_dir, x[:x.find(' ')] +
self.annotations_suffix) for x in contents]
else:
raise ValueError
return path_lists
def load_json(self):
if self.image_set == 'test':
json_name = [os.path.join(self.image_dir, 'test_label.json')]
elif self.image_set == 'val':
json_name = [os.path.join(self.image_dir, 'label_data_0531.json')]
elif self.image_set == 'train':
json_name = [os.path.join(self.image_dir, 'label_data_0313.json'),
os.path.join(self.image_dir, 'label_data_0601.json')]
else:
raise ValueError
return json_name
def get_points_in_txtfile(self, file_path):
coords = []
with open(file_path, 'r') as f:
for lane in f.readlines():
lane = lane.split(' ')
coord = []
for i in range(0, len(lane) - 1, 2):
if float(lane[i]) >= 0:
coord.append([float(lane[i]), float(lane[i + 1])])
coord = np.array(coord)
if self.norm and len(coord) != 0:
coord[:, 0] = coord[:, 0] / self.image_width
coord[:, -1] = coord[:, -1] / self.image_height
coords.append(coord)
return coords
def get_points_in_json(self, itm):
lanes = itm['lanes']
coords_list = []
h_sample = itm['h_samples']
for lane in lanes:
coord = []
for x, y in zip(lane, h_sample):
if x >= 0:
coord.append([float(x), float(y)])
coord = np.array(coord)
if self.norm and len(coord) != 0:
coord[:, 0] = coord[:, 0] / self.image_width
coord[:, -1] = coord[:, -1] / self.image_height
coords_list.append(coord)
return coords_list
def load_annotations(self):
print('Loading dataset...')
coords = OrderedDict()
if self.data_set in ['culane', 'llamas', 'curvelanes']:
file_lists = self.load_txt_path(dataset=self.data_set)
for f in tqdm(file_lists):
coords[f[len(self.root) + 1:]] = self.get_points_in_txtfile(f)
elif self.data_set == 'tusimple':
jsonfiles = self.load_json()
results = []
for jsonfile in jsonfiles:
with open(jsonfile, 'r') as f:
results += [json.loads(x.strip()) for x in f.readlines()]
for lane_json in tqdm(results):
coords[lane_json['raw_file']] = self.get_points_in_json(lane_json)
else:
raise ValueError
print('Finished')
return coords
def concat_jsons(self, filenames):
# Concat tusimple lists in jsons (actually only each line is json)
results = []
for filename in filenames:
with open(filename, 'r') as f:
results += [json.loads(x.strip()) for x in f.readlines()]
return results

View File

@@ -0,0 +1,180 @@
import argparse
import cv2
import numpy as np
try:
import ujson as json
except ImportError:
import json
from tqdm import tqdm
from tabulate import tabulate
from scipy.spatial import distance
def show_preds(pred, gt):
img = np.zeros((720, 1280, 3), dtype=np.uint8)
print(len(gt), 'gts and', len(pred), 'preds')
for lane in gt:
for p in lane:
cv2.circle(img, tuple(map(int, p)), 5, thickness=-1, color=(255, 0, 255))
for lane in pred:
for p in lane:
cv2.circle(img, tuple(map(int, p)), 4, thickness=-1, color=(0, 255, 0))
cv2.imshow('img', img)
cv2.waitKey(0)
def area_distance(pred_x, pred_y, gt_x, gt_y, placeholder=np.nan):
pred = np.vstack([pred_x, pred_y]).T
gt = np.vstack([gt_x, gt_y]).T
# pred = pred[pred[:, 0] > 0][:3, :]
# gt = gt[gt[:, 0] > 0][:5, :]
dist_matrix = distance.cdist(pred, gt, metric='euclidean')
dist = 0.5 * (np.min(dist_matrix, axis=0).sum() + np.min(dist_matrix, axis=1).sum())
d = np.max(gt_y) - np.min(gt_y)
if d == 0:
d = 1.0
dist /= d
return dist
def area_metric(pred, gt, debug=None):
pred = sorted(pred, key=lambda ps: abs(ps[0][0] - 720 / 2.))[:2]
gt = sorted(gt, key=lambda ps: abs(ps[0][0] - 720 / 2.))[:2]
if len(pred) == 0:
return 0., 0., len(gt)
line_dists = []
fp = 0.
matched = 0.
gt_matches = [False] * len(gt)
pred_matches = [False] * len(pred)
pred_dists = [None] * len(pred)
distances = np.ones((len(gt), len(pred)), dtype=np.float32)
for i_gt, gt_points in enumerate(gt):
x_gts = [x for x, _ in gt_points]
y_gts = [y for _, y in gt_points]
for i_pred, pred_points in enumerate(pred):
x_preds = [x for x, _ in pred_points]
y_preds = [y for _, y in pred_points]
distances[i_gt, i_pred] = area_distance(x_preds, y_preds, x_gts, y_gts)
best_preds = np.argmin(distances, axis=1)
best_gts = np.argmin(distances, axis=0)
fp = 0.
fn = 0.
dist = 0.
is_fp = []
is_fn = []
for i_pred, best_gt in enumerate(best_gts):
if best_preds[best_gt] == i_pred:
dist += distances[best_gt, i_pred]
is_fp.append(False)
else:
fp += 1
is_fp.append(True)
for i_gt, best_pred in enumerate(best_preds):
if best_gts[best_pred] != i_gt:
fn += 1
is_fn.append(True)
else:
is_fn.append(False)
if debug:
print('is fp')
print(is_fp)
print('is fn')
print(is_fn)
print('distances')
dists = np.min(distances, axis=0)
dists[np.array(is_fp)] = 0
print(dists)
show_preds(pred, gt)
return dist, fp, fn
def convert_tusimple_format(json_gt):
output = []
for data in json_gt:
lanes = [[(x, y) for (x, y) in zip(lane, data['h_samples']) if x >= 0] for lane in data['lanes']
if any(x > 0 for x in lane)]
output.append({
'raw_file': data['raw_file'],
'run_time': data['run_time'] if 'run_time' in data else None,
'lanes': lanes
})
return output
def eval_json(pred_file, gt_file, json_type=None, debug=False):
try:
json_pred = [json.loads(line) for line in open(pred_file).readlines()]
except BaseException as e:
raise Exception('Fail to load json file of the prediction.')
json_gt = [json.loads(line) for line in open(gt_file).readlines()]
if len(json_gt) != len(json_pred):
raise Exception('We do not get the predictions of all the test tasks')
if json_type == 'tusimple':
for gt, pred in zip(json_gt, json_pred):
pred['h_samples'] = gt['h_samples']
json_gt = convert_tusimple_format(json_gt)
json_pred = convert_tusimple_format(json_pred)
gts = {l['raw_file']: l for l in json_gt}
total_distance, total_fp, total_fn, run_time = 0., 0., 0., 0.
for pred in tqdm(json_pred):
if 'raw_file' not in pred or 'lanes' not in pred:
raise Exception('raw_file or lanes not in some predictions.')
raw_file = pred['raw_file']
pred_lanes = pred['lanes']
run_time += pred['run_time'] if 'run_time' in pred else 1.
if raw_file not in gts:
raise Exception('Some raw_file from your predictions do not exist in the test tasks.')
gt = gts[raw_file]
gt_lanes = gt['lanes']
distance, fp, fn = area_metric(pred_lanes, gt_lanes, debug=debug)
total_distance += distance
total_fp += fp
total_fn += fn
num = len(gts)
return json.dumps([{
'name': 'Distance',
'value': total_distance / num,
'order': 'desc'
}, {
'name': 'FP',
'value': total_fp,
'order': 'asc'
}, {
'name': 'FN',
'value': total_fn,
'order': 'asc'
}
])
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="PytorchAutoDrive curve utils")
parser.add_argument('--preds', required=True, type=str, help=".json with the predictions")
parser.add_argument('--gt', required=True, type=str, help=".json with the GT")
parser.add_argument('--gt-type', type=str, help='pass `tusimple` if using the TuSimple file format')
parser.add_argument('--debug', action='store_true', help='show metrics and preds/gts')
argv = vars(parser.parse_args())
result = json.loads(eval_json(argv['preds'], argv['gt'], argv['gt_type'], argv['debug']))
# pretty-print
table = {}
for metric in result:
if metric['name'] not in table.keys():
table[metric['name']] = []
table[metric['name']].append(metric['value'])
print(tabulate(table, headers='keys'))

View File

@@ -0,0 +1,122 @@
import os
import json
import argparse
import numpy as np
from tqdm import tqdm
from loader import SimpleKPLoader
from _utils import root_map, size_map
from importmagician import import_from
with import_from('./'):
from utils.curve_utils import BezierCurve as Bezier, Polynomial as Poly
from utils.common import warnings
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='PytorchAutoDrive curve utils')
parser.add_argument('--dataset', type=str, default='culane')
parser.add_argument('--state', type=int, default=1, help='1: test set/2: val test')
parser.add_argument('--fit-function', type=str, default='bezier', help='bezier/poly')
parser.add_argument('--num-points', type=int, default=50, help='the number of sampled points')
parser.add_argument('--order', type=int, default=2)
parser.add_argument('--norm', action='store_true', default=False, help='normalize coordinates')
args = parser.parse_args()
root = root_map[args.dataset]
image_size = size_map[args.dataset]
bezier_threshold = 5
image_set = 'test' if args.state == 1 else 'val'
if args.dataset == 'llamas' and image_set != 'val':
warnings.warn('LLAMAS test labels not available! Switching to validation set!')
image_set = 'val'
order = args.order
lkp = SimpleKPLoader(root=root, image_set=image_set, data_set=args.dataset, image_size=image_size, norm=args.norm)
lane_interpolate = True if args.dataset == 'curvelanes' else False
keypoints = lkp.load_annotations()
all_lanes = []
for kps in tqdm(keypoints.keys()):
coordinates = []
for kp in keypoints[kps]:
if args.fit_function == 'bezier':
fcns = Bezier(order=order)
fcns.get_control_points(kp[:, 0], kp[:, 1], interpolate=lane_interpolate)
elif args.fit_function == 'poly':
fcns = Poly(order=order)
fcns.poly_fit(kp[:, 0], kp[:, 1], interpolate=lane_interpolate)
else:
raise ValueError
if args.dataset == 'tusimple':
temp = []
if args.fit_function == 'bezier':
h_samples = [(160 + y * 10) for y in range(56)]
sampled_points = fcns.get_sample_point(n=args.num_points,
image_size=image_size if args.norm else None)
for h_sample in h_samples:
dis = np.abs(h_sample - sampled_points[:, 1])
idx = np.argmin(dis)
if dis[idx] > bezier_threshold:
temp.append(-2)
else:
temp.append(round(sampled_points[:, 0][idx], 3))
coordinates.append(temp)
elif args.fit_function == 'poly':
if args.norm:
h_samples = [(160 + y * 10) / image_size[0] for y in range(56)]
else:
h_samples = [(160 + y * 10) for y in range(56)]
# sampled_points = fcns.get_sample_point(kp[:, 1])
start_y = kp[:, 1][0]
end_y = kp[:, 1][-1]
for h_sample in h_samples:
if h_sample < start_y:
temp.append(-2)
elif h_sample >= start_y and h_sample <= end_y:
temp.append(
round(fcns.compute_x_based_y(h_sample, image_size=image_size if args.norm else None),
3))
elif h_sample > end_y:
temp.append(-2)
coordinates.append(temp)
else:
raise ValueError
else:
if args.fit_function == 'bezier':
coordinates.append(
fcns.get_sample_point(n=args.num_points, image_size=image_size if args.norm else None))
elif args.fit_function == 'poly':
coordinates.append(fcns.get_sample_point(kp[:, 1], image_size=image_size if args.norm else None))
else:
raise ValueError
# save the result
if args.dataset in ['culane', 'llamas', 'curvelanes']:
filepath = os.path.join('./output', kps)
if args.dataset == 'llamas':
filepath = filepath.replace('/color_images', '')
filepath = filepath.replace('_color_rect', '')
dir_name = filepath[:filepath.rfind('/')]
if not os.path.exists(dir_name):
os.makedirs(dir_name)
with open(filepath, "w") as f:
for coordinate in coordinates:
for j in range(len(coordinate)):
print("{} {}".format(round(coordinate[j][0], 3), round(coordinate[j][1]), 3), end=" ", file=f)
print(file=f)
elif args.dataset == 'tusimple':
formatted = {
"h_samples": [160 + y * 10 for y in range(56)],
"lanes": coordinates,
"run_time": 0,
"raw_file": kps
}
all_lanes.append(json.dumps(formatted))
if args.dataset == 'tusimple':
with open('./output/upperbound_' + args.fit_function + '_' + str(args.order) + '.json', 'w') as f:
for lane in all_lanes:
print(lane, end="\n", file=f)

View File

@@ -0,0 +1,48 @@
from importmagician import import_from
with import_from('./'):
from utils.models.common_models import DCN_v2_Ref
import torch
# from fvcore.nn import FlopCountAnalysis
from thop import profile
def thop_count(x, y, f):
macs, params = profile(f, inputs=(x, y))
return macs * 2, params
# def fvcore_count(x, y, f):
# flops = FlopCountAnalysis(f, (x, y))
# return flops.total() * 2, 0
H = 360
W = 640
C = 256
OS = 16
fH = (H - 1) // OS + 1
fW = (W - 1) // OS + 1
inputs1 = torch.ones(1, C, fH, fW).cuda()
inputs2 = torch.ones(1, C, (H - 1) // OS + 1, (W - 1) // OS + 1).cuda()
# model = SimpleFlip_2D(channels=256).cuda()
model = DCN_v2_Ref(C, C, kernel_size=(3, 3), padding=1).cuda()
model.eval()
print(thop_count(inputs1, inputs2, model)) # Also doubly counts sigmoid (damn the activations)
# print(fvcore_count(inputs1, inputs2, model))
# Only modulated_deform_conv2d() is ignored
# conv Flops = 2 x k^2 x Cin x Cout x W x H
# dcn Flops = + W x H x k^2 x 13 + W x H x k^2 x 9 x Cin (bilinear interpolate)
# or just: ->0 + W x H x k^2 x 9 x Cin (3 weighted plus)
# ->0 coordinates: W x H x k^2 x 13
# dcnv2: ++ W x H x k^2 x Cin
# ~ (additional flops on bias is not considered):
standard_conv_flops = fW * fH * (3 * 3) * C * C
ignored_dcnv2_flops = 10 * fW * fH * (3 * 3) * C + fW * fH * (3 * 3) * 13
print('DCN_v2_Ref ignored flops by thop:')
print(standard_conv_flops + ignored_dcnv2_flops)

View File

@@ -0,0 +1,17 @@
# This script generates Cityscapes official demos from downloaded demo images
import os
from utils.frames_to_video import frames2video
from importmagician import import_from
with import_from('./'):
from configs.semantic_segmentation.common.datasets._utils import CITYSCAPES_ROOT
base = os.path.join(CITYSCAPES_ROOT, 'all_demoVideo', 'leftImg8bit', 'demoVideo')
# Get image file list
sub_dirs = sorted(os.listdir(base))
for sub_dir in sub_dirs:
filenames = sorted(os.listdir(os.path.join(base, sub_dir)))
# Save video
frames2video(os.path.join(base, sub_dir), sub_dir + '.avi', filenames, fps=17)

View File

@@ -0,0 +1,31 @@
import os
from importmagician import import_from
with import_from('./'):
from configs.semantic_segmentation.common.datasets._utils import GTAV_ROOT as base
# Pad with 0
def pad(x):
zero = '0'
length = len(x)
if length < 5:
x = zero * (5 - length) + x
x += '\n'
return x
# Count
start = 1
end = 24966
train_list = [pad(str(x)) for x in range(start, end + 1)]
print('Whole training set size: ' + str(len(train_list)))
# Save training list
lists_dir = os.path.join(base, "data_lists")
if not os.path.exists(lists_dir):
os.makedirs(lists_dir)
with open(os.path.join(lists_dir, "train.txt"), "w") as f:
f.writelines(train_list)
print("Complete.")

View File

@@ -0,0 +1,247 @@
"""
Copied from https://github.com/karstenBehrendt/unsupervised_llamas/blob/master/culane_metric/evaluate.py
Evaluation script for the CULane metric on the LLAMAS dataset.
This script will compute the F1, precision and recall metrics as described in the CULane benchmark.
The predictions format is the same one used in the CULane benchmark.
In summary, for every annotation file:
labels/a/b/c.json
There should be a prediction file:
predictions/a/b/c.lines.txt
Inside each .lines.txt file each line will contain a sequence of points (x, y) separated by spaces.
For more information, please see https://xingangpan.github.io/projects/CULane.html
This script uses two methods to compute the IoU: one using an image to draw the lanes (named `discrete` here) and
another one that uses shapes with the shapely library (named `continuous` here). The results achieved with the first
method are very close to the official CULane implementation. Although the second should be a more exact method and is
faster to compute, it deviates more from the official implementation. By default, the method closer to the official
metric is used.
"""
import os
import argparse
import cv2
import fcntl
import ujson as json
import numpy as np
from p_tqdm import t_map, p_map
from functools import partial
from scipy.interpolate import splprep, splev
from scipy.optimize import linear_sum_assignment
from shapely.geometry import LineString, Polygon
from llamas_official_scripts import get_files_from_folder, get_horizontal_values_for_four_lanes, get_label_base
LLAMAS_IMG_RES = [717, 1276]
IMAGE_HEIGHT, IMAGE_WIDTH = LLAMAS_IMG_RES[0], LLAMAS_IMG_RES[1]
def add_ys(xs):
"""For each x in xs, make a tuple with x and its corresponding y."""
xs = np.array(xs[300:])
valid = xs >= 0
xs = xs[valid]
assert len(xs) > 1
ys = np.arange(300, 717)[valid]
return list(zip(xs, ys))
def draw_lane(lane, img=None, img_shape=None, width=30):
"""Draw a lane (a list of points) on an image by drawing a line with width `width` through each
pair of points i and i+i"""
if img is None:
img = np.zeros(img_shape, dtype=np.uint8)
lane = lane.astype(np.int32)
for p1, p2 in zip(lane[:-1], lane[1:]):
cv2.line(img, tuple(p1), tuple(p2), color=(1,), thickness=width)
return img
def discrete_cross_iou(xs, ys, width=30, img_shape=LLAMAS_IMG_RES):
"""For each lane in xs, compute its Intersection Over Union (IoU) with each lane in ys by drawing the lanes on
an image"""
xs = [draw_lane(lane, img_shape=img_shape, width=width) > 0 for lane in xs]
ys = [draw_lane(lane, img_shape=img_shape, width=width) > 0 for lane in ys]
ious = np.zeros((len(xs), len(ys)))
for i, x in enumerate(xs):
for j, y in enumerate(ys):
# IoU by the definition: sum all intersections (binary and) and divide by the sum of the union (binary or)
ious[i, j] = (x & y).sum() / (x | y).sum()
return ious
def continuous_cross_iou(xs, ys, width=30):
"""For each lane in xs, compute its Intersection Over Union (IoU) with each lane in ys using the area between each
pair of points"""
h, w = IMAGE_HEIGHT, IMAGE_WIDTH
image = Polygon([(0, 0), (0, h - 1), (w - 1, h - 1), (w - 1, 0)])
xs = [LineString(lane).buffer(distance=width / 2., cap_style=1, join_style=2).intersection(image) for lane in xs]
ys = [LineString(lane).buffer(distance=width / 2., cap_style=1, join_style=2).intersection(image) for lane in ys]
ious = np.zeros((len(xs), len(ys)))
for i, x in enumerate(xs):
for j, y in enumerate(ys):
ious[i, j] = x.intersection(y).area / x.union(y).area
return ious
def remove_con_dup(x):
"""Customize a set op to remove consecutive duplications"""
y = []
for t in x:
if len(y) > 0 and y[-1] == t:
continue
y.append(t)
return y
def interpolate_lane(points, n=50):
"""Spline interpolation of a lane. Used on the predictions"""
# Consecutive duplications cause internal error for scipy's splprep:
# https://stackoverflow.com/a/47949170/15449902
points = remove_con_dup(points)
# B-Spline interpolate
x = [x for x, _ in points]
y = [y for _, y in points]
tck, _ = splprep([x, y], s=0, t=n, k=min(3, len(points) - 1))
u = np.linspace(0., 1., n)
return np.array(splev(u, tck)).T
def culane_metric(pred, anno, width=30, iou_threshold=0.5, unofficial=False, img_shape=LLAMAS_IMG_RES):
"""Computes CULane's metric for a single image"""
if len(pred) == 0:
return 0, 0, len(anno)
if len(anno) == 0:
return 0, len(pred), 0
interp_pred = np.array([interpolate_lane(pred_lane, n=50) for pred_lane in pred]) # (4, 50, 2)
anno = np.array([np.array(anno_lane) for anno_lane in anno], dtype=object)
if unofficial:
ious = continuous_cross_iou(interp_pred, anno, width=width)
else:
ious = discrete_cross_iou(interp_pred, anno, width=width, img_shape=img_shape)
row_ind, col_ind = linear_sum_assignment(1 - ious)
tp = int((ious[row_ind, col_ind] > iou_threshold).sum())
fp = len(pred) - tp
fn = len(anno) - tp
return tp, fp, fn
def load_prediction(path):
"""Loads an image's predictions
Returns a list of lanes, where each lane is a list of points (x,y)
"""
with open(path, 'r') as data_file:
img_data = data_file.readlines()
img_data = [line.split() for line in img_data]
img_data = [list(map(float, lane)) for lane in img_data]
img_data = [[(lane[i], lane[i + 1]) for i in range(0, len(lane), 2)] for lane in img_data]
img_data = [lane for lane in img_data if len(lane) >= 2]
return img_data
def load_prediction_list(label_paths, pred_dir):
return [load_prediction(os.path.join(pred_dir, path.replace('.json', '.lines.txt'))) for path in label_paths]
def load_labels(label_dir):
"""Loads the annotations and its paths
Each annotation is converted to a list of points (x, y)
"""
label_paths = get_files_from_folder(label_dir, '.json')
annos = [[add_ys(xs) for xs in get_horizontal_values_for_four_lanes(label_path) if
(np.array(xs) >= 0).sum() > 1] # lanes annotated with a single point are ignored
for label_path in label_paths]
label_paths = [
get_label_base(p) for p in label_paths
]
return np.array(annos, dtype=object), np.array(label_paths, dtype=object)
def eval_predictions(pred_dir, anno_dir, width=30, unofficial=True, sequential=False):
"""Evaluates the predictions in pred_dir and returns CULane's metrics (precision, recall, F1 and its components)"""
print(f'Loading annotation data ({anno_dir})...')
annotations, label_paths = load_labels(anno_dir)
print(f'Loading prediction data ({pred_dir})...')
predictions = load_prediction_list(label_paths, pred_dir)
print('Calculating metric {}...'.format('sequentially' if sequential else 'in parallel'))
if sequential:
results = t_map(partial(culane_metric, width=width, unofficial=unofficial, img_shape=LLAMAS_IMG_RES),
predictions,
annotations)
else:
results = p_map(partial(culane_metric, width=width, unofficial=unofficial, img_shape=LLAMAS_IMG_RES),
predictions,
annotations)
total_tp = sum(tp for tp, _, _ in results)
total_fp = sum(fp for _, fp, _ in results)
total_fn = sum(fn for _, _, fn in results)
if total_tp == 0:
precision = 0
recall = 0
f1 = 0
else:
precision = float(total_tp) / (total_tp + total_fp)
recall = float(total_tp) / (total_tp + total_fn)
f1 = 2 * precision * recall / (precision + recall)
return {'TP': total_tp, 'FP': total_fp, 'FN': total_fn, 'Precision': precision, 'Recall': recall, 'F1': f1}
def parse_args():
parser = argparse.ArgumentParser(description="Measure CULane's metric on the LLAMAS dataset")
parser.add_argument("--pred_dir", help="Path to directory containing the predicted lanes", required=True)
parser.add_argument("--anno_dir", help="Path to directory containing the annotated lanes", required=True)
parser.add_argument('--exp_name', type=str, default='', help='Name of experiment')
parser.add_argument('--save-dir', type=str, help='Path prefix to save full res.')
parser.add_argument("--width", type=int, default=30, help="Width of the lane")
parser.add_argument("--sequential", action='store_true', help="Run sequentially instead of in parallel")
parser.add_argument("--unofficial", action='store_true', help="Use a faster but unofficial algorithm")
return parser.parse_args()
def main():
args = parse_args()
results = eval_predictions(args.pred_dir,
args.anno_dir,
width=args.width,
unofficial=args.unofficial,
sequential=args.sequential)
header = '=' * 20 + ' Results' + '=' * 20
print(header)
for metric, value in results.items():
if isinstance(value, float):
output = '{}: {:.4f}'.format(metric, value)
print(output)
else:
print('{}: {}'.format(metric, value))
with open('../../log.txt', 'a') as f:
fcntl.flock(f, fcntl.LOCK_EX)
f.write(args.exp_name + ': ' + str(results['F1']) + '\n')
fcntl.flock(f, fcntl.LOCK_UN)
print('=' * len(header))
res = json.dumps(results)
with open('./output/' + args.exp_name + '.json', 'w') as f:
f.write(res)
if args.save_dir is not None:
import os
prefix = 'val'
if 'valid' not in args.anno_dir:
prefix = 'custom_anno_dir_' + args.anno_dir[args.anno_dir.rfind('/') + 1:]
save_dir = os.path.join('../../', args.save_dir, args.exp_name)
os.makedirs(save_dir, exist_ok=True)
with open(os.path.join(save_dir, prefix + '_result.json'), 'w') as f:
f.write(res)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,374 @@
# Its license is copied here
# ##### Begin License ######
# MIT License
# Copyright (c) 2019 Karsten Behrendt, Robert Bosch LLC
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ##### End License ######
# copied from https://github.com/karstenBehrendt/unsupervised_llamas/tree/master/label_scripts
# Start code under the previous license
import json
import os
import numpy as np
def _extend_lane(lane, projection_matrix):
"""Extends marker closest to the camera
Adds an extra marker that reaches the end of the image
Parameters
----------
lane : iterable of markers
projection_matrix : 3x3 projection matrix
"""
# Unfortunately, we did not store markers beyond the image plane. That hurts us now
# z is the orthongal distance to the car. It's good enough
# The markers are automatically detected, mapped, and labeled. There exist faulty ones,
# e.g., horizontal markers which need to be filtered
filtered_markers = filter(
lambda x: (x['pixel_start']['y'] != x['pixel_end']['y'] and x['pixel_start']['x'] != x['pixel_end']['x']),
lane['markers'])
# might be the first marker in the list but not guaranteed
closest_marker = min(filtered_markers, key=lambda x: x['world_start']['z'])
if closest_marker['world_start']['z'] < 0: # This one likely equals "if False"
return lane
# World marker extension approximation
x_gradient = (closest_marker['world_end']['x'] - closest_marker['world_start']['x']) / \
(closest_marker['world_end']['z'] - closest_marker['world_start']['z'])
y_gradient = (closest_marker['world_end']['y'] - closest_marker['world_start']['y']) / \
(closest_marker['world_end']['z'] - closest_marker['world_start']['z'])
zero_x = closest_marker['world_start']['x'] - (closest_marker['world_start']['z'] - 1) * x_gradient
zero_y = closest_marker['world_start']['y'] - (closest_marker['world_start']['z'] - 1) * y_gradient
# Pixel marker extension approximation
pixel_x_gradient = (closest_marker['pixel_end']['x'] - closest_marker['pixel_start']['x']) / \
(closest_marker['pixel_end']['y'] - closest_marker['pixel_start']['y'])
pixel_y_gradient = (closest_marker['pixel_end']['y'] - closest_marker['pixel_start']['y']) / \
(closest_marker['pixel_end']['x'] - closest_marker['pixel_start']['x'])
pixel_zero_x = closest_marker['pixel_start']['x'] + (716 - closest_marker['pixel_start']['y']) * pixel_x_gradient
if pixel_zero_x < 0:
left_y = closest_marker['pixel_start']['y'] - closest_marker['pixel_start']['x'] * pixel_y_gradient
new_pixel_point = (0, left_y)
elif pixel_zero_x > 1276:
right_y = closest_marker['pixel_start']['y'] + (1276 - closest_marker['pixel_start']['x']) * pixel_y_gradient
new_pixel_point = (1276, right_y)
else:
new_pixel_point = (pixel_zero_x, 716)
new_marker = {
'lane_marker_id': 'FAKE',
'world_end': {
'x': closest_marker['world_start']['x'],
'y': closest_marker['world_start']['y'],
'z': closest_marker['world_start']['z']
},
'world_start': {
'x': zero_x,
'y': zero_y,
'z': 1
},
'pixel_end': {
'x': closest_marker['pixel_start']['x'],
'y': closest_marker['pixel_start']['y']
},
'pixel_start': {
'x': ir(new_pixel_point[0]),
'y': ir(new_pixel_point[1])
}
}
lane['markers'].insert(0, new_marker)
return lane
class SplineCreator():
"""
For each lane divder
- all lines are projected
- linearly interpolated to limit oscillations
- interpolated by a spline
- subsampled to receive individual pixel values
The spline creation can be optimized!
- Better spline parameters
- Extend lowest marker to reach bottom of image would also help
- Extending last marker may in some cases be interesting too
Any help is welcome.
Call create_all_points and get the points in self.sampled_points
It has an x coordinate for each value for each lane
"""
def __init__(self, json_path):
self.json_path = json_path
self.json_content = read_json(json_path)
self.lanes = self.json_content['lanes']
self.lane_marker_points = {}
self.sampled_points = {} # <--- the interesting part
self.debug_image = np.zeros((717, 1276, 3), dtype=np.uint8)
def _sample_points(self, lane, ypp=5, between_markers=True):
""" Markers are given by start and endpoint. This one adds extra points
which need to be considered for the interpolation. Otherwise the spline
could arbitrarily oscillate between start and end of the individual markers
Parameters
----------
lane: polyline, in theory but there are artifacts which lead to inconsistencies
in ordering. There may be parallel lines. The lines may be dashed. It's messy.
ypp: y-pixels per point, e.g. 10 leads to a point every ten pixels
between_markers : bool, interpolates inbetween dashes
Notes
-----
Especially, adding points in the lower parts of the image (high y-values) because
the start and end points are too sparse.
Removing upper lane markers that have starting and end points mapped into the same pixel.
"""
# Collect all x values from all markers along a given line. There may be multiple
# intersecting markers, i.e., multiple entries for some y values
x_values = [[] for i in range(717)]
for marker in lane['markers']:
x_values[marker['pixel_start']['y']].append(marker['pixel_start']['x'])
height = marker['pixel_start']['y'] - marker['pixel_end']['y']
if height > 2:
slope = (marker['pixel_end']['x'] - marker['pixel_start']['x']) / height
step_size = (marker['pixel_start']['y'] - marker['pixel_end']['y']) / float(height)
for i in range(height + 1):
x = marker['pixel_start']['x'] + slope * step_size * i
y = marker['pixel_start']['y'] - step_size * i
x_values[ir(y)].append(ir(x))
# Calculate average x values for each y value
for y, xs in enumerate(x_values):
if not xs:
x_values[y] = -1
else:
x_values[y] = sum(xs) / float(len(xs))
# In the following, we will only interpolate between markers if needed
if not between_markers:
return x_values # TODO ypp
# # interpolate between markers
current_y = 0
while x_values[current_y] == -1: # skip missing first entries
current_y += 1
# Also possible using numpy.interp when accounting for beginning and end
next_set_y = 0
try:
while current_y < 717:
if x_values[current_y] != -1: # set. Nothing to be done
current_y += 1
continue
# Finds target x value for interpolation
while next_set_y <= current_y or x_values[next_set_y] == -1:
next_set_y += 1
if next_set_y >= 717:
raise StopIteration
x_values[current_y] = x_values[current_y - 1] + (x_values[next_set_y] - x_values[current_y - 1]) / \
(next_set_y - current_y + 1)
current_y += 1
except StopIteration:
pass # Done with lane
return x_values
def _lane_points_fit(self, lane):
# TODO name and docstring
""" Fits spline in image space for the markers of a single lane (side)
Parameters
----------
lane: dict as specified in label
Returns
-------
Pixel level values for curve along the y-axis
Notes
-----
This one can be drastically improved. Probably fairly easy as well.
"""
# NOTE all variable names represent image coordinates, interpolation coordinates are swapped!
lane = _extend_lane(lane, self.json_content['projection_matrix'])
sampled_points = self._sample_points(lane, ypp=1)
self.sampled_points[lane['lane_id']] = sampled_points
return sampled_points
def create_all_points(self, ):
""" Creates splines for given label """
for lane in self.lanes:
self._lane_points_fit(lane)
def get_horizontal_values_for_four_lanes(json_path):
""" Gets an x value for every y coordinate for l1, l0, r0, r1
This allows to easily train a direct curve approximation. For each value along
the y-axis, the respective x-values can be compared, e.g. squared distance.
Missing values are filled with -1. Missing values are values missing from the spline.
There is no extrapolation to the image start/end (yet).
But values are interpolated between markers. Space between dashed markers is not missing.
Parameters
----------
json_path: str
path to label-file
Returns
-------
List of [l1, l0, r0, r1], each of which represents a list of ints the length of
the number of vertical pixels of the image
Notes
-----
The points are currently based on the splines. The splines are interpolated based on the
segmentation values. The spline interpolation has lots of room for improvement, e.g.
the lines could be interpolated in 3D, a better approach to spline interpolation could
be used, there is barely any error checking, sometimes the splines oscillate too much.
This was used for a quick poly-line regression training only.
"""
sc = SplineCreator(json_path)
sc.create_all_points()
l1 = sc.sampled_points.get('l1', [-1] * 717)
l0 = sc.sampled_points.get('l0', [-1] * 717)
r0 = sc.sampled_points.get('r0', [-1] * 717)
r1 = sc.sampled_points.get('r1', [-1] * 717)
lanes = [l1, l0, r0, r1]
return lanes
def _filter_lanes_by_size(label, min_height=40):
""" May need some tuning """
filtered_lanes = []
for lane in label['lanes']:
lane_start = min([int(marker['pixel_start']['y']) for marker in lane['markers']])
lane_end = max([int(marker['pixel_start']['y']) for marker in lane['markers']])
if (lane_end - lane_start) < min_height:
continue
filtered_lanes.append(lane)
label['lanes'] = filtered_lanes
def _filter_few_markers(label, min_markers=2):
"""Filter lines that consist of only few markers"""
filtered_lanes = []
for lane in label['lanes']:
if len(lane['markers']) >= min_markers:
filtered_lanes.append(lane)
label['lanes'] = filtered_lanes
def _fix_lane_names(label):
""" Given keys ['l3', 'l2', 'l0', 'r0', 'r2'] returns ['l2', 'l1', 'l0', 'r0', 'r1']"""
# Create mapping
l_counter = 0
r_counter = 0
mapping = {}
lane_ids = [lane['lane_id'] for lane in label['lanes']]
for key in sorted(lane_ids):
if key[0] == 'l':
mapping[key] = 'l' + str(l_counter)
l_counter += 1
if key[0] == 'r':
mapping[key] = 'r' + str(r_counter)
r_counter += 1
for lane in label['lanes']:
lane['lane_id'] = mapping[lane['lane_id']]
def read_json(json_path, min_lane_height=20):
""" Reads and cleans label file information by path"""
with open(json_path, 'r') as jf:
label_content = json.load(jf)
_filter_lanes_by_size(label_content, min_height=min_lane_height)
_filter_few_markers(label_content, min_markers=2)
_fix_lane_names(label_content)
content = {'projection_matrix': label_content['projection_matrix'], 'lanes': label_content['lanes']}
for lane in content['lanes']:
for marker in lane['markers']:
for pixel_key in marker['pixel_start'].keys():
marker['pixel_start'][pixel_key] = int(marker['pixel_start'][pixel_key])
for pixel_key in marker['pixel_end'].keys():
marker['pixel_end'][pixel_key] = int(marker['pixel_end'][pixel_key])
for pixel_key in marker['world_start'].keys():
marker['world_start'][pixel_key] = float(marker['world_start'][pixel_key])
for pixel_key in marker['world_end'].keys():
marker['world_end'][pixel_key] = float(marker['world_end'][pixel_key])
return content
def ir(some_value):
""" Rounds and casts to int
Useful for pixel values that cannot be floats
Parameters
----------
some_value : float
numeric value
Returns
--------
Rounded integer
Raises
------
ValueError for non scalar types
"""
return int(round(some_value))
def get_files_from_folder(directory, extension=None):
"""Get all files within a folder that fit the extension """
# NOTE Can be replaced by glob for newer python versions
label_files = []
for root, _, files in os.walk(directory):
for some_file in files:
label_files.append(os.path.abspath(os.path.join(root, some_file)))
if extension is not None:
label_files = list(filter(lambda x: x.endswith(extension), label_files))
return label_files
def get_label_base(label_path):
""" Gets directory independent label path """
return '/'.join(label_path.split('/')[-2:])

View File

@@ -0,0 +1,105 @@
import os
from tqdm import tqdm
from llamas_evaluation.llamas_official_scripts import get_horizontal_values_for_four_lanes
from importmagician import import_from
with import_from('./'):
from configs.lane_detection.common.datasets._utils import LLAMAS_ROOT as base
LLAMAS_H = 717
#
list_path = os.path.join(base, 'lists')
image_path = os.path.join(base, 'color_images')
label_path = os.path.join(base, 'labels')
if os.path.exists(list_path) is False:
os.makedirs(list_path)
file_names = ['train', 'val', 'valfast', 'test']
def get_file_paths(dir, type):
paths = []
for root, dirs, files in os.walk(dir):
for file in files:
if file.endswith(type):
paths.append(os.path.join(root, file))
return paths
def coords2str(lane):
s = ""
for coords in lane:
s = s + str(round(coords[0], 3)) + " "
s = s + str(coords[1]) + " "
s = s + '\n'
return s
def get_txtfile(filepath, lanes):
with open(filepath, 'a') as f:
for lane in lanes:
f.writelines(coords2str(lane))
return 0
def existence2str(exist):
s = ""
for idx in exist:
s = s + str(idx) + " "
return s
def spline_annotation(json_name, image_name, get_txt):
spline_lanes = get_horizontal_values_for_four_lanes(json_name)
lanes = [[(x, y) for x, y in zip(lane, range(LLAMAS_H)) if x >= 0] for lane in spline_lanes]
lanes_exist = [1 if len(lane) > 0 else 0 for lane in lanes]
lanes = [lane for lane in lanes if len(lane) > 0]
if get_txt is True:
txt_path = image_name.replace('.png', '.lines.txt')
get_txtfile(txt_path, lanes)
return lanes_exist
def get_spline(filetype, filename, get_txt=False, existence=False, ant_exist=True):
images_list = get_file_paths(os.path.join(image_path, filetype), ".png")
images_list.sort()
json_list = get_file_paths(os.path.join(label_path, filetype), ".json")
if len(json_list) != 0:
json_list.sort()
length_of_list = len(images_list)
for idx in tqdm(range(0, length_of_list)):
lanes_exist = []
if ant_exist:
lanes_exist = spline_annotation(json_list[idx], images_list[idx], get_txt)
with open(os.path.join(list_path, filename), 'a') as f:
if existence is True:
f.writelines(
images_list[idx][len(image_path) + 1:].replace('.png', '') + " " + existence2str(lanes_exist) + "\n")
else:
f.writelines(images_list[idx][len(image_path) + 1:].replace('.png', '') + "\n")
return 0
def generate_spline_annotation():
for file_name in file_names:
if file_name == 'train':
print(file_name+".txt is processing...")
get_spline(file_name, file_name + '.txt', get_txt=True, existence=True, ant_exist=True)
elif file_name == 'valfast':
print(file_name + ".txt is processing...")
get_spline('valid', file_name + '.txt', get_txt=True, existence=True, ant_exist=True)
elif file_name == 'val':
print(file_name + ".txt is processing...")
get_spline('valid', file_name + '.txt', get_txt=False, existence=False, ant_exist=False)
elif file_name == 'test':
print(file_name + ".txt is processing...")
get_spline(file_name, file_name + '.txt', get_txt=False, existence=False, ant_exist=False)
return 0
if __name__ == '__main__':
generate_spline_annotation()

View File

@@ -0,0 +1,81 @@
import argparse
import torch
from importmagician import import_from
with import_from('./'):
from utils.args import read_config, parse_arg_cfg, cmd_dict, add_shortcuts
from utils.models import MODELS
from utils.common import load_checkpoint
from utils.profiling_utils import init_dataset, speed_evaluate_real, speed_evaluate_simple, model_profile
if __name__ == '__main__':
# Settings
parser = argparse.ArgumentParser(description='PytorchAutoDrive Profiling', conflict_handler='resolve')
add_shortcuts(parser)
parser.add_argument('--config', type=str, help='Path to config file', required=True)
# Optional args/to overwrite configs
parser.add_argument('--height', type=int, default=288,
help='Image input height (default: 288)')
parser.add_argument('--width', type=int, default=800,
help='Image input width (default: 800)')
parser.add_argument('--mode', type=str, default='simple',
help='Profiling mode (simple/real)')
parser.add_argument('--times', type=int, default=1,
help='Select test times')
parser.add_argument('--cfg-options', type=cmd_dict,
help='Override config options with \"x1=y1 x2=y2 xn=yn\"')
group2 = parser.add_mutually_exclusive_group()
group2.add_argument('--continue-from', type=str,
help='[Deprecated] Continue training from a previous checkpoint')
group2.add_argument('--checkpoint', type=str,
help='Continue/Load from a previous checkpoint')
args = parser.parse_args()
# Parse configs and build model
cfg = read_config(args.config)
args, cfg = parse_arg_cfg(args, cfg)
net = MODELS.from_dict(cfg['model'])
device = torch.device('cpu')
if torch.cuda.is_available():
device = torch.device('cuda:0')
print(device)
net.to(device)
if args.mode == 'simple':
dummy = torch.ones((1, 3, args.height, args.width))
print(dummy.dtype)
fps = []
for i in range(0, args.times):
fps.append(speed_evaluate_simple(net=net, device=device, dummy=dummy, num=300))
print('GPU FPS: {: .2f}'.format(max(fps)))
elif args.mode == 'real':
if cfg['test']['checkpoint'] is not None:
load_checkpoint(net=net, optimizer=None, lr_scheduler=None, filename=cfg['test']['checkpoint'])
val_loader = init_dataset(cfg['dataset'], cfg['test_augmentations'], (args.height, args.width))
fps = []
gpu_fps = []
for i in range(0, args.times):
fps_item, gpu_fps_item = speed_evaluate_real(net=net, device=device, loader=val_loader, num=300)
fps.append(fps_item)
gpu_fps.append(gpu_fps_item)
print('Real FPS: {: .2f}'.format(max(fps)))
print('GPU FPS: {: .2f}'.format(max(gpu_fps)))
else:
raise ValueError
macs, _ = model_profile(net, args.height, args.width, device)
flops = 2 * macs
try:
net.eval(profiling=True)
except TypeError:
net.eval()
params = sum(p.numel() for p in net.parameters())
print('FLOPs(G): {: .2f}'.format(flops / 1e9))
print('Number of parameters: {: .2f}'.format(params / 1e6))
print('Profiling, please clear your GPU memory before doing this.')

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: deeplabv2_cityscapes_256x512_20201225.pt
python main_semseg.py --train --config=configs/semantic_segmentation/deeplabv2/resnet101_cityscapes_256x512.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/deeplabv2/resnet101_cityscapes_256x512.py --mixed-precision

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: deeplabv2_cityscapes_256x512_fp32_20201227.pt
python main_semseg.py --train --config=configs/semantic_segmentation/deeplabv2/resnet101_cityscapes_256x512.py
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/deeplabv2/resnet101_cityscapes_256x512.py

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: deeplabv2_cityscapes_512x1024_20201219.pt
python main_semseg.py --train --config=configs/semantic_segmentation/deeplabv2/resnet101_cityscapes_512x1024.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/deeplabv2/resnet101_cityscapes_512x1024.py --mixed-precision

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: deeplabv2_gtav_512x1024_20201223.pt
python main_semseg.py --train --config=configs/semantic_segmentation/deeplabv2/resnet101_gtav_512x1024.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/deeplabv2/resnet101_gtav_512x1024.py --mixed-precision

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: deeplabv2_pascalvoc_321x321_20201108.pt
python main_semseg.py --train --config=configs/semantic_segmentation/deeplabv2/resnet101_pascalvoc_321x321.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/deeplabv2/resnet101_pascalvoc_321x321.py --mixed-precision

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: deeplabv2_synthia_512x1024_20201225.pt
python main_semseg.py --train --config=configs/semantic_segmentation/deeplabv2/resnet101_synthia_512x1024.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/deeplabv2/resnet101_synthia_512x1024.py --mixed-precision

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: deeplabv3_city_256x512_20201226.pt
python main_semseg.py --train --config=configs/semantic_segmentation/deeplabv3/resnet101_cityscapes_256x512.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/deeplabv3/resnet101_cityscapes_256x512.py --mixed-precision

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: deeplabv3_cityscapes_512x1024_20210322.pt
python main_semseg.py --train --config=configs/semantic_segmentation/deeplabv3/resnet101_cityscapes_512x1024.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/deeplabv3/resnet101_cityscapes_512x1024.py --mixed-precision

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: deeplabv3_voc_321x321_20201110.pt
python main_semseg.py --train --config=configs/semantic_segmentation/deeplabv3/resnet101_pascalvoc_321x321.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/deeplabv3/resnet101_pascalvoc_321x321.py --mixed-precision

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: enet_baseline_culane_20210312.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/enet_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/enet_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh enet_baseline_culane test checkpoints

View File

@@ -0,0 +1,7 @@
#!/bin/bash
# Trained weights: enet_baseline_tusimple_20210312.pt
python main_landet.py --train --config=configs/lane_detection/baseline/enet_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/enet_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh enet_baseline_tusimple test checkpoints

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# Trained weights: enet_cityscapes_512x1024_20210219.pt
# Step-1: Pre-train encoder
python main_semseg.py --train --config=configs/semantic_segmentation/enet/cityscapes_512x1024_encoder.py --mixed-precision
# Step-2: Train the entire network
python main_semseg.py --train --config=configs/semantic_segmentation/enet/cityscapes_512x1024.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/enet/cityscapes_512x1024.py --mixed-precision

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: erfnet_baseline_tusimple-aug_20210723.pt
# Training
python -m torch.distributed.launch --nproc_per_node=2 --use_env main_landet.py --train --config=configs/lane_detection/baseline/erfnet_tusimple_aug.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/erfnet_tusimple.py
# Testing with official scripts
./autotest_tusimple.sh erfnet_baseline_tusimple-aug test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: erfnet_baseline_culane_20210204.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/erfnet_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/erfnet_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh erfnet_baseline_culane test checkpoints

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# Trained weights: erfnet_baseline_llamas_20210625.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/erfnet_llamas.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --val --config=configs/lane_detection/baseline/erfnet_llamas.py --mixed-precision
# Testing with official scripts
./autotest_llamas.sh erfnet_baseline_llamas val checkpoints
# Predict lane points for the eval server, find results in ./output
python main_landet.py --test --config=configs/lane_detection/baseline/erfnet_llamas.py --mixed-precision

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: erfnet_baseline_tusimple_20210424.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/erfnet_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/erfnet_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh erfnet_baseline_tusimple test checkpoints

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: erfnet_cityscapes_512x1024_20200918.pt
python main_semseg.py --train --config=configs/semantic_segmentation/erfnet/cityscapes_512x1024.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/erfnet/cityscapes_512x1024.py --mixed-precision

View File

@@ -0,0 +1,7 @@
#!/bin/bash
# Training
python main_landet.py --train --config=configs/lane_detection/resa/erfnet_culane.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/resa/erfnet_culane.py
# Testing with official scripts
./autotest_culane.sh erfnet_resa_culane test checkpoints

View File

@@ -0,0 +1,7 @@
#!/bin/bash
# Training
python main_landet.py --train --config=configs/lane_detection/resa/erfnet_tusimple.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/resa/erfnet_tusimple.py
# Testing with official scripts
./autotest_tusimple.sh erfnet_resa_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: erfnet_scnn_tusimple-aug_20210723.pt
# Training
python -m torch.distributed.launch --nproc_per_node=2 --use_env main_landet.py --train --config=configs/lane_detection/scnn/erfnet_tusimple_aug.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/scnn/erfnet_tusimple.py
# Testing with official scripts
./autotest_tusimple.sh erfnet_scnn_tusimple-aug test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: erfnet_scnn_culane_20210206.pt
# Training
python main_landet.py --train --config=configs/lane_detection/scnn/erfnet_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/scnn/erfnet_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh erfnet_scnn_culane test checkpoints

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# Trained weights: erfnet_scnn_llamas_20210625.pt
# Training
python main_landet.py --train --config=configs/lane_detection/scnn/erfnet_llamas.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --val --config=configs/lane_detection/scnn/erfnet_llamas.py --mixed-precision
# Testing with official scripts
./autotest_llamas.sh erfnet_scnn_llamas val checkpoints
# Predict lane points for the eval server, find results in ./output
python main_landet.py --test --config=configs/lane_detection/scnn/erfnet_llamas.py --mixed-precision

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: erfnet_scnn_tusimple_20210202.pt
# Training
python main_landet.py --train --config=configs/lane_detection/scnn/erfnet_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/scnn/erfnet_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh erfnet_scnn_tusimple test checkpoints

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: fcn_cityscapes_256x512_20201226.pt
python main_semseg.py --train --config=configs/semantic_segmentation/fcn/resnet101_cityscapes_256x512.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/fcn/resnet101_cityscapes_256x512.py --mixed-precision

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: fcn_pascalvoc_321x321_20201111.pt
python main_semseg.py --train --config=configs/semantic_segmentation/fcn/resnet101_pascalvoc_321x321.py --mixed-precision
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/fcn/resnet101_pascalvoc_321x321.py --mixed-precision

View File

@@ -0,0 +1,6 @@
#!/bin/bash
# Trained weights: fcn_pascalvoc_321x321_fp32_20201111.pt
python main_semseg.py --train --config=configs/semantic_segmentation/fcn/resnet101_pascalvoc_321x321.py
# Val
python main_semseg.py --val --config=configs/semantic_segmentation/fcn/resnet101_pascalvoc_321x321.py

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: mobilenetv2_baseline_culane_20220209.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/mobilenetv2_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/mobilenetv2_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh mobilenetv2_baseline_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: mobilenetv2_baseline_tusimple_20220209.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/mobilenetv2_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/mobilenetv2_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh mobilenetv2_baseline_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: mobilenetv2_resa_culane_20220209.pt
# Training
python main_landet.py --train --config=configs/lane_detection/resa/mobilenetv2_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/resa/mobilenetv2_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh mobilenetv2_resa_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: mobilenetv2_resa_tusimple_20220209.pt
# Training
python main_landet.py --train --config=configs/lane_detection/resa/mobilenetv2_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/resa/mobilenetv2_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh mobilenetv2_resa_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: mobilenetv3-large_baseline_culane_20220209.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/mobilenetv3_large_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/mobilenetv3_large_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh mobilenetv3-large_baseline_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: mobilenetv3-large_baseline_tusimple_20220209.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/mobilenetv3_large_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/mobilenetv3_large_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh mobilenetv3-large_baseline_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: mobilenetv3-large_resa_culane_20220209.pt
# Training
python main_landet.py --train --config=configs/lane_detection/resa/mobilenetv3_large_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/resa/mobilenetv3_large_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh mobilenetv3-large_resa_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: mobilenetv3-large_resa_tusimple_20220209.pt
# Training
python main_landet.py --train --config=configs/lane_detection/resa/mobilenetv3_large_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/resa/mobilenetv3_large_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh mobilenetv3-large_resa_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: repvgg-a0_baseline_culane_20220112.pt
# Training
python -m torch.distributed.launch --nproc_per_node=2 --use_env main_landet.py --train --mixed-precision --config configs/lane_detection/baseline/repvgg_a0_culane.py
# Predicting lane points for testing
python main_landet.py --test --config configs/lane_detection/baseline/repvgg_a0_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh repvgg-a0_baseline_culane test

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: repvgg-a1_baseline_culane_20220112.pt
# Training
python -m torch.distributed.launch --nproc_per_node=2 --use_env main_landet.py --train --mixed-precision --config configs/lane_detection/baseline/repvgg_a1_culane.py
# Predicting lane points for testing
python main_landet.py --test --config configs/lane_detection/baseline/repvgg_a1_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh repvgg-a1_baseline_culane test

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: repvgg-a1_scnn_culane_20220112.pt
# Training
python -m torch.distributed.launch --nproc_per_node=2 --use_env main_landet.py --train --mixed-precision --config configs/lane_detection/scnn/repvgg_a1_culane.py
# Predicting lane points for testing
python main_landet.py --test --config configs/lane_detection/scnn/repvgg_a1_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh repvgg-a1_scnn_culane test

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: repvgg-b0_baseline_culane_20220112.pt
# Training
python -m torch.distributed.launch --nproc_per_node=2 --use_env main_landet.py --train --mixed-precision --config configs/lane_detection/baseline/repvgg_b0_culane.py
# Predicting lane points for testing
python main_landet.py --test --config configs/lane_detection/baseline/repvgg_b0_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh repvgg-b0_baseline_culane test

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: repvgg-b1g2_baseline_culane_20220112.pt
# Training
python -m torch.distributed.launch --nproc_per_node=2 --use_env main_landet.py --train --mixed-precision --config configs/lane_detection/baseline/repvgg_b1g2_culane.py
# Predicting lane points for testing
python main_landet.py --test --config configs/lane_detection/baseline/repvgg_b1g2_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh repvgg-b1g2_baseline_culane test

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: repvgg-b2_baseline_culane_20220112.pt
# Training
python -m torch.distributed.launch --nproc_per_node=2 --use_env main_landet.py --train --mixed-precision --config configs/lane_detection/baseline/repvgg_b2_culane.py
# Predicting lane points for testing
python main_landet.py --test --config configs/lane_detection/baseline/repvgg_b2_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh repvgg-b2_baseline_culane test

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet101_baseline_culane_20210312.pt
# Training, scale lr linearly on 11G GPU (square root scaling does not converge on this dataset)
python main_landet.py --train --config=configs/lane_detection/baseline/resnet101_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/resnet101_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh resnet101_baseline_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet101_baseline_tusimple_20210424.pt
# Training, scale lr by square root on 11G GPU
python main_landet.py --train --config=configs/lane_detection/baseline/resnet101_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/resnet101_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh resnet101_baseline_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet101_resa_culane_20211016.pt
# Training
python -m torch.distributed.launch --nproc_per_node=8 --use_env main_landet.py --train --config=configs/lane_detection/resa/resnet101_culane.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/resa/resnet101_culane.py
# Testing with official scripts
./autotest_culane.sh resnet101_resa_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet101_resa_tusimple_20211019.pt
# Training
python -m torch.distributed.launch --nproc_per_node=8 --use_env main_landet.py --train --config=configs/lane_detection/resa/resnet101_tusimple.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/resa/resnet101_tusimple.py
# Testing with official scripts
./autotest_tusimple.sh resnet101_resa_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet101_scnn_culane_20210314.pt
# Training, scale lr linearly on 11G GPU (square root scaling does not converge on this dataset)
python main_landet.py --train --config=configs/lane_detection/scnn/resnet101_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/scnn/resnet101_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh resnet101_scnn_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet101_scnn_tusimple_20210218.pt
# Training, scale lr by square root on 11G GPU
python main_landet.py --train --config=configs/lane_detection/scnn/resnet101_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/scnn/resnet101_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh resnet101_scnn_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18_baseline_culane_20210222.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/resnet18_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/resnet18_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh resnet18_baseline_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18_baseline_tusimple_20210215.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/resnet18_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/resnet18_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh resnet18_baseline_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18_bezierlanenet_culane-aug1b_20211109.pt
# Training
python main_landet.py --train --config=configs/lane_detection/bezierlanenet/resnet18_culane_aug1b.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/bezierlanenet/resnet18_culane_aug1b.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh resnet18_bezierlanenet_culane-aug1b test checkpoints

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# Trained weights: resnet18_bezierlanenet_llamas-aug1b_20211109.pt
# Training
python main_landet.py --train --config=configs/lane_detection/bezierlanenet/resnet18_llamas_aug1b.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --val --config=configs/lane_detection/bezierlanenet/resnet18_llamas_aug1b.py --mixed-precision
# Testing with official scripts
./autotest_llamas.sh resnet18_bezierlanenet_llamas-aug1b val checkpoints
# Predict lane points for the eval server, find results in ./output
python main_landet.py --test --config=configs/lane_detection/bezierlanenet/resnet18_llamas_aug1b.py --mixed-precision

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18_bezierlanenet_tusimple-aug1b_20211109.pt
# Training
python main_landet.py --train --config=configs/lane_detection/bezierlanenet/resnet18_tusimple_aug1b.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/bezierlanenet/resnet18_tusimple_aug1b.py
# Testing with official scripts
./autotest_tusimple.sh resnet18_bezierlanenet_tusimple-aug1b test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18_laneatt_culane_20220225.pt
# Training
python -m torch.distributed.launch --nproc_per_node=2 --use_env main_landet.py --train --config=configs/lane_detection/laneatt/resnet18_culane.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/laneatt/resnet18_culane.py
# Testing with official scripts
./autotest_culane.sh resnet18_laneatt_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18_resa_culane_20211016.pt
# Training
python -m torch.distributed.launch --nproc_per_node=4 --use_env main_landet.py --train --config=configs/lane_detection/resa/resnet18_culane.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/resa/resnet18_culane.py
# Testing with official scripts
./autotest_culane.sh resnet18_resa_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18_resa_tusimple_20211019.pt
# Training
python -m torch.distributed.launch --nproc_per_node=4 --use_env main_landet.py --train --config=configs/lane_detection/resa/resnet18_tusimple.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/resa/resnet18_tusimple.py
# Testing with official scripts
./autotest_tusimple.sh resnet18_resa_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18_scnn_culane_20210222.pt
# Training
python main_landet.py --train --config=configs/lane_detection/scnn/resnet18_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/scnn/resnet18_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh resnet18_scnn_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18_scnn_tusimple_20210424.pt
# Training
python main_landet.py --train --config=configs/lane_detection/scnn/resnet18_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/scnn/resnet18_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh resnet18_scnn_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18s_lstr-aug_culane_20210721.pt
# Training
python main_landet.py --train --config=configs/lane_detection/lstr/resnet18s_culane_aug.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/lstr/resnet18s_culane_aug.py
# Testing with official scripts
./autotest_culane.sh resnet18s_lstr-aug_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18s_lstr-aug_tusimple_20210629.pt
# Training
python main_landet.py --train --config=configs/lane_detection/lstr/resnet18s_tusimple_aug.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/lstr/resnet18s_tusimple_aug.py
# Testing with official scripts
./autotest_tusimple.sh resnet18s_lstr-aug_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18s_lstr_culane_20210722.pt
# Training
python main_landet.py --train --config=configs/lane_detection/lstr/resnet18s_culane.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/lstr/resnet18s_culane.py
# Testing with official scripts
./autotest_culane.sh resnet18s_lstr_culane test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet18s_lstr_tusimple_20210701.pt
# Training
python main_landet.py --train --config=configs/lane_detection/lstr/resnet18s_tusimple.py
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/lstr/resnet18s_tusimple.py
# Testing with official scripts
./autotest_tusimple.sh resnet18s_lstr_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet34_baseline-aug_tusimple_20210723.pt
# Training
python -m torch.distributed.launch --nproc_per_node=2 --use_env main_landet.py --train --config=configs/lane_detection/baseline/resnet34_tusimple_aug.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/resnet34_tusimple_aug.py --mixed-precision
# Testing with official scripts
./autotest_tusimple-aug.sh resnet34_baseline_tusimple-aug test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet34_baseline_culane_20210219.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/resnet34_culane.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/resnet34_culane.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh resnet34_baseline_culane test checkpoints

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# Trained weights: resnet34_baseline_llamas_20210625.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/resnet34_llamas.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --val --config=configs/lane_detection/baseline/resnet34_llamas.py --mixed-precision
# Testing with official scripts
./autotest_llamas.sh resnet34_baseline_llamas val checkpoints
# Predict lane points for the eval server, find results in ./output
python main_landet.py --test --config=configs/lane_detection/baseline/resnet34_llamas.py --mixed-precision

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet34_baseline_tusimple_20210424.pt
# Training
python main_landet.py --train --config=configs/lane_detection/baseline/resnet34_tusimple.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/baseline/resnet34_tusimple.py --mixed-precision
# Testing with official scripts
./autotest_tusimple.sh resnet34_baseline_tusimple test checkpoints

View File

@@ -0,0 +1,8 @@
#!/bin/bash
# Trained weights: resnet34_bezierlanenet_culane-aug1b_20211109.pt
# Training
python main_landet.py --train --config=configs/lane_detection/bezierlanenet/resnet34_culane_aug1b.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --test --config=configs/lane_detection/bezierlanenet/resnet34_culane_aug1b.py --mixed-precision
# Testing with official scripts
./autotest_culane.sh resnet34_bezierlanenet_culane-aug1b test checkpoints

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# Trained weights: resnet34_bezierlanenet_llamas-aug1b_20211109.pt
# Training
python main_landet.py --train --config=configs/lane_detection/bezierlanenet/resnet34_llamas_aug1b.py --mixed-precision
# Predicting lane points for testing
python main_landet.py --val --config=configs/lane_detection/bezierlanenet/resnet34_llamas_aug1b.py --mixed-precision
# Testing with official scripts
./autotest_llamas.sh resnet34_bezierlanenet_llamas-aug1b val checkpoints
# Predict lane points for the eval server, find results in ./output
python main_landet.py --test --config=configs/lane_detection/bezierlanenet/resnet34_llamas_aug1b.py --mixed-precision

Some files were not shown because too many files have changed in this diff Show More