├── src ├── LaneDetector32 ├── CameraInfo.conf ├── run.sh ├── CameraInfoOpt.ggo ├── main.hh ├── Makefile ├── mcv.hh ├── cmdline.ggo ├── Stoplines.conf ├── Lanes.conf ├── CameraInfoOpt.h ├── Lanes-mode2.conf ├── mcv.cc ├── InversePerspectiveMapping.hh ├── cmdline.h ├── ranker.h ├── main.cc ├── LaneDetectorOpt.ggo ├── InversePerspectiveMapping.cc ├── CameraInfoOpt.c └── cmdline.c ├── matlab ├── Stats.m ├── ccvCheckMergeSplines.m ├── ccvReadLaneDetectionResultsFile.m ├── ccvEvalBezSpline.m ├── ccvGetLaneDetectionStats.m └── ccvLabel.m └── README.txt /src/LaneDetector32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aranyadan/caltech-lane-detection/HEAD/src/LaneDetector32 -------------------------------------------------------------------------------- /src/CameraInfo.conf: -------------------------------------------------------------------------------- 1 | 2 | # focal length 3 | focalLengthX 309.4362 4 | focalLengthY 344.2161 5 | 6 | # optical center 7 | opticalCenterX 317.9034 8 | opticalCenterY 256.5352 9 | 10 | # height of the camera in mm 11 | cameraHeight 2179.8 # 393.7 + 1786.1 12 | 13 | # pitch of the camera 14 | pitch 14.0 15 | 16 | # yaw of the camera 17 | yaw 0.0 18 | 19 | # imag width and height 20 | imageWidth 640 21 | imageHeight 480 22 | -------------------------------------------------------------------------------- /matlab/Stats.m: -------------------------------------------------------------------------------- 1 | function Stats 2 | % STATS computes stats for the results of LaneDetector 3 | % 4 | % Inputs: 5 | % ------- 6 | % 7 | % Outputs: 8 | % -------- 9 | % 10 | 11 | % The detection files 12 | detectionFiles = { 13 | '../clips/cordova1/list.txt_results.txt' 14 | '../clips/cordova2/list.txt_results.txt' 15 | '../clips/washington1/list.txt_results.txt' 16 | '../clips/washington1/list.txt_results.txt' 17 | }; 18 | 19 | % The ground truth labels 20 | truthFiles = { 21 | '../clips/cordova1/labels.ccvl' 22 | '../clips/cordova2/labels.ccvl' 23 | '../clips/washington1/labels.ccvl' 24 | '../clips/washington1/labels.ccvl' 25 | }; 26 | 27 | % Get statistics 28 | ccvGetLaneDetectionStats(detectionFiles, truthFiles); 29 | -------------------------------------------------------------------------------- /src/run.sh: -------------------------------------------------------------------------------- 1 | # This file runs the lane detection binary on the four clips available 2 | # in the dataset 3 | 4 | # Author: Mohamed Aly 5 | # Date: 10/7/2010 6 | 7 | #clips to run 8 | path="../clips" 9 | clips="cordova1 cordova2 washington1 washington2" 10 | 11 | #get options 12 | options=" --show --save-lanes --wait=50 --lanes-conf=Lanes.conf \ 13 | --camera-conf=CameraInfo.conf " 14 | 15 | # suffix 16 | binary="./LaneDetector$(getconf LONG_BIT)" 17 | 18 | #run 19 | for clip in $clips; do 20 | echo "Running for $clip..." 21 | echo "------------------------------------------------------------------" 22 | echo 23 | 24 | # command 25 | command="$binary $options --list-file=$path/$clip/list.txt \ 26 | --list-path=$path/$clip/ --output-suffix=_results " 27 | echo $command 28 | 29 | # run 30 | $command 31 | done 32 | -------------------------------------------------------------------------------- /src/CameraInfoOpt.ggo: -------------------------------------------------------------------------------- 1 | #Parameters for camera info 2 | #command line: gengetopt -i cameraInfoOpt.ggo -F cameraInfoOpt \ 3 | # --func-name=cameraInfoParser --arg-struct-name=CameraInfoParserInfo \ 4 | # --conf-parser 5 | 6 | package "inversePerspectiveMapping" 7 | version "0.1" 8 | 9 | option "focalLengthX" - 10 | "Focal lenght in horizontal direction in pixels" double required 11 | option "focalLengthY" - 12 | "Focal lenght in vertical direction in pixels" double required 13 | option "opticalCenterX" - 14 | "X-coordinate of optical center in pixels" double required 15 | option "opticalCenterY" - 16 | "Y-coordinate of optical center in pixels" double required 17 | option "cameraHeight" - 18 | "Height of camera above ground in mm" double required 19 | option "pitch" - 20 | "pitch of camera in degrees (+ve downwards)" double required 21 | option "yaw" - 22 | "yaw of camera in degrees (+ve clockwise)" double required 23 | option "imageWidth" - 24 | "width of image in pixels" double required 25 | option "imageHeight" - 26 | "height of image in pixels" double required 27 | 28 | -------------------------------------------------------------------------------- /matlab/ccvCheckMergeSplines.m: -------------------------------------------------------------------------------- 1 | function merge = ccvCheckMergeSplines(spline1, spline2, meanDistThreshold, ... 2 | medianDistThreshold) 3 | % CCVCHECKMERGESPLINES checks if two splines are to be merged (matched) or 4 | % not. It does this by computing the distance from every point in each 5 | % spline to every other point in the other spline and checking that the mean 6 | % or median distances are below the given thresholds. 7 | % 8 | % Inputs: 9 | % ------- 10 | % spline2: Nx2 matrix of spline control points 11 | % spline2: Nx2 matrix of spline control points 12 | % meanDistThreshold: threshold for the mean distance between points on the 13 | % two splines 14 | % medianDistThreshold: threshold for median distance between points on the 15 | % two splines 16 | % 17 | % Outputs: 18 | % -------- 19 | % merge: 1 if to merge, 0 otherwise 20 | % 21 | 22 | %get points on both 23 | p1 = ccvEvalBezSpline(spline1, .01); 24 | p2 = ccvEvalBezSpline(spline2, .01); 25 | 26 | %now for every point in spline1, compute nearest in spline2, and get that 27 | %distance 28 | dist1 = zeros(1, size(p1,1)); 29 | for i=1:size(p1, 1) 30 | %get diff 31 | d = repmat(p1(i,:), size(p2, 1), 1) - p2; 32 | %get distance 33 | d = sqrt(sum(d.^2, 2)); 34 | %get min 35 | dist1(i) = min(d); 36 | end; 37 | dist2 = zeros(1, size(p2,1)); 38 | for i=1:size(p2, 1) 39 | %get diff 40 | d = repmat(p2(i,:), size(p1, 1), 1) - p1; 41 | %get distance 42 | d = sqrt(sum(d.^2, 2)); 43 | %get min 44 | dist2(i) = min(d); 45 | end; 46 | 47 | %compute mean and median 48 | meanDist = min(mean(dist1), mean(dist2)); 49 | medianDist = min(median(dist1), median(dist2)); 50 | 51 | merge = (meanDist <= meanDistThreshold) || (medianDist <= medianDistThreshold); 52 | -------------------------------------------------------------------------------- /src/main.hh: -------------------------------------------------------------------------------- 1 | /** 2 | * \file main.hh 3 | * \author Mohamed Aly 4 | * \date Wed Oct 6, 2010 5 | * 6 | */ 7 | 8 | #ifndef LANE_DETECTOR_HH 9 | #define LANE_DETECTOR_HH 10 | 11 | #include "mcv.hh" 12 | #include "InversePerspectiveMapping.hh" 13 | #include "LaneDetector.hh" 14 | #include "cmdline.h" 15 | 16 | #include 17 | #include 18 | 19 | using namespace std; 20 | 21 | namespace LaneDetector 22 | { 23 | 24 | /** 25 | * This function processes an input image and detects lanes/stoplines 26 | * based on the passed in command line arguments 27 | * 28 | * \param filename the input file name 29 | * \param cameraInfo the camera calibration info 30 | * \param lanesConf the lane detection settings 31 | * \param stoplinesConf the stop line detection settings 32 | * \param options the command line arguments 33 | * \param outputFile the output file stream to write output lanes to 34 | * \param index the image index (used for saving output files) 35 | * \param elapsedTime if NOT NULL, it is accumulated with clock ticks for 36 | * the detection operation 37 | */ 38 | void ProcessImage(const char* filename, CameraInfo& cameraInfo, 39 | LaneDetectorConf& lanesConf, LaneDetectorConf& stoplinesConf, 40 | gengetopt_args_info& options, ofstream* outputFile = NULL, 41 | int index = 0, clock_t *elapsedTime = NULL); 42 | 43 | /** 44 | * This function reads lines from the input file into a vector of strings 45 | * 46 | * \param filename the input file name 47 | * \param lines the output vector of lines 48 | */ 49 | bool ReadLines(const char* filename, vector *lines); 50 | 51 | } // namespace LaneDetector 52 | 53 | #endif //define LANE_DETECTOR_HH 54 | 55 | -------------------------------------------------------------------------------- /matlab/ccvReadLaneDetectionResultsFile.m: -------------------------------------------------------------------------------- 1 | function [frames] = ccvReadLaneDetectionResultsFile(filename) 2 | % CCVREADLANEDETECTIONRESULTSFILE reads a results file from the binary 3 | % LaneDetector saved with --save-lanes flag 4 | % 5 | % INPUTS 6 | % ------ 7 | % filename - the input results file 8 | % 9 | % OUTPUTS 10 | % ------- 11 | % frames - the output structure array, one per frame (image) with fields 12 | % .id - the frame id 13 | % .splines - the splines cell array 14 | % .numSplines - the number of splines 15 | % .scores - the scores of the splines 16 | % 17 | % See also 18 | % 19 | 20 | %open file 21 | file = fopen(filename, 'r'); 22 | 23 | %loop on file and read data 24 | frames = []; 25 | while 1 26 | %read frame 27 | d = fscanf(file, 'frame#%08d has %d splines\n', 2); 28 | %if no frames, then exit 29 | if isempty(d), break; end; 30 | 31 | %get id and number of splines 32 | id = d(1); 33 | numSplines = d(2); 34 | 35 | %now loop for this amount 36 | frame = []; 37 | splines = {}; 38 | scores = []; 39 | for i=1:numSplines 40 | %get header 41 | d = fscanf(file, '\tspline#%d has %d points and score %f\n'); 42 | if isempty(d), continue; end; 43 | scores = [scores, d(3)]; 44 | 45 | %get spline points 46 | d = fscanf(file, '\t\t%f, %f\n'); 47 | if isempty(d), continue, end; 48 | spline = reshape(d, 2, [])'; 49 | 50 | %put spline 51 | splines = [splines, spline]; 52 | end; 53 | 54 | %put frame 55 | frame.id = id; 56 | frame.splines = splines; 57 | frame.numSplines = length(splines); 58 | frame.scores = scores; 59 | frames = [frames, frame]; 60 | 61 | end; 62 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Make file for LaneDetector 3 | # 4 | 5 | # Author: Mohamed Aly 6 | # Date: 10/7/2010 7 | 8 | OCVFLAGS = `pkg-config --cflags opencv` 9 | OCVLIBS = `pkg-config --libs opencv` -lstdc++ 10 | 11 | CPP = g++ 12 | 13 | # type of system? 14 | LBITS = $(shell getconf LONG_BIT) 15 | ifeq ($(LBITS),64) 16 | # do 64 bit stuff here, like set some CFLAGS 17 | SFX = 64 18 | else 19 | SFX = 32 20 | endif 21 | 22 | # Add stop-line detection 23 | SRCS += CameraInfoOpt.c LaneDetectorOpt.c cmdline.c LaneDetector.cc \ 24 | InversePerspectiveMapping.cc mcv.cc main.cc 25 | OBJECTS += CameraInfoOpt.o LaneDetectorOpt.o cmdline.o \ 26 | LaneDetector.o InversePerspectiveMapping.o mcv.o \ 27 | main.o 28 | CFLAGS += $(OCVFLAGS) 29 | LIBS += $(OCVLIBS) 30 | BINARY = LaneDetector$(SFX) 31 | 32 | all: release 33 | 34 | release: $(OBJECTS) 35 | $(CPP) $^ $(LDFLAGS) $(LIBS) $(CFLAGS) -O3 -o $(BINARY) 36 | 37 | debug: $(OBJECTS) 38 | $(CPP) $^ $(LDFLAGS) $(LIBS) $(CFLAGS) -g -O0 -o $(BINARY) 39 | 40 | # Generate getopts header 41 | LaneDetectorOpt.h: LaneDetectorOpt.ggo 42 | gengetopt -i LaneDetectorOpt.ggo --conf-parser -F LaneDetectorOpt \ 43 | --func-name=LaneDetectorParser --arg-struct-name=LaneDetectorParserInfo 44 | 45 | #get opts for cameraInfo and stopLinePerceptor 46 | cameraInfoOpt.h: cameraInfoOpt.ggo 47 | gengetopt -i cameraInfoOpt.ggo -F cameraInfoOpt \ 48 | --func-name=cameraInfoParser \ 49 | --arg-struct-name=CameraInfoParserInfo \ 50 | --conf-parser 51 | 52 | cmdline.h: cmdline.ggo 53 | gengetopt -i cmdline.ggo -u --conf-parser 54 | 55 | clean: 56 | rm -f *.a $(OBJECTS) $(BINARY) 57 | 58 | .cc.o: 59 | g++ $< $(CFLAGS) $(LIBS) $(LDFLAGS) -c -o $@ 60 | 61 | # headers and sources 62 | .hh.cc: 63 | .h.c: 64 | 65 | # generating gengetopt headers 66 | cmdline.o: cmdline.h 67 | CameraInfoOpt.o: CameraInfoOpt.h 68 | LaneDetectorOpt.o: LaneDetectorOpt.h 69 | -------------------------------------------------------------------------------- /src/mcv.hh: -------------------------------------------------------------------------------- 1 | /*** 2 | * \file mcv.hh 3 | * \author Mohamed Aly 4 | * \date 11/29/2006 5 | */ 6 | 7 | #ifndef MCV_HH_ 8 | #define MCV_HH_ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | using namespace std; 16 | 17 | namespace LaneDetector 18 | { 19 | 20 | //constant definitions 21 | #define FLOAT_MAT_TYPE CV_32FC1 22 | #define FLOAT_MAT_ELEM_TYPE float 23 | 24 | #define INT_MAT_TYPE CV_8UC1 25 | #define INT_MAT_ELEM_TYPE unsigned char 26 | 27 | #define FLOAT_IMAGE_TYPE IPL_DEPTH_32F 28 | #define FLOAT_IMAGE_ELEM_TYPE float 29 | 30 | #define INT_IMAGE_TYPE IPL_DEPTH_8U 31 | #define INT_IMAGE_ELEM_TYPE unsigned char 32 | 33 | #define FLOAT_POINT2D CvPoint2D32f 34 | #define FLOAT_POINT2D_F cvPoint2D632f 35 | 36 | #define FLOAT float 37 | #define INT int 38 | #define SHORT_INT unsigned char 39 | 40 | //some helper functions for debugging 41 | void SHOW_MAT(const CvMat *pmat, char str[]="Matrix"); 42 | 43 | void SHOT_MAT_TYPE(const CvMat *pmat); 44 | 45 | void SHOW_IMAGE(const CvMat *pmat, const char str[]="Window", int wait=0); 46 | void SHOW_IMAGE(const IplImage *pmat, char str[]="Window"); 47 | 48 | void SHOW_POINT(const FLOAT_POINT2D pt, char str[]="Point:"); 49 | 50 | void SHOW_RECT(const CvRect rect, char str[]="Rect:"); 51 | 52 | /** 53 | * This function reads in an image from file and returns the original color 54 | * image and the first (red) channel scaled to [0 .. 1] with float type. The 55 | * images are allocated inside the function, so you will need to deallocate 56 | * them 57 | * 58 | * \param filename the input file name 59 | * \param clrImage the raw input image 60 | * \param channelImage the first channel 61 | */ 62 | void mcvLoadImage(const char *filename, CvMat **clrImage, CvMat** channelImage); 63 | 64 | 65 | /** 66 | * This function scales the input image to have values 0->1 67 | * 68 | * \param inImage the input image 69 | * \param outImage hte output iamge 70 | */ 71 | void mcvScaleMat(const CvMat *inImage, CvMat *outMat); 72 | 73 | /** 74 | * This function creates a double matrix from an input vector 75 | * 76 | * \param vec the input vector 77 | * \param mat the output matrix (column vector) 78 | * 79 | */ 80 | template 81 | CvMat* mcvVector2Mat(const vector &vec); 82 | 83 | } // namespace LaneDetector 84 | 85 | #endif /*MCV_HH_*/ 86 | -------------------------------------------------------------------------------- /src/cmdline.ggo: -------------------------------------------------------------------------------- 1 | 2 | # Command-line options (use gengetopt to generate C the source code) 3 | 4 | package "LinePerceptor" 5 | purpose "Detects lanes in street images." 6 | version "1.0" 7 | 8 | #------------------------------------------------------------------------- 9 | section "Basic options" 10 | #------------------------------------------------------------------------- 11 | 12 | option "lanes-conf" - 13 | "Configuration file for lane detection" string default ="Lanes.conf" 14 | optional 15 | 16 | option "stoplines-conf" - 17 | "Configuration file for stopline detection" string default="StopLines.conf" 18 | optional 19 | 20 | option "no-stoplines" - 21 | "Don't detect stop lines" flag on 22 | 23 | option "no-lanes" - 24 | "Don't detect lanes" flag off 25 | 26 | option "camera-conf" - 27 | "Configuration file for the camera paramters" string 28 | default="CameraInfo.conf" optional 29 | 30 | option "list-file" - 31 | "Text file containing a list of images one per line" string optional 32 | 33 | option "list-path" - 34 | "Path where the image files are located, this is just appended at the front of each line in --list-file" 35 | default="" string optional 36 | 37 | option "image-file" - 38 | "The path to an image" string optional 39 | 40 | 41 | #------------------------------------------------------------------------- 42 | section "Debugging options" 43 | #------------------------------------------------------------------------- 44 | 45 | option "wait" - "Number of milliseconds to show the detected lanes. Put 0 for infinite i.e. waits for keypress." int 46 | default="0" optional 47 | 48 | option "show" - 49 | "Show the detected lines" flag off 50 | 51 | option "step" - 52 | "Step through each image (needs a keypress) or fall through (waits for --wait msecs)" flag off 53 | 54 | option "show-lane-numbers" - 55 | "Show the lane numbers on the output image" flag off 56 | 57 | option "output-suffix" - 58 | "Suffix of images and results" string default="_results" optional 59 | 60 | option "save-images" - 61 | "Export all images with detected lanes to the by appending --output-suffix + '.png' to each input image" 62 | flag off 63 | 64 | option "save-lanes" - 65 | "Export all detected lanes to a text file by appending --output-suffix + '.txt' to --list-file" flag off 66 | 67 | option "debug" - 68 | "Show debugging information and images" flag off 69 | -------------------------------------------------------------------------------- /matlab/ccvEvalBezSpline.m: -------------------------------------------------------------------------------- 1 | function [outPoints, tangent] = ccvEvalBezSpline(spline, h) 2 | % ccvEvalBezSpline evaluates a Bezier spline with the specified degree 3 | 4 | % INPUTS 5 | % ------ 6 | % spline - input 3 or 4 points in a matrix 3x2 or 4x2 [xs, ys] 7 | % h - [0.05] the interval to use for evaluation 8 | % 9 | % OUTPUTS 10 | % ------- 11 | % outPoints - output points nx2 [xs; ys] 12 | % tangent - the tangent at the two end-points [t0; t1] 13 | % 14 | % EXAMPLE 15 | % ------- 16 | % [p, t] = ccvEvalBezSpline(sp, 0.1); 17 | % 18 | % See also ccvDrawBezSpline 19 | 20 | if nargin<2, h = 0.05; end 21 | 22 | %get the degree 23 | degree = size(spline, 1) - 1; 24 | 25 | %compute number of return points 26 | n = floor(1/h)+1; 27 | 28 | %degree 29 | switch degree 30 | %Quadratic Bezier curve 31 | case 2 32 | M = [1, -2, 1; ... 33 | -2, 2, 0; ... 34 | 1, 0, 0]; 35 | 36 | %compute constants [a, b, c] 37 | abcd = M * spline; 38 | a = abcd(1,:); b = abcd(2,:); c = abcd(3,:); 39 | 40 | %compute at time 0 41 | P = c; 42 | dP = b * h + a * h^2; 43 | ddP = 2*a*h^2; 44 | 45 | %loop 46 | outPoints = zeros(n, size(spline,2)); 47 | outPoints(1,:) = P; 48 | for i=2:n 49 | %calculate new point 50 | P = P + dP; 51 | %update steps 52 | dP = dP + ddP; 53 | %put back 54 | outPoints(i,:) = P; 55 | end; 56 | 57 | %tangents: t0 = b 58 | t0 = b; 59 | %t1 = 2a+b 60 | t1 = 2*a+b; 61 | 62 | %Cubic Bezier curve 63 | case 3 64 | M = [-1, 3, -3, 1; ... 65 | 3, -6, 3, 0; ... 66 | -3, 3, 0, 0; ... 67 | 1, 0, 0, 0]; 68 | 69 | %compute constants [a, b, c, d] 70 | abcd = M * spline; 71 | a = abcd(1,:); b = abcd(2,:); c = abcd(3,:); d = abcd(4,:); 72 | 73 | %compute at time 0 74 | P = d; 75 | dP = c*h + b * h^2 + a * h^3; 76 | ddP = 2*b*h^2 + 6*a*h^3; 77 | dddP = 6*a*h^3; 78 | 79 | %loop 80 | outPoints = zeros(n, size(spline,2)); 81 | outPoints(1,:) = P; 82 | for i=2:n 83 | %calculate new point 84 | P = P + dP; 85 | %update steps 86 | dP = dP + ddP; 87 | ddP = ddP + dddP; 88 | %put back 89 | outPoints(i,:) = P; 90 | end; 91 | 92 | %tangents: t0 = c 93 | t0 = c; 94 | %t1 = 3a+2*b+c 95 | t1 = 3*a+2*b+c; 96 | end; 97 | 98 | %put tangents together 99 | tangent = [t0; t1]; 100 | 101 | -------------------------------------------------------------------------------- /src/Stoplines.conf: -------------------------------------------------------------------------------- 1 | #settings for stop line perceptor 2 | 3 | #128 4 | ipmWidth = 160 5 | #96 6 | ipmHeight = 120 7 | ipmLeft = 85 8 | ipmRight = 550 9 | ipmTop = 50 10 | ipmBottom = 380 #350 #300 for latest St-lukes data 11 | 12 | #0 bilinear, 1: NN 13 | ipmInterpolation = 0 14 | 15 | ipmVpPortion = .2#.075#0.1 #.05 16 | 17 | 18 | lineWidth = 2000 19 | lineHeight = 304.8 20 | 21 | kernelWidth = 2 22 | kernelHeight = 2 23 | 24 | lowerQuantile = .975#.98#0.975 #0.98 #0.985 25 | 26 | localMaxima = 1 27 | 28 | #grouping type: 0 for HV lines, and 1 for Hough lines 29 | groupingType = 1#0#0#1#0 30 | 31 | binarize = 0 #0 32 | 33 | #0.0015 for outdoor scenes 34 | #in the shop, it deosn't make sense, as there's no flat road ahead :) 35 | # threshold: (~0.004) ~.15 for HV lines 36 | # (~1) ~.4 for Hough 37 | #3-11: ~2 for Hough, 38 | #4-13: ~.8 39 | detectionThreshold = 1#.5#3.5#2 #.15 #.4#.15#.0008#0#.008#2 #0.004#0.005#0.0015#0.012#0.025 40 | 41 | smoothScores = 0#1 42 | 43 | ##Hough Transform settings 44 | rMin = 0#0 45 | rMax = 120#120 46 | rStep = 3#3#1 47 | thetaMin = 80#80#85 48 | thetaMax = 100#100#95 49 | thetaStep = 1#2#1 50 | 51 | 52 | getEndPoints = 0 53 | 54 | group = 1 55 | groupThreshold = 15 56 | 57 | #RANSAC options 58 | ransac = 1 59 | 60 | ransacLineNumSamples = 5 61 | ransacLineNumIterations = 10 62 | ransacLineNumGoodFit = 10 63 | ransacLineThreshold = .4#.2 64 | ransacLineScoreThreshold = .4#.25#.3 65 | #.25 for LF Stluke 7-10 66 | ransacLineBinarize = 0 67 | ransacLineWindow = 15 68 | 69 | ransacSplineNumSamples = 5 70 | ransacSplineNumIterations = 10 71 | ransacSplineNumGoodFit = 10 72 | ransacSplineThreshold = .4#.2 73 | ransacSplineScoreThreshold = .4#.25#.3 74 | #.25 for LF Stluke 7-10 75 | ransacSplineBinarize = 0 76 | ransacSplineWindow = 15 77 | 78 | ransacSpline = 0 79 | ransacSplineDegree = 2 80 | ransacLine = 1 81 | 82 | ransacSplineStep = .1 83 | 84 | #spline scores 85 | splineScoreJitter = 2 86 | splineScoreLengthRatio = .5 87 | splineScoreAngleRatio = .8 88 | splineScoreStep = .1 89 | 90 | #grouping of bounding boxes 91 | overlapThreshold = 0.5 92 | 93 | #localization of points 94 | localizeAngleThreshold = .7 95 | localizeNumLinePixels = 20 96 | 97 | 98 | #extension of points 99 | extendAngleThreshold = .7 100 | extendMeanDirAngleThreshold = .7 101 | extendLinePixelsTangent = 5 102 | extendLinePixelsNormal = 20 103 | extendContThreshold = .1 104 | extendDeviationThreshold = 2 105 | extendRectTop = 200 106 | extendRectBottom = 380 107 | 108 | extendIPMAngleThreshold = .9 109 | extendIPMMeanDirAngleThreshold = .86 #.86 #.7 110 | extendIPMLinePixelsTangent = 5 #10 #5 111 | extendIPMLinePixelsNormal = 10 112 | extendIPMContThreshold = .1 #.35 #.3 #.25 #.25 #.2 #.1 113 | extendIPMDeviationThreshold = 2 #1 #2 114 | extendIPMRectTop = 0 115 | extendIPMRectBottom = 380 116 | 117 | 118 | #tracking 119 | splineTrackingNumAbsentFrames = 3 120 | splineTrackingNumSeenFrames = 5 121 | 122 | #spline merging 123 | mergeSplineThetaThreshold = .7#523 #30 deg 124 | mergeSplineRThreshold = 30#15 125 | mergeSplineMeanThetaThreshold = .7#523 #30 deg 126 | mergeSplineMeanRThreshold = 30#15 127 | mergeSplineCentroidThreshold = 100 #50 128 | 129 | 130 | #line tracking 131 | lineTrackingNumAbsentFrames = 3 132 | lineTrackingNumSeenFrames = 5 133 | 134 | #spline merging 135 | mergeLineThetaThreshold = .2#.3#52 #30 deg 136 | mergeLineRThreshold = 30#15 137 | 138 | numStrips = 1 139 | 140 | checkSplines = 0 141 | checkSplinesCurvenessThreshold = .93 142 | checkSplinesLengthThreshold = 30 143 | checkSplinesThetaDiffThreshold = .1 144 | checkSplinesThetaThreshold = 1.22 #70 deg 145 | 146 | checkIPMSplines = 0 147 | checkIPMSplinesCurvenessThreshold = .85 148 | checkIPMSplinesLengthThreshold = 30 149 | checkIPMSplinesThetaDiffThreshold = .1 150 | checkIPMSplinesThetaThreshold = 1.4 #1.4->80deg 1.22->70deg 151 | 152 | 153 | finalSplineScoreThreshold = 0 154 | 155 | useGroundPlane = 1 156 | 157 | checkColor = 0 158 | checkColorWindow = 3 159 | checkColorNumBins = 16 160 | checkColorNumYellowMin = .5 161 | checkColorRGMin = 1 162 | checkColorRGMax = 40 163 | checkColorGBMin = 15 164 | checkColorRBMin = 25 165 | checkColorRBFThreshold = -.05 166 | checkColorRBF = 1 167 | 168 | ipmWindowClear = 0 169 | ipmWindowLeft = 50 #60 170 | ipmWindowRight = 110 #100 171 | 172 | checkLaneWidth = 0 173 | checkLaneWidthMean = 25 174 | checkLaneWidthStd = 5 #10 -------------------------------------------------------------------------------- /src/Lanes.conf: -------------------------------------------------------------------------------- 1 | #settings for stop line perceptor 2 | 3 | #128 4 | ipmWidth = 160 #160#320#160 5 | #96 6 | ipmHeight = 120 #120#240#120 7 | 8 | ipmLeft = 100 #80 #90 #115 #140 #50 #85 #100 #85 9 | ipmRight = 460 #500 #530 #500 #590 #550 10 | ipmTop = 220 #220 #200 #50 11 | ipmBottom = 350 #360 #350 #380 12 | 13 | #0 bilinear, 1: NN 14 | ipmInterpolation = 0 15 | 16 | ipmVpPortion = 0 #.09 #0.06 #.05 #.125 #.2 #.15 #.075#0.1 #.05 17 | 18 | lineWidth = 2000 19 | lineHeight = 304.8 20 | 21 | kernelWidth = 2 22 | kernelHeight = 2 23 | 24 | #changed to detect center broken lines .98 25 | lowerQuantile = .975 #.975 #.98 #.985 #.99 #.985#.99#.98#.99#.98#0.975 #0.98 #0.985 26 | 27 | localMaxima = 1 28 | 29 | #grouping type: 0 for HV lines, and 1 for Hough lines 30 | groupingType = 0#1#0#1#0 31 | 32 | #center broken lines: 1 33 | binarize = 0 #1#0#1 #0 34 | 35 | #cetner broken lines 4 36 | detectionThreshold = 4 #2 #2 #4 #5 #6 #5 #7 #10 #.5 #4 #5 #2#0.4#0.6#.8#30#1.8#30#3.5#2 #.15 #.4#.15#.0008#0#.008#2 #0.004#0.005#0.0015#0.012#0.025 37 | 38 | smoothScores = 1 #0#0#1 39 | 40 | ##Hough Transform settings 41 | rMin = 10#0 42 | rMax = 150#300#150#120 43 | rStep = 2#2#3#1 44 | thetaMin = -45#-30#-20#-40#80#85 45 | thetaMax = 45#30#20#40#100#95 46 | thetaStep = 2#3#2#1 47 | 48 | 49 | getEndPoints = 0 50 | 51 | group = 1 52 | groupThreshold = 10 #15 #20#25#20#15 53 | 54 | #RANSAC options 55 | ransac = 1 56 | 57 | ransacLineNumSamples = 4 58 | ransacLineNumIterations = 40 #25 #40 #50 59 | ransacLineNumGoodFit = 10 #15#10 60 | ransacLineThreshold = .2 61 | ransacLineScoreThreshold = 0 #4 #6#4#2.5#5#1#1.5#1.5#3#1.5#3 #20 without smoothing and with binarizing 62 | #15 with smoothing and with binarizing: lines 63 | #1.5 without binarizing or smoothing: lines 64 | #splines: 3 wihtout binarizing or smoothing 65 | #splines: 5 with spline length in score 66 | ransacLineBinarize = 0 67 | ransacLineWindow = 15 #8 #15 68 | 69 | ransacSplineNumSamples = 4 70 | ransacSplineNumIterations = 40 #50 71 | ransacSplineNumGoodFit = 10 #15#10 72 | ransacSplineThreshold = .2 73 | ransacSplineScoreThreshold = 0 #4 #6#4#2.5#5#1#1.5#1.5#3#1.5#3 #20 without smoothing and with binarizing 74 | #15 with smoothing and with binarizing: lines 75 | #1.5 without binarizing or smoothing: lines 76 | #splines: 3 wihtout binarizing or smoothing 77 | #splines: 5 with spline length in score 78 | ransacSplineBinarize = 0 79 | ransacSplineWindow = 10 #15 #8 #15 80 | 81 | ransacSpline = 1 82 | ransacSplineDegree = 3#2#3 83 | ransacLine = 1 #1 84 | 85 | ransacSplineStep = .1 86 | 87 | #spline scores 88 | splineScoreJitter = 2 #2 #2 89 | splineScoreLengthRatio = 1.5 #1.5 #1.2 #1 #.4 #0.6 #.5 90 | splineScoreAngleRatio = 1.2 #1.2 #1.7 #1.5 #1 #.9 #0.8 #.8 91 | splineScoreStep = .01 #.02 92 | 93 | #grouping of bounding boxes 94 | overlapThreshold = .3 #0.5 95 | 96 | #localization of points 97 | localizeAngleThreshold = .9 #.7#.7 98 | localizeNumLinePixels = 20 99 | 100 | 101 | #extension of points 102 | extendAngleThreshold = .86 #.7 103 | extendMeanDirAngleThreshold = .95 #.86 #.86 #.7 104 | extendLinePixelsTangent = 10 #5 105 | extendLinePixelsNormal = 20 106 | extendContThreshold = .35 #.3 #.25 #.25 #.2 #.1 107 | extendDeviationThreshold = 2 #1 #2 108 | extendRectTop = 200 109 | extendRectBottom = 380 110 | 111 | extendIPMAngleThreshold = .95 #.9 112 | extendIPMMeanDirAngleThreshold = .86 #.86 #.7 113 | extendIPMLinePixelsTangent = 5 #10 #5 114 | extendIPMLinePixelsNormal = 10 115 | extendIPMContThreshold = .05 #0# .05 #.1 #.35 #.3 #.25 #.25 #.2 #.1 116 | extendIPMDeviationThreshold = 2 #1 #2 117 | extendIPMRectTop = 0 118 | extendIPMRectBottom = 118 119 | 120 | 121 | #tracking 122 | splineTrackingNumAbsentFrames = 3 123 | splineTrackingNumSeenFrames = 5 124 | 125 | #spline merging 126 | mergeSplineThetaThreshold = .3 #52 #30 deg 127 | mergeSplineRThreshold = 15 128 | mergeSplineMeanThetaThreshold = .2#52 #30 deg 129 | mergeSplineMeanRThreshold = 20#15 130 | mergeSplineCentroidThreshold = 80 #50 131 | 132 | #line tracking 133 | lineTrackingNumAbsentFrames = 2 #3 134 | lineTrackingNumSeenFrames = 3 #5 135 | 136 | #spline merging 137 | mergeLineThetaThreshold = .3#52 #30 deg 138 | mergeLineRThreshold = 15 139 | 140 | numStrips = 1 141 | 142 | checkSplines = 1 143 | checkSplinesCurvenessThreshold = .80 #.9 #.93 144 | checkSplinesLengthThreshold = 30 145 | checkSplinesThetaDiffThreshold = .1 146 | checkSplinesThetaThreshold = 1.22 #70 deg 147 | 148 | checkIPMSplines = 1 149 | checkIPMSplinesCurvenessThreshold = .8 #.85 150 | checkIPMSplinesLengthThreshold = 30 151 | checkIPMSplinesThetaDiffThreshold = .1 152 | checkIPMSplinesThetaThreshold = 1.22 #1.4 #1.4->80deg 1.22->70deg 153 | 154 | finalSplineScoreThreshold = 0 155 | 156 | useGroundPlane = 0 157 | 158 | checkColor = 0 159 | checkColorWindow = 3 160 | checkColorNumBins = 16 161 | checkColorNumYellowMin = .3 162 | checkColorRGMin = 1 163 | checkColorRGMax = 40 164 | checkColorGBMin = 10 #15 165 | checkColorRBMin = 25 166 | checkColorRBFThreshold = -.1 167 | checkColorRBF = 1 168 | 169 | ipmWindowClear = 0 170 | ipmWindowLeft = 50 #60 171 | ipmWindowRight = 110 #100 172 | 173 | checkLaneWidth = 0 174 | checkLaneWidthMean = 25 175 | checkLaneWidthStd = 5 #10 176 | -------------------------------------------------------------------------------- /src/CameraInfoOpt.h: -------------------------------------------------------------------------------- 1 | /* cameraInfoOpt.h */ 2 | 3 | /* File autogenerated by gengetopt version 2.18 */ 4 | 5 | #ifndef CAMERAINFOOPT_H 6 | #define CAMERAINFOOPT_H 7 | 8 | /* If we use autoconf. */ 9 | #ifdef HAVE_CONFIG_H 10 | #include "config.h" 11 | #endif 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif /* __cplusplus */ 16 | 17 | #ifndef CAMERAINFOPARSER_PACKAGE 18 | #define CAMERAINFOPARSER_PACKAGE "inversePerspectiveMapping" 19 | #endif 20 | 21 | #ifndef CAMERAINFOPARSER_VERSION 22 | #define CAMERAINFOPARSER_VERSION "0.1" 23 | #endif 24 | 25 | struct CameraInfoParserInfo 26 | { 27 | const char *help_help; /* Print help and exit help description. */ 28 | const char *version_help; /* Print version and exit help description. */ 29 | double focalLengthX_arg; /* Focal lenght in horizontal direction in pixels. */ 30 | char * focalLengthX_orig; /* Focal lenght in horizontal direction in pixels original value given at command line. */ 31 | const char *focalLengthX_help; /* Focal lenght in horizontal direction in pixels help description. */ 32 | double focalLengthY_arg; /* Focal lenght in vertical direction in pixels. */ 33 | char * focalLengthY_orig; /* Focal lenght in vertical direction in pixels original value given at command line. */ 34 | const char *focalLengthY_help; /* Focal lenght in vertical direction in pixels help description. */ 35 | double opticalCenterX_arg; /* X-coordinate of optical center in pixels. */ 36 | char * opticalCenterX_orig; /* X-coordinate of optical center in pixels original value given at command line. */ 37 | const char *opticalCenterX_help; /* X-coordinate of optical center in pixels help description. */ 38 | double opticalCenterY_arg; /* Y-coordinate of optical center in pixels. */ 39 | char * opticalCenterY_orig; /* Y-coordinate of optical center in pixels original value given at command line. */ 40 | const char *opticalCenterY_help; /* Y-coordinate of optical center in pixels help description. */ 41 | double cameraHeight_arg; /* Height of camera above ground in mm. */ 42 | char * cameraHeight_orig; /* Height of camera above ground in mm original value given at command line. */ 43 | const char *cameraHeight_help; /* Height of camera above ground in mm help description. */ 44 | double pitch_arg; /* pitch of camera in degrees (+ve downwards). */ 45 | char * pitch_orig; /* pitch of camera in degrees (+ve downwards) original value given at command line. */ 46 | const char *pitch_help; /* pitch of camera in degrees (+ve downwards) help description. */ 47 | double yaw_arg; /* yaw of camera in degrees (+ve clockwise). */ 48 | char * yaw_orig; /* yaw of camera in degrees (+ve clockwise) original value given at command line. */ 49 | const char *yaw_help; /* yaw of camera in degrees (+ve clockwise) help description. */ 50 | double imageWidth_arg; /* width of image in pixels. */ 51 | char * imageWidth_orig; /* width of image in pixels original value given at command line. */ 52 | const char *imageWidth_help; /* width of image in pixels help description. */ 53 | double imageHeight_arg; /* height of image in pixels. */ 54 | char * imageHeight_orig; /* height of image in pixels original value given at command line. */ 55 | const char *imageHeight_help; /* height of image in pixels help description. */ 56 | 57 | int help_given ; /* Whether help was given. */ 58 | int version_given ; /* Whether version was given. */ 59 | int focalLengthX_given ; /* Whether focalLengthX was given. */ 60 | int focalLengthY_given ; /* Whether focalLengthY was given. */ 61 | int opticalCenterX_given ; /* Whether opticalCenterX was given. */ 62 | int opticalCenterY_given ; /* Whether opticalCenterY was given. */ 63 | int cameraHeight_given ; /* Whether cameraHeight was given. */ 64 | int pitch_given ; /* Whether pitch was given. */ 65 | int yaw_given ; /* Whether yaw was given. */ 66 | int imageWidth_given ; /* Whether imageWidth was given. */ 67 | int imageHeight_given ; /* Whether imageHeight was given. */ 68 | 69 | } ; 70 | 71 | extern const char *CameraInfoParserInfo_purpose; 72 | extern const char *CameraInfoParserInfo_usage; 73 | extern const char *CameraInfoParserInfo_help[]; 74 | 75 | int cameraInfoParser (int argc, char * const *argv, 76 | struct CameraInfoParserInfo *args_info); 77 | int cameraInfoParser2 (int argc, char * const *argv, 78 | struct CameraInfoParserInfo *args_info, 79 | int override, int initialize, int check_required); 80 | int cameraInfoParser_file_save(const char *filename, 81 | struct CameraInfoParserInfo *args_info); 82 | 83 | void cameraInfoParser_print_help(void); 84 | void cameraInfoParser_print_version(void); 85 | 86 | void cameraInfoParser_init (struct CameraInfoParserInfo *args_info); 87 | void cameraInfoParser_free (struct CameraInfoParserInfo *args_info); 88 | 89 | int cameraInfoParser_configfile (char * const filename, 90 | struct CameraInfoParserInfo *args_info, 91 | int override, int initialize, int check_required); 92 | 93 | int cameraInfoParser_required (struct CameraInfoParserInfo *args_info, 94 | const char *prog_name); 95 | 96 | 97 | #ifdef __cplusplus 98 | } 99 | #endif /* __cplusplus */ 100 | #endif /* CAMERAINFOOPT_H */ 101 | -------------------------------------------------------------------------------- /src/Lanes-mode2.conf: -------------------------------------------------------------------------------- 1 | #settings for stop line perceptor 2 | 3 | #128 4 | ipmWidth = 160 #160#320#160 5 | #96 6 | ipmHeight = 120 #120#240#120 7 | 8 | ipmLeft = 140 #100 #80 #90 #115 #140 #50 #85 #100 #85 9 | ipmRight = 500 #410 #420 #410 #400 #460 #500 #530 #500 #590 #550 10 | ipmTop = 220 #220 #220 #200 #50 11 | ipmBottom = 360 #360 #350 #380 12 | 13 | #0 bilinear, 1: NN 14 | ipmInterpolation = 0 15 | 16 | ipmVpPortion = 0 #.09 #0.06 #.05 #.125 #.2 #.15 #.075#0.1 #.05 17 | 18 | lineWidth = 2000 19 | lineHeight = 304.8 20 | 21 | kernelWidth = 2 22 | kernelHeight = 2 23 | 24 | #changed to detect center broken lines .98 25 | lowerQuantile = .985 #.98 #.975 #.98 #.985 #.99 #.985#.99#.98#.99#.98#0.975 #0.98 #0.985 26 | 27 | localMaxima = 1 28 | 29 | #grouping type: 0 for HV lines, and 1 for Hough lines 30 | groupingType = 0#1#0#1#0 31 | 32 | #center broken lines: 1 33 | binarize = 0 #1#0#1 #0 34 | 35 | #cetner broken lines 4 36 | detectionThreshold = 6 #6 #5 #4 #2 #2 #4 #5 #6 #5 #7 #10 #.5 #4 #5 #2#0.4#0.6#.8#30#1.8#30#3.5#2 #.15 #.4#.15#.0008#0#.008#2 #0.004#0.005#0.0015#0.012#0.025 37 | 38 | smoothScores = 1 #0#0#1 39 | 40 | ##Hough Transform settings 41 | rMin = 10#0 42 | rMax = 150#300#150#120 43 | rStep = 2#2#3#1 44 | thetaMin = -45#-30#-20#-40#80#85 45 | thetaMax = 45#30#20#40#100#95 46 | thetaStep = 2#3#2#1 47 | 48 | 49 | getEndPoints = 0 50 | 51 | group = 1 52 | groupThreshold = 15 #25 #25 #10 #15 #20#25#20#15 53 | 54 | #RANSAC options 55 | ransac = 1 56 | 57 | ransacLineNumSamples = 4 58 | ransacLineNumIterations = 25 #40 #25 #40 #50 59 | ransacLineNumGoodFit = 10 #15#10 60 | ransacLineThreshold = .2 61 | ransacLineScoreThreshold = 0 #4 #6#4#2.5#5#1#1.5#1.5#3#1.5#3 #20 without smoothing and with binarizing 62 | #15 with smoothing and with binarizing: lines 63 | #1.5 without binarizing or smoothing: lines 64 | #splines: 3 wihtout binarizing or smoothing 65 | #splines: 5 with spline length in score 66 | ransacLineBinarize = 0 67 | ransacLineWindow = 8 #15 #15 #8 #15 68 | 69 | ransacSplineNumSamples = 4 70 | ransacSplineNumIterations = 75 #60 #50 71 | ransacSplineNumGoodFit = 10 #15#10 72 | ransacSplineThreshold = .2 73 | ransacSplineScoreThreshold = 0 #4 #6#4#2.5#5#1#1.5#1.5#3#1.5#3 #20 without smoothing and with binarizing 74 | #15 with smoothing and with binarizing: lines 75 | #1.5 without binarizing or smoothing: lines 76 | #splines: 3 wihtout binarizing or smoothing 77 | #splines: 5 with spline length in score 78 | ransacSplineBinarize = 0 79 | ransacSplineWindow = 6 #10 #15 #10 #15 #8 #15 80 | 81 | ransacSpline = 1 82 | ransacSplineDegree = 3#2#3 83 | ransacLine = 1 #1 84 | 85 | ransacSplineStep = .1 86 | 87 | #spline scores 88 | splineScoreJitter = 2 #2 #2 89 | splineScoreLengthRatio = 1.5 #1.5 #1.2 #1 #.4 #0.6 #.5 90 | splineScoreAngleRatio = 1 #1.2 #1.7 #1.5 #1 #.9 #0.8 #.8 91 | splineScoreStep = .01 #.02 92 | 93 | #grouping of bounding boxes 94 | overlapThreshold = .8 #.3 #0.5 95 | 96 | #localization of points 97 | localizeAngleThreshold = .9 #.7#.7 98 | localizeNumLinePixels = 20 99 | 100 | 101 | #extension of points 102 | extendAngleThreshold = .86 #.7 103 | extendMeanDirAngleThreshold = .95 #.86 #.86 #.7 104 | extendLinePixelsTangent = 10 #5 105 | extendLinePixelsNormal = 20 106 | extendContThreshold = .35 #.3 #.25 #.25 #.2 #.1 107 | extendDeviationThreshold = 2 #1 #2 108 | extendRectTop = 200 109 | extendRectBottom = 380 110 | 111 | extendIPMAngleThreshold = .95 #.9 112 | extendIPMMeanDirAngleThreshold = .86 #.86 #.7 113 | extendIPMLinePixelsTangent = 5 #10 #5 114 | extendIPMLinePixelsNormal = 10 115 | extendIPMContThreshold = .05 #0# .05 #.1 #.35 #.3 #.25 #.25 #.2 #.1 116 | extendIPMDeviationThreshold = 2 #1 #2 117 | extendIPMRectTop = 0 118 | extendIPMRectBottom = 118 119 | 120 | 121 | #tracking 122 | splineTrackingNumAbsentFrames = 3 #3 123 | splineTrackingNumSeenFrames = 2 #5 124 | 125 | #spline merging 126 | mergeSplineThetaThreshold = .3 #52 #30 deg 127 | mergeSplineRThreshold = 15 128 | mergeSplineMeanThetaThreshold = .2#52 #30 deg 129 | mergeSplineMeanRThreshold = 20#15 130 | mergeSplineCentroidThreshold = 80 #50 131 | 132 | #line tracking 133 | lineTrackingNumAbsentFrames = 2 #3 134 | lineTrackingNumSeenFrames = 2 #5 135 | 136 | #spline merging 137 | mergeLineThetaThreshold = .3#52 #30 deg 138 | mergeLineRThreshold = 15 139 | 140 | numStrips = 1 141 | 142 | checkSplines = 1 143 | checkSplinesCurvenessThreshold = .85 #.80 #.9 #.93 144 | checkSplinesLengthThreshold = 40 #30 145 | checkSplinesThetaDiffThreshold = .1 146 | checkSplinesThetaThreshold = 1.22 #70 deg 147 | 148 | checkIPMSplines = 1 149 | checkIPMSplinesCurvenessThreshold = .8 #.85 150 | checkIPMSplinesLengthThreshold = 50 #30 151 | checkIPMSplinesThetaDiffThreshold = .12 #.1 152 | checkIPMSplinesThetaThreshold = 1.22 #1.4 #1.4->80deg 1.22->70deg 153 | 154 | finalSplineScoreThreshold = 0 155 | 156 | useGroundPlane = 0 157 | 158 | checkColor = 0 159 | checkColorWindow = 3 160 | checkColorNumBins = 16 161 | checkColorNumYellowMin = .3 162 | checkColorRGMin = 1 163 | checkColorRGMax = 40 164 | checkColorGBMin = 10 #15 165 | checkColorRBMin = 25 166 | checkColorRBFThreshold = -.1 167 | checkColorRBF = 1 168 | 169 | ipmWindowClear = 1 170 | ipmWindowLeft = 60 171 | ipmWindowRight = 100 172 | 173 | checkLaneWidth = 1 174 | checkLaneWidthMean = 30 #25 175 | checkLaneWidthStd = 10 #10 -------------------------------------------------------------------------------- /src/mcv.cc: -------------------------------------------------------------------------------- 1 | /*** 2 | * \file mcv.cc 3 | * \author Mohamed Aly 4 | * \date 11/29/2006 5 | */ 6 | 7 | #include "mcv.hh" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | #include 16 | #include 17 | 18 | namespace LaneDetector 19 | { 20 | 21 | //some helper functions for debugging 22 | 23 | //print the matrix passed to it 24 | void SHOW_MAT(const CvMat *pmat, char str[]) 25 | { 26 | cerr << str << "\n"; 27 | for(int i=0; irows; i++) 28 | { 29 | for(int j=0; jcols; j++) 30 | cerr << cvGetReal2D(pmat, i, j) << " "; 31 | cerr << "\n"; 32 | } 33 | } 34 | 35 | void SHOT_MAT_TYPE(const CvMat *pmat) 36 | { 37 | cout << CV_MAT_TYPE(pmat->type) << "\n"; 38 | } 39 | 40 | void SHOW_IMAGE(const CvMat *pmat, const char str[], int wait) 41 | { 42 | //cout << "channels:" << CV_MAT_CN(pmat->type) << "\n"; 43 | //scale it 44 | //CvMat *mat = cvCreateMat(pmat->height, pmat->width, pmat->type); 45 | //cvCopy(pmat, mat); 46 | CvMat *mat = cvCloneMat(pmat);//->rows, pmat->cols, INT_MAT_TYPE);//cvCloneMat(pmat); 47 | assert(mat); 48 | //convert to int type 49 | //cvConvert(pmat, mat); 50 | if(CV_MAT_CN(mat->type) == 1)//FLOAT_MAT_TYPE) 51 | mcvScaleMat(mat, mat); 52 | //show it 53 | //cout << "in\n"; 54 | cvNamedWindow(str, CV_WINDOW_AUTOSIZE); //0 1 55 | cvShowImage(str, mat); 56 | cvWaitKey(wait); 57 | //cvDestroyWindow(str); 58 | //clear 59 | cvReleaseMat(&mat); 60 | //cout << "out\n"; 61 | } 62 | 63 | void SHOW_IMAGE(const IplImage *pmat, char str[]) 64 | { 65 | //cout << "channels:" << CV_MAT_CN(pmat->type) << "\n"; 66 | //scale it 67 | //CvMat *mat = cvCreateMat(pmat->height, pmat->width, pmat->type); 68 | //cvCopy(pmat, mat); 69 | //CvMat *mat = cvCloneMat(pmat); 70 | //assert(mat); 71 | // mcvScaleMat(mat, mat); 72 | //show it 73 | //cout << "in\n"; 74 | cvNamedWindow(str, 1); 75 | cvShowImage(str, pmat); 76 | cvWaitKey(0); 77 | //cvDestroyWindow(str); 78 | //clear 79 | //cvReleaseMat(&mat); 80 | //cout << "out\n"; 81 | } 82 | 83 | void SHOW_POINT(const FLOAT_POINT2D pt, char str[]) 84 | { 85 | cerr << str << "(" << pt.x << "," << pt.y << ")\n"; 86 | cerr.flush(); 87 | } 88 | 89 | 90 | void SHOW_RECT(const CvRect rect, char str[]) 91 | { 92 | cerr << str << "(x=" << rect.x << ", y=" << rect.y 93 | << ", width=" << rect.width << ", height=" 94 | << rect.height << ")" << endl; 95 | cerr.flush(); 96 | } 97 | 98 | /** 99 | * This function reads in an image from file and returns the original color 100 | * image and the first (red) channel scaled to [0 .. 1] with float type. 101 | * images are allocated inside the function, so you will need to deallocate 102 | * them 103 | * 104 | * \param filename the input file name 105 | * \param clrImage the raw input image 106 | * \param channelImage the first channel 107 | */ 108 | void mcvLoadImage(const char *filename, CvMat **clrImage, CvMat** channelImage) 109 | { 110 | // load the image 111 | IplImage* im; 112 | im = cvLoadImage(filename, CV_LOAD_IMAGE_COLOR); 113 | // convert to mat and get first channel 114 | CvMat temp; 115 | cvGetMat(im, &temp); 116 | *clrImage = cvCloneMat(&temp); 117 | // convert to single channel 118 | CvMat *schannel_mat; 119 | CvMat* tchannelImage = cvCreateMat(im->height, im->width, INT_MAT_TYPE); 120 | cvSplit(*clrImage, tchannelImage, NULL, NULL, NULL); 121 | // convert to float 122 | *channelImage = cvCreateMat(im->height, im->width, FLOAT_MAT_TYPE); 123 | cvConvertScale(tchannelImage, *channelImage, 1./255); 124 | // destroy 125 | cvReleaseMat(&tchannelImage); 126 | cvReleaseImage(&im); 127 | } 128 | 129 | /** 130 | * This function scales the input image to have values 0->1 131 | * 132 | * \param inImage the input image 133 | * \param outImage hte output iamge 134 | */ 135 | void mcvScaleMat(const CvMat *inMat, CvMat *outMat) 136 | { 137 | //convert inMat type to outMat type 138 | cvConvert(inMat, outMat); 139 | //if (CV_MAT_DEPTH(inMat->type) 140 | //get the min and subtract it 141 | double min; 142 | cvMinMaxLoc(inMat, &min, 0, 0, 0, 0); 143 | cvSubS(inMat, cvRealScalar(min), outMat); 144 | 145 | //get max and divide by it 146 | double max; 147 | cvMinMaxLoc(outMat, 0, &max, 0, 0, 0); 148 | if(CV_MAT_TYPE(outMat->type) == FLOAT_MAT_TYPE) 149 | cvConvertScale(outMat, outMat, 1/max); 150 | else if(CV_MAT_TYPE(outMat->type) == INT_MAT_TYPE) 151 | cvConvertScale(outMat, outMat, 255/max); 152 | } 153 | 154 | /** 155 | * This function creates a double matrix from an input vector 156 | * 157 | * \param vec the input vector 158 | * \param mat the output matrix (column vector) 159 | * 160 | */ 161 | template 162 | CvMat* mcvVector2Mat(const vector &vec) 163 | { 164 | CvMat *mat = 0; 165 | 166 | if (vec.size()>0) 167 | { 168 | //create the matrix 169 | mat = cvCreateMat(vec.size(), 1, CV_64FC1); 170 | //loop and get values 171 | for (int i=0; i<(int)vec.size(); i++) 172 | CV_MAT_ELEM(*mat, double, i, 0) =(double) vec[i]; 173 | } 174 | 175 | //return 176 | return mat; 177 | } 178 | 179 | // template CvMat* mcvVector2Mat(const vector &vec); 180 | // template CvMat* mcvVector2Mat(const vector &vec); 181 | 182 | } // namespace LaneDetector 183 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | # Author: Mohamed Aly 2 | # Date: 10/7/2010 3 | 4 | ============================================================================ 5 | REAL TIME LANE DETECTOR SOFTWARE 6 | ============================================================================ 7 | 8 | This package contains source code and dataset that implements the work in the 9 | paper [1]. 10 | 11 | ========= 12 | Contents 13 | ========= 14 | src/: contains the C/C++ source files 15 | 16 | |_ CameraInfo.conf: contains the camera calibration ifo 17 | 18 | |_ CameraInfoOpt.*: contain gengetopt files for parsing the camera info files 19 | 20 | |_ cmdline.*: contains gengetopt files for parsing command lines 21 | 22 | |_ InversePerspectiveMapping.*: code for obtainig the IPM of an image 23 | 24 | |_ LaneDetector.*: code for the bulk of the algorithm, including Hough 25 | Transforms, Spline fitting, Post processing, ... 26 | 27 | |_ Lanes.conf: the typical configuration file for lane detection 28 | 29 | |_ main.*: code for the main binary 30 | 31 | |_ Makefile: the Make file 32 | 33 | |_ mcv.*: contain utility functions 34 | 35 | |_ ranker.h: code for obtaining the median of a vector 36 | 37 | |_ run.sh: Shell script for running the detector on the four clips in 38 | Caltech Lanes Dataset 39 | 40 | matlab/: contains the Matlab source files 41 | 42 | |_ ccvCheckMergeSplines.m: checks if two splines are matching 43 | 44 | |_ ccvEvalBezSpline.m: returns points on a spline given its control points 45 | 46 | |_ ccvGetLaneDetectionStats.m: computes stats from detections and ground truth 47 | 48 | |_ ccvLabel.m: handles the ground truth labels 49 | 50 | |_ ccvReadLaneDetectionResultsFile.m: reads a detection file output from the 51 | binary file LaneDetector32/64 52 | 53 | |_ Stats.m: computes stats for the detections on the Caltech Lanes Dataset and 54 | its ground truth labels 55 | 56 | ============== 57 | Prerequisites 58 | ============== 59 | 1. OpenCV 2.0 or higher http://sourceforge.net/projects/opencvlibrary/ 60 | 3. (Optional) Gengetopt http://www.gnu.org/software/gengetopt/ 61 | 62 | =========== 63 | Compiling 64 | =========== 65 | Unzip the archive somewhere, let's say ~/lane-detector: 66 | 67 | unzip lane-detector.zip -d ~/lane-detector 68 | cd ~/lane-detector/src 69 | make release 70 | 71 | This will generate LaneDetector32 or LaneDetector64 depending on your system. 72 | 73 | ====================== 74 | Caltech Lanes Dataset 75 | ====================== 76 | To view the lane detector in action, you can download the Caltech Lanes Dataset 77 | available at http://www.vision.caltech.edu/malaa/datasets/caltech-lanes 78 | 79 | =========== 80 | Running 81 | =========== 82 | To run the detector on the Caltech Lanes dataset, which might be in 83 | ~/caltech-lanes/ 84 | 85 | cd ~/lane-detector/ 86 | ln -s ~/caltech-lanes/ clips 87 | cd ~/lane-detector/src/ 88 | bash run.sh 89 | 90 | This will create the results files inside 91 | ~/caltech-lanes/*/list.txt_results.txt 92 | 93 | To view the statistics of the results, open Matlab and run the file: 94 | 95 | cd ~/lane-detector/matlab/ 96 | matlab& 97 | >>Stats 98 | 99 | ====================== 100 | Command line options 101 | ====================== 102 | LinePerceptor 1.0 103 | 104 | Detects lanes in street images. 105 | 106 | Usage: LinePerceptor [OPTIONS]... [FILES]... 107 | 108 | -h, --help Print help and exit 109 | -V, --version Print version and exit 110 | 111 | Basic options: 112 | --lanes-conf=STRING Configuration file for lane detection 113 | (default=`Lanes.conf') 114 | --stoplines-conf=STRING Configuration file for stopline detection 115 | (default=`StopLines.conf') 116 | --no-stoplines Don't detect stop lines (default=on) 117 | --no-lanes Don't detect lanes (default=off) 118 | --camera-conf=STRING Configuration file for the camera paramters 119 | (default=`CameraInfo.conf') 120 | --list-file=STRING Text file containing a list of images one per 121 | line 122 | --list-path=STRING Path where the image files are located, this is 123 | just appended at the front of each line in 124 | --list-file (default=`') 125 | --image-file=STRING The path to an image 126 | 127 | Debugging options: 128 | --wait=INT Number of milliseconds to show the detected 129 | lanes. Put 0 for infinite i.e. waits for 130 | keypress. (default=`0') 131 | --show Show the detected lines (default=off) 132 | --step Step through each image (needs a keypress) or 133 | fall through (waits for --wait msecs) 134 | (default=off) 135 | --show-lane-numbers Show the lane numbers on the output image 136 | (default=off) 137 | --output-suffix=STRING Suffix of images and results 138 | (default=`_results') 139 | --save-images Export all images with detected lanes to the by 140 | appending --output-suffix + '.png' to each 141 | input image (default=off) 142 | --save-lanes Export all detected lanes to a text file by 143 | appending --output-suffix + '.txt' to 144 | --list-file (default=off) 145 | --debug Show debugging information and images 146 | (default=off) 147 | 148 | =========== 149 | References 150 | =========== 151 | [1] Mohamed Aly, Real time Detection of Lane Markers in Urban Streets, 152 | IEEE Intelligent Vehicles Symposium, Eindhoven, The Netherlands, June 2008. 153 | -------------------------------------------------------------------------------- /matlab/ccvGetLaneDetectionStats.m: -------------------------------------------------------------------------------- 1 | function ccvGetLaneDetectionStats(detectionFiles, truthFiles) 2 | % CCVGETLANEDETECTIONSTATS computes stats for the results compared to the 3 | % ground truth 4 | % 5 | % INPUTS 6 | % ------ 7 | % detectionFiles - a cell array of the detection files 8 | % truthFiles - a cell array of the corresponding ground truth files 9 | % 10 | % OUTPUTS 11 | % ------- 12 | % 13 | % See also ccvLabel 14 | % 15 | 16 | % Thresholds for merging i.e. matching splines 17 | meanDistThreshold = 15; 18 | medianDistThreshold = 20; 19 | 20 | % Initialize 21 | allResults = []; 22 | allDetectionTotal = 0; 23 | allTruthTotal = 0; 24 | allNumFrames = 0; 25 | allTp = 0; 26 | allFp = 0; 27 | 28 | disp('------------------------------------------------------------------'); 29 | 30 | for d=1:length(detectionFiles) 31 | %get detection and truth file 32 | detectionFile = detectionFiles{d}; 33 | truthFile = truthFiles{d}; 34 | 35 | %load the ground truth 36 | truths = ccvLabel('read', truthFile); 37 | 38 | %load the detections file 39 | detections = ccvReadLaneDetectionResultsFile(detectionFile); 40 | 41 | %results for this file 42 | results = []; 43 | detectionTotal = 0; 44 | truthTotal = 0; 45 | numFrames = 0; 46 | 47 | %progress index 48 | prog = 0; 49 | progress= '-\|/'; 50 | fprintf(1, '\n-'); 51 | 52 | %loop on results and compare splines 53 | for i=1:length(detections) 54 | %get frame 55 | detectionFrame = detections(i); 56 | detectionSplines = detectionFrame.splines; 57 | 58 | %display progress 59 | if mod(length(results), 10)==0 60 | fprintf(1, '\b%s', progress(prog+1)); 61 | prog = mod(prog+1, length(progress)); 62 | end; 63 | 64 | %get truth splines for that frame 65 | truthFrame = ccvLabel('getFrame', truths, i); 66 | if isempty(truthFrame), continue; end; 67 | numFrames = numFrames + 1; 68 | truthSplines = GetTruthSplines(truthFrame.labels); 69 | 70 | %update totals 71 | detectionTotal = detectionTotal + length(detectionSplines); 72 | truthTotal = truthTotal + length(truthSplines); 73 | 74 | %loop on these splines and compare to ground truth to get the closest 75 | frameDetections = []; 76 | truthDetections = zeros(1, length(truthSplines)); 77 | for j=1:length(detectionSplines) 78 | %flag 79 | detection = 0; 80 | %loop on truth and get which one 81 | k = 1; 82 | while detection==0 && k<=length(truthSplines) 83 | if ccvCheckMergeSplines(detectionSplines{j}, ... 84 | truthSplines{k}, meanDistThreshold, ... 85 | medianDistThreshold); 86 | %not false pos 87 | detection = 1; 88 | truthDetections(k) = 1; 89 | end; 90 | %inc 91 | k = k+1; 92 | end; %while 93 | 94 | %check result 95 | result.score = detectionFrame.scores(j); 96 | result.detection = detection; 97 | results = [results, result]; 98 | frameDetections = [frameDetections, detection]; 99 | end; %for 100 | 101 | %get number of missed splines 102 | frameNumMissed = length(truthSplines) - length(find(frameDetections==1)); 103 | frameNumFalse = length(find(frameDetections==0)); 104 | end; % for i 105 | 106 | %print out some stats 107 | tp = length(find([results.detection]==1)); 108 | fp = length(find([results.detection]==0)); 109 | % numFrames = length(detections); 110 | 111 | fprintf(1,'\n\n\n'); 112 | disp(sprintf('Detection File %d: %s', i, detectionFile)); 113 | disp(sprintf('Number of frames = %d', numFrames)); 114 | disp(' '); 115 | disp(sprintf('Total detections = %d', detectionTotal)); 116 | disp(sprintf('Total truth = %d', truthTotal)); 117 | disp(' '); 118 | disp(sprintf('Number of correct detections = %d', tp)); 119 | disp(sprintf('Number of false detections = %d', fp)); 120 | disp(' '); 121 | disp(sprintf('Percentage of correct detections = %f', tp/truthTotal)); 122 | disp(sprintf('Percentage of false detections = %f', fp/truthTotal)); 123 | disp(' '); 124 | disp(sprintf('False detections/frame= %f', fp/numFrames)); 125 | 126 | %put in total stats 127 | allResults = [allResults, results]; 128 | allDetectionTotal = allDetectionTotal + detectionTotal; 129 | allTruthTotal = allTruthTotal + truthTotal; 130 | allNumFrames = allNumFrames + numFrames; 131 | allTp = allTp + tp; 132 | allFp = allFp + fp; 133 | 134 | dResults{d} = results; 135 | dDetectionTotal(d) = detectionTotal; 136 | dTruthTotal(d) = truthTotal; 137 | dNumFrames(d) = numFrames; 138 | dTp(d) = tp; 139 | dFp(d) = fp; 140 | end; %for 141 | 142 | 143 | fprintf(1,'\n\n\n'); 144 | disp('Overall results'); 145 | disp(sprintf('Number of frames = %d', allNumFrames)); 146 | disp(' '); 147 | disp(sprintf('Total detections = %d', allDetectionTotal)); 148 | disp(sprintf('Total truth = %d', allTruthTotal)); 149 | disp(' '); 150 | disp(sprintf('Number of correct detections = %d', allTp)); 151 | disp(sprintf('Number of false detections = %d', allFp)); 152 | disp(' '); 153 | disp(sprintf('Percentage of correct detections = %f', allTp/allTruthTotal)); 154 | disp(sprintf('Percentage of false detections = %f', allFp/allTruthTotal)); 155 | disp(' '); 156 | disp(sprintf('False detections/frame= %f', allFp/allNumFrames)); 157 | 158 | 159 | fprintf(1,'\n\n\n-----'); 160 | disp('Summary results'); 161 | for d=1:length(dDetectionTotal) 162 | disp(' '); 163 | disp(sprintf('Detection %s', detectionFile)); 164 | disp(sprintf('Total = %d', dTruthTotal(d))); 165 | disp(sprintf('Total detections = %d', dDetectionTotal(d))); 166 | disp(sprintf('correct detections = %.2f', 100*dTp(d)/dTruthTotal(d))); 167 | disp(sprintf('false detections = %.2f', 100*dFp(d)/dTruthTotal(d))); 168 | disp(sprintf('false detections / frame = %.3f', dFp(d)/dNumFrames(d))); 169 | end; 170 | 171 | % --------------------------------------------------------------------------- 172 | function splines = GetTruthSplines(labels) 173 | % returns splines in the labels as a cell array of splines 174 | splines = {}; 175 | for i=1:length(labels) 176 | if strcmp(labels(i).type, 'spline') 177 | splines{end+1} = labels(i).points; 178 | end; 179 | end; 180 | -------------------------------------------------------------------------------- /src/InversePerspectiveMapping.hh: -------------------------------------------------------------------------------- 1 | /*** 2 | * \file InversePerspectiveMapping.hh 3 | * \author Mohamed Aly 4 | * \date 11/29/2006 5 | */ 6 | 7 | #ifndef INVERSEPERSPECTIVEMAPPING_HH_ 8 | #define INVERSEPERSPECTIVEMAPPING_HH_ 9 | 10 | 11 | #include "cv.h" 12 | #include "mcv.hh" 13 | #include 14 | 15 | //conf file for cameraInfo 16 | #include "CameraInfoOpt.h" 17 | 18 | using namespace std; 19 | 20 | namespace LaneDetector 21 | { 22 | 23 | /** 24 | * Structure to hold the info about IPM transformation 25 | */ 26 | typedef struct IPMInfo 27 | { 28 | ///min and max x-value on ground in world coordinates 29 | FLOAT xLimits[2]; 30 | ///min and max y-value on ground in world coordinates 31 | FLOAT yLimits[2]; 32 | ///conversion between mm in world coordinate on the ground 33 | ///in x-direction and pixel in image 34 | FLOAT xScale; 35 | ///conversion between mm in world coordinate on the ground 36 | ///in y-direction and pixel in image 37 | FLOAT yScale; 38 | ///width 39 | int width; 40 | ///height 41 | int height; 42 | ///portion of image height to add to y-coordinate of 43 | ///vanishing point 44 | float vpPortion; 45 | ///Left point in original image of region to make IPM for 46 | float ipmLeft; 47 | ///Right point in original image of region to make IPM for 48 | float ipmRight; 49 | ///Top point in original image of region to make IPM for 50 | float ipmTop; 51 | ///Bottom point in original image of region to make IPM for 52 | float ipmBottom; 53 | ///interpolation to use for IPM (0: bilinear, 1:nearest neighbor) 54 | int ipmInterpolation; 55 | }IPMInfo; 56 | 57 | ///Camera Calibration info 58 | typedef struct CameraInfo 59 | { 60 | ///focal length in x and y 61 | FLOAT_POINT2D focalLength; 62 | ///optical center coordinates in image frame (origin is (0,0) at top left) 63 | FLOAT_POINT2D opticalCenter; 64 | ///height of camera above ground 65 | FLOAT cameraHeight; 66 | ///pitch angle in radians (+ve downwards) 67 | FLOAT pitch; 68 | ///yaw angle in radians (+ve clockwise) 69 | FLOAT yaw; 70 | ///width of images 71 | FLOAT imageWidth; 72 | ///height of images 73 | FLOAT imageHeight; 74 | }CameraInfo; 75 | 76 | //functions definitions 77 | /** 78 | * This function returns the Inverse Perspective Mapping 79 | * of the input image, assuming a flat ground plane, and 80 | * given the camera parameters. 81 | * 82 | * \param inImage the input image 83 | * \param outImage the output image in IPM 84 | * \param ipmInfo the returned IPM info for the transformation 85 | * \param focalLength focal length (in x and y direction) 86 | * \param cameraInfo the camera parameters 87 | */ 88 | void mcvGetIPM(const CvMat* inImage, CvMat* outImage, 89 | IPMInfo *ipmInfo, const CameraInfo *cameraInfo, 90 | list* outPoints=NULL); 91 | 92 | 93 | /** 94 | * Transforms points from the image frame (uv-coordinates) 95 | * into the real world frame on the ground plane (z=-height) 96 | * 97 | * \param inPoints input points in the image frame (2xN matrix) 98 | * \param outPoints output points in the world frame on the ground 99 | * (z=-height) (2xN matrix with xw, yw and implicit z=-height) 100 | * \param cemaraInfo the input camera parameters 101 | * 102 | */ 103 | void mcvTransformImage2Ground(const CvMat *inPoints, 104 | CvMat *outPoints, const CameraInfo *cameraInfo); 105 | 106 | 107 | /** 108 | * Transforms points from the ground plane (z=-h) in the world frame 109 | * into points on the image in image frame (uv-coordinates) 110 | * 111 | * \param inPoints 2xN array of input points on the ground in world coordinates 112 | * \param outPoints 2xN output points in on the image in image coordinates 113 | * \param cameraInfo the camera parameters 114 | * 115 | */ 116 | void mcvTransformGround2Image(const CvMat *inPoints, 117 | CvMat *outPoints, const CameraInfo *cameraInfo); 118 | 119 | /** 120 | * Computes the vanishing point in the image plane uv. It is 121 | * the point of intersection of the image plane with the line 122 | * in the XY-plane in the world coordinates that makes an 123 | * angle yaw clockwise (form Y-axis) with Y-axis 124 | * 125 | * \param cameraInfo the input camera parameter 126 | * 127 | * \return the computed vanishing point in image frame 128 | * 129 | */ 130 | FLOAT_POINT2D mcvGetVanishingPoint(const CameraInfo *cameraInfo); 131 | 132 | /** 133 | * Converts a point from IPM pixel coordinates into world coordinates 134 | * 135 | * \param point in/out point 136 | * \param ipmInfo the ipm info from mcvGetIPM 137 | * 138 | */ 139 | void mcvPointImIPM2World(FLOAT_POINT2D *point, const IPMInfo *ipmInfo); 140 | 141 | /** 142 | * Initializes the cameraInfo structure with data read from the conf file 143 | * 144 | * \param fileName the input camera conf file name 145 | * \param cameraInfo the returned camera parametrs struct 146 | * 147 | */ 148 | void mcvInitCameraInfo (char *const fileName, CameraInfo *cameraInfo); 149 | 150 | /** 151 | * Scales the cameraInfo according to the input image size 152 | * 153 | * \param cameraInfo the input/return structure 154 | * \param size the input image size 155 | * 156 | */ 157 | void mcvScaleCameraInfo (CameraInfo *cameraInfo, CvSize size); 158 | 159 | /** 160 | * Gets the extent of the image on the ground plane given the camera parameters 161 | * 162 | * \param cameraInfo the input camera info 163 | * \param ipmInfo the IPM info containing the extent on ground plane: 164 | * xLimits & yLimits only are changed 165 | * 166 | */ 167 | void mcvGetIPMExtent(const CameraInfo *cameraInfo, IPMInfo *ipmInfo); 168 | 169 | /** 170 | * Converts from IPM pixel coordinates into world coordinates 171 | * 172 | * \param inMat input matrix 2xN 173 | * \param outMat output matrix 2xN 174 | * \param ipmInfo the ipm info from mcvGetIPM 175 | * 176 | */ 177 | void mcvTransformImIPM2Ground(const CvMat *inMat, CvMat* outMat, 178 | const IPMInfo *ipmInfo); 179 | 180 | /** 181 | * Converts from IPM pixel coordinates into Image coordinates 182 | * 183 | * \param inMat input matrix 2xN 184 | * \param outMat output matrix 2xN 185 | * \param ipmInfo the ipm info from mcvGetIPM 186 | * \param cameraInfo the camera info 187 | * 188 | */ 189 | void mcvTransformImIPM2Im(const CvMat *inMat, CvMat* outMat, 190 | const IPMInfo *ipmInfo, 191 | const CameraInfo *cameraInfo); 192 | 193 | } // namespace LaneDetector 194 | 195 | #endif /*INVERSEPERSPECTIVEMAPPING_HH_*/ 196 | -------------------------------------------------------------------------------- /src/cmdline.h: -------------------------------------------------------------------------------- 1 | /* cmdline.h */ 2 | 3 | /* File autogenerated by gengetopt version 2.18 */ 4 | 5 | #ifndef CMDLINE_H 6 | #define CMDLINE_H 7 | 8 | /* If we use autoconf. */ 9 | #ifdef HAVE_CONFIG_H 10 | #include "config.h" 11 | #endif 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif /* __cplusplus */ 16 | 17 | #ifndef CMDLINE_PARSER_PACKAGE 18 | #define CMDLINE_PARSER_PACKAGE "LinePerceptor" 19 | #endif 20 | 21 | #ifndef CMDLINE_PARSER_VERSION 22 | #define CMDLINE_PARSER_VERSION "1.0" 23 | #endif 24 | 25 | struct gengetopt_args_info 26 | { 27 | const char *help_help; /* Print help and exit help description. */ 28 | const char *version_help; /* Print version and exit help description. */ 29 | char * lanes_conf_arg; /* Configuration file for lane detection (default='Lanes.conf'). */ 30 | char * lanes_conf_orig; /* Configuration file for lane detection original value given at command line. */ 31 | const char *lanes_conf_help; /* Configuration file for lane detection help description. */ 32 | char * stoplines_conf_arg; /* Configuration file for stopline detection (default='StopLines.conf'). */ 33 | char * stoplines_conf_orig; /* Configuration file for stopline detection original value given at command line. */ 34 | const char *stoplines_conf_help; /* Configuration file for stopline detection help description. */ 35 | int no_stoplines_flag; /* Don't detect stop lines (default=on). */ 36 | const char *no_stoplines_help; /* Don't detect stop lines help description. */ 37 | int no_lanes_flag; /* Don't detect lanes (default=off). */ 38 | const char *no_lanes_help; /* Don't detect lanes help description. */ 39 | char * camera_conf_arg; /* Configuration file for the camera paramters (default='CameraInfo.conf'). */ 40 | char * camera_conf_orig; /* Configuration file for the camera paramters original value given at command line. */ 41 | const char *camera_conf_help; /* Configuration file for the camera paramters help description. */ 42 | char * list_file_arg; /* Text file containing a list of images one per line. */ 43 | char * list_file_orig; /* Text file containing a list of images one per line original value given at command line. */ 44 | const char *list_file_help; /* Text file containing a list of images one per line help description. */ 45 | char * list_path_arg; /* Path where the image files are located, this is just appended at the front of each line in --list-file (default=''). */ 46 | char * list_path_orig; /* Path where the image files are located, this is just appended at the front of each line in --list-file original value given at command line. */ 47 | const char *list_path_help; /* Path where the image files are located, this is just appended at the front of each line in --list-file help description. */ 48 | char * image_file_arg; /* The path to an image. */ 49 | char * image_file_orig; /* The path to an image original value given at command line. */ 50 | const char *image_file_help; /* The path to an image help description. */ 51 | int wait_arg; /* Number of milliseconds to show the detected lanes. Put 0 for infinite i.e. waits for keypress. (default='0'). */ 52 | char * wait_orig; /* Number of milliseconds to show the detected lanes. Put 0 for infinite i.e. waits for keypress. original value given at command line. */ 53 | const char *wait_help; /* Number of milliseconds to show the detected lanes. Put 0 for infinite i.e. waits for keypress. help description. */ 54 | int show_flag; /* Show the detected lines (default=off). */ 55 | const char *show_help; /* Show the detected lines help description. */ 56 | int step_flag; /* Step through each image (needs a keypress) or fall through (waits for --wait msecs) (default=off). */ 57 | const char *step_help; /* Step through each image (needs a keypress) or fall through (waits for --wait msecs) help description. */ 58 | int show_lane_numbers_flag; /* Show the lane numbers on the output image (default=off). */ 59 | const char *show_lane_numbers_help; /* Show the lane numbers on the output image help description. */ 60 | char * output_suffix_arg; /* Suffix of images and results (default='_results'). */ 61 | char * output_suffix_orig; /* Suffix of images and results original value given at command line. */ 62 | const char *output_suffix_help; /* Suffix of images and results help description. */ 63 | int save_images_flag; /* Export all images with detected lanes to the by appending --output-suffix + '.png' to each input image (default=off). */ 64 | const char *save_images_help; /* Export all images with detected lanes to the by appending --output-suffix + '.png' to each input image help description. */ 65 | int save_lanes_flag; /* Export all detected lanes to a text file by appending --output-suffix + '.txt' to --list-file (default=off). */ 66 | const char *save_lanes_help; /* Export all detected lanes to a text file by appending --output-suffix + '.txt' to --list-file help description. */ 67 | int debug_flag; /* Show debugging information and images (default=off). */ 68 | const char *debug_help; /* Show debugging information and images help description. */ 69 | 70 | int help_given ; /* Whether help was given. */ 71 | int version_given ; /* Whether version was given. */ 72 | int lanes_conf_given ; /* Whether lanes-conf was given. */ 73 | int stoplines_conf_given ; /* Whether stoplines-conf was given. */ 74 | int no_stoplines_given ; /* Whether no-stoplines was given. */ 75 | int no_lanes_given ; /* Whether no-lanes was given. */ 76 | int camera_conf_given ; /* Whether camera-conf was given. */ 77 | int list_file_given ; /* Whether list-file was given. */ 78 | int list_path_given ; /* Whether list-path was given. */ 79 | int image_file_given ; /* Whether image-file was given. */ 80 | int wait_given ; /* Whether wait was given. */ 81 | int show_given ; /* Whether show was given. */ 82 | int step_given ; /* Whether step was given. */ 83 | int show_lane_numbers_given ; /* Whether show-lane-numbers was given. */ 84 | int output_suffix_given ; /* Whether output-suffix was given. */ 85 | int save_images_given ; /* Whether save-images was given. */ 86 | int save_lanes_given ; /* Whether save-lanes was given. */ 87 | int debug_given ; /* Whether debug was given. */ 88 | 89 | char **inputs ; /* unamed options */ 90 | unsigned inputs_num ; /* unamed options number */ 91 | } ; 92 | 93 | extern const char *gengetopt_args_info_purpose; 94 | extern const char *gengetopt_args_info_usage; 95 | extern const char *gengetopt_args_info_help[]; 96 | 97 | int cmdline_parser (int argc, char * const *argv, 98 | struct gengetopt_args_info *args_info); 99 | int cmdline_parser2 (int argc, char * const *argv, 100 | struct gengetopt_args_info *args_info, 101 | int override, int initialize, int check_required); 102 | int cmdline_parser_file_save(const char *filename, 103 | struct gengetopt_args_info *args_info); 104 | 105 | void cmdline_parser_print_help(void); 106 | void cmdline_parser_print_version(void); 107 | 108 | void cmdline_parser_init (struct gengetopt_args_info *args_info); 109 | void cmdline_parser_free (struct gengetopt_args_info *args_info); 110 | 111 | int cmdline_parser_configfile (char * const filename, 112 | struct gengetopt_args_info *args_info, 113 | int override, int initialize, int check_required); 114 | 115 | int cmdline_parser_required (struct gengetopt_args_info *args_info, 116 | const char *prog_name); 117 | 118 | 119 | #ifdef __cplusplus 120 | } 121 | #endif /* __cplusplus */ 122 | #endif /* CMDLINE_H */ 123 | -------------------------------------------------------------------------------- /src/ranker.h: -------------------------------------------------------------------------------- 1 | #ifndef RANKER_H 2 | #define RANKER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using std::vector; 9 | using std::string; 10 | 11 | #ifndef uint 12 | typedef unsigned int uint; 13 | #endif 14 | 15 | template 16 | class lt { public: static int compare(T a, T b) { return(a < b); } }; 17 | template 18 | class gt { public: static int compare(T a, T b) { return(a > b); } }; 19 | 20 | template 21 | class ranker 22 | { 23 | private: 24 | const T* p; 25 | uint sz; 26 | 27 | public: 28 | ranker(const vector& v) : p(&v[0]), sz(v.size()) { } 29 | ranker(const T* tp, uint s) : p(tp), sz(s) { } 30 | 31 | int operator()(uint i1, uint i2) const { return(C::compare(p[i1],p[i2])); } 32 | 33 | template 34 | void get_orders(vector& w) const { 35 | w.resize(sz); 36 | w.front() = 0; 37 | for (typename vector::iterator i = w.begin(); i != w.end() - 1; ++i) 38 | *(i + 1) = *i + 1; 39 | std::sort(w.begin(), w.end(), *this); 40 | } 41 | 42 | template 43 | void get_partial_orders(vector& w, uint num) const { 44 | if (num > sz) num = sz; 45 | w.resize(sz); 46 | w.front() = 0; 47 | for (typename vector::iterator i = w.begin(); i != w.end() - 1; ++i) 48 | *(i + 1) = *i + 1; 49 | std::partial_sort(w.begin(), w.begin() + num, w.end(), *this); 50 | w.resize(num); 51 | } 52 | 53 | template 54 | void get_ranks(vector& w, const string& method) const { 55 | w.resize(sz); 56 | vector tmp(w.size()); 57 | get_orders(tmp); 58 | if (method == "average") { 59 | for (uint c = 0, reps; c < w.size(); c += reps) { reps = 1; 60 | while (c + reps < w.size() && p[tmp[c]] == p[tmp[c + reps]]) ++reps; 61 | for (uint k = 0; k < reps; ++k) 62 | w[tmp[c + k]] = S(2 * c + reps - 1) / 2 + 1; 63 | } 64 | } else if (method == "min") { 65 | for (uint c = 0, reps; c < w.size(); c += reps) { reps = 1; 66 | while (c + reps < w.size() && p[tmp[c]] == p[tmp[c + reps]]) ++reps; 67 | for (uint k = 0; k < reps; ++k) w[tmp[c + k]] = c + 1; 68 | } 69 | } else if (method == "max") { 70 | for (uint c = 0, reps; c < w.size(); c += reps) { reps = 1; 71 | while (c + reps < w.size() && p[tmp[c]] == p[tmp[c + reps]]) ++reps; 72 | for (uint k = 0; k < reps; ++k) w[tmp[c + k]] = c + reps; 73 | } 74 | } else // default 75 | for (uint c = 0; c < w.size(); ++c) w[tmp[c]] = c + 1; 76 | } 77 | 78 | template 79 | void get_partial_ranks(vector& w, const string& method, size_t num) const { 80 | if (num > sz) num = sz; 81 | vector tmp(sz); 82 | get_partial_orders(tmp, num); 83 | w.resize(sz); 84 | fill(w.begin(), w.end(), 0); 85 | if (method == "average") { 86 | for (uint c = 0, reps; c < num; c += reps) { reps = 1; 87 | while (c + reps < num && p[tmp[c]] == p[tmp[c + reps]]) ++reps; 88 | for (uint k = 0; k < reps; ++k) 89 | w[tmp[c + k]] = S(2 * c + reps - 1) / 2 + 1; 90 | } 91 | } else if (method == "min") { 92 | for (uint c = 0, reps; c < num; c += reps) { reps = 1; 93 | while (c + reps < num && p[tmp[c]] == p[tmp[c + reps]]) ++reps; 94 | for (uint k = 0; k < reps; ++k) w[tmp[c + k]] = c + 1; 95 | } 96 | } else if (method == "max") { 97 | for (uint c = 0, reps; c < num; c += reps) { reps = 1; 98 | while (c + reps < num && p[tmp[c]] == p[tmp[c + reps]]) ++reps; 99 | for (uint k = 0; k < reps; ++k) w[tmp[c + k]] = c + reps; 100 | } 101 | } else // default 102 | for (uint c = 0; c < num; ++c) w[tmp[c]] = c + 1; 103 | } 104 | 105 | }; 106 | 107 | template 108 | inline void rank(const vector& v, vector& w, 109 | const string& method = "average") 110 | { ranker > r(v); r.get_ranks(w, method); } 111 | 112 | template 113 | inline void rank(const T* d, uint size, vector& w, 114 | const string& method = "average") 115 | { ranker > r(d, size); r.get_ranks(w, method); } 116 | 117 | template 118 | inline void partial_rank(const vector& v, vector& w, uint num, 119 | const string& method = "average") 120 | { ranker > r(v); r.get_partial_ranks(w, method, num); } 121 | 122 | template 123 | inline void partial_rank(const T* d, uint size, vector& w, uint num, 124 | const string& method = "average") 125 | { ranker > r(d, size); r.get_partial_ranks(w, method, num); } 126 | 127 | template 128 | inline void order(const vector& v, vector& w) 129 | { ranker > r(v); r.get_orders(w); } 130 | 131 | template 132 | inline void order(const T* d, uint size, vector& w) 133 | { ranker > r(d, size); r.get_orders(w); } 134 | 135 | template 136 | inline void partial_order(const vector& v, vector& w, uint num) 137 | { ranker > r(v); r.get_partial_orders(w, num); } 138 | 139 | template 140 | inline void partial_order(const T* d, uint size, vector& w, uint num) 141 | { ranker > r(d, size); r.get_partial_orders(w, num); } 142 | 143 | template 144 | inline void rankhigh(const vector& v, vector& w, 145 | const string& method = "average") 146 | { ranker > r(v); r.get_ranks(w, method); } 147 | 148 | template 149 | inline void rankhigh(const T* d, uint size, vector& w, 150 | const string& method = "average") 151 | { ranker > r(d, size); r.get_ranks(w, method); } 152 | 153 | template 154 | inline void partial_rankhigh(const vector& v, vector& w, uint num, 155 | const string& method = "average") 156 | { ranker > r(v); r.get_partial_ranks(w, method, num); } 157 | 158 | template 159 | inline void partial_rankhigh(const T* d, uint size, vector& w, uint num, 160 | const string& method = "average") 161 | { ranker > r(d, size); r.get_partial_ranks(w, method, num); } 162 | 163 | template 164 | inline void orderhigh(const vector& v, vector& w) 165 | { ranker > r(v); r.get_orders(w); } 166 | 167 | template 168 | inline void orderhigh(const T* d, uint size, vector& w) 169 | { ranker > r(d, size); r.get_orders(w); } 170 | 171 | template 172 | inline void partial_orderhigh(const vector& v, vector& w, uint num) 173 | { ranker > r(v); r.get_partial_orders(w, num); } 174 | 175 | template 176 | inline void partial_orderhigh(const T* d, uint size, vector& w, uint num) 177 | { ranker > r(d, size); r.get_partial_orders(w, num); } 178 | 179 | template 180 | inline T quantile(const T* d, const uint size, const double q) 181 | { 182 | if (size == 0) return T(0); 183 | if (size == 1) return d[0]; 184 | if (q <= 0) return *std::min_element(d, d + size); 185 | if (q >= 1) return *std::max_element(d, d + size); 186 | 187 | double pos = (size - 1) * q; 188 | uint ind = uint(pos); 189 | double delta = pos - ind; 190 | vector w(size); std::copy(d, d + size, w.begin()); 191 | std::nth_element(w.begin(), w.begin() + ind, w.end()); 192 | T i1 = *(w.begin() + ind); 193 | T i2 = *std::min_element(w.begin() + ind + 1, w.end()); 194 | return (T) (i1 * (1.0 - delta) + i2 * delta); 195 | } 196 | 197 | template 198 | inline T quantile(const vector& v, const double q) 199 | { return quantile(&v[0], v.size(), q); } 200 | 201 | #endif 202 | 203 | -------------------------------------------------------------------------------- /src/main.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * \file main.cc 3 | * \author Mohamed Aly 4 | * \date Wed Oct 6, 2010 5 | * 6 | */ 7 | 8 | #include "main.hh" 9 | 10 | #include "cmdline.h" 11 | #include "LaneDetector.hh" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | // Useful message macro 24 | #define MSG(fmt, ...) \ 25 | (fprintf(stdout, "%s:%d msg " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__) ? 0 : 0) 26 | 27 | // Useful error macro 28 | #define ERROR(fmt, ...) \ 29 | (fprintf(stderr, "%s:%d error " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__) ? -1 : -1) 30 | 31 | 32 | namespace LaneDetector 33 | { 34 | 35 | /** 36 | * This function reads lines from the input file into a vector of strings 37 | * 38 | * \param filename the input file name 39 | * \param lines the output vector of lines 40 | */ 41 | bool ReadLines(const char* filename, vector *lines) 42 | { 43 | // make sure it's not NULL 44 | if (!lines) 45 | return false; 46 | // resize 47 | lines->clear(); 48 | 49 | ifstream file; 50 | file.open(filename, ifstream::in); 51 | char buf[5000]; 52 | // read lines and process 53 | while (file.getline(buf, 5000)) 54 | { 55 | string str(buf); 56 | lines->push_back(str); 57 | } 58 | // close 59 | file.close(); 60 | return true; 61 | } 62 | 63 | 64 | /** 65 | * This function processes an input image and detects lanes/stoplines 66 | * based on the passed in command line arguments 67 | * 68 | * \param filename the input file name 69 | * \param cameraInfo the camera calibration info 70 | * \param lanesConf the lane detection settings 71 | * \param stoplinesConf the stop line detection settings 72 | * \param options the command line arguments 73 | * \param outputFile the output file stream to write output lanes to 74 | * \param index the image index (used for saving output files) 75 | * \param elapsedTime if NOT NULL, it is accumulated with clock ticks for 76 | * the detection operation 77 | */ 78 | void ProcessImage(const char* filename, CameraInfo& cameraInfo, 79 | LaneDetectorConf& lanesConf, LaneDetectorConf& stoplinesConf, 80 | gengetopt_args_info& options, ofstream* outputFile, 81 | int index, clock_t *elapsedTime) 82 | { 83 | // load the image 84 | CvMat *raw_mat, *mat; 85 | mcvLoadImage(filename, &raw_mat, &mat); 86 | 87 | // detect lanes 88 | vector lineScores, splineScores; 89 | vector lanes; 90 | vector splines; 91 | clock_t startTime = clock(); 92 | mcvGetLanes(mat, raw_mat, &lanes, &lineScores, &splines, &splineScores, 93 | &cameraInfo, &lanesConf, NULL); 94 | clock_t endTime = clock(); 95 | MSG("Found %d lanes in %f msec", splines.size(), 96 | static_cast(endTime - startTime) / CLOCKS_PER_SEC * 1000.); 97 | // update elapsed time 98 | if (elapsedTime) 99 | (*elapsedTime) += endTime - startTime; 100 | 101 | // save results? 102 | if (options.save_lanes_flag && outputFile && outputFile->is_open()) 103 | { 104 | (*outputFile) << "frame#" << setw(8) << setfill('0') << index << 105 | " has " << splines.size() << " splines" << endl; 106 | for (int i=0; i(elapsed) / CLOCKS_PER_SEC; 214 | MSG("Total time %f secs for 1 image = %f Hz", elapsedTime, 215 | 1. / elapsedTime); 216 | } 217 | 218 | // process a list of images 219 | if (options.list_file_given) 220 | { 221 | // get the path if exists 222 | string path = ""; 223 | if (options.list_path_given) 224 | path = options.list_path_arg; 225 | 226 | // read file 227 | vector files; 228 | ReadLines(options.list_file_arg, &files); 229 | int numImages = files.size(); 230 | if (numImages<1) 231 | ERROR("File %s is empty", options.list_file_arg); 232 | else 233 | { 234 | // save results? 235 | ofstream outputFile; 236 | stringstream ss; 237 | if (options.save_lanes_flag) 238 | { 239 | ss << options.list_file_arg << options.output_suffix_arg << ".txt"; 240 | outputFile.open(ss.str().c_str(), ios_base::out); 241 | } 242 | 243 | // elapsed time 244 | clock_t elapsed = 0; 245 | // loop 246 | for (int i=0; i(elapsed) / CLOCKS_PER_SEC; 254 | MSG("Total time %f secs for %d images = %f Hz", 255 | elapsedTime, numImages, numImages / elapsedTime); 256 | 257 | // close results file (if open) 258 | if (options.save_lanes_flag) 259 | { 260 | outputFile.close(); 261 | MSG("Results written to %s", ss.str().c_str()); 262 | } 263 | } 264 | } 265 | 266 | return 0; 267 | } 268 | 269 | } // namespace LaneDetector 270 | 271 | using LaneDetector::Process; 272 | 273 | // main entry point 274 | int main(int argc, char** argv) 275 | { 276 | return Process(argc, argv); 277 | } 278 | -------------------------------------------------------------------------------- /matlab/ccvLabel.m: -------------------------------------------------------------------------------- 1 | function varargout = ccvLabel(f, varargin) 2 | % CCVLABEL performs different tasks on the label structure, like creating 3 | % new structure, adding frames, labels, ...etc. 4 | % 5 | % INPUTS 6 | % ------ 7 | % f - the input function to perform 8 | % varargin - the rest of the inputs (potentially zero) 9 | % 10 | % OUTPUTS 11 | % ------- 12 | % varargout - the outputs from the selected operation 13 | % 14 | % See also ccvLabeler 15 | % 16 | % AUTHOR - Mohamed Aly 17 | % DATE - May 26, 2009 18 | % 19 | 20 | %check if we have a valid input function 21 | if isempty(f) || ~exist(f, 'file'), error('Please enter a valid function'); end; 22 | 23 | %call the function 24 | varargout = cell(1, nargout); 25 | [varargout{:}] = feval(f, varargin{:}); 26 | end 27 | 28 | function ld = create() 29 | % NEW creates a new empty structure 30 | % 31 | % INPUTS 32 | % ------ 33 | % 34 | % OUTPUTS 35 | % ------- 36 | % ld - the output empty label data 37 | % 38 | 39 | ld.version = 0; 40 | ld.source = 'image'; 41 | ld.frames = struct('frame', {}, ... 42 | 'labels', struct('points',{}, 'type',{}, 'subtype',{}, 'obj',{})); 43 | ld.objects = struct('id',{}); 44 | end 45 | 46 | function ld = read(fname) 47 | % READ loads label data from a file 48 | % 49 | % INPUTS 50 | % ------ 51 | % fname - the input file name 52 | % 53 | % OUTPUTS 54 | % ------- 55 | % ld - the output empty label data 56 | % 57 | 58 | %load the file 59 | ld = []; 60 | try 61 | load(fname, '-mat'); 62 | catch 63 | return; 64 | end; 65 | 66 | %check version 67 | if ~exist('ld', 'var') || ~ld.version<0 68 | error('invalid input file'); 69 | end; 70 | 71 | %check objects 72 | if ~isfield(ld,'objects'), ld.objects = []; end; 73 | 74 | 75 | end 76 | 77 | function write(fname, ld) %#ok 78 | % WRITE saves label data to a file 79 | % 80 | % INPUTS 81 | % ------ 82 | % fname - the input file name 83 | % ld - the input label data 84 | % 85 | % OUTPUTS 86 | % ------- 87 | % 88 | 89 | %load the file 90 | save(fname, 'ld', '-mat'); 91 | 92 | end 93 | 94 | function [obj] = createObj(objId) 95 | % CREATEOBJ creates a new object and returns it 96 | % 97 | % INPUTS 98 | % ------ 99 | % objId - the object id of the new object 100 | % 101 | % OUTPUTS 102 | % ------- 103 | % obj - the new obj 104 | % 105 | 106 | obj = struct('id', objId); 107 | 108 | end 109 | 110 | function [ld, objId] = addObj(ld) 111 | % ADDOBJ adds a new object and returns the object id 112 | % 113 | % INPUTS 114 | % ------ 115 | % ld - the input label data 116 | % 117 | % OUTPUTS 118 | % ------- 119 | % ld - the output label data 120 | % objId - the id of the new object added 121 | % 122 | 123 | %get id of new object 124 | objId = max([ld.objects.id]) + 1; 125 | if isempty(objId), objId = 1; end; 126 | %add it 127 | ld.objects = [ld.objects createObj(objId)]; 128 | 129 | end 130 | 131 | function ld = removeObj(ld, objId) 132 | % REMOVEOBJ deletes an object and clears objects of every label with that 133 | % object id 134 | % 135 | % INPUTS 136 | % ------ 137 | % ld - the input label data 138 | % objId - the id of the object to remove 139 | % 140 | % OUTPUTS 141 | % ------- 142 | % ld - the output label data 143 | % 144 | 145 | %get index of object 146 | objInd = find([ld.objects.id] == objId); 147 | %make sure it's valid 148 | if ~isempty(objInd) 149 | %clear it 150 | ld.objects(objInd) = []; 151 | %update all labels with that object id, loop all frames and check 152 | for f=1:length(ld.frames) 153 | %reset labels with that object label 154 | for l=1:length(ld.frames(f).labels) 155 | if ld.frames(f).labels(l).obj == objId, 156 | ld.frames(f).labels(l).obj = []; 157 | end; 158 | end; 159 | % lbls = find([ld.frames(f).labels.obj] == objId); 160 | % for l=lbls, ld.frames(f).labels(l).obj = []; end; 161 | end; 162 | end; %if 163 | 164 | end 165 | 166 | function [objIds] = getObjIds(ld) 167 | % GETOBJIDS returns the object ids present 168 | % 169 | % INPUTS 170 | % ------ 171 | % ld - the input label data 172 | % 173 | % OUTPUTS 174 | % ------- 175 | % objIds - the list of object ids 176 | % 177 | 178 | %get ids of objects 179 | objIds = [ld.objects.id]; 180 | 181 | end 182 | 183 | function nframes = nFrames(ld) 184 | % NFRAMES returns the number of frames 185 | % 186 | % INPUTS 187 | % ------ 188 | % ld - the input label data 189 | % 190 | % OUTPUTS 191 | % ------- 192 | % nframes - the number of frames 193 | % 194 | 195 | %get the frame 196 | nframes = length(ld.frames); 197 | end 198 | 199 | function frame = getFrame(ld, frameIdx) 200 | % GETFRAME returns the required frame 201 | % 202 | % INPUTS 203 | % ------ 204 | % ld - the input label data 205 | % frameIdx - the frame index 206 | % 207 | % OUTPUTS 208 | % ------- 209 | % frame - the returned frame, which is a structure with fields 210 | % .frame - the index or file name of the frame 211 | % .labels - the array of labels in this frame 212 | % 213 | 214 | %get the frame 215 | frame = ld.frames(frameIdx); 216 | end 217 | 218 | function frm = createFrame(frame, labels) 219 | % CREATEFRAME creates a new frame 220 | % 221 | % INPUTS 222 | % ------ 223 | % frame - the frame id or file name 224 | % labels - the frame labels 225 | % 226 | % OUTPUTS 227 | % ------- 228 | % frm - the output new frame 229 | % 230 | if nargin<1, frame = []; end; 231 | if nargin<2, labels = createLabel(); end; 232 | 233 | %create the new frame 234 | frm = struct('frame',frame, 'labels',labels); 235 | 236 | end 237 | 238 | function [ld, frameIdx] = addFrame(ld, frame, labels) 239 | % ADDFRAME adds a frame into the data structure 240 | % 241 | % INPUTS 242 | % ------ 243 | % ld - the input label data 244 | % frame - the frame id or file name 245 | % labels - the frame labels 246 | % 247 | % OUTPUTS 248 | % ------- 249 | % ld - the update ld structure 250 | % frameIdx - the index of the new frame 251 | % 252 | if nargin<2, frame = []; end; 253 | if nargin<3, labels = createLabel(); end; 254 | 255 | %get the frame index 256 | frameIdx = length(ld.frames) + 1; 257 | 258 | %put the new frame 259 | ld.frames(frameIdx) = createFrame(frame, labels); 260 | 261 | end 262 | 263 | function ld = removeFrame(ld, frameIdx) 264 | % REMOVEFRAME removes the frame 265 | % 266 | % INPUTS 267 | % ------ 268 | % ld - the input label data 269 | % frameIdx - the frame index 270 | % 271 | % OUTPUTS 272 | % ------- 273 | % ld - the update ld structure 274 | % 275 | 276 | %remove the frame 277 | ld.frames(frameIdx) = []; 278 | end 279 | 280 | function label = createLabel(points, type, subtype, objId) 281 | % CREATELABEL creates a new label 282 | % 283 | % INPUTS 284 | % ------ 285 | % points - the points for that label 286 | % type - the type of label 287 | % subtype - the subtype of the label 288 | % objId - the objId of the label 289 | % 290 | % OUTPUTS 291 | % ------- 292 | % ld - the output updated label data 293 | % 294 | if nargin<1, points = {}; end; 295 | if nargin<2, type = []; end; 296 | if nargin<3, subtype = []; end; 297 | if nargin<4, objId = []; end; 298 | 299 | %create a new label 300 | label = struct('points',points, 'type',type, ... 301 | 'subtype',subtype, 'obj',objId); 302 | 303 | end 304 | 305 | function nl = nLabels(ld, frameIdx) 306 | % NLABELS gets the number of labels in the required frame 307 | % 308 | % INPUTS 309 | % ------ 310 | % ld - the input label data 311 | % frameIdx - the frame index 312 | % 313 | % OUTPUTS 314 | % ------- 315 | % nl - the number of labels 316 | % 317 | 318 | nl = length(ld.frames(frameIdx).labels); 319 | 320 | end 321 | 322 | 323 | function [ld, lblIdx] = addLabel(ld, frameIdx, points, type, subtype, objId) 324 | % ADDLABEL adds a new label 325 | % 326 | % INPUTS 327 | % ------ 328 | % ld - the input label data 329 | % frameIdx - the frame index 330 | % points - the points for that label or the label structure if given 331 | % type - the type of label 332 | % subtype - the subtype of the label 333 | % objId - the objId of the label 334 | % 335 | % OUTPUTS 336 | % ------- 337 | % ld - the output updated label data 338 | % lblIdx - the new label index 339 | % 340 | if nargin<3, points = []; end; 341 | if nargin<4, type = []; end; 342 | if nargin<5, subtype = []; end; 343 | if nargin<6, objId = []; end; 344 | 345 | %get the new label index 346 | lblIdx = nLabels(ld, frameIdx) + 1; 347 | 348 | %create the new label if not a struct 349 | if isstruct(points), label = points; 350 | else label = createLabel(points, type, subtype, objId); 351 | end; 352 | 353 | %add the label to the required frame 354 | ld.frames(frameIdx).labels(lblIdx) = label; 355 | 356 | end 357 | 358 | function ld = updateLabel(ld, frameIdx, lblIdx, points, type, subtype, objId) 359 | % UPDATELABEL updates an existing label 360 | % 361 | % INPUTS 362 | % ------ 363 | % ld - the input label data 364 | % frameIdx - the frame id 365 | % lblIdx - the index of the label to change 366 | % points - the points for that label (don't change if nan). It can also 367 | % be a structure, in which case it is a label structure, 368 | % so just replace it 369 | % type - the type of label (don't change if nan) 370 | % subtype - the subtype of the label (don't change if nan) 371 | % objId - the objId of the label (don't change if nan) 372 | % 373 | % OUTPUTS 374 | % ------- 375 | % ld - the output updated label data 376 | % 377 | 378 | %check if just to replace it 379 | if nargin>=4 && isstruct(points) 380 | label = points; 381 | %we are passaed in independent components of the labels 382 | else 383 | %get the label 384 | label = ld.frames(frameIdx).labels(lblIdx); 385 | 386 | %update the label 387 | if nargin>=7 && ~any(isnan(objId)), label.obj = objId; end; 388 | if nargin>=6 && ~any(isnan(subtype)), label.subtype = subtype; end; 389 | if nargin>=5 && ~any(isnan(type)), label.type = type ; end; 390 | if nargin>=4 && ~any(any(isnan(points))), label.points = points; end; 391 | end; 392 | 393 | %put it back 394 | ld.frames(frameIdx).labels(lblIdx) = label; 395 | end 396 | 397 | function label = getLabel(ld, frameIdx, lblIdx) 398 | % GETLABEL retuns the required label 399 | % 400 | % INPUTS 401 | % ------ 402 | % ld - the input label data 403 | % frameIdx - the frame index 404 | % lblIdx - the index of the label to return. If empty or absent, then 405 | % return the labels in this frame 406 | % 407 | % OUTPUTS 408 | % ------- 409 | % label - the returned label(s), which is a structure with fields 410 | % .points - the label points 411 | % .type - the label type 412 | % .subtype - the label subtype 413 | % .obj - the label object id 414 | % 415 | 416 | %get the label 417 | if nargin<3 || isempty(lblIdx) 418 | lblIdx = 1:length(ld.frames(frameIdx).labels); 419 | end; 420 | %return 421 | label = ld.frames(frameIdx).labels(lblIdx); 422 | 423 | end 424 | 425 | function ld = removeLabel(ld, frameIdx, lblIdx) 426 | % REMOVELABEL removes a label 427 | % 428 | % INPUTS 429 | % ------ 430 | % ld - the input label data 431 | % frameIdx - the frame id 432 | % lblIdx - the index of the label to remove 433 | % 434 | % OUTPUTS 435 | % ------- 436 | % ld - the output updated label data 437 | % 438 | 439 | %remove the label 440 | ld.frames(frameIdx).labels(lblIdx) = []; 441 | 442 | end 443 | 444 | 445 | -------------------------------------------------------------------------------- /src/LaneDetectorOpt.ggo: -------------------------------------------------------------------------------- 1 | #Parameters for Lane Detector 2 | #command line: gengetopt -i LaneDetectorOpt.ggo -F LaneDetectorOpt \ 3 | # --func-name=LaneDetectorParser --arg-struct-name=LaneDetectorParserInfo \ 4 | # --conf-parser 5 | 6 | package "LaneDetector" 7 | version "0.1" 8 | 9 | option "ipmWidth" - 10 | "width of IPM image to use" int required 11 | option "ipmHeight" - 12 | "height of IPM image to use" int required 13 | option "ipmTop" - 14 | "Top point in original image of region to make IPM for" int required 15 | option "ipmLeft" - 16 | "Left point in original image of region to make IPM for" int required 17 | option "ipmRight" - 18 | "Right point in original image region to make IPM for" int required 19 | option "ipmBottom" - 20 | "Bottom point in original image region to make IPM for" int required 21 | 22 | option "ipmInterpolation" - 23 | "The method to use for IPM interpolation" int required 24 | 25 | option "lineWidth" - 26 | "width of line to detect in mm (in the world)" double required 27 | option "lineHeight" - 28 | "height of line to detect in mm (in the world)" double required 29 | option "kernelWidth" - 30 | "widht of kernel to use for filtering" int required 31 | option "kernelHeight" - 32 | "Height of kernel to use for filtering" int required 33 | option "lowerQuantile" - 34 | "lower quantile to use for thresholding the filtered image" 35 | double required 36 | option "localMaxima" - 37 | "whether to return local maxima or just the maximum" 38 | int required 39 | option "groupingType" - 40 | "type of grouping to use (default 0: HV lines)" int required 41 | option "binarize" - 42 | "whether to binarize the thresholded image or use the raw values" 43 | double required 44 | option "detectionThreshold" - 45 | "threshold for line scores to declare as line" double required 46 | option "smoothScores" - 47 | "whether to smooth scores of lines detected or not" int required 48 | 49 | option "rMin" - 50 | "rMin for Hough transform (in pixels)" double required 51 | option "rMax" - 52 | "rMax for Hough transform (in pixels)" double required 53 | option "rStep" - 54 | "rStep for Hough transform (in pixels)" double required 55 | option "thetaMin" - 56 | "thetaMin for Hough transform (in degrees)" double required 57 | option "thetaMax" - 58 | "thetaMax for Hough transform (in degrees)" double required 59 | option "thetaStep" - 60 | "thetaStep for Hough transform (in degrees)" double required 61 | 62 | option "ipmVpPortion" - 63 | "Portion of IPM image height to add to y-coordinate of VP" double required 64 | 65 | option "getEndPoints" - 66 | "Get the endpoints of the line" int required 67 | 68 | option "group" - 69 | "group nearby lines or not (default 1: group)" int required 70 | 71 | option "groupThreshold" - 72 | "Threshold for grouping nearby lines (default 10)" double required 73 | 74 | #RANSAC options 75 | option "ransac" - 76 | "use RANSAC (1) or not (0)" int required 77 | 78 | option "ransacLineNumSamples" - 79 | "Number of samples to use for RANSAC" int required 80 | option "ransacLineNumIterations" - 81 | "Number of iterations to use for RANSAC" int required 82 | option "ransacLineNumGoodFit" - 83 | "Number of close points to consider a good line fit" int required 84 | option "ransacLineThreshold" - 85 | "Threshold to consider a point close" double required 86 | option "ransacLineScoreThreshold" - 87 | "Threshold for detected line scores" double required 88 | option "ransacLineBinarize" - 89 | "Whether to binarize image for RANSAC or not" int required 90 | option "ransacLineWindow" - 91 | "Half width to use for ransac window" int required 92 | 93 | option "ransacSplineNumSamples" - 94 | "Number of samples to use for RANSAC" int required 95 | option "ransacSplineNumIterations" - 96 | "Number of iterations to use for RANSAC" int required 97 | option "ransacSplineNumGoodFit" - 98 | "Number of close points to consider a good line fit" int required 99 | option "ransacSplineThreshold" - 100 | "Threshold to consider a point close" double required 101 | option "ransacSplineScoreThreshold" - 102 | "Threshold for detected line scores" double required 103 | option "ransacSplineBinarize" - 104 | "Whether to binarize image for RANSAC or not" int required 105 | option "ransacSplineWindow" - 106 | "Half width to use for ransac window" int required 107 | 108 | option "ransacSplineDegree" - 109 | "Degree of spline to use" int required 110 | option "ransacSpline" - 111 | "Whether to use splines" int required 112 | option "ransacLine" - 113 | "Whether to use lines" int required 114 | 115 | option "ransacSplineStep" - 116 | "Step to use when pixelzing spline in ransac" float required 117 | 118 | 119 | option "overlapThreshold" - 120 | "Overlap threshold to use for grouping of bounding boxes" float required 121 | 122 | 123 | option "localizeAngleThreshold" - 124 | "Angle threshold used for localization (cosine, 1: most restrictive, 0: most liberal)" float required 125 | option "localizeNumLinePixels" - 126 | "Number of pixels to go in normal direction for localization" int required 127 | 128 | 129 | option "extendAngleThreshold" - 130 | "Angle threshold used for extending (cosine, 1: most restrictive, 0: most liberal)" float required 131 | option "extendMeanDirAngleThreshold" - 132 | "Angle threshold from mean direction used for extending (cosine, 1: most restrictive, 0: most liberal)" float required 133 | option "extendLinePixelsTangent" - 134 | "Number of pixels to go in tangent direction for extending" int required 135 | option "extendLinePixelsNormal" - 136 | "Number of pixels to go in tangent direction for extending" int required 137 | option "extendContThreshold" - 138 | "Threhsold used for stopping the extending process (higher -> less extending)" float required 139 | option "extendDeviationThreshold" - 140 | "Stop extending when number of deviating points exceeds this threshold" int required 141 | option "extendRectTop" - 142 | "Top point for extension bounding box" int required 143 | option "extendRectBottom" - 144 | "Bottom point for extension bounding box" int required 145 | 146 | option "extendIPMAngleThreshold" - 147 | "Angle threshold used for extending (cosine, 1: most restrictive, 0: most liberal)" float required 148 | option "extendIPMMeanDirAngleThreshold" - 149 | "Angle threshold from mean direction used for extending (cosine, 1: most restrictive, 0: most liberal)" float required 150 | option "extendIPMLinePixelsTangent" - 151 | "Number of pixels to go in tangent direction for extending" int required 152 | option "extendIPMLinePixelsNormal" - 153 | "Number of pixels to go in tangent direction for extending" int required 154 | option "extendIPMContThreshold" - 155 | "Threhsold used for stopping the extending process (higher -> less extending)" float required 156 | option "extendIPMDeviationThreshold" - 157 | "Stop extending when number of deviating points exceeds this threshold" int required 158 | option "extendIPMRectTop" - 159 | "Top point for extension bounding box" int required 160 | option "extendIPMRectBottom" - 161 | "Bottom point for extension bounding box" int required 162 | 163 | 164 | option "splineScoreJitter" - 165 | "Number of pixels to go around the spline to compute score" int required 166 | option "splineScoreLengthRatio" - 167 | "Ratio of spline length to use" float required 168 | option "splineScoreAngleRatio" - 169 | "Ratio of spline angle to use" float required 170 | option "splineScoreStep" - 171 | "Step to use for spline score computation" float required 172 | 173 | 174 | option "splineTrackingNumAbsentFrames" - 175 | "number of frames the track is allowed to be absent before deleting it" int required 176 | option "splineTrackingNumSeenFrames" - 177 | "number of frames before considering the track good" int required 178 | 179 | option "mergeSplineThetaThreshold" - 180 | "Angle threshold for merging splines (radians)" float required 181 | option "mergeSplineRThreshold" - 182 | "R threshold (distance from origin) for merginn splines" float required 183 | option "mergeSplineMeanThetaThreshold" - 184 | "Mean Angle threshold for merging splines (radians)" float required 185 | option "mergeSplineMeanRThreshold" - 186 | "Mean R threshold (distance from origin) for merginn splines" float required 187 | option "mergeSplineCentroidThreshold" - 188 | "Distance threshold between spline cetroids for merging" float required 189 | 190 | option "lineTrackingNumAbsentFrames" - 191 | "number of frames the track is allowed to be absent before deleting it" int required 192 | option "lineTrackingNumSeenFrames" - 193 | "number of frames before considering the track good" int required 194 | 195 | option "mergeLineThetaThreshold" - 196 | "Angle threshold for merging lines (radians)" float required 197 | option "mergeLineRThreshold" - 198 | "R threshold (distance from origin) for merging lines" float required 199 | 200 | option "numStrips" - 201 | "Number of horizontal strips to divide the image to" int required 202 | 203 | option "checkSplines" - 204 | "Whtethet to check splines or not" int required 205 | option "checkSplinesCurvenessThreshold" - 206 | "Curveness Threshold for checking splines" float required 207 | option "checkSplinesLengthThreshold" - 208 | "Length Threshold for checking splines" float required 209 | option "checkSplinesThetaDiffThreshold" - 210 | "ThetaDiff Threshold for checking splines" float required 211 | option "checkSplinesThetaThreshold" - 212 | "ThetaThreshold Threshold for checking splines" float required 213 | 214 | option "checkIPMSplines" - 215 | "Whtethet to check IPM splines or not" int required 216 | option "checkIPMSplinesCurvenessThreshold" - 217 | "Curveness Threshold for checking splines" float required 218 | option "checkIPMSplinesLengthThreshold" - 219 | "Length Threshold for checking splines" float required 220 | option "checkIPMSplinesThetaDiffThreshold" - 221 | "ThetaDiff Threshold for checking splines" float required 222 | option "checkIPMSplinesThetaThreshold" - 223 | "ThetaThreshold Threshold for checking splines" float required 224 | 225 | option "finalSplineScoreThreshold" - 226 | "Final Threshold for declaring a valid spline" float required 227 | 228 | option "useGroundPlane" - 229 | "Use groudn plane or not when sending to map" int required 230 | 231 | option "checkColor" - 232 | "Whether to check colors or not" int required 233 | option "checkColorWindow" - 234 | "Size of window to use" int required 235 | option "checkColorNumBins" - 236 | "Number of bins to use" int required 237 | option "checkColorNumYellowMin" - 238 | "Min ratio of yellow points" float required 239 | option "checkColorRGMin" - 240 | "Min RG diff" float required 241 | option "checkColorRGMax" - 242 | "Max RG diff" float required 243 | option "checkColorGBMin" - 244 | "Min GB diff" float required 245 | option "checkColorRBMin" - 246 | "Min RB diff" float required 247 | option "checkColorRBFThreshold" - 248 | "RBF Threshold" float required 249 | option "checkColorRBF" - 250 | "Whether to use RBF or not" int required 251 | 252 | option "ipmWindowClear" - 253 | "Whether to clear part of the IPM image" int required 254 | option "ipmWindowLeft" - 255 | "Left corrdinate of window to keep in IPM" int required 256 | option "ipmWindowRight" - 257 | "Left corrdinate of window to keep in IPM" int required 258 | 259 | option "checkLaneWidth" - 260 | "Whether to check lane width or not" int required 261 | option "checkLaneWidthMean" - 262 | "Mean of lane width to look for" float required 263 | option "checkLaneWidthStd" - 264 | "Std deviation of lane width to look for" float required 265 | 266 | 267 | 268 | 269 | 270 | -------------------------------------------------------------------------------- /src/InversePerspectiveMapping.cc: -------------------------------------------------------------------------------- 1 | /*** 2 | * \file InversePerspectiveMapping.cc 3 | * \author Mohamed Aly 4 | * \date 11/29/2006 5 | */ 6 | 7 | #include "InversePerspectiveMapping.hh" 8 | 9 | #include "CameraInfoOpt.h" 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace std; 17 | #include 18 | #include 19 | 20 | namespace LaneDetector 21 | { 22 | 23 | #define VP_PORTION 0.05 24 | 25 | /* 26 | We are assuming the world coordinate frame center is at the camera, 27 | the ground plane is at height -h, the X-axis is going right, 28 | the Y-axis is going forward, the Z-axis is going up. The 29 | camera is looking forward with optical axis in direction of 30 | Y-axis, with possible pitch angle (above or below the Y-axis) 31 | and yaw angle (left or right). 32 | The camera coordinates have the same center as the world, but the Xc-axis goes right, 33 | the Yc-axis goes down, and the Zc-axis (optical cxis) goes forward. The 34 | uv-plane of the image is such that u is horizontal going right, v is 35 | vertical going down. 36 | The image coordinates uv are such that the pixels are at half coordinates 37 | i.e. first pixel is (.5,.5) ...etc where the top-left point is (0,0) i.e. 38 | the tip of the first pixel is (0,0) 39 | */ 40 | 41 | /** 42 | * This function returns the Inverse Perspective Mapping 43 | * of the input image, assuming a flat ground plane, and 44 | * given the camera parameters. 45 | * 46 | * \param inImage the input image 47 | * \param outImage the output image in IPM 48 | * \param ipmInfo the returned IPM info for the transformation 49 | * \param focalLength focal length (in x and y direction) 50 | * \param cameraInfo the camera parameters 51 | * \param outPoints indices of points outside the image 52 | */ 53 | void mcvGetIPM(const CvMat* inImage, CvMat* outImage, 54 | IPMInfo *ipmInfo, const CameraInfo *cameraInfo, 55 | list *outPoints) 56 | { 57 | //check input images types 58 | //CvMat inMat, outMat; 59 | //cvGetMat(inImage, &inMat); 60 | //cvGetMat(outImage, &outMat); 61 | //cout << CV_MAT_TYPE(inImage->type) << " " << CV_MAT_TYPE(FLOAT_MAT_TYPE) << " " << CV_MAT_TYPE(INT_MAT_TYPE)<<"\n"; 62 | if (!(CV_ARE_TYPES_EQ(inImage, outImage) && 63 | (CV_MAT_TYPE(inImage->type)==CV_MAT_TYPE(FLOAT_MAT_TYPE) || 64 | (CV_MAT_TYPE(inImage->type)==CV_MAT_TYPE(INT_MAT_TYPE))))) 65 | { 66 | cerr << "Unsupported image types in mcvGetIPM"; 67 | exit(1); 68 | } 69 | 70 | //get size of input image 71 | FLOAT u, v; 72 | v = inImage->height; 73 | u = inImage->width; 74 | 75 | //get the vanishing point 76 | FLOAT_POINT2D vp; 77 | vp = mcvGetVanishingPoint(cameraInfo); 78 | vp.y = MAX(0, vp.y); 79 | //vp.y = 30; 80 | 81 | //get extent of the image in the xfyf plane 82 | FLOAT_MAT_ELEM_TYPE eps = ipmInfo->vpPortion * v;//VP_PORTION*v; 83 | ipmInfo->ipmLeft = MAX(0, ipmInfo->ipmLeft); 84 | ipmInfo->ipmRight = MIN(u-1, ipmInfo->ipmRight); 85 | ipmInfo->ipmTop = MAX(vp.y+eps, ipmInfo->ipmTop); 86 | ipmInfo->ipmBottom = MIN(v-1, ipmInfo->ipmBottom); 87 | FLOAT_MAT_ELEM_TYPE uvLimitsp[] = {vp.x, 88 | ipmInfo->ipmRight, ipmInfo->ipmLeft, vp.x, 89 | ipmInfo->ipmTop, ipmInfo->ipmTop, ipmInfo->ipmTop, ipmInfo->ipmBottom}; 90 | //{vp.x, u, 0, vp.x, 91 | //vp.y+eps, vp.y+eps, vp.y+eps, v}; 92 | CvMat uvLimits = cvMat(2, 4, FLOAT_MAT_TYPE, uvLimitsp); 93 | 94 | //get these points on the ground plane 95 | CvMat * xyLimitsp = cvCreateMat(2, 4, FLOAT_MAT_TYPE); 96 | CvMat xyLimits = *xyLimitsp; 97 | mcvTransformImage2Ground(&uvLimits, &xyLimits,cameraInfo); 98 | //SHOW_MAT(xyLimitsp, "xyLImits"); 99 | 100 | //get extent on the ground plane 101 | CvMat row1, row2; 102 | cvGetRow(&xyLimits, &row1, 0); 103 | cvGetRow(&xyLimits, &row2, 1); 104 | double xfMax, xfMin, yfMax, yfMin; 105 | cvMinMaxLoc(&row1, (double*)&xfMin, (double*)&xfMax, 0, 0, 0); 106 | cvMinMaxLoc(&row2, (double*)&yfMin, (double*)&yfMax, 0, 0, 0); 107 | 108 | INT outRow = outImage->height; 109 | INT outCol = outImage->width; 110 | 111 | FLOAT_MAT_ELEM_TYPE stepRow = (yfMax-yfMin)/outRow; 112 | FLOAT_MAT_ELEM_TYPE stepCol = (xfMax-xfMin)/outCol; 113 | 114 | //construct the grid to sample 115 | CvMat *xyGrid = cvCreateMat(2, outRow*outCol, FLOAT_MAT_TYPE); 116 | INT i, j; 117 | FLOAT_MAT_ELEM_TYPE x, y; 118 | //fill it with x-y values on the ground plane in world frame 119 | for (i=0, y=yfMax-.5*stepRow; iu-1 || vi<0 || vi>v-1) \*/ \ 144 | if (uiipmLeft || ui>ipmInfo->ipmRight || \ 145 | viipmTop || vi>ipmInfo->ipmBottom) \ 146 | { \ 147 | CV_MAT_ELEM(*outImage, type, i, j) = (type)mean; \ 148 | } \ 149 | /*not out of bounds, then get nearest neighbor*/ \ 150 | else \ 151 | { \ 152 | /*Bilinear interpolation*/ \ 153 | if (ipmInfo->ipmInterpolation == 0) \ 154 | { \ 155 | int x1 = int(ui), x2 = int(ui+1); \ 156 | int y1 = int(vi), y2 = int(vi+1); \ 157 | float x = ui - x1, y = vi - y1; \ 158 | float val = CV_MAT_ELEM(*inImage, type, y1, x1) * (1-x) * (1-y) + \ 159 | CV_MAT_ELEM(*inImage, type, y1, x2) * x * (1-y) + \ 160 | CV_MAT_ELEM(*inImage, type, y2, x1) * (1-x) * y + \ 161 | CV_MAT_ELEM(*inImage, type, y2, x2) * x * y; \ 162 | CV_MAT_ELEM(*outImage, type, i, j) = (type)val; \ 163 | } \ 164 | /*nearest-neighbor interpolation*/ \ 165 | else \ 166 | CV_MAT_ELEM(*outImage, type, i, j) = \ 167 | CV_MAT_ELEM(*inImage, type, int(vi+.5), int(ui+.5)); \ 168 | } \ 169 | if (outPoints && \ 170 | (uiipmLeft+10 || ui>ipmInfo->ipmRight-10 || \ 171 | viipmTop || vi>ipmInfo->ipmBottom-2) )\ 172 | outPoints->push_back(cvPoint(j, i)); \ 173 | } 174 | if (CV_MAT_TYPE(inImage->type)==FLOAT_MAT_TYPE) 175 | { 176 | MCV_GET_IPM(FLOAT_MAT_ELEM_TYPE) 177 | } 178 | else 179 | { 180 | MCV_GET_IPM(INT_MAT_ELEM_TYPE) 181 | } 182 | //return the ipm info 183 | ipmInfo->xLimits[0] = CV_MAT_ELEM(*xyGrid, FLOAT_MAT_ELEM_TYPE, 0, 0); 184 | ipmInfo->xLimits[1] = 185 | CV_MAT_ELEM(*xyGrid, FLOAT_MAT_ELEM_TYPE, 0, (outRow-1)*outCol+outCol-1); 186 | ipmInfo->yLimits[1] = CV_MAT_ELEM(*xyGrid, FLOAT_MAT_ELEM_TYPE, 1, 0); 187 | ipmInfo->yLimits[0] = 188 | CV_MAT_ELEM(*xyGrid, FLOAT_MAT_ELEM_TYPE, 1, (outRow-1)*outCol+outCol-1); 189 | ipmInfo->xScale = 1/stepCol; 190 | ipmInfo->yScale = 1/stepRow; 191 | ipmInfo->width = outCol; 192 | ipmInfo->height = outRow; 193 | 194 | //clean 195 | cvReleaseMat(&xyLimitsp); 196 | cvReleaseMat(&xyGrid); 197 | cvReleaseMat(&uvGrid); 198 | } 199 | 200 | 201 | /** 202 | * Transforms points from the image frame (uv-coordinates) 203 | * into the real world frame on the ground plane (z=-height) 204 | * 205 | * \param inPoints input points in the image frame 206 | * \param outPoints output points in the world frame on the ground 207 | * (z=-height) 208 | * \param cemaraInfo the input camera parameters 209 | * 210 | */ 211 | void mcvTransformImage2Ground(const CvMat *inPoints, 212 | CvMat *outPoints, const CameraInfo *cameraInfo) 213 | { 214 | 215 | //add two rows to the input points 216 | CvMat *inPoints4 = cvCreateMat(inPoints->rows+2, inPoints->cols, 217 | cvGetElemType(inPoints)); 218 | 219 | //copy inPoints to first two rows 220 | CvMat inPoints2, inPoints3, inPointsr4, inPointsr3; 221 | cvGetRows(inPoints4, &inPoints2, 0, 2); 222 | cvGetRows(inPoints4, &inPoints3, 0, 3); 223 | cvGetRow(inPoints4, &inPointsr3, 2); 224 | cvGetRow(inPoints4, &inPointsr4, 3); 225 | cvSet(&inPointsr3, cvRealScalar(1)); 226 | cvCopy(inPoints, &inPoints2); 227 | //create the transformation matrix 228 | float c1 = cos(cameraInfo->pitch); 229 | float s1 = sin(cameraInfo->pitch); 230 | float c2 = cos(cameraInfo->yaw); 231 | float s2 = sin(cameraInfo->yaw); 232 | float matp[] = { 233 | -cameraInfo->cameraHeight*c2/cameraInfo->focalLength.x, 234 | cameraInfo->cameraHeight*s1*s2/cameraInfo->focalLength.y, 235 | (cameraInfo->cameraHeight*c2*cameraInfo->opticalCenter.x/ 236 | cameraInfo->focalLength.x)- 237 | (cameraInfo->cameraHeight *s1*s2* cameraInfo->opticalCenter.y/ 238 | cameraInfo->focalLength.y) - cameraInfo->cameraHeight *c1*s2, 239 | 240 | cameraInfo->cameraHeight *s2 /cameraInfo->focalLength.x, 241 | cameraInfo->cameraHeight *s1*c2 /cameraInfo->focalLength.y, 242 | (-cameraInfo->cameraHeight *s2* cameraInfo->opticalCenter.x 243 | /cameraInfo->focalLength.x)-(cameraInfo->cameraHeight *s1*c2* 244 | cameraInfo->opticalCenter.y /cameraInfo->focalLength.y) - 245 | cameraInfo->cameraHeight *c1*c2, 246 | 247 | 0, 248 | cameraInfo->cameraHeight *c1 /cameraInfo->focalLength.y, 249 | (-cameraInfo->cameraHeight *c1* cameraInfo->opticalCenter.y / 250 | cameraInfo->focalLength.y) + cameraInfo->cameraHeight *s1, 251 | 252 | 0, 253 | -c1 /cameraInfo->focalLength.y, 254 | (c1* cameraInfo->opticalCenter.y /cameraInfo->focalLength.y) - s1, 255 | }; 256 | CvMat mat = cvMat(4, 3, CV_32FC1, matp); 257 | //multiply 258 | cvMatMul(&mat, &inPoints3, inPoints4); 259 | //divide by last row of inPoints4 260 | for (int i=0; icols; i++) 261 | { 262 | float div = CV_MAT_ELEM(inPointsr4, float, 0, i); 263 | CV_MAT_ELEM(*inPoints4, float, 0, i) = 264 | CV_MAT_ELEM(*inPoints4, float, 0, i) / div ; 265 | CV_MAT_ELEM(*inPoints4, float, 1, i) = 266 | CV_MAT_ELEM(*inPoints4, float, 1, i) / div; 267 | } 268 | //put back the result into outPoints 269 | cvCopy(&inPoints2, outPoints); 270 | //clear 271 | cvReleaseMat(&inPoints4); 272 | } 273 | 274 | 275 | /** 276 | * Transforms points from the ground plane (z=-h) in the world frame 277 | * into points on the image in image frame (uv-coordinates) 278 | * 279 | * \param inPoints 2xN array of input points on the ground in world coordinates 280 | * \param outPoints 2xN output points in on the image in image coordinates 281 | * \param cameraInfo the camera parameters 282 | * 283 | */ 284 | void mcvTransformGround2Image(const CvMat *inPoints, 285 | CvMat *outPoints, const CameraInfo *cameraInfo) 286 | { 287 | //add two rows to the input points 288 | CvMat *inPoints3 = cvCreateMat(inPoints->rows+1, inPoints->cols, 289 | cvGetElemType(inPoints)); 290 | 291 | //copy inPoints to first two rows 292 | CvMat inPoints2, inPointsr3; 293 | cvGetRows(inPoints3, &inPoints2, 0, 2); 294 | cvGetRow(inPoints3, &inPointsr3, 2); 295 | cvSet(&inPointsr3, cvRealScalar(-cameraInfo->cameraHeight)); 296 | cvCopy(inPoints, &inPoints2); 297 | //create the transformation matrix 298 | float c1 = cos(cameraInfo->pitch); 299 | float s1 = sin(cameraInfo->pitch); 300 | float c2 = cos(cameraInfo->yaw); 301 | float s2 = sin(cameraInfo->yaw); 302 | float matp[] = { 303 | cameraInfo->focalLength.x * c2 + c1*s2* cameraInfo->opticalCenter.x, 304 | -cameraInfo->focalLength.x * s2 + c1*c2* cameraInfo->opticalCenter.x, 305 | - s1 * cameraInfo->opticalCenter.x, 306 | 307 | s2 * (-cameraInfo->focalLength.y * s1 + c1* cameraInfo->opticalCenter.y), 308 | c2 * (-cameraInfo->focalLength.y * s1 + c1* cameraInfo->opticalCenter.y), 309 | -cameraInfo->focalLength.y * c1 - s1* cameraInfo->opticalCenter.y, 310 | 311 | c1*s2, 312 | c1*c2, 313 | -s1 314 | }; 315 | CvMat mat = cvMat(3, 3, CV_32FC1, matp); 316 | //multiply 317 | cvMatMul(&mat, inPoints3, inPoints3); 318 | //divide by last row of inPoints4 319 | for (int i=0; icols; i++) 320 | { 321 | float div = CV_MAT_ELEM(inPointsr3, float, 0, i); 322 | CV_MAT_ELEM(*inPoints3, float, 0, i) = 323 | CV_MAT_ELEM(*inPoints3, float, 0, i) / div ; 324 | CV_MAT_ELEM(*inPoints3, float, 1, i) = 325 | CV_MAT_ELEM(*inPoints3, float, 1, i) / div; 326 | } 327 | //put back the result into outPoints 328 | cvCopy(&inPoints2, outPoints); 329 | //clear 330 | cvReleaseMat(&inPoints3); 331 | } 332 | 333 | 334 | /** 335 | * Computes the vanishing point in the image plane uv. It is 336 | * the point of intersection of the image plane with the line 337 | * in the XY-plane in the world coordinates that makes an 338 | * angle yaw clockwise (form Y-axis) with Y-axis 339 | * 340 | * \param cameraInfo the input camera parameter 341 | * 342 | * \return the computed vanishing point in image frame 343 | * 344 | */ 345 | FLOAT_POINT2D mcvGetVanishingPoint(const CameraInfo *cameraInfo) 346 | { 347 | //get the vp in world coordinates 348 | FLOAT_MAT_ELEM_TYPE vpp[] = {sin(cameraInfo->yaw)/cos(cameraInfo->pitch), 349 | cos(cameraInfo->yaw)/cos(cameraInfo->pitch), 0}; 350 | CvMat vp = cvMat(3, 1, FLOAT_MAT_TYPE, vpp); 351 | 352 | //transform from world to camera coordinates 353 | // 354 | //rotation matrix for yaw 355 | FLOAT_MAT_ELEM_TYPE tyawp[] = {cos(cameraInfo->yaw), -sin(cameraInfo->yaw), 0, 356 | sin(cameraInfo->yaw), cos(cameraInfo->yaw), 0, 357 | 0, 0, 1}; 358 | CvMat tyaw = cvMat(3, 3, FLOAT_MAT_TYPE, tyawp); 359 | //rotation matrix for pitch 360 | FLOAT_MAT_ELEM_TYPE tpitchp[] = {1, 0, 0, 361 | 0, -sin(cameraInfo->pitch), -cos(cameraInfo->pitch), 362 | 0, cos(cameraInfo->pitch), -sin(cameraInfo->pitch)}; 363 | CvMat transform = cvMat(3, 3, FLOAT_MAT_TYPE, tpitchp); 364 | //combined transform 365 | cvMatMul(&transform, &tyaw, &transform); 366 | 367 | // 368 | //transformation from (xc, yc) in camra coordinates 369 | // to (u,v) in image frame 370 | // 371 | //matrix to shift optical center and focal length 372 | FLOAT_MAT_ELEM_TYPE t1p[] = { 373 | cameraInfo->focalLength.x, 0, 374 | cameraInfo->opticalCenter.x, 375 | 0, cameraInfo->focalLength.y, 376 | cameraInfo->opticalCenter.y, 377 | 0, 0, 1}; 378 | CvMat t1 = cvMat(3, 3, FLOAT_MAT_TYPE, t1p); 379 | //combine transform 380 | cvMatMul(&t1, &transform, &transform); 381 | //transform 382 | cvMatMul(&transform, &vp, &vp); 383 | 384 | // 385 | //clean and return 386 | // 387 | FLOAT_POINT2D ret; 388 | ret.x = cvGetReal1D(&vp, 0); 389 | ret.y = cvGetReal1D(&vp, 1); 390 | return ret; 391 | } 392 | 393 | 394 | /** 395 | * Converts a point from IPM pixel coordinates into world coordinates 396 | * 397 | * \param point in/out point 398 | * \param ipmInfo the ipm info from mcvGetIPM 399 | * 400 | */ 401 | void mcvPointImIPM2World(FLOAT_POINT2D *point, const IPMInfo *ipmInfo) 402 | { 403 | //x-direction 404 | point->x /= ipmInfo->xScale; 405 | point->x += ipmInfo->xLimits[0]; 406 | //y-direction 407 | point->y /= ipmInfo->yScale; 408 | point->y = ipmInfo->yLimits[1] - point->y; 409 | } 410 | 411 | 412 | /** 413 | * Converts from IPM pixel coordinates into world coordinates 414 | * 415 | * \param inMat input matrix 2xN 416 | * \param outMat output matrix 2xN 417 | * \param ipmInfo the ipm info from mcvGetIPM 418 | * 419 | */ 420 | void mcvTransformImIPM2Ground(const CvMat *inMat, CvMat* outMat, const IPMInfo *ipmInfo) 421 | { 422 | CvMat *mat; 423 | mat = outMat; 424 | if(inMat != mat) 425 | { 426 | cvCopy(inMat, mat); 427 | } 428 | 429 | //work on the x-direction i.e. first row 430 | CvMat row; 431 | cvGetRow(mat, &row, 0); 432 | cvConvertScale(&row, &row, 1./ipmInfo->xScale, ipmInfo->xLimits[0]); 433 | 434 | //work on y-direction 435 | cvGetRow(mat, &row, 1); 436 | cvConvertScale(&row, &row, -1./ipmInfo->yScale, ipmInfo->yLimits[1]); 437 | } 438 | 439 | /** 440 | * Converts from IPM pixel coordinates into Image coordinates 441 | * 442 | * \param inMat input matrix 2xN 443 | * \param outMat output matrix 2xN 444 | * \param ipmInfo the ipm info from mcvGetIPM 445 | * \param cameraInfo the camera info 446 | * 447 | */ 448 | void mcvTransformImIPM2Im(const CvMat *inMat, CvMat* outMat, const IPMInfo *ipmInfo, 449 | const CameraInfo *cameraInfo) 450 | { 451 | //convert to world coordinates 452 | mcvTransformImIPM2Ground(inMat, outMat, ipmInfo); 453 | 454 | //convert to image coordinates 455 | mcvTransformGround2Image(outMat, outMat, cameraInfo); 456 | 457 | } 458 | 459 | 460 | /** 461 | * Initializes the cameraInfo structure with data read from the conf file 462 | * 463 | * \param fileName the input camera conf file name 464 | * \param cameraInfo the returned camera parametrs struct 465 | * 466 | */ 467 | void mcvInitCameraInfo (char * const fileName, CameraInfo *cameraInfo) 468 | { 469 | //parsed camera data 470 | CameraInfoParserInfo camInfo; 471 | //read the data 472 | assert(cameraInfoParser_configfile(fileName, &camInfo, 0, 1, 1)==0); 473 | //init the strucure 474 | cameraInfo->focalLength.x = camInfo.focalLengthX_arg; 475 | cameraInfo->focalLength.y = camInfo.focalLengthY_arg; 476 | cameraInfo->opticalCenter.x = camInfo.opticalCenterX_arg; 477 | cameraInfo->opticalCenter.y = camInfo.opticalCenterY_arg; 478 | cameraInfo->cameraHeight = camInfo.cameraHeight_arg; 479 | cameraInfo->pitch = camInfo.pitch_arg * CV_PI/180; 480 | cameraInfo->yaw = camInfo.yaw_arg * CV_PI/180; 481 | cameraInfo->imageWidth = camInfo.imageWidth_arg; 482 | cameraInfo->imageHeight = camInfo.imageHeight_arg; 483 | } 484 | 485 | 486 | /** 487 | * Scales the cameraInfo according to the input image size 488 | * 489 | * \param cameraInfo the input/return structure 490 | * \param size the input image size 491 | * 492 | */ 493 | void mcvScaleCameraInfo (CameraInfo *cameraInfo, CvSize size) 494 | { 495 | //compute the scale factor 496 | double scaleX = size.width/cameraInfo->imageWidth; 497 | double scaleY = size.height/cameraInfo->imageHeight; 498 | //scale 499 | cameraInfo->imageWidth = size.width; 500 | cameraInfo->imageHeight = size.height; 501 | cameraInfo->focalLength.x *= scaleX; 502 | cameraInfo->focalLength.y *= scaleY; 503 | cameraInfo->opticalCenter.x *= scaleX; 504 | cameraInfo->opticalCenter.y *= scaleY; 505 | } 506 | 507 | 508 | /** 509 | * Gets the extent of the image on the ground plane given the camera parameters 510 | * 511 | * \param cameraInfo the input camera info 512 | * \param ipmInfo the IPM info containing the extent on ground plane: 513 | * xLimits & yLimits only are changed 514 | * 515 | */ 516 | void mcvGetIPMExtent(const CameraInfo *cameraInfo, IPMInfo *ipmInfo ) 517 | { 518 | //get size of input image 519 | FLOAT u, v; 520 | v = cameraInfo->imageHeight; 521 | u = cameraInfo->imageWidth; 522 | 523 | //get the vanishing point 524 | FLOAT_POINT2D vp; 525 | vp = mcvGetVanishingPoint(cameraInfo); 526 | vp.y = MAX(0, vp.y); 527 | 528 | //get extent of the image in the xfyf plane 529 | FLOAT_MAT_ELEM_TYPE eps = VP_PORTION*v; 530 | FLOAT_MAT_ELEM_TYPE uvLimitsp[] = {vp.x, u, 0, vp.x, 531 | vp.y+eps, vp.y+eps, vp.y+eps, v}; 532 | CvMat uvLimits = cvMat(2, 4, FLOAT_MAT_TYPE, uvLimitsp); 533 | 534 | //get these points on the ground plane 535 | CvMat * xyLimitsp = cvCreateMat(2, 4, FLOAT_MAT_TYPE); 536 | CvMat xyLimits = *xyLimitsp; 537 | mcvTransformImage2Ground(&uvLimits, &xyLimits,cameraInfo); 538 | //SHOW_MAT(xyLimitsp, "xyLImits"); 539 | 540 | //get extent on the ground plane 541 | CvMat row1, row2; 542 | cvGetRow(&xyLimits, &row1, 0); 543 | cvGetRow(&xyLimits, &row2, 1); 544 | double xfMax, xfMin, yfMax, yfMin; 545 | cvMinMaxLoc(&row1, (double*)&xfMin, (double*)&xfMax, 0, 0, 0); 546 | cvMinMaxLoc(&row2, (double*)&yfMin, (double*)&yfMax, 0, 0, 0); 547 | 548 | //return 549 | ipmInfo->xLimits[0] = xfMin; 550 | ipmInfo->xLimits[1] = xfMax; 551 | ipmInfo->yLimits[1] = yfMax; 552 | ipmInfo->yLimits[0] = yfMin; 553 | 554 | } 555 | 556 | } // namespace LaneDetector 557 | -------------------------------------------------------------------------------- /src/CameraInfoOpt.c: -------------------------------------------------------------------------------- 1 | /* 2 | File autogenerated by gengetopt version 2.18 3 | generated with the following command: 4 | gengetopt -i cameraInfoOpt.ggo -F cameraInfoOpt --func-name=cameraInfoParser --arg-struct-name=CameraInfoParserInfo --conf-parser 5 | 6 | The developers of gengetopt consider the fixed text that goes in all 7 | gengetopt output files to be in the public domain: 8 | we make no copyright claims on it. 9 | */ 10 | 11 | /* If we use autoconf. */ 12 | #ifdef HAVE_CONFIG_H 13 | #include "config.h" 14 | #endif 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "getopt.h" 21 | 22 | #include "CameraInfoOpt.h" 23 | 24 | const char *CameraInfoParserInfo_purpose = ""; 25 | 26 | const char *CameraInfoParserInfo_usage = "Usage: inversePerspectiveMapping [OPTIONS]..."; 27 | 28 | const char *CameraInfoParserInfo_help[] = { 29 | " -h, --help Print help and exit", 30 | " -V, --version Print version and exit", 31 | " --focalLengthX=DOUBLE Focal lenght in horizontal direction in pixels", 32 | " --focalLengthY=DOUBLE Focal lenght in vertical direction in pixels", 33 | " --opticalCenterX=DOUBLE X-coordinate of optical center in pixels", 34 | " --opticalCenterY=DOUBLE Y-coordinate of optical center in pixels", 35 | " --cameraHeight=DOUBLE Height of camera above ground in mm", 36 | " --pitch=DOUBLE pitch of camera in degrees (+ve downwards)", 37 | " --yaw=DOUBLE yaw of camera in degrees (+ve clockwise)", 38 | " --imageWidth=DOUBLE width of image in pixels", 39 | " --imageHeight=DOUBLE height of image in pixels", 40 | 0 41 | }; 42 | 43 | static 44 | void clear_given (struct CameraInfoParserInfo *args_info); 45 | static 46 | void clear_args (struct CameraInfoParserInfo *args_info); 47 | 48 | static int 49 | cameraInfoParser_internal (int argc, char * const *argv, struct CameraInfoParserInfo *args_info, int override, int initialize, int check_required, const char *additional_error); 50 | 51 | static int 52 | cameraInfoParser_required2 (struct CameraInfoParserInfo *args_info, const char *prog_name, const char *additional_error); 53 | struct line_list 54 | { 55 | char * string_arg; 56 | struct line_list * next; 57 | }; 58 | 59 | static struct line_list *cmd_line_list = 0; 60 | static struct line_list *cmd_line_list_tmp = 0; 61 | 62 | static void 63 | free_cmd_list(void) 64 | { 65 | /* free the list of a previous call */ 66 | if (cmd_line_list) 67 | { 68 | while (cmd_line_list) { 69 | cmd_line_list_tmp = cmd_line_list; 70 | cmd_line_list = cmd_line_list->next; 71 | free (cmd_line_list_tmp->string_arg); 72 | free (cmd_line_list_tmp); 73 | } 74 | } 75 | } 76 | 77 | 78 | static char * 79 | gengetopt_strdup (const char *s); 80 | 81 | static 82 | void clear_given (struct CameraInfoParserInfo *args_info) 83 | { 84 | args_info->help_given = 0 ; 85 | args_info->version_given = 0 ; 86 | args_info->focalLengthX_given = 0 ; 87 | args_info->focalLengthY_given = 0 ; 88 | args_info->opticalCenterX_given = 0 ; 89 | args_info->opticalCenterY_given = 0 ; 90 | args_info->cameraHeight_given = 0 ; 91 | args_info->pitch_given = 0 ; 92 | args_info->yaw_given = 0 ; 93 | args_info->imageWidth_given = 0 ; 94 | args_info->imageHeight_given = 0 ; 95 | } 96 | 97 | static 98 | void clear_args (struct CameraInfoParserInfo *args_info) 99 | { 100 | args_info->focalLengthX_orig = NULL; 101 | args_info->focalLengthY_orig = NULL; 102 | args_info->opticalCenterX_orig = NULL; 103 | args_info->opticalCenterY_orig = NULL; 104 | args_info->cameraHeight_orig = NULL; 105 | args_info->pitch_orig = NULL; 106 | args_info->yaw_orig = NULL; 107 | args_info->imageWidth_orig = NULL; 108 | args_info->imageHeight_orig = NULL; 109 | 110 | } 111 | 112 | static 113 | void init_args_info(struct CameraInfoParserInfo *args_info) 114 | { 115 | args_info->help_help = CameraInfoParserInfo_help[0] ; 116 | args_info->version_help = CameraInfoParserInfo_help[1] ; 117 | args_info->focalLengthX_help = CameraInfoParserInfo_help[2] ; 118 | args_info->focalLengthY_help = CameraInfoParserInfo_help[3] ; 119 | args_info->opticalCenterX_help = CameraInfoParserInfo_help[4] ; 120 | args_info->opticalCenterY_help = CameraInfoParserInfo_help[5] ; 121 | args_info->cameraHeight_help = CameraInfoParserInfo_help[6] ; 122 | args_info->pitch_help = CameraInfoParserInfo_help[7] ; 123 | args_info->yaw_help = CameraInfoParserInfo_help[8] ; 124 | args_info->imageWidth_help = CameraInfoParserInfo_help[9] ; 125 | args_info->imageHeight_help = CameraInfoParserInfo_help[10] ; 126 | 127 | } 128 | 129 | void 130 | cameraInfoParser_print_version (void) 131 | { 132 | printf ("%s %s\n", CAMERAINFOPARSER_PACKAGE, CAMERAINFOPARSER_VERSION); 133 | } 134 | 135 | void 136 | cameraInfoParser_print_help (void) 137 | { 138 | int i = 0; 139 | cameraInfoParser_print_version (); 140 | 141 | if (strlen(CameraInfoParserInfo_purpose) > 0) 142 | printf("\n%s\n", CameraInfoParserInfo_purpose); 143 | 144 | printf("\n%s\n\n", CameraInfoParserInfo_usage); 145 | while (CameraInfoParserInfo_help[i]) 146 | printf("%s\n", CameraInfoParserInfo_help[i++]); 147 | } 148 | 149 | void 150 | cameraInfoParser_init (struct CameraInfoParserInfo *args_info) 151 | { 152 | clear_given (args_info); 153 | clear_args (args_info); 154 | init_args_info (args_info); 155 | } 156 | 157 | static void 158 | cameraInfoParser_release (struct CameraInfoParserInfo *args_info) 159 | { 160 | 161 | if (args_info->focalLengthX_orig) 162 | { 163 | free (args_info->focalLengthX_orig); /* free previous argument */ 164 | args_info->focalLengthX_orig = 0; 165 | } 166 | if (args_info->focalLengthY_orig) 167 | { 168 | free (args_info->focalLengthY_orig); /* free previous argument */ 169 | args_info->focalLengthY_orig = 0; 170 | } 171 | if (args_info->opticalCenterX_orig) 172 | { 173 | free (args_info->opticalCenterX_orig); /* free previous argument */ 174 | args_info->opticalCenterX_orig = 0; 175 | } 176 | if (args_info->opticalCenterY_orig) 177 | { 178 | free (args_info->opticalCenterY_orig); /* free previous argument */ 179 | args_info->opticalCenterY_orig = 0; 180 | } 181 | if (args_info->cameraHeight_orig) 182 | { 183 | free (args_info->cameraHeight_orig); /* free previous argument */ 184 | args_info->cameraHeight_orig = 0; 185 | } 186 | if (args_info->pitch_orig) 187 | { 188 | free (args_info->pitch_orig); /* free previous argument */ 189 | args_info->pitch_orig = 0; 190 | } 191 | if (args_info->yaw_orig) 192 | { 193 | free (args_info->yaw_orig); /* free previous argument */ 194 | args_info->yaw_orig = 0; 195 | } 196 | if (args_info->imageWidth_orig) 197 | { 198 | free (args_info->imageWidth_orig); /* free previous argument */ 199 | args_info->imageWidth_orig = 0; 200 | } 201 | if (args_info->imageHeight_orig) 202 | { 203 | free (args_info->imageHeight_orig); /* free previous argument */ 204 | args_info->imageHeight_orig = 0; 205 | } 206 | 207 | clear_given (args_info); 208 | } 209 | 210 | int 211 | cameraInfoParser_file_save(const char *filename, struct CameraInfoParserInfo *args_info) 212 | { 213 | FILE *outfile; 214 | int i = 0; 215 | 216 | outfile = fopen(filename, "w"); 217 | 218 | if (!outfile) 219 | { 220 | fprintf (stderr, "%s: cannot open file for writing: %s\n", CAMERAINFOPARSER_PACKAGE, filename); 221 | return EXIT_FAILURE; 222 | } 223 | 224 | if (args_info->help_given) { 225 | fprintf(outfile, "%s\n", "help"); 226 | } 227 | if (args_info->version_given) { 228 | fprintf(outfile, "%s\n", "version"); 229 | } 230 | if (args_info->focalLengthX_given) { 231 | if (args_info->focalLengthX_orig) { 232 | fprintf(outfile, "%s=\"%s\"\n", "focalLengthX", args_info->focalLengthX_orig); 233 | } else { 234 | fprintf(outfile, "%s\n", "focalLengthX"); 235 | } 236 | } 237 | if (args_info->focalLengthY_given) { 238 | if (args_info->focalLengthY_orig) { 239 | fprintf(outfile, "%s=\"%s\"\n", "focalLengthY", args_info->focalLengthY_orig); 240 | } else { 241 | fprintf(outfile, "%s\n", "focalLengthY"); 242 | } 243 | } 244 | if (args_info->opticalCenterX_given) { 245 | if (args_info->opticalCenterX_orig) { 246 | fprintf(outfile, "%s=\"%s\"\n", "opticalCenterX", args_info->opticalCenterX_orig); 247 | } else { 248 | fprintf(outfile, "%s\n", "opticalCenterX"); 249 | } 250 | } 251 | if (args_info->opticalCenterY_given) { 252 | if (args_info->opticalCenterY_orig) { 253 | fprintf(outfile, "%s=\"%s\"\n", "opticalCenterY", args_info->opticalCenterY_orig); 254 | } else { 255 | fprintf(outfile, "%s\n", "opticalCenterY"); 256 | } 257 | } 258 | if (args_info->cameraHeight_given) { 259 | if (args_info->cameraHeight_orig) { 260 | fprintf(outfile, "%s=\"%s\"\n", "cameraHeight", args_info->cameraHeight_orig); 261 | } else { 262 | fprintf(outfile, "%s\n", "cameraHeight"); 263 | } 264 | } 265 | if (args_info->pitch_given) { 266 | if (args_info->pitch_orig) { 267 | fprintf(outfile, "%s=\"%s\"\n", "pitch", args_info->pitch_orig); 268 | } else { 269 | fprintf(outfile, "%s\n", "pitch"); 270 | } 271 | } 272 | if (args_info->yaw_given) { 273 | if (args_info->yaw_orig) { 274 | fprintf(outfile, "%s=\"%s\"\n", "yaw", args_info->yaw_orig); 275 | } else { 276 | fprintf(outfile, "%s\n", "yaw"); 277 | } 278 | } 279 | if (args_info->imageWidth_given) { 280 | if (args_info->imageWidth_orig) { 281 | fprintf(outfile, "%s=\"%s\"\n", "imageWidth", args_info->imageWidth_orig); 282 | } else { 283 | fprintf(outfile, "%s\n", "imageWidth"); 284 | } 285 | } 286 | if (args_info->imageHeight_given) { 287 | if (args_info->imageHeight_orig) { 288 | fprintf(outfile, "%s=\"%s\"\n", "imageHeight", args_info->imageHeight_orig); 289 | } else { 290 | fprintf(outfile, "%s\n", "imageHeight"); 291 | } 292 | } 293 | 294 | fclose (outfile); 295 | 296 | i = EXIT_SUCCESS; 297 | return i; 298 | } 299 | 300 | void 301 | cameraInfoParser_free (struct CameraInfoParserInfo *args_info) 302 | { 303 | cameraInfoParser_release (args_info); 304 | } 305 | 306 | 307 | /* gengetopt_strdup() */ 308 | /* strdup.c replacement of strdup, which is not standard */ 309 | char * 310 | gengetopt_strdup (const char *s) 311 | { 312 | char *result = NULL; 313 | if (!s) 314 | return result; 315 | 316 | result = (char*)malloc(strlen(s) + 1); 317 | if (result == (char*)0) 318 | return (char*)0; 319 | strcpy(result, s); 320 | return result; 321 | } 322 | 323 | int 324 | cameraInfoParser (int argc, char * const *argv, struct CameraInfoParserInfo *args_info) 325 | { 326 | return cameraInfoParser2 (argc, argv, args_info, 0, 1, 1); 327 | } 328 | 329 | int 330 | cameraInfoParser2 (int argc, char * const *argv, struct CameraInfoParserInfo *args_info, int override, int initialize, int check_required) 331 | { 332 | int result; 333 | 334 | result = cameraInfoParser_internal (argc, argv, args_info, override, initialize, check_required, NULL); 335 | 336 | if (result == EXIT_FAILURE) 337 | { 338 | cameraInfoParser_free (args_info); 339 | exit (EXIT_FAILURE); 340 | } 341 | 342 | return result; 343 | } 344 | 345 | int 346 | cameraInfoParser_required (struct CameraInfoParserInfo *args_info, const char *prog_name) 347 | { 348 | int result = EXIT_SUCCESS; 349 | 350 | if (cameraInfoParser_required2(args_info, prog_name, NULL) > 0) 351 | result = EXIT_FAILURE; 352 | 353 | if (result == EXIT_FAILURE) 354 | { 355 | cameraInfoParser_free (args_info); 356 | exit (EXIT_FAILURE); 357 | } 358 | 359 | return result; 360 | } 361 | 362 | int 363 | cameraInfoParser_required2 (struct CameraInfoParserInfo *args_info, const char *prog_name, const char *additional_error) 364 | { 365 | int error = 0; 366 | 367 | /* checks for required options */ 368 | if (! args_info->focalLengthX_given) 369 | { 370 | fprintf (stderr, "%s: '--focalLengthX' option required%s\n", prog_name, (additional_error ? additional_error : "")); 371 | error = 1; 372 | } 373 | 374 | if (! args_info->focalLengthY_given) 375 | { 376 | fprintf (stderr, "%s: '--focalLengthY' option required%s\n", prog_name, (additional_error ? additional_error : "")); 377 | error = 1; 378 | } 379 | 380 | if (! args_info->opticalCenterX_given) 381 | { 382 | fprintf (stderr, "%s: '--opticalCenterX' option required%s\n", prog_name, (additional_error ? additional_error : "")); 383 | error = 1; 384 | } 385 | 386 | if (! args_info->opticalCenterY_given) 387 | { 388 | fprintf (stderr, "%s: '--opticalCenterY' option required%s\n", prog_name, (additional_error ? additional_error : "")); 389 | error = 1; 390 | } 391 | 392 | if (! args_info->cameraHeight_given) 393 | { 394 | fprintf (stderr, "%s: '--cameraHeight' option required%s\n", prog_name, (additional_error ? additional_error : "")); 395 | error = 1; 396 | } 397 | 398 | if (! args_info->pitch_given) 399 | { 400 | fprintf (stderr, "%s: '--pitch' option required%s\n", prog_name, (additional_error ? additional_error : "")); 401 | error = 1; 402 | } 403 | 404 | if (! args_info->yaw_given) 405 | { 406 | fprintf (stderr, "%s: '--yaw' option required%s\n", prog_name, (additional_error ? additional_error : "")); 407 | error = 1; 408 | } 409 | 410 | if (! args_info->imageWidth_given) 411 | { 412 | fprintf (stderr, "%s: '--imageWidth' option required%s\n", prog_name, (additional_error ? additional_error : "")); 413 | error = 1; 414 | } 415 | 416 | if (! args_info->imageHeight_given) 417 | { 418 | fprintf (stderr, "%s: '--imageHeight' option required%s\n", prog_name, (additional_error ? additional_error : "")); 419 | error = 1; 420 | } 421 | 422 | 423 | /* checks for dependences among options */ 424 | 425 | return error; 426 | } 427 | 428 | int 429 | cameraInfoParser_internal (int argc, char * const *argv, struct CameraInfoParserInfo *args_info, int override, int initialize, int check_required, const char *additional_error) 430 | { 431 | int c; /* Character of the parsed option. */ 432 | 433 | int error = 0; 434 | struct CameraInfoParserInfo local_args_info; 435 | 436 | if (initialize) 437 | cameraInfoParser_init (args_info); 438 | 439 | cameraInfoParser_init (&local_args_info); 440 | 441 | optarg = 0; 442 | optind = 0; 443 | opterr = 1; 444 | optopt = '?'; 445 | 446 | while (1) 447 | { 448 | int option_index = 0; 449 | char *stop_char; 450 | 451 | static struct option long_options[] = { 452 | { "help", 0, NULL, 'h' }, 453 | { "version", 0, NULL, 'V' }, 454 | { "focalLengthX", 1, NULL, 0 }, 455 | { "focalLengthY", 1, NULL, 0 }, 456 | { "opticalCenterX", 1, NULL, 0 }, 457 | { "opticalCenterY", 1, NULL, 0 }, 458 | { "cameraHeight", 1, NULL, 0 }, 459 | { "pitch", 1, NULL, 0 }, 460 | { "yaw", 1, NULL, 0 }, 461 | { "imageWidth", 1, NULL, 0 }, 462 | { "imageHeight", 1, NULL, 0 }, 463 | { NULL, 0, NULL, 0 } 464 | }; 465 | 466 | stop_char = 0; 467 | c = getopt_long (argc, argv, "hV", long_options, &option_index); 468 | 469 | if (c == -1) break; /* Exit from `while (1)' loop. */ 470 | 471 | switch (c) 472 | { 473 | case 'h': /* Print help and exit. */ 474 | cameraInfoParser_print_help (); 475 | cameraInfoParser_free (&local_args_info); 476 | exit (EXIT_SUCCESS); 477 | 478 | case 'V': /* Print version and exit. */ 479 | cameraInfoParser_print_version (); 480 | cameraInfoParser_free (&local_args_info); 481 | exit (EXIT_SUCCESS); 482 | 483 | 484 | case 0: /* Long option with no short option */ 485 | /* Focal lenght in horizontal direction in pixels. */ 486 | if (strcmp (long_options[option_index].name, "focalLengthX") == 0) 487 | { 488 | if (local_args_info.focalLengthX_given) 489 | { 490 | fprintf (stderr, "%s: `--focalLengthX' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 491 | goto failure; 492 | } 493 | if (args_info->focalLengthX_given && ! override) 494 | continue; 495 | local_args_info.focalLengthX_given = 1; 496 | args_info->focalLengthX_given = 1; 497 | args_info->focalLengthX_arg = strtod (optarg, &stop_char); 498 | if (!(stop_char && *stop_char == '\0')) { 499 | fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); 500 | goto failure; 501 | } 502 | if (args_info->focalLengthX_orig) 503 | free (args_info->focalLengthX_orig); /* free previous string */ 504 | args_info->focalLengthX_orig = gengetopt_strdup (optarg); 505 | } 506 | /* Focal lenght in vertical direction in pixels. */ 507 | else if (strcmp (long_options[option_index].name, "focalLengthY") == 0) 508 | { 509 | if (local_args_info.focalLengthY_given) 510 | { 511 | fprintf (stderr, "%s: `--focalLengthY' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 512 | goto failure; 513 | } 514 | if (args_info->focalLengthY_given && ! override) 515 | continue; 516 | local_args_info.focalLengthY_given = 1; 517 | args_info->focalLengthY_given = 1; 518 | args_info->focalLengthY_arg = strtod (optarg, &stop_char); 519 | if (!(stop_char && *stop_char == '\0')) { 520 | fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); 521 | goto failure; 522 | } 523 | if (args_info->focalLengthY_orig) 524 | free (args_info->focalLengthY_orig); /* free previous string */ 525 | args_info->focalLengthY_orig = gengetopt_strdup (optarg); 526 | } 527 | /* X-coordinate of optical center in pixels. */ 528 | else if (strcmp (long_options[option_index].name, "opticalCenterX") == 0) 529 | { 530 | if (local_args_info.opticalCenterX_given) 531 | { 532 | fprintf (stderr, "%s: `--opticalCenterX' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 533 | goto failure; 534 | } 535 | if (args_info->opticalCenterX_given && ! override) 536 | continue; 537 | local_args_info.opticalCenterX_given = 1; 538 | args_info->opticalCenterX_given = 1; 539 | args_info->opticalCenterX_arg = strtod (optarg, &stop_char); 540 | if (!(stop_char && *stop_char == '\0')) { 541 | fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); 542 | goto failure; 543 | } 544 | if (args_info->opticalCenterX_orig) 545 | free (args_info->opticalCenterX_orig); /* free previous string */ 546 | args_info->opticalCenterX_orig = gengetopt_strdup (optarg); 547 | } 548 | /* Y-coordinate of optical center in pixels. */ 549 | else if (strcmp (long_options[option_index].name, "opticalCenterY") == 0) 550 | { 551 | if (local_args_info.opticalCenterY_given) 552 | { 553 | fprintf (stderr, "%s: `--opticalCenterY' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 554 | goto failure; 555 | } 556 | if (args_info->opticalCenterY_given && ! override) 557 | continue; 558 | local_args_info.opticalCenterY_given = 1; 559 | args_info->opticalCenterY_given = 1; 560 | args_info->opticalCenterY_arg = strtod (optarg, &stop_char); 561 | if (!(stop_char && *stop_char == '\0')) { 562 | fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); 563 | goto failure; 564 | } 565 | if (args_info->opticalCenterY_orig) 566 | free (args_info->opticalCenterY_orig); /* free previous string */ 567 | args_info->opticalCenterY_orig = gengetopt_strdup (optarg); 568 | } 569 | /* Height of camera above ground in mm. */ 570 | else if (strcmp (long_options[option_index].name, "cameraHeight") == 0) 571 | { 572 | if (local_args_info.cameraHeight_given) 573 | { 574 | fprintf (stderr, "%s: `--cameraHeight' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 575 | goto failure; 576 | } 577 | if (args_info->cameraHeight_given && ! override) 578 | continue; 579 | local_args_info.cameraHeight_given = 1; 580 | args_info->cameraHeight_given = 1; 581 | args_info->cameraHeight_arg = strtod (optarg, &stop_char); 582 | if (!(stop_char && *stop_char == '\0')) { 583 | fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); 584 | goto failure; 585 | } 586 | if (args_info->cameraHeight_orig) 587 | free (args_info->cameraHeight_orig); /* free previous string */ 588 | args_info->cameraHeight_orig = gengetopt_strdup (optarg); 589 | } 590 | /* pitch of camera in degrees (+ve downwards). */ 591 | else if (strcmp (long_options[option_index].name, "pitch") == 0) 592 | { 593 | if (local_args_info.pitch_given) 594 | { 595 | fprintf (stderr, "%s: `--pitch' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 596 | goto failure; 597 | } 598 | if (args_info->pitch_given && ! override) 599 | continue; 600 | local_args_info.pitch_given = 1; 601 | args_info->pitch_given = 1; 602 | args_info->pitch_arg = strtod (optarg, &stop_char); 603 | if (!(stop_char && *stop_char == '\0')) { 604 | fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); 605 | goto failure; 606 | } 607 | if (args_info->pitch_orig) 608 | free (args_info->pitch_orig); /* free previous string */ 609 | args_info->pitch_orig = gengetopt_strdup (optarg); 610 | } 611 | /* yaw of camera in degrees (+ve clockwise). */ 612 | else if (strcmp (long_options[option_index].name, "yaw") == 0) 613 | { 614 | if (local_args_info.yaw_given) 615 | { 616 | fprintf (stderr, "%s: `--yaw' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 617 | goto failure; 618 | } 619 | if (args_info->yaw_given && ! override) 620 | continue; 621 | local_args_info.yaw_given = 1; 622 | args_info->yaw_given = 1; 623 | args_info->yaw_arg = strtod (optarg, &stop_char); 624 | if (!(stop_char && *stop_char == '\0')) { 625 | fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); 626 | goto failure; 627 | } 628 | if (args_info->yaw_orig) 629 | free (args_info->yaw_orig); /* free previous string */ 630 | args_info->yaw_orig = gengetopt_strdup (optarg); 631 | } 632 | /* width of image in pixels. */ 633 | else if (strcmp (long_options[option_index].name, "imageWidth") == 0) 634 | { 635 | if (local_args_info.imageWidth_given) 636 | { 637 | fprintf (stderr, "%s: `--imageWidth' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 638 | goto failure; 639 | } 640 | if (args_info->imageWidth_given && ! override) 641 | continue; 642 | local_args_info.imageWidth_given = 1; 643 | args_info->imageWidth_given = 1; 644 | args_info->imageWidth_arg = strtod (optarg, &stop_char); 645 | if (!(stop_char && *stop_char == '\0')) { 646 | fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); 647 | goto failure; 648 | } 649 | if (args_info->imageWidth_orig) 650 | free (args_info->imageWidth_orig); /* free previous string */ 651 | args_info->imageWidth_orig = gengetopt_strdup (optarg); 652 | } 653 | /* height of image in pixels. */ 654 | else if (strcmp (long_options[option_index].name, "imageHeight") == 0) 655 | { 656 | if (local_args_info.imageHeight_given) 657 | { 658 | fprintf (stderr, "%s: `--imageHeight' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 659 | goto failure; 660 | } 661 | if (args_info->imageHeight_given && ! override) 662 | continue; 663 | local_args_info.imageHeight_given = 1; 664 | args_info->imageHeight_given = 1; 665 | args_info->imageHeight_arg = strtod (optarg, &stop_char); 666 | if (!(stop_char && *stop_char == '\0')) { 667 | fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); 668 | goto failure; 669 | } 670 | if (args_info->imageHeight_orig) 671 | free (args_info->imageHeight_orig); /* free previous string */ 672 | args_info->imageHeight_orig = gengetopt_strdup (optarg); 673 | } 674 | 675 | break; 676 | case '?': /* Invalid option. */ 677 | /* `getopt_long' already printed an error message. */ 678 | goto failure; 679 | 680 | default: /* bug: option not considered. */ 681 | fprintf (stderr, "%s: option unknown: %c%s\n", CAMERAINFOPARSER_PACKAGE, c, (additional_error ? additional_error : "")); 682 | abort (); 683 | } /* switch */ 684 | } /* while */ 685 | 686 | 687 | 688 | if (check_required) 689 | { 690 | error += cameraInfoParser_required2 (args_info, argv[0], additional_error); 691 | } 692 | 693 | cameraInfoParser_release (&local_args_info); 694 | 695 | if ( error ) 696 | return (EXIT_FAILURE); 697 | 698 | return 0; 699 | 700 | failure: 701 | 702 | cameraInfoParser_release (&local_args_info); 703 | return (EXIT_FAILURE); 704 | } 705 | 706 | #ifndef CONFIG_FILE_LINE_SIZE 707 | #define CONFIG_FILE_LINE_SIZE 2048 708 | #endif 709 | #define ADDITIONAL_ERROR " in configuration file " 710 | 711 | #define CONFIG_FILE_LINE_BUFFER_SIZE (CONFIG_FILE_LINE_SIZE+3) 712 | /* 3 is for "--" and "=" */ 713 | 714 | char my_argv[CONFIG_FILE_LINE_BUFFER_SIZE+1]; 715 | 716 | int 717 | cameraInfoParser_configfile (char * const filename, struct CameraInfoParserInfo *args_info, int override, int initialize, int check_required) 718 | { 719 | FILE* file; 720 | char linebuf[CONFIG_FILE_LINE_SIZE]; 721 | int line_num = 0; 722 | int i, result, equal; 723 | char *fopt, *farg; 724 | char *str_index; 725 | size_t len, next_token; 726 | char delimiter; 727 | int my_argc = 0; 728 | char **my_argv_arg; 729 | char *additional_error; 730 | 731 | /* store the program name */ 732 | cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); 733 | cmd_line_list_tmp->next = cmd_line_list; 734 | cmd_line_list = cmd_line_list_tmp; 735 | cmd_line_list->string_arg = gengetopt_strdup (CAMERAINFOPARSER_PACKAGE); 736 | 737 | if ((file = fopen(filename, "r")) == NULL) 738 | { 739 | fprintf (stderr, "%s: Error opening configuration file '%s'\n", 740 | CAMERAINFOPARSER_PACKAGE, filename); 741 | result = EXIT_FAILURE; 742 | goto conf_failure; 743 | } 744 | 745 | while ((fgets(linebuf, CONFIG_FILE_LINE_SIZE, file)) != NULL) 746 | { 747 | ++line_num; 748 | my_argv[0] = '\0'; 749 | len = strlen(linebuf); 750 | if (len > (CONFIG_FILE_LINE_BUFFER_SIZE-1)) 751 | { 752 | fprintf (stderr, "%s:%s:%d: Line too long in configuration file\n", 753 | CAMERAINFOPARSER_PACKAGE, filename, line_num); 754 | result = EXIT_FAILURE; 755 | goto conf_failure; 756 | } 757 | 758 | /* find first non-whitespace character in the line */ 759 | next_token = strspn ( linebuf, " \t\r\n"); 760 | str_index = linebuf + next_token; 761 | 762 | if ( str_index[0] == '\0' || str_index[0] == '#') 763 | continue; /* empty line or comment line is skipped */ 764 | 765 | fopt = str_index; 766 | 767 | /* truncate fopt at the end of the first non-valid character */ 768 | next_token = strcspn (fopt, " \t\r\n="); 769 | 770 | if (fopt[next_token] == '\0') /* the line is over */ 771 | { 772 | farg = NULL; 773 | equal = 0; 774 | goto noarg; 775 | } 776 | 777 | /* remember if equal sign is present */ 778 | equal = (fopt[next_token] == '='); 779 | fopt[next_token++] = '\0'; 780 | 781 | /* advance pointers to the next token after the end of fopt */ 782 | next_token += strspn (fopt + next_token, " \t\r\n"); 783 | /* check for the presence of equal sign, and if so, skip it */ 784 | if ( !equal ) 785 | if ((equal = (fopt[next_token] == '='))) 786 | { 787 | next_token++; 788 | next_token += strspn (fopt + next_token, " \t\r\n"); 789 | } 790 | str_index += next_token; 791 | 792 | /* find argument */ 793 | farg = str_index; 794 | if ( farg[0] == '\"' || farg[0] == '\'' ) 795 | { /* quoted argument */ 796 | str_index = strchr (++farg, str_index[0] ); /* skip opening quote */ 797 | if (! str_index) 798 | { 799 | fprintf 800 | (stderr, 801 | "%s:%s:%d: unterminated string in configuration file\n", 802 | CAMERAINFOPARSER_PACKAGE, filename, line_num); 803 | result = EXIT_FAILURE; 804 | goto conf_failure; 805 | } 806 | } 807 | else 808 | { /* read up the remaining part up to a delimiter */ 809 | next_token = strcspn (farg, " \t\r\n#\'\""); 810 | str_index += next_token; 811 | } 812 | 813 | /* truncate farg at the delimiter and store it for further check */ 814 | delimiter = *str_index, *str_index++ = '\0'; 815 | 816 | /* everything but comment is illegal at the end of line */ 817 | if (delimiter != '\0' && delimiter != '#') 818 | { 819 | str_index += strspn(str_index, " \t\r\n"); 820 | if (*str_index != '\0' && *str_index != '#') 821 | { 822 | fprintf 823 | (stderr, 824 | "%s:%s:%d: malformed string in configuration file\n", 825 | CAMERAINFOPARSER_PACKAGE, filename, line_num); 826 | result = EXIT_FAILURE; 827 | goto conf_failure; 828 | } 829 | } 830 | 831 | noarg: 832 | ++my_argc; 833 | len = strlen(fopt); 834 | 835 | strcat (my_argv, len > 1 ? "--" : "-"); 836 | strcat (my_argv, fopt); 837 | if (len > 1 && ((farg &&*farg) || equal)) 838 | strcat (my_argv, "="); 839 | if (farg && *farg) 840 | strcat (my_argv, farg); 841 | 842 | cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); 843 | cmd_line_list_tmp->next = cmd_line_list; 844 | cmd_line_list = cmd_line_list_tmp; 845 | cmd_line_list->string_arg = gengetopt_strdup(my_argv); 846 | } /* while */ 847 | 848 | ++my_argc; /* for program name */ 849 | my_argv_arg = (char **) malloc((my_argc+1) * sizeof(char *)); 850 | cmd_line_list_tmp = cmd_line_list; 851 | for (i = my_argc - 1; i >= 0; --i) { 852 | my_argv_arg[i] = cmd_line_list_tmp->string_arg; 853 | cmd_line_list_tmp = cmd_line_list_tmp->next; 854 | } 855 | my_argv_arg[my_argc] = 0; 856 | 857 | additional_error = (char *)malloc(strlen(filename) + strlen(ADDITIONAL_ERROR) + 1); 858 | strcpy (additional_error, ADDITIONAL_ERROR); 859 | strcat (additional_error, filename); 860 | result = 861 | cameraInfoParser_internal (my_argc, my_argv_arg, args_info, override, initialize, check_required, additional_error); 862 | 863 | free (additional_error); 864 | free (my_argv_arg); 865 | 866 | conf_failure: 867 | if (file) 868 | fclose(file); 869 | 870 | free_cmd_list(); 871 | if (result == EXIT_FAILURE) 872 | { 873 | cameraInfoParser_free (args_info); 874 | exit (EXIT_FAILURE); 875 | } 876 | 877 | return result; 878 | } 879 | -------------------------------------------------------------------------------- /src/cmdline.c: -------------------------------------------------------------------------------- 1 | /* 2 | File autogenerated by gengetopt version 2.18 3 | generated with the following command: 4 | gengetopt -i cmdline.ggo -u --conf-parser 5 | 6 | The developers of gengetopt consider the fixed text that goes in all 7 | gengetopt output files to be in the public domain: 8 | we make no copyright claims on it. 9 | */ 10 | 11 | /* If we use autoconf. */ 12 | #ifdef HAVE_CONFIG_H 13 | #include "config.h" 14 | #endif 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "getopt.h" 21 | 22 | #include "cmdline.h" 23 | 24 | const char *gengetopt_args_info_purpose = "Detects lanes in street images."; 25 | 26 | const char *gengetopt_args_info_usage = "Usage: LinePerceptor [OPTIONS]... [FILES]..."; 27 | 28 | const char *gengetopt_args_info_help[] = { 29 | " -h, --help Print help and exit", 30 | " -V, --version Print version and exit", 31 | "\nBasic options:", 32 | " --lanes-conf=STRING Configuration file for lane detection \n (default=`Lanes.conf')", 33 | " --stoplines-conf=STRING Configuration file for stopline detection \n (default=`StopLines.conf')", 34 | " --no-stoplines Don't detect stop lines (default=on)", 35 | " --no-lanes Don't detect lanes (default=off)", 36 | " --camera-conf=STRING Configuration file for the camera paramters \n (default=`CameraInfo.conf')", 37 | " --list-file=STRING Text file containing a list of images one per \n line", 38 | " --list-path=STRING Path where the image files are located, this is \n just appended at the front of each line in \n --list-file (default=`')", 39 | " --image-file=STRING The path to an image", 40 | "\nDebugging options:", 41 | " --wait=INT Number of milliseconds to show the detected \n lanes. Put 0 for infinite i.e. waits for \n keypress. (default=`0')", 42 | " --show Show the detected lines (default=off)", 43 | " --step Step through each image (needs a keypress) or \n fall through (waits for --wait msecs) \n (default=off)", 44 | " --show-lane-numbers Show the lane numbers on the output image \n (default=off)", 45 | " --output-suffix=STRING Suffix of images and results \n (default=`_results')", 46 | " --save-images Export all images with detected lanes to the by \n appending --output-suffix + '.png' to each \n input image (default=off)", 47 | " --save-lanes Export all detected lanes to a text file by \n appending --output-suffix + '.txt' to \n --list-file (default=off)", 48 | " --debug Show debugging information and images \n (default=off)", 49 | 0 50 | }; 51 | 52 | static 53 | void clear_given (struct gengetopt_args_info *args_info); 54 | static 55 | void clear_args (struct gengetopt_args_info *args_info); 56 | 57 | static int 58 | cmdline_parser_internal (int argc, char * const *argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required, const char *additional_error); 59 | 60 | struct line_list 61 | { 62 | char * string_arg; 63 | struct line_list * next; 64 | }; 65 | 66 | static struct line_list *cmd_line_list = 0; 67 | static struct line_list *cmd_line_list_tmp = 0; 68 | 69 | static void 70 | free_cmd_list(void) 71 | { 72 | /* free the list of a previous call */ 73 | if (cmd_line_list) 74 | { 75 | while (cmd_line_list) { 76 | cmd_line_list_tmp = cmd_line_list; 77 | cmd_line_list = cmd_line_list->next; 78 | free (cmd_line_list_tmp->string_arg); 79 | free (cmd_line_list_tmp); 80 | } 81 | } 82 | } 83 | 84 | 85 | static char * 86 | gengetopt_strdup (const char *s); 87 | 88 | static 89 | void clear_given (struct gengetopt_args_info *args_info) 90 | { 91 | args_info->help_given = 0 ; 92 | args_info->version_given = 0 ; 93 | args_info->lanes_conf_given = 0 ; 94 | args_info->stoplines_conf_given = 0 ; 95 | args_info->no_stoplines_given = 0 ; 96 | args_info->no_lanes_given = 0 ; 97 | args_info->camera_conf_given = 0 ; 98 | args_info->list_file_given = 0 ; 99 | args_info->list_path_given = 0 ; 100 | args_info->image_file_given = 0 ; 101 | args_info->wait_given = 0 ; 102 | args_info->show_given = 0 ; 103 | args_info->step_given = 0 ; 104 | args_info->show_lane_numbers_given = 0 ; 105 | args_info->output_suffix_given = 0 ; 106 | args_info->save_images_given = 0 ; 107 | args_info->save_lanes_given = 0 ; 108 | args_info->debug_given = 0 ; 109 | } 110 | 111 | static 112 | void clear_args (struct gengetopt_args_info *args_info) 113 | { 114 | args_info->lanes_conf_arg = gengetopt_strdup ("Lanes.conf"); 115 | args_info->lanes_conf_orig = NULL; 116 | args_info->stoplines_conf_arg = gengetopt_strdup ("StopLines.conf"); 117 | args_info->stoplines_conf_orig = NULL; 118 | args_info->no_stoplines_flag = 1; 119 | args_info->no_lanes_flag = 0; 120 | args_info->camera_conf_arg = gengetopt_strdup ("CameraInfo.conf"); 121 | args_info->camera_conf_orig = NULL; 122 | args_info->list_file_arg = NULL; 123 | args_info->list_file_orig = NULL; 124 | args_info->list_path_arg = gengetopt_strdup (""); 125 | args_info->list_path_orig = NULL; 126 | args_info->image_file_arg = NULL; 127 | args_info->image_file_orig = NULL; 128 | args_info->wait_arg = 0; 129 | args_info->wait_orig = NULL; 130 | args_info->show_flag = 0; 131 | args_info->step_flag = 0; 132 | args_info->show_lane_numbers_flag = 0; 133 | args_info->output_suffix_arg = gengetopt_strdup ("_results"); 134 | args_info->output_suffix_orig = NULL; 135 | args_info->save_images_flag = 0; 136 | args_info->save_lanes_flag = 0; 137 | args_info->debug_flag = 0; 138 | 139 | } 140 | 141 | static 142 | void init_args_info(struct gengetopt_args_info *args_info) 143 | { 144 | args_info->help_help = gengetopt_args_info_help[0] ; 145 | args_info->version_help = gengetopt_args_info_help[1] ; 146 | args_info->lanes_conf_help = gengetopt_args_info_help[3] ; 147 | args_info->stoplines_conf_help = gengetopt_args_info_help[4] ; 148 | args_info->no_stoplines_help = gengetopt_args_info_help[5] ; 149 | args_info->no_lanes_help = gengetopt_args_info_help[6] ; 150 | args_info->camera_conf_help = gengetopt_args_info_help[7] ; 151 | args_info->list_file_help = gengetopt_args_info_help[8] ; 152 | args_info->list_path_help = gengetopt_args_info_help[9] ; 153 | args_info->image_file_help = gengetopt_args_info_help[10] ; 154 | args_info->wait_help = gengetopt_args_info_help[12] ; 155 | args_info->show_help = gengetopt_args_info_help[13] ; 156 | args_info->step_help = gengetopt_args_info_help[14] ; 157 | args_info->show_lane_numbers_help = gengetopt_args_info_help[15] ; 158 | args_info->output_suffix_help = gengetopt_args_info_help[16] ; 159 | args_info->save_images_help = gengetopt_args_info_help[17] ; 160 | args_info->save_lanes_help = gengetopt_args_info_help[18] ; 161 | args_info->debug_help = gengetopt_args_info_help[19] ; 162 | 163 | } 164 | 165 | void 166 | cmdline_parser_print_version (void) 167 | { 168 | printf ("%s %s\n", CMDLINE_PARSER_PACKAGE, CMDLINE_PARSER_VERSION); 169 | } 170 | 171 | void 172 | cmdline_parser_print_help (void) 173 | { 174 | int i = 0; 175 | cmdline_parser_print_version (); 176 | 177 | if (strlen(gengetopt_args_info_purpose) > 0) 178 | printf("\n%s\n", gengetopt_args_info_purpose); 179 | 180 | printf("\n%s\n\n", gengetopt_args_info_usage); 181 | while (gengetopt_args_info_help[i]) 182 | printf("%s\n", gengetopt_args_info_help[i++]); 183 | } 184 | 185 | void 186 | cmdline_parser_init (struct gengetopt_args_info *args_info) 187 | { 188 | clear_given (args_info); 189 | clear_args (args_info); 190 | init_args_info (args_info); 191 | 192 | args_info->inputs = NULL; 193 | args_info->inputs_num = 0; 194 | } 195 | 196 | static void 197 | cmdline_parser_release (struct gengetopt_args_info *args_info) 198 | { 199 | 200 | unsigned int i; 201 | if (args_info->lanes_conf_arg) 202 | { 203 | free (args_info->lanes_conf_arg); /* free previous argument */ 204 | args_info->lanes_conf_arg = 0; 205 | } 206 | if (args_info->lanes_conf_orig) 207 | { 208 | free (args_info->lanes_conf_orig); /* free previous argument */ 209 | args_info->lanes_conf_orig = 0; 210 | } 211 | if (args_info->stoplines_conf_arg) 212 | { 213 | free (args_info->stoplines_conf_arg); /* free previous argument */ 214 | args_info->stoplines_conf_arg = 0; 215 | } 216 | if (args_info->stoplines_conf_orig) 217 | { 218 | free (args_info->stoplines_conf_orig); /* free previous argument */ 219 | args_info->stoplines_conf_orig = 0; 220 | } 221 | if (args_info->camera_conf_arg) 222 | { 223 | free (args_info->camera_conf_arg); /* free previous argument */ 224 | args_info->camera_conf_arg = 0; 225 | } 226 | if (args_info->camera_conf_orig) 227 | { 228 | free (args_info->camera_conf_orig); /* free previous argument */ 229 | args_info->camera_conf_orig = 0; 230 | } 231 | if (args_info->list_file_arg) 232 | { 233 | free (args_info->list_file_arg); /* free previous argument */ 234 | args_info->list_file_arg = 0; 235 | } 236 | if (args_info->list_file_orig) 237 | { 238 | free (args_info->list_file_orig); /* free previous argument */ 239 | args_info->list_file_orig = 0; 240 | } 241 | if (args_info->list_path_arg) 242 | { 243 | free (args_info->list_path_arg); /* free previous argument */ 244 | args_info->list_path_arg = 0; 245 | } 246 | if (args_info->list_path_orig) 247 | { 248 | free (args_info->list_path_orig); /* free previous argument */ 249 | args_info->list_path_orig = 0; 250 | } 251 | if (args_info->image_file_arg) 252 | { 253 | free (args_info->image_file_arg); /* free previous argument */ 254 | args_info->image_file_arg = 0; 255 | } 256 | if (args_info->image_file_orig) 257 | { 258 | free (args_info->image_file_orig); /* free previous argument */ 259 | args_info->image_file_orig = 0; 260 | } 261 | if (args_info->wait_orig) 262 | { 263 | free (args_info->wait_orig); /* free previous argument */ 264 | args_info->wait_orig = 0; 265 | } 266 | if (args_info->output_suffix_arg) 267 | { 268 | free (args_info->output_suffix_arg); /* free previous argument */ 269 | args_info->output_suffix_arg = 0; 270 | } 271 | if (args_info->output_suffix_orig) 272 | { 273 | free (args_info->output_suffix_orig); /* free previous argument */ 274 | args_info->output_suffix_orig = 0; 275 | } 276 | 277 | for (i = 0; i < args_info->inputs_num; ++i) 278 | free (args_info->inputs [i]); 279 | 280 | if (args_info->inputs_num) 281 | free (args_info->inputs); 282 | 283 | clear_given (args_info); 284 | } 285 | 286 | int 287 | cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) 288 | { 289 | FILE *outfile; 290 | int i = 0; 291 | 292 | outfile = fopen(filename, "w"); 293 | 294 | if (!outfile) 295 | { 296 | fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); 297 | return EXIT_FAILURE; 298 | } 299 | 300 | if (args_info->help_given) { 301 | fprintf(outfile, "%s\n", "help"); 302 | } 303 | if (args_info->version_given) { 304 | fprintf(outfile, "%s\n", "version"); 305 | } 306 | if (args_info->lanes_conf_given) { 307 | if (args_info->lanes_conf_orig) { 308 | fprintf(outfile, "%s=\"%s\"\n", "lanes-conf", args_info->lanes_conf_orig); 309 | } else { 310 | fprintf(outfile, "%s\n", "lanes-conf"); 311 | } 312 | } 313 | if (args_info->stoplines_conf_given) { 314 | if (args_info->stoplines_conf_orig) { 315 | fprintf(outfile, "%s=\"%s\"\n", "stoplines-conf", args_info->stoplines_conf_orig); 316 | } else { 317 | fprintf(outfile, "%s\n", "stoplines-conf"); 318 | } 319 | } 320 | if (args_info->no_stoplines_given) { 321 | fprintf(outfile, "%s\n", "no-stoplines"); 322 | } 323 | if (args_info->no_lanes_given) { 324 | fprintf(outfile, "%s\n", "no-lanes"); 325 | } 326 | if (args_info->camera_conf_given) { 327 | if (args_info->camera_conf_orig) { 328 | fprintf(outfile, "%s=\"%s\"\n", "camera-conf", args_info->camera_conf_orig); 329 | } else { 330 | fprintf(outfile, "%s\n", "camera-conf"); 331 | } 332 | } 333 | if (args_info->list_file_given) { 334 | if (args_info->list_file_orig) { 335 | fprintf(outfile, "%s=\"%s\"\n", "list-file", args_info->list_file_orig); 336 | } else { 337 | fprintf(outfile, "%s\n", "list-file"); 338 | } 339 | } 340 | if (args_info->list_path_given) { 341 | if (args_info->list_path_orig) { 342 | fprintf(outfile, "%s=\"%s\"\n", "list-path", args_info->list_path_orig); 343 | } else { 344 | fprintf(outfile, "%s\n", "list-path"); 345 | } 346 | } 347 | if (args_info->image_file_given) { 348 | if (args_info->image_file_orig) { 349 | fprintf(outfile, "%s=\"%s\"\n", "image-file", args_info->image_file_orig); 350 | } else { 351 | fprintf(outfile, "%s\n", "image-file"); 352 | } 353 | } 354 | if (args_info->wait_given) { 355 | if (args_info->wait_orig) { 356 | fprintf(outfile, "%s=\"%s\"\n", "wait", args_info->wait_orig); 357 | } else { 358 | fprintf(outfile, "%s\n", "wait"); 359 | } 360 | } 361 | if (args_info->show_given) { 362 | fprintf(outfile, "%s\n", "show"); 363 | } 364 | if (args_info->step_given) { 365 | fprintf(outfile, "%s\n", "step"); 366 | } 367 | if (args_info->show_lane_numbers_given) { 368 | fprintf(outfile, "%s\n", "show-lane-numbers"); 369 | } 370 | if (args_info->output_suffix_given) { 371 | if (args_info->output_suffix_orig) { 372 | fprintf(outfile, "%s=\"%s\"\n", "output-suffix", args_info->output_suffix_orig); 373 | } else { 374 | fprintf(outfile, "%s\n", "output-suffix"); 375 | } 376 | } 377 | if (args_info->save_images_given) { 378 | fprintf(outfile, "%s\n", "save-images"); 379 | } 380 | if (args_info->save_lanes_given) { 381 | fprintf(outfile, "%s\n", "save-lanes"); 382 | } 383 | if (args_info->debug_given) { 384 | fprintf(outfile, "%s\n", "debug"); 385 | } 386 | 387 | fclose (outfile); 388 | 389 | i = EXIT_SUCCESS; 390 | return i; 391 | } 392 | 393 | void 394 | cmdline_parser_free (struct gengetopt_args_info *args_info) 395 | { 396 | cmdline_parser_release (args_info); 397 | } 398 | 399 | 400 | /* gengetopt_strdup() */ 401 | /* strdup.c replacement of strdup, which is not standard */ 402 | char * 403 | gengetopt_strdup (const char *s) 404 | { 405 | char *result = NULL; 406 | if (!s) 407 | return result; 408 | 409 | result = (char*)malloc(strlen(s) + 1); 410 | if (result == (char*)0) 411 | return (char*)0; 412 | strcpy(result, s); 413 | return result; 414 | } 415 | 416 | int 417 | cmdline_parser (int argc, char * const *argv, struct gengetopt_args_info *args_info) 418 | { 419 | return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); 420 | } 421 | 422 | int 423 | cmdline_parser2 (int argc, char * const *argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) 424 | { 425 | int result; 426 | 427 | result = cmdline_parser_internal (argc, argv, args_info, override, initialize, check_required, NULL); 428 | 429 | if (result == EXIT_FAILURE) 430 | { 431 | cmdline_parser_free (args_info); 432 | exit (EXIT_FAILURE); 433 | } 434 | 435 | return result; 436 | } 437 | 438 | int 439 | cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) 440 | { 441 | return EXIT_SUCCESS; 442 | } 443 | 444 | int 445 | cmdline_parser_internal (int argc, char * const *argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required, const char *additional_error) 446 | { 447 | int c; /* Character of the parsed option. */ 448 | 449 | int error = 0; 450 | struct gengetopt_args_info local_args_info; 451 | 452 | if (initialize) 453 | cmdline_parser_init (args_info); 454 | 455 | cmdline_parser_init (&local_args_info); 456 | 457 | optarg = 0; 458 | optind = 0; 459 | opterr = 1; 460 | optopt = '?'; 461 | 462 | while (1) 463 | { 464 | int option_index = 0; 465 | char *stop_char; 466 | 467 | static struct option long_options[] = { 468 | { "help", 0, NULL, 'h' }, 469 | { "version", 0, NULL, 'V' }, 470 | { "lanes-conf", 1, NULL, 0 }, 471 | { "stoplines-conf", 1, NULL, 0 }, 472 | { "no-stoplines", 0, NULL, 0 }, 473 | { "no-lanes", 0, NULL, 0 }, 474 | { "camera-conf", 1, NULL, 0 }, 475 | { "list-file", 1, NULL, 0 }, 476 | { "list-path", 1, NULL, 0 }, 477 | { "image-file", 1, NULL, 0 }, 478 | { "wait", 1, NULL, 0 }, 479 | { "show", 0, NULL, 0 }, 480 | { "step", 0, NULL, 0 }, 481 | { "show-lane-numbers", 0, NULL, 0 }, 482 | { "output-suffix", 1, NULL, 0 }, 483 | { "save-images", 0, NULL, 0 }, 484 | { "save-lanes", 0, NULL, 0 }, 485 | { "debug", 0, NULL, 0 }, 486 | { NULL, 0, NULL, 0 } 487 | }; 488 | 489 | stop_char = 0; 490 | c = getopt_long (argc, argv, "hV", long_options, &option_index); 491 | 492 | if (c == -1) break; /* Exit from `while (1)' loop. */ 493 | 494 | switch (c) 495 | { 496 | case 'h': /* Print help and exit. */ 497 | cmdline_parser_print_help (); 498 | cmdline_parser_free (&local_args_info); 499 | exit (EXIT_SUCCESS); 500 | 501 | case 'V': /* Print version and exit. */ 502 | cmdline_parser_print_version (); 503 | cmdline_parser_free (&local_args_info); 504 | exit (EXIT_SUCCESS); 505 | 506 | 507 | case 0: /* Long option with no short option */ 508 | /* Configuration file for lane detection. */ 509 | if (strcmp (long_options[option_index].name, "lanes-conf") == 0) 510 | { 511 | if (local_args_info.lanes_conf_given) 512 | { 513 | fprintf (stderr, "%s: `--lanes-conf' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 514 | goto failure; 515 | } 516 | if (args_info->lanes_conf_given && ! override) 517 | continue; 518 | local_args_info.lanes_conf_given = 1; 519 | args_info->lanes_conf_given = 1; 520 | if (args_info->lanes_conf_arg) 521 | free (args_info->lanes_conf_arg); /* free previous string */ 522 | args_info->lanes_conf_arg = gengetopt_strdup (optarg); 523 | if (args_info->lanes_conf_orig) 524 | free (args_info->lanes_conf_orig); /* free previous string */ 525 | args_info->lanes_conf_orig = gengetopt_strdup (optarg); 526 | } 527 | /* Configuration file for stopline detection. */ 528 | else if (strcmp (long_options[option_index].name, "stoplines-conf") == 0) 529 | { 530 | if (local_args_info.stoplines_conf_given) 531 | { 532 | fprintf (stderr, "%s: `--stoplines-conf' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 533 | goto failure; 534 | } 535 | if (args_info->stoplines_conf_given && ! override) 536 | continue; 537 | local_args_info.stoplines_conf_given = 1; 538 | args_info->stoplines_conf_given = 1; 539 | if (args_info->stoplines_conf_arg) 540 | free (args_info->stoplines_conf_arg); /* free previous string */ 541 | args_info->stoplines_conf_arg = gengetopt_strdup (optarg); 542 | if (args_info->stoplines_conf_orig) 543 | free (args_info->stoplines_conf_orig); /* free previous string */ 544 | args_info->stoplines_conf_orig = gengetopt_strdup (optarg); 545 | } 546 | /* Don't detect stop lines. */ 547 | else if (strcmp (long_options[option_index].name, "no-stoplines") == 0) 548 | { 549 | if (local_args_info.no_stoplines_given) 550 | { 551 | fprintf (stderr, "%s: `--no-stoplines' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 552 | goto failure; 553 | } 554 | if (args_info->no_stoplines_given && ! override) 555 | continue; 556 | local_args_info.no_stoplines_given = 1; 557 | args_info->no_stoplines_given = 1; 558 | args_info->no_stoplines_flag = !(args_info->no_stoplines_flag); 559 | } 560 | /* Don't detect lanes. */ 561 | else if (strcmp (long_options[option_index].name, "no-lanes") == 0) 562 | { 563 | if (local_args_info.no_lanes_given) 564 | { 565 | fprintf (stderr, "%s: `--no-lanes' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 566 | goto failure; 567 | } 568 | if (args_info->no_lanes_given && ! override) 569 | continue; 570 | local_args_info.no_lanes_given = 1; 571 | args_info->no_lanes_given = 1; 572 | args_info->no_lanes_flag = !(args_info->no_lanes_flag); 573 | } 574 | /* Configuration file for the camera paramters. */ 575 | else if (strcmp (long_options[option_index].name, "camera-conf") == 0) 576 | { 577 | if (local_args_info.camera_conf_given) 578 | { 579 | fprintf (stderr, "%s: `--camera-conf' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 580 | goto failure; 581 | } 582 | if (args_info->camera_conf_given && ! override) 583 | continue; 584 | local_args_info.camera_conf_given = 1; 585 | args_info->camera_conf_given = 1; 586 | if (args_info->camera_conf_arg) 587 | free (args_info->camera_conf_arg); /* free previous string */ 588 | args_info->camera_conf_arg = gengetopt_strdup (optarg); 589 | if (args_info->camera_conf_orig) 590 | free (args_info->camera_conf_orig); /* free previous string */ 591 | args_info->camera_conf_orig = gengetopt_strdup (optarg); 592 | } 593 | /* Text file containing a list of images one per line. */ 594 | else if (strcmp (long_options[option_index].name, "list-file") == 0) 595 | { 596 | if (local_args_info.list_file_given) 597 | { 598 | fprintf (stderr, "%s: `--list-file' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 599 | goto failure; 600 | } 601 | if (args_info->list_file_given && ! override) 602 | continue; 603 | local_args_info.list_file_given = 1; 604 | args_info->list_file_given = 1; 605 | if (args_info->list_file_arg) 606 | free (args_info->list_file_arg); /* free previous string */ 607 | args_info->list_file_arg = gengetopt_strdup (optarg); 608 | if (args_info->list_file_orig) 609 | free (args_info->list_file_orig); /* free previous string */ 610 | args_info->list_file_orig = gengetopt_strdup (optarg); 611 | } 612 | /* Path where the image files are located, this is just appended at the front of each line in --list-file. */ 613 | else if (strcmp (long_options[option_index].name, "list-path") == 0) 614 | { 615 | if (local_args_info.list_path_given) 616 | { 617 | fprintf (stderr, "%s: `--list-path' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 618 | goto failure; 619 | } 620 | if (args_info->list_path_given && ! override) 621 | continue; 622 | local_args_info.list_path_given = 1; 623 | args_info->list_path_given = 1; 624 | if (args_info->list_path_arg) 625 | free (args_info->list_path_arg); /* free previous string */ 626 | args_info->list_path_arg = gengetopt_strdup (optarg); 627 | if (args_info->list_path_orig) 628 | free (args_info->list_path_orig); /* free previous string */ 629 | args_info->list_path_orig = gengetopt_strdup (optarg); 630 | } 631 | /* The path to an image. */ 632 | else if (strcmp (long_options[option_index].name, "image-file") == 0) 633 | { 634 | if (local_args_info.image_file_given) 635 | { 636 | fprintf (stderr, "%s: `--image-file' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 637 | goto failure; 638 | } 639 | if (args_info->image_file_given && ! override) 640 | continue; 641 | local_args_info.image_file_given = 1; 642 | args_info->image_file_given = 1; 643 | if (args_info->image_file_arg) 644 | free (args_info->image_file_arg); /* free previous string */ 645 | args_info->image_file_arg = gengetopt_strdup (optarg); 646 | if (args_info->image_file_orig) 647 | free (args_info->image_file_orig); /* free previous string */ 648 | args_info->image_file_orig = gengetopt_strdup (optarg); 649 | } 650 | /* Number of milliseconds to show the detected lanes. Put 0 for infinite i.e. waits for keypress.. */ 651 | else if (strcmp (long_options[option_index].name, "wait") == 0) 652 | { 653 | if (local_args_info.wait_given) 654 | { 655 | fprintf (stderr, "%s: `--wait' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 656 | goto failure; 657 | } 658 | if (args_info->wait_given && ! override) 659 | continue; 660 | local_args_info.wait_given = 1; 661 | args_info->wait_given = 1; 662 | args_info->wait_arg = strtol (optarg, &stop_char, 0); 663 | if (!(stop_char && *stop_char == '\0')) { 664 | fprintf(stderr, "%s: invalid numeric value: %s\n", argv[0], optarg); 665 | goto failure; 666 | } 667 | if (args_info->wait_orig) 668 | free (args_info->wait_orig); /* free previous string */ 669 | args_info->wait_orig = gengetopt_strdup (optarg); 670 | } 671 | /* Show the detected lines. */ 672 | else if (strcmp (long_options[option_index].name, "show") == 0) 673 | { 674 | if (local_args_info.show_given) 675 | { 676 | fprintf (stderr, "%s: `--show' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 677 | goto failure; 678 | } 679 | if (args_info->show_given && ! override) 680 | continue; 681 | local_args_info.show_given = 1; 682 | args_info->show_given = 1; 683 | args_info->show_flag = !(args_info->show_flag); 684 | } 685 | /* Step through each image (needs a keypress) or fall through (waits for --wait msecs). */ 686 | else if (strcmp (long_options[option_index].name, "step") == 0) 687 | { 688 | if (local_args_info.step_given) 689 | { 690 | fprintf (stderr, "%s: `--step' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 691 | goto failure; 692 | } 693 | if (args_info->step_given && ! override) 694 | continue; 695 | local_args_info.step_given = 1; 696 | args_info->step_given = 1; 697 | args_info->step_flag = !(args_info->step_flag); 698 | } 699 | /* Show the lane numbers on the output image. */ 700 | else if (strcmp (long_options[option_index].name, "show-lane-numbers") == 0) 701 | { 702 | if (local_args_info.show_lane_numbers_given) 703 | { 704 | fprintf (stderr, "%s: `--show-lane-numbers' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 705 | goto failure; 706 | } 707 | if (args_info->show_lane_numbers_given && ! override) 708 | continue; 709 | local_args_info.show_lane_numbers_given = 1; 710 | args_info->show_lane_numbers_given = 1; 711 | args_info->show_lane_numbers_flag = !(args_info->show_lane_numbers_flag); 712 | } 713 | /* Suffix of images and results. */ 714 | else if (strcmp (long_options[option_index].name, "output-suffix") == 0) 715 | { 716 | if (local_args_info.output_suffix_given) 717 | { 718 | fprintf (stderr, "%s: `--output-suffix' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 719 | goto failure; 720 | } 721 | if (args_info->output_suffix_given && ! override) 722 | continue; 723 | local_args_info.output_suffix_given = 1; 724 | args_info->output_suffix_given = 1; 725 | if (args_info->output_suffix_arg) 726 | free (args_info->output_suffix_arg); /* free previous string */ 727 | args_info->output_suffix_arg = gengetopt_strdup (optarg); 728 | if (args_info->output_suffix_orig) 729 | free (args_info->output_suffix_orig); /* free previous string */ 730 | args_info->output_suffix_orig = gengetopt_strdup (optarg); 731 | } 732 | /* Export all images with detected lanes to the by appending --output-suffix + '.png' to each input image. */ 733 | else if (strcmp (long_options[option_index].name, "save-images") == 0) 734 | { 735 | if (local_args_info.save_images_given) 736 | { 737 | fprintf (stderr, "%s: `--save-images' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 738 | goto failure; 739 | } 740 | if (args_info->save_images_given && ! override) 741 | continue; 742 | local_args_info.save_images_given = 1; 743 | args_info->save_images_given = 1; 744 | args_info->save_images_flag = !(args_info->save_images_flag); 745 | } 746 | /* Export all detected lanes to a text file by appending --output-suffix + '.txt' to --list-file. */ 747 | else if (strcmp (long_options[option_index].name, "save-lanes") == 0) 748 | { 749 | if (local_args_info.save_lanes_given) 750 | { 751 | fprintf (stderr, "%s: `--save-lanes' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 752 | goto failure; 753 | } 754 | if (args_info->save_lanes_given && ! override) 755 | continue; 756 | local_args_info.save_lanes_given = 1; 757 | args_info->save_lanes_given = 1; 758 | args_info->save_lanes_flag = !(args_info->save_lanes_flag); 759 | } 760 | /* Show debugging information and images. */ 761 | else if (strcmp (long_options[option_index].name, "debug") == 0) 762 | { 763 | if (local_args_info.debug_given) 764 | { 765 | fprintf (stderr, "%s: `--debug' option given more than once%s\n", argv[0], (additional_error ? additional_error : "")); 766 | goto failure; 767 | } 768 | if (args_info->debug_given && ! override) 769 | continue; 770 | local_args_info.debug_given = 1; 771 | args_info->debug_given = 1; 772 | args_info->debug_flag = !(args_info->debug_flag); 773 | } 774 | 775 | break; 776 | case '?': /* Invalid option. */ 777 | /* `getopt_long' already printed an error message. */ 778 | goto failure; 779 | 780 | default: /* bug: option not considered. */ 781 | fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); 782 | abort (); 783 | } /* switch */ 784 | } /* while */ 785 | 786 | 787 | 788 | 789 | cmdline_parser_release (&local_args_info); 790 | 791 | if ( error ) 792 | return (EXIT_FAILURE); 793 | 794 | if (optind < argc) 795 | { 796 | int i = 0 ; 797 | int found_prog_name = 0; 798 | /* whether program name, i.e., argv[0], is in the remaining args 799 | (this may happen with some implementations of getopt, 800 | but surely not with the one included by gengetopt) */ 801 | 802 | i = optind; 803 | while (i < argc) 804 | if (argv[i++] == argv[0]) { 805 | found_prog_name = 1; 806 | break; 807 | } 808 | i = 0; 809 | 810 | args_info->inputs_num = argc - optind - found_prog_name; 811 | args_info->inputs = 812 | (char **)(malloc ((args_info->inputs_num)*sizeof(char *))) ; 813 | while (optind < argc) 814 | if (argv[optind++] != argv[0]) 815 | args_info->inputs[ i++ ] = gengetopt_strdup (argv[optind-1]) ; 816 | } 817 | 818 | return 0; 819 | 820 | failure: 821 | 822 | cmdline_parser_release (&local_args_info); 823 | return (EXIT_FAILURE); 824 | } 825 | 826 | #ifndef CONFIG_FILE_LINE_SIZE 827 | #define CONFIG_FILE_LINE_SIZE 2048 828 | #endif 829 | #define ADDITIONAL_ERROR " in configuration file " 830 | 831 | #define CONFIG_FILE_LINE_BUFFER_SIZE (CONFIG_FILE_LINE_SIZE+3) 832 | /* 3 is for "--" and "=" */ 833 | 834 | char my_argv[CONFIG_FILE_LINE_BUFFER_SIZE+1]; 835 | 836 | int 837 | cmdline_parser_configfile (char * const filename, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) 838 | { 839 | FILE* file; 840 | char linebuf[CONFIG_FILE_LINE_SIZE]; 841 | int line_num = 0; 842 | int i, result, equal; 843 | char *fopt, *farg; 844 | char *str_index; 845 | size_t len, next_token; 846 | char delimiter; 847 | int my_argc = 0; 848 | char **my_argv_arg; 849 | char *additional_error; 850 | 851 | /* store the program name */ 852 | cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); 853 | cmd_line_list_tmp->next = cmd_line_list; 854 | cmd_line_list = cmd_line_list_tmp; 855 | cmd_line_list->string_arg = gengetopt_strdup (CMDLINE_PARSER_PACKAGE); 856 | 857 | if ((file = fopen(filename, "r")) == NULL) 858 | { 859 | fprintf (stderr, "%s: Error opening configuration file '%s'\n", 860 | CMDLINE_PARSER_PACKAGE, filename); 861 | result = EXIT_FAILURE; 862 | goto conf_failure; 863 | } 864 | 865 | while ((fgets(linebuf, CONFIG_FILE_LINE_SIZE, file)) != NULL) 866 | { 867 | ++line_num; 868 | my_argv[0] = '\0'; 869 | len = strlen(linebuf); 870 | if (len > (CONFIG_FILE_LINE_BUFFER_SIZE-1)) 871 | { 872 | fprintf (stderr, "%s:%s:%d: Line too long in configuration file\n", 873 | CMDLINE_PARSER_PACKAGE, filename, line_num); 874 | result = EXIT_FAILURE; 875 | goto conf_failure; 876 | } 877 | 878 | /* find first non-whitespace character in the line */ 879 | next_token = strspn ( linebuf, " \t\r\n"); 880 | str_index = linebuf + next_token; 881 | 882 | if ( str_index[0] == '\0' || str_index[0] == '#') 883 | continue; /* empty line or comment line is skipped */ 884 | 885 | fopt = str_index; 886 | 887 | /* truncate fopt at the end of the first non-valid character */ 888 | next_token = strcspn (fopt, " \t\r\n="); 889 | 890 | if (fopt[next_token] == '\0') /* the line is over */ 891 | { 892 | farg = NULL; 893 | equal = 0; 894 | goto noarg; 895 | } 896 | 897 | /* remember if equal sign is present */ 898 | equal = (fopt[next_token] == '='); 899 | fopt[next_token++] = '\0'; 900 | 901 | /* advance pointers to the next token after the end of fopt */ 902 | next_token += strspn (fopt + next_token, " \t\r\n"); 903 | /* check for the presence of equal sign, and if so, skip it */ 904 | if ( !equal ) 905 | if ((equal = (fopt[next_token] == '='))) 906 | { 907 | next_token++; 908 | next_token += strspn (fopt + next_token, " \t\r\n"); 909 | } 910 | str_index += next_token; 911 | 912 | /* find argument */ 913 | farg = str_index; 914 | if ( farg[0] == '\"' || farg[0] == '\'' ) 915 | { /* quoted argument */ 916 | str_index = strchr (++farg, str_index[0] ); /* skip opening quote */ 917 | if (! str_index) 918 | { 919 | fprintf 920 | (stderr, 921 | "%s:%s:%d: unterminated string in configuration file\n", 922 | CMDLINE_PARSER_PACKAGE, filename, line_num); 923 | result = EXIT_FAILURE; 924 | goto conf_failure; 925 | } 926 | } 927 | else 928 | { /* read up the remaining part up to a delimiter */ 929 | next_token = strcspn (farg, " \t\r\n#\'\""); 930 | str_index += next_token; 931 | } 932 | 933 | /* truncate farg at the delimiter and store it for further check */ 934 | delimiter = *str_index, *str_index++ = '\0'; 935 | 936 | /* everything but comment is illegal at the end of line */ 937 | if (delimiter != '\0' && delimiter != '#') 938 | { 939 | str_index += strspn(str_index, " \t\r\n"); 940 | if (*str_index != '\0' && *str_index != '#') 941 | { 942 | fprintf 943 | (stderr, 944 | "%s:%s:%d: malformed string in configuration file\n", 945 | CMDLINE_PARSER_PACKAGE, filename, line_num); 946 | result = EXIT_FAILURE; 947 | goto conf_failure; 948 | } 949 | } 950 | 951 | noarg: 952 | ++my_argc; 953 | len = strlen(fopt); 954 | 955 | strcat (my_argv, len > 1 ? "--" : "-"); 956 | strcat (my_argv, fopt); 957 | if (len > 1 && ((farg &&*farg) || equal)) 958 | strcat (my_argv, "="); 959 | if (farg && *farg) 960 | strcat (my_argv, farg); 961 | 962 | cmd_line_list_tmp = (struct line_list *) malloc (sizeof (struct line_list)); 963 | cmd_line_list_tmp->next = cmd_line_list; 964 | cmd_line_list = cmd_line_list_tmp; 965 | cmd_line_list->string_arg = gengetopt_strdup(my_argv); 966 | } /* while */ 967 | 968 | ++my_argc; /* for program name */ 969 | my_argv_arg = (char **) malloc((my_argc+1) * sizeof(char *)); 970 | cmd_line_list_tmp = cmd_line_list; 971 | for (i = my_argc - 1; i >= 0; --i) { 972 | my_argv_arg[i] = cmd_line_list_tmp->string_arg; 973 | cmd_line_list_tmp = cmd_line_list_tmp->next; 974 | } 975 | my_argv_arg[my_argc] = 0; 976 | 977 | additional_error = (char *)malloc(strlen(filename) + strlen(ADDITIONAL_ERROR) + 1); 978 | strcpy (additional_error, ADDITIONAL_ERROR); 979 | strcat (additional_error, filename); 980 | result = 981 | cmdline_parser_internal (my_argc, my_argv_arg, args_info, override, initialize, check_required, additional_error); 982 | 983 | free (additional_error); 984 | free (my_argv_arg); 985 | 986 | conf_failure: 987 | if (file) 988 | fclose(file); 989 | 990 | free_cmd_list(); 991 | if (result == EXIT_FAILURE) 992 | { 993 | cmdline_parser_free (args_info); 994 | exit (EXIT_FAILURE); 995 | } 996 | 997 | return result; 998 | } 999 | --------------------------------------------------------------------------------