diff --git a/modules/line_descriptor/CMakeLists.txt b/modules/line_descriptor/CMakeLists.txt new file mode 100644 index 000000000..b21a10bd4 --- /dev/null +++ b/modules/line_descriptor/CMakeLists.txt @@ -0,0 +1,64 @@ +#INCLUDE_DIRECTORIES(/data1/lz/LilianTests/ARPACKLAB/arpack++/include/) +#INCLUDE_DIRECTORIES(/data1/lz/LilianTests/ARPACKLAB/arpack++) +INCLUDE_DIRECTORIES(/usr/include/arpack++/include/) +INCLUDE_DIRECTORIES(/usr/include/arpack++) + +#project name +PROJECT(LILIANTESTS) + +cmake_minimum_required(VERSION 2.8) + +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +SET(BUILD_SHARED_LIBS ON) + +## where are user-specific cmake modules +SET(CMAKE_MODULE_PATH $ENV{CMAKE_MODULE_PATH}) + +OPTION(USE_BIAS OFF) + +#IF(USE_BIAS) +#FIND_PACKAGE(BIAS) +#IF(BIAS_FOUND) +# INCLUDE(${BIAS_USE_FILE}) +#ELSE(BIAS_FOUND) +# MESSAGE(SEND_ERROR "BIAS lib not found.") +#ENDIF(BIAS_FOUND) +#ENDIF(USE_BIAS) + + +IF(USE_BIAS) +INCLUDE_DIRECTORIES(${BIAS_INCLUDE_DIR} /usr/local/include/BIAS /usr/include/ImageMagick /usr/local/include/opencv2 ${WXWIDGETS_INCLUDE_DIR}) +LINK_DIRECTORIES( ${BIAS_LINK_DIRECTORIES}) +ENDIF(USE_BIAS) + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${BIAS_CXX_FLAGS} -std=c++0x") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${BIAS_C_FLAGS}") + +# source files of library "LineMatchingLib" to be created +SET(LineMatchingLib_SRCS + #src/PairwiseLineMatching.cpp + src/LineDescriptor.cpp + src/EDLineDetector.cpp +) +# header files to be installed +SET(LineMatchingLib_HEADER + #include/PairwiseLineMatching.hh + include/LineDescriptor.hh + include/EDLineDetector.hh + include/LineStructure.hh +) + + +ADD_LIBRARY(LineMatchingLib + ${LineMatchingLib_SRCS} + ${LineMatchingLib_HEADER}) +TARGET_LINK_LIBRARIES(LineMatchingLib /usr/lib/libsuperlu.so opencv_core opencv_highgui opencv_imgproc) + + +#ADD_EXECUTABLE(TestLineMatchingAlgorithm src/TestLineMatchingAlgorithm.cpp) +#TARGET_LINK_LIBRARIES(TestLineMatchingAlgorithm LineMatchingLib ) + + diff --git a/modules/line_descriptor/include/opencv2/line_descriptor/EDLineDetector.hh b/modules/line_descriptor/include/opencv2/line_descriptor/EDLineDetector.hh new file mode 100644 index 000000000..40b991058 --- /dev/null +++ b/modules/line_descriptor/include/opencv2/line_descriptor/EDLineDetector.hh @@ -0,0 +1,434 @@ +/*IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + + By downloading, copying, installing or using the software you agree to this license. + If you do not agree to this license, do not download, install, + copy or use the software. + + + License Agreement + For Open Source Computer Vision Library + +Copyright (C) 2011-2012, Lilian Zhang, all rights reserved. +Copyright (C) 2013, Manuele Tamburrano, Stefano Fabri, all rights reserved. +Third party copyrights are property of their respective owners. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name of the copyright holders may not be used to endorse or promote products + derived from this software without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are disclaimed. +In no event shall the Intel Corporation or contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or services; +loss of use, data, or profits; or business interruption) however caused +and on any theory of liability, whether in contract, strict liability, +or tort (including negligence or otherwise) arising in any way out of +the use of this software, even if advised of the possibility of such damage. +*/ + +#ifndef EDLINEDETECTOR_HH_ +#define EDLINEDETECTOR_HH_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct Pixel{ + unsigned int x;//X coordinate + unsigned int y;//Y coordinate +}; +struct EdgeChains{ + std::vector xCors;//all the x coordinates of edge points + std::vector yCors;//all the y coordinates of edge points + std::vector sId; //the start index of each edge in the coordinate arrays + unsigned int numOfEdges;//the number of edges whose length are larger than minLineLen; numOfEdges < sId.size; +}; +struct LineChains{ + std::vector xCors;//all the x coordinates of line points + std::vector yCors;//all the y coordinates of line points + std::vector sId; //the start index of each line in the coordinate arrays + unsigned int numOfLines;//the number of lines whose length are larger than minLineLen; numOfLines < sId.size; +}; + +typedef std::list PixelChain;//each edge is a pixel chain + + +struct EDLineParam{ + int ksize; + float sigma; + float gradientThreshold; + float anchorThreshold; + int scanIntervals; + int minLineLen; + double lineFitErrThreshold; +}; + +#define RELATIVE_ERROR_FACTOR 100.0 +#define M_LN10 2.30258509299404568402 +#define log_gamma(x) ((x)>15.0?log_gamma_windschitl(x):log_gamma_lanczos(x)) + + +inline void writeMat(cv::Mat m, std::string name, int n) +{ + std::stringstream ss; + std::string s; + ss << n; + ss >> s; + std::string fileNameConf = name + s; + cv::FileStorage fsConf(fileNameConf, cv::FileStorage::WRITE); + fsConf << "m" << m; + + fsConf.release(); +} + +/* This class is used to detect lines from input image. + * First, edges are extracted from input image following the method presented in Cihan Topal and + * Cuneyt Akinlar's paper:"Edge Drawing: A Heuristic Approach to Robust Real-Time Edge Detection", 2010. + * Then, lines are extracted from the edge image following the method presented in Cuneyt Akinlar and + * Cihan Topal's paper:"EDLines: A real-time line segment detector with a false detection control", 2011 + * PS: The linking step of edge detection has a little bit difference with the Edge drawing algorithm + * described in the paper. The edge chain doesn't stop when the pixel direction is changed. + */ +class EDLineDetector +{ +public: + EDLineDetector(); + EDLineDetector(EDLineParam param); + ~EDLineDetector(); + + /*extract edges from image + *image: In, gray image; + *edges: Out, store the edges, each edge is a pixel chain + *smoothed: In, flag to mark whether the image has already been smoothed by Gaussian filter. + *return -1: error happen + */ + int EdgeDrawing(cv::Mat &image, EdgeChains &edgeChains, bool smoothed=false); + /*extract lines from image + *image: In, gray image; + *lines: Out, store the extracted lines, + *smoothed: In, flag to mark whether the image has already been smoothed by Gaussian filter. + *return -1: error happen + */ + int EDline(cv::Mat &image, LineChains &lines, bool smoothed=false); + /*extract line from image, and store them*/ + int EDline(cv::Mat &image, bool smoothed=false); + + cv::Mat dxImg_;//store the dxImg; + cv::Mat dyImg_;//store the dyImg; + cv::Mat gImgWO_;//store the gradient image without threshold; + LineChains lines_; //store the detected line chains; + //store the line Equation coefficients, vec3=[w1,w2,w3] for line w1*x + w2*y + w3=0; + std::vector > lineEquations_; + //store the line endpoints, [x1,y1,x2,y3] + std::vector > lineEndpoints_; + //store the line direction + std::vector lineDirection_; + //store the line salience, which is the summation of gradients of pixels on line + std::vector lineSalience_; + unsigned int imageWidth; + unsigned int imageHeight; + + + /*The threshold of line fit error; + *If lineFitErr is large than this threshold, then + *the pixel chain is not accepted as a single line segment.*/ + double lineFitErrThreshold_; + /*the threshold of pixel gradient magnitude. + *Only those pixel whose gradient magnitude are larger than this threshold will be + *taken as possible edge points. Default value is 36*/ + short gradienThreshold_; + /*If the pixel's gradient value is bigger than both of its neighbors by a + *certain threshold (ANCHOR_THRESHOLD), the pixel is marked to be an anchor. + *Default value is 8*/ + unsigned char anchorThreshold_; + /*anchor testing can be performed at different scan intervals, i.e., + *every row/column, every second row/column etc. + *Default value is 2*/ + unsigned int scanIntervals_; + int minLineLen_;//minimal acceptable line length + +private: + void InitEDLine_(); + /*For an input edge chain, find the best fit line, the default chain length is minLineLen_ + *xCors: In, pointer to the X coordinates of pixel chain; + *yCors: In, pointer to the Y coordinates of pixel chain; + *offsetS:In, start index of this chain in array; + *lineEquation: Out, [a,b] which are the coefficient of lines y=ax+b(horizontal) or x=ay+b(vertical); + *return: line fit error; -1:error happens; + */ + double LeastSquaresLineFit_(unsigned int *xCors, unsigned int *yCors, + unsigned int offsetS, std::array &lineEquation); + /*For an input pixel chain, find the best fit line. Only do the update based on new points. + *For A*x=v, Least square estimation of x = Inv(A^T * A) * (A^T * v); + *If some new observations are added, i.e, [A; A'] * x = [v; v'], + *then x' = Inv(A^T * A + (A')^T * A') * (A^T * v + (A')^T * v'); + *xCors: In, pointer to the X coordinates of pixel chain; + *yCors: In, pointer to the Y coordinates of pixel chain; + *offsetS:In, start index of this chain in array; + *newOffsetS: In, start index of extended part; + *offsetE:In, end index of this chain in array; + *lineEquation: Out, [a,b] which are the coefficient of lines y=ax+b(horizontal) or x=ay+b(vertical); + *return: line fit error; -1:error happens; + */ + double LeastSquaresLineFit_(unsigned int *xCors, unsigned int *yCors, + unsigned int offsetS, unsigned int newOffsetS, + unsigned int offsetE, std::array &lineEquation); + /* Validate line based on the Helmholtz principle, which basically states that + * for a structure to be perceptually meaningful, the expectation of this structure + * by chance must be very low. + */ + bool LineValidation_(unsigned int *xCors, unsigned int *yCors, + unsigned int offsetS, unsigned int offsetE, + std::array &lineEquation, float &direction); + bool bValidate_;//flag to decide whether line will be validated + int ksize_; //the size of Gaussian kernel: ksize X ksize, default value is 5. + float sigma_;//the sigma of Gaussian kernal, default value is 1.0. + + /*For example, there two edges in the image: + *edge1 = [(7,4), (8,5), (9,6),| (10,7)|, (11, 8), (12,9)] and + *edge2 = [(14,9), (15,10), (16,11), (17,12),| (18, 13)|, (19,14)] ; then we store them as following: + *pFirstPartEdgeX_ = [10, 11, 12, 18, 19];//store the first part of each edge[from middle to end] + *pFirstPartEdgeY_ = [7, 8, 9, 13, 14]; + *pFirstPartEdgeS_ = [0,3,5];// the index of start point of first part of each edge + *pSecondPartEdgeX_ = [10, 9, 8, 7, 18, 17, 16, 15, 14];//store the second part of each edge[from middle to front] + *pSecondPartEdgeY_ = [7, 6, 5, 4, 13, 12, 11, 10, 9];//anchor points(10, 7) and (18, 13) are stored again + *pSecondPartEdgeS_ = [0, 4, 9];// the index of start point of second part of each edge + *This type of storage order is because of the order of edge detection process. + *For each edge, start from one anchor point, first go right, then go left or first go down, then go up*/ + unsigned int *pFirstPartEdgeX_;//store the X coordinates of the first part of the pixels for chains + unsigned int *pFirstPartEdgeY_;//store the Y coordinates of the first part of the pixels for chains + unsigned int *pFirstPartEdgeS_;//store the start index of every edge chain in the first part arrays + unsigned int *pSecondPartEdgeX_;//store the X coordinates of the second part of the pixels for chains + unsigned int *pSecondPartEdgeY_;//store the Y coordinates of the second part of the pixels for chains + unsigned int *pSecondPartEdgeS_;//store the start index of every edge chain in the second part arrays + unsigned int *pAnchorX_;//store the X coordinates of anchors + unsigned int *pAnchorY_;//store the Y coordinates of anchors + cv::Mat edgeImage_; + + + + cv::Mat gImg_;//store the gradient image; + cv::Mat dirImg_;//store the direction image + double logNT_; + cv::Mat_ ATA; //the previous matrix of A^T * A; + cv::Mat_ ATV; //the previous vector of A^T * V; + cv::Mat_ fitMatT; //the matrix used in line fit function; + cv::Mat_ fitVec; //the vector used in line fit function; + cv::Mat_ tempMatLineFit; //the matrix used in line fit function; + cv::Mat_ tempVecLineFit; //the vector used in line fit function; + + + /** Compare doubles by relative error. + The resulting rounding error after floating point computations + depend on the specific operations done. The same number computed by + different algorithms could present different rounding errors. For a + useful comparison, an estimation of the relative rounding error + should be considered and compared to a factor times EPS. The factor + should be related to the accumulated rounding error in the chain of + computation. Here, as a simplification, a fixed factor is used. + */ + static int double_equal(double a, double b) + { + double abs_diff,aa,bb,abs_max; + /* trivial case */ + if( a == b ) return true; + abs_diff = fabs(a-b); + aa = fabs(a); + bb = fabs(b); + abs_max = aa > bb ? aa : bb; + /* DBL_MIN is the smallest normalized number, thus, the smallest + number whose relative error is bounded by DBL_EPSILON. For + smaller numbers, the same quantization steps as for DBL_MIN + are used. Then, for smaller numbers, a meaningful "relative" + error should be computed by dividing the difference by DBL_MIN. */ + if( abs_max < DBL_MIN ) abs_max = DBL_MIN; + /* equal if relative error <= factor x eps */ + return (abs_diff / abs_max) <= (RELATIVE_ERROR_FACTOR * DBL_EPSILON); + } + /** Computes the natural logarithm of the absolute value of + the gamma function of x using the Lanczos approximation. + See http://www.rskey.org/gamma.htm + The formula used is + @f[ + \Gamma(x) = \frac{ \sum_{n=0}^{N} q_n x^n }{ \Pi_{n=0}^{N} (x+n) } + (x+5.5)^{x+0.5} e^{-(x+5.5)} + @f] + so + @f[ + \log\Gamma(x) = \log\left( \sum_{n=0}^{N} q_n x^n \right) + + (x+0.5) \log(x+5.5) - (x+5.5) - \sum_{n=0}^{N} \log(x+n) + @f] + and + q0 = 75122.6331530, + q1 = 80916.6278952, + q2 = 36308.2951477, + q3 = 8687.24529705, + q4 = 1168.92649479, + q5 = 83.8676043424, + q6 = 2.50662827511. + */ + static double log_gamma_lanczos(double x) + { + static double q[7] = { 75122.6331530, 80916.6278952, 36308.2951477, + 8687.24529705, 1168.92649479, 83.8676043424, + 2.50662827511 }; + double a = (x+0.5) * log(x+5.5) - (x+5.5); + double b = 0.0; + int n; + for(n=0;n<7;n++){ + a -= log( x + (double) n ); + b += q[n] * pow( x, (double) n ); + } + return a + log(b); + } + /** Computes the natural logarithm of the absolute value of + the gamma function of x using Windschitl method. + See http://www.rskey.org/gamma.htm + The formula used is + @f[ + \Gamma(x) = \sqrt{\frac{2\pi}{x}} \left( \frac{x}{e} + \sqrt{ x\sinh(1/x) + \frac{1}{810x^6} } \right)^x + @f] + so + @f[ + \log\Gamma(x) = 0.5\log(2\pi) + (x-0.5)\log(x) - x + + 0.5x\log\left( x\sinh(1/x) + \frac{1}{810x^6} \right). + @f] + This formula is a good approximation when x > 15. + */ + static double log_gamma_windschitl(double x) + { + return 0.918938533204673 + (x-0.5)*log(x) - x + + 0.5*x*log( x*sinh(1/x) + 1/(810.0*pow(x,6.0)) ); + } + /** Computes -log10(NFA). + NFA stands for Number of False Alarms: + @f[ + \mathrm{NFA} = NT \cdot B(n,k,p) + @f] + - NT - number of tests + - B(n,k,p) - tail of binomial distribution with parameters n,k and p: + @f[ + B(n,k,p) = \sum_{j=k}^n + \left(\begin{array}{c}n\\j\end{array}\right) + p^{j} (1-p)^{n-j} + @f] + The value -log10(NFA) is equivalent but more intuitive than NFA: + - -1 corresponds to 10 mean false alarms + - 0 corresponds to 1 mean false alarm + - 1 corresponds to 0.1 mean false alarms + - 2 corresponds to 0.01 mean false alarms + - ... + Used this way, the bigger the value, better the detection, + and a logarithmic scale is used. + @param n,k,p binomial parameters. + @param logNT logarithm of Number of Tests + The computation is based in the gamma function by the following + relation: + @f[ + \left(\begin{array}{c}n\\k\end{array}\right) + = \frac{ \Gamma(n+1) }{ \Gamma(k+1) \cdot \Gamma(n-k+1) }. + @f] + We use efficient algorithms to compute the logarithm of + the gamma function. + To make the computation faster, not all the sum is computed, part + of the terms are neglected based on a bound to the error obtained + (an error of 10% in the result is accepted). + */ + static double nfa(int n, int k, double p, double logNT) + { + double tolerance = 0.1; /* an error of 10% in the result is accepted */ + double log1term,term,bin_term,mult_term,bin_tail,err,p_term; + int i; + + /* check parameters */ + if( n<0 || k<0 || k>n || p<=0.0 || p>=1.0 ){ + std::cout<<"nfa: wrong n, k or p values."< (double) n * p ) /* at begin or end of the tail? */ + return -log1term / M_LN10 - logNT; /* end: use just the first term */ + else + return -logNT; /* begin: the tail is roughly 1 */ + } + + /* compute more terms if needed */ + bin_tail = term; + for(i=k+1;i<=n;i++){ + /* As + term_i = bincoef(n,i) * p^i * (1-p)^(n-i) + and + bincoef(n,i)/bincoef(n,i-1) = n-i+1 / i, + then, + term_i / term_i-1 = (n-i+1)/i * p/(1-p) + and + term_i = term_i-1 * (n-i+1)/i * p/(1-p). + p/(1-p) is computed only once and stored in 'p_term'. + */ + bin_term = (double) (n-i+1) / (double) i; + mult_term = bin_term * p_term; + term *= mult_term; + bin_tail += term; + if(bin_term<1.0){ + /* When bin_term<1 then mult_term_ji. + Then, the error on the binomial tail when truncated at + the i term can be bounded by a geometric series of form + term_i * sum mult_term_i^j. */ + err = term * ( ( 1.0 - pow( mult_term, (double) (n-i+1) ) ) / + (1.0-mult_term) - 1.0 ); + /* One wants an error at most of tolerance*final_result, or: + tolerance * abs(-log10(bin_tail)-logNT). + Now, the error that can be accepted on bin_tail is + given by tolerance*final_result divided by the derivative + of -log10(x) when x=bin_tail. that is: + tolerance * abs(-log10(bin_tail)-logNT) / (1/bin_tail) + Finally, we truncate the tail if the error is less than: + tolerance * abs(-log10(bin_tail)-logNT) * bin_tail */ + if( err < tolerance * fabs(-log10(bin_tail)-logNT) * bin_tail ) break; + } + } + return -log10(bin_tail) - logNT; + } +}; + +#endif /* EDLINEDETECTOR_HH_ */ diff --git a/modules/line_descriptor/include/opencv2/line_descriptor/LineDescriptor.hh b/modules/line_descriptor/include/opencv2/line_descriptor/LineDescriptor.hh new file mode 100644 index 000000000..04aecd13b --- /dev/null +++ b/modules/line_descriptor/include/opencv2/line_descriptor/LineDescriptor.hh @@ -0,0 +1,133 @@ +/*IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + + By downloading, copying, installing or using the software you agree to this license. + If you do not agree to this license, do not download, install, + copy or use the software. + + + License Agreement + For Open Source Computer Vision Library + +Copyright (C) 2011-2012, Lilian Zhang, all rights reserved. +Copyright (C) 2013, Manuele Tamburrano, Stefano Fabri, all rights reserved. +Third party copyrights are property of their respective owners. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name of the copyright holders may not be used to endorse or promote products + derived from this software without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are disclaimed. +In no event shall the Intel Corporation or contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or services; +loss of use, data, or profits; or business interruption) however caused +and on any theory of liability, whether in contract, strict liability, +or tort (including negligence or otherwise) arising in any way out of +the use of this software, even if advised of the possibility of such damage. +*/ + +#ifndef LINEDESCRIPTOR_HH_ +#define LINEDESCRIPTOR_HH_ + + +#include "EDLineDetector.hh" +#include "LineStructure.hh" + + +#include +struct OctaveLine{ + unsigned int octaveCount;//the octave which this line is detected + unsigned int lineIDInOctave;//the line ID in that octave image + unsigned int lineIDInScaleLineVec;//the line ID in Scale line vector + float lineLength; //the length of line in original image scale +}; + + +/* This class is used to generate the line descriptors from multi-scale images */ +class LineDescriptor +{ +public: + LineDescriptor(int n_octave); + LineDescriptor(unsigned int numOfBand, unsigned int widthOfBand, int n_octave); + ~LineDescriptor(); + enum{ + NearestNeighbor=0, //the nearest neighbor is taken as matching + NNDR=1//nearest/next ratio + }; + /*This function is used to detect lines from multi-scale images.*/ + int OctaveKeyLines(cv::Mat & image, ScaleLines &keyLines); + int GetLineDescriptor(cv::Mat & image, + ScaleLines &keyLines); + int GetLineDescriptor(cv::Mat & image, + ScaleLines &keyLines, bool lsd); + + void findNearestParallelLines(ScaleLines & keyLines); + + void GetLineBinaryDescriptor(std::vector & oct_binaryDescMat, ScaleLines & keyLines); + int MatchLineByDescriptor(ScaleLines &keyLinesLeft, ScaleLines &keyLinesRight, + std::vector &matchLeft, std::vector &matchRight, + int criteria=NNDR); + float LowestThreshold;//global threshold for line descriptor distance, default is 0.35 + float NNDRThreshold;//the NNDR threshold for line descriptor distance, default is 0.6 + + int ksize_; //the size of Gaussian kernel: ksize X ksize, default value is 5. + unsigned int numOfOctave_;//the number of image octave + unsigned int numOfBand_;//the number of band used to compute line descriptor + unsigned int widthOfBand_;//the width of band; + std::vector gaussCoefL_;//the local gaussian coefficient apply to the orthogonal line direction within each band; + std::vector gaussCoefG_;//the global gaussian coefficient apply to each Row within line support region + + +private: + + void sample(float *igray,float *ogray, float factor, int width, int height) + { + + int swidth = (int)((float) width / factor); + int sheight = (int)((float) height / factor); + + for(int j=0; j < sheight; j++) + for(int i=0; i < swidth; i++) + ogray[j*swidth + i] = igray[(int)((float) j * factor) * width + (int) ((float) i*factor)]; + + } + void sampleUchar(uchar *igray,uchar *ogray, float factor, int width, int height) + { + + int swidth = (int)((float) width / factor); + int sheight = (int)((float) height / factor); + + for(int j=0; j < sheight; j++) + for(int i=0; i < swidth; i++) + ogray[j*swidth + i] = igray[(int)((float) j * factor) * width + (int) ((float) i*factor)]; + + } + /*Compute the line descriptor of input line set. This function should be called + *after OctaveKeyLines() function; */ + int ComputeLBD_(ScaleLines &keyLines); + /*For each octave of image, we define an EDLineDetector, because we can get gradient images (dxImg, dyImg, gImg) + *from the EDLineDetector class without extra computation cost. Another reason is that, if we use + *a single EDLineDetector to detect lines in different octave of images, then we need to allocate and release + *memory for gradient images (dxImg, dyImg, gImg) repeatedly for their varying size*/ + std::vector edLineVec_; + + +}; + + + + + + +#endif /* LINEDESCRIPTOR_HH_ */ diff --git a/modules/line_descriptor/include/opencv2/line_descriptor/LineStructure.hh b/modules/line_descriptor/include/opencv2/line_descriptor/LineStructure.hh new file mode 100644 index 000000000..8ee19fdc6 --- /dev/null +++ b/modules/line_descriptor/include/opencv2/line_descriptor/LineStructure.hh @@ -0,0 +1,110 @@ +/*IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + + By downloading, copying, installing or using the software you agree to this license. + If you do not agree to this license, do not download, install, + copy or use the software. + + + License Agreement + For Open Source Computer Vision Library + +Copyright (C) 2011-2012, Lilian Zhang, all rights reserved. +Copyright (C) 2013, Manuele Tamburrano, Stefano Fabri, all rights reserved. +Third party copyrights are property of their respective owners. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name of the copyright holders may not be used to endorse or promote products + derived from this software without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are disclaimed. +In no event shall the Intel Corporation or contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or services; +loss of use, data, or profits; or business interruption) however caused +and on any theory of liability, whether in contract, strict liability, +or tort (including negligence or otherwise) arising in any way out of +the use of this software, even if advised of the possibility of such damage. +*/ + +#ifndef LINESTRUCTURE_HH_ +#define LINESTRUCTURE_HH_ + +#include +// A 2D line (normal equation parameters). +struct SingleLine +{ + //note: rho and theta are based on coordinate origin, i.e. the top-left corner of image + double rho;//unit: pixel length + double theta;//unit: rad + double linePointX;// = rho * cos(theta); + double linePointY;// = rho * sin(theta); + //for EndPoints, the coordinate origin is the top-left corner of image. + double startPointX; + double startPointY; + double endPointX; + double endPointY; + //direction of a line, the angle between positive line direction (dark side is in the left) and positive X axis. + double direction; + //mean gradient magnitude + double gradientMagnitude; + //mean gray value of pixels in dark side of line + double darkSideGrayValue; + //mean gray value of pixels in light side of line + double lightSideGrayValue; + //the length of line + double lineLength; + //the width of line; + double width; + //number of pixels + int numOfPixels; + //the decriptor of line + std::vector descriptor; +}; + +// Specifies a vector of lines. +typedef std::vector Lines_list; + +struct OctaveSingleLine +{ + /*endPoints, the coordinate origin is the top-left corner of the original image. + *startPointX = sPointInOctaveX * (factor)^octaveCount; */ + float startPointX; + float startPointY; + float endPointX; + float endPointY; + //endPoints, the coordinate origin is the top-left corner of the octave image. + float sPointInOctaveX; + float sPointInOctaveY; + float ePointInOctaveX; + float ePointInOctaveY; + //direction of a line, the angle between positive line direction (dark side is in the left) and positive X axis. + float direction; + //the summation of gradient magnitudes of pixels on lines + float salience; + //the length of line + float lineLength; + //number of pixels + unsigned int numOfPixels; + //the octave which this line is detected + unsigned int octaveCount; + //the decriptor of line + std::vector descriptor; +}; + +// Specifies a vector of lines. +typedef std::vector LinesVec; + +typedef std::vector ScaleLines;//each element in ScaleLines is a vector of lines which corresponds the same line detected in different octave images. + +#endif /* LINESTRUCTURE_HH_ */ diff --git a/modules/line_descriptor/src/EDLineDetector.cpp b/modules/line_descriptor/src/EDLineDetector.cpp new file mode 100644 index 000000000..67a2a7347 --- /dev/null +++ b/modules/line_descriptor/src/EDLineDetector.cpp @@ -0,0 +1,1285 @@ +/*IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + + By downloading, copying, installing or using the software you agree to this license. + If you do not agree to this license, do not download, install, + copy or use the software. + + + License Agreement + For Open Source Computer Vision Library + +Copyright (C) 2011-2012, Lilian Zhang, all rights reserved. +Copyright (C) 2013, Manuele Tamburrano, Stefano Fabri, all rights reserved. +Third party copyrights are property of their respective owners. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * The name of the copyright holders may not be used to endorse or promote products + derived from this software without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are disclaimed. +In no event shall the Intel Corporation or contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or services; +loss of use, data, or profits; or business interruption) however caused +and on any theory of liability, whether in contract, strict liability, +or tort (including negligence or otherwise) arising in any way out of +the use of this software, even if advised of the possibility of such damage. +*/ + + +#include "../include/EDLineDetector.hh" + +#define Horizontal 255//if |dx|<|dy|; +#define Vertical 0//if |dy|<=|dx|; +#define UpDir 1 +#define RightDir 2 +#define DownDir 3 +#define LeftDir 4 +#define TryTime 6 +#define SkipEdgePoint 2 + +//#define DEBUGEdgeDrawing +//#define DEBUGEDLine + +using namespace std; +EDLineDetector::EDLineDetector() +{ + // cout<<"Call EDLineDetector constructor function"<(2,2); + ATV = cv::Mat_(1,2); + tempMatLineFit = cv::Mat_(2,2); + tempVecLineFit = cv::Mat_(1,2); + fitMatT = cv::Mat_(2,minLineLen_); + fitVec = cv::Mat_(1,minLineLen_); + for(int i=0; idata.ptr, pImage, pixelNum*sizeof(unsigned char)); +// } + + unsigned int edgePixelArraySize = pixelNum/5; + unsigned int maxNumOfEdge = edgePixelArraySize/20; + //compute dx, dy images + if(gImg_.cols!= imageWidth||gImg_.rows!= imageHeight){ + if(pFirstPartEdgeX_!= NULL){ + delete [] pFirstPartEdgeX_; + delete [] pFirstPartEdgeY_; + delete [] pSecondPartEdgeX_; + delete [] pSecondPartEdgeY_; + delete [] pFirstPartEdgeS_; + delete [] pSecondPartEdgeS_; + delete [] pAnchorX_; + delete [] pAnchorY_; + } + dxImg_.create(imageHeight, imageWidth, CV_16SC1); + dyImg_.create(imageHeight, imageWidth, CV_16SC1 ); + gImgWO_.create(imageHeight, imageWidth, CV_16SC1 ); + gImg_.create(imageHeight, imageWidth, CV_16SC1 ); + dirImg_.create(imageHeight, imageWidth, CV_8UC1 ); + edgeImage_.create(imageHeight, imageWidth, CV_8UC1 ); + pFirstPartEdgeX_ = new unsigned int[edgePixelArraySize]; + pFirstPartEdgeY_ = new unsigned int[edgePixelArraySize]; + pSecondPartEdgeX_ = new unsigned int[edgePixelArraySize]; + pSecondPartEdgeY_ = new unsigned int[edgePixelArraySize]; + pFirstPartEdgeS_ = new unsigned int[maxNumOfEdge]; + pSecondPartEdgeS_ = new unsigned int[maxNumOfEdge]; + pAnchorX_ = new unsigned int[edgePixelArraySize]; + pAnchorY_ = new unsigned int[edgePixelArraySize]; + } + cv::Sobel( image, dxImg_, CV_16SC1, 1, 0, 3); + cv::Sobel( image, dyImg_, CV_16SC1, 0, 1, 3); + + + #ifdef DEBUGEdgeDrawing + cv::imshow("dxImg_", dxImg_); + cv::imshow("dyImg_", dyImg_); + cv::waitKey(); + #endif + + //compute gradient and direction images + +// double t = (double)cv::getTickCount(); + cv::Mat dxABS_m = cv::abs(dxImg_); + cv::Mat dyABS_m = cv::abs(dyImg_); + cv::Mat sumDxDy; + cv::add(dyABS_m, dxABS_m, sumDxDy); + + + cv::threshold(sumDxDy,gImg_, gradienThreshold_+1, 255, cv::THRESH_TOZERO); + gImg_ = gImg_/4; + gImgWO_ = sumDxDy/4; + cv::compare(dxABS_m, dyABS_m, dirImg_, cv::CMP_LT); + +// t = ((double)cv::getTickCount() - t)/cv::getTickFrequency(); +// std::cout<<"FOR ABS: "<(); + short *pdyImg = dyImg_.ptr(); + short *pgImg = gImg_.ptr(); + unsigned char *pdirImg = dirImg_.ptr(); + + //extract the anchors in the gradient image, store into a vector + memset(pAnchorX_, 0, edgePixelArraySize*sizeof(unsigned int));//initialization + memset(pAnchorY_, 0, edgePixelArraySize*sizeof(unsigned int)); + unsigned int anchorsSize = 0; + int indexInArray; + unsigned char gValue1, gValue2, gValue3; + for(unsigned int w=1; w=pgImg[indexInArray-imageWidth]+anchorThreshold_ + &&pgImg[indexInArray]>=pgImg[indexInArray+imageWidth]+anchorThreshold_){// (w,h) is accepted as an anchor + pAnchorX_[anchorsSize] = w; + pAnchorY_[anchorsSize++] = h; + } + }else{// if(pdirImg[indexInArray]==Vertical){//it is vertical edge, should be compared with left and right + //gValue2 = pgImg[indexInArray]; + if(pgImg[indexInArray]>=pgImg[indexInArray-1]+anchorThreshold_ + &&pgImg[indexInArray]>=pgImg[indexInArray+1]+anchorThreshold_){// (w,h) is accepted as an anchor + pAnchorX_[anchorsSize] = w; + pAnchorY_[anchorsSize++] = h; + } + } + } + } + if(anchorsSize>edgePixelArraySize){ + cout<<"anchor size is larger than its maximal size. anchorsSize="< lineEquation; + lineEquations_.clear(); + lineEndpoints_.clear(); + lineDirection_.clear(); + unsigned char *pdirImg = dirImg_.data; + unsigned int numOfLines = 0; + unsigned int offsetInEdgeArrayS, offsetInEdgeArrayE, newOffsetS;//start index and end index + unsigned int offsetInLineArray=0; + float direction;//line direction + + for(unsigned int edgeID=0; edgeID offsetInEdgeArrayS+minLineLen_){//extract line segments from an edge, may find more than one segments + //find an initial line segment + while(offsetInEdgeArrayE > offsetInEdgeArrayS+minLineLen_){ + lineFitErr = LeastSquaresLineFit_(pEdgeXCors,pEdgeYCors, + offsetInEdgeArrayS,lineEquation); + if(lineFitErr<=lineFitErrThreshold_) break;//ok, an initial line segment detected + offsetInEdgeArrayS +=SkipEdgePoint; //skip the first two pixel in the chain and try with the remaining pixels + } + if(lineFitErr>lineFitErrThreshold_) break; //no line is detected + //An initial line segment is detected. Try to extend this line segment + pLineSID[numOfLines] = offsetInLineArray; + double coef1;//for a line ax+by+c=0, coef1 = 1/sqrt(a^2+b^2); + double pointToLineDis;//for a line ax+by+c=0 and a point(xi, yi), pointToLineDis = coef1*|a*xi+b*yi+c| + bool bExtended=true; + bool bFirstTry = true; + int numOfOutlier;//to against noise, we accept a few outlier of a line. + int tryTimes = 0; + if(pdirImg[pEdgeYCors[offsetInEdgeArrayS]*imageWidth + pEdgeXCors[offsetInEdgeArrayS]]==Horizontal){//y=ax+b, i.e. ax-y+b=0 + while(bExtended){ + tryTimes++; + if(bFirstTry){ + bFirstTry = false; + for(int i=0; i offsetInEdgeArrayS){ + pointToLineDis = fabs(lineEquation[0]*pEdgeXCors[offsetInEdgeArrayS] - + pEdgeYCors[offsetInEdgeArrayS] + lineEquation[1])*coef1; + pLineXCors[offsetInLineArray] = pEdgeXCors[offsetInEdgeArrayS]; + pLineYCors[offsetInLineArray++] = pEdgeYCors[offsetInEdgeArrayS++]; + if(pointToLineDis>lineFitErrThreshold_){ + numOfOutlier++; + if(numOfOutlier>3) break; + }else{//we count number of connective outliers. + numOfOutlier=0; + } + } + //pop back the last few outliers from lines and return them to edge chain + offsetInLineArray -=numOfOutlier; + offsetInEdgeArrayS -=numOfOutlier; + if(offsetInLineArray - newOffsetS>0&&tryTimes lineEqu = {lineEquation[0]*coef1, -1*coef1, lineEquation[1]*coef1}; + if(LineValidation_(pLineXCors,pLineYCors,pLineSID[numOfLines],offsetInLineArray,lineEqu,direction)){//check the line + //store the line equation coefficients + lineEquations_.push_back(lineEqu); + /*At last, compute the line endpoints and store them. + *we project the first and last pixels in the pixelChain onto the best fit line + *to get the line endpoints. + *xp= (w2^2*x0-w1*w2*y0-w3*w1)/(w1^2+w2^2) + *yp= (w1^2*y0-w1*w2*x0-w3*w2)/(w1^2+w2^2) */ + std::array lineEndP;//line endpoints + double a1 = lineEqu[1]*lineEqu[1]; + double a2 = lineEqu[0]*lineEqu[0]; + double a3 = lineEqu[0]*lineEqu[1]; + double a4 = lineEqu[2]*lineEqu[0]; + double a5 = lineEqu[2]*lineEqu[1]; + unsigned int Px = pLineXCors[pLineSID[numOfLines] ];//first pixel + unsigned int Py = pLineYCors[pLineSID[numOfLines] ]; + lineEndP[0] = a1*Px-a3*Py-a4;//x + lineEndP[1] = a2*Py-a3*Px-a5;//y + Px = pLineXCors[offsetInLineArray -1 ];//last pixel + Py = pLineYCors[offsetInLineArray -1 ]; + lineEndP[2] = a1*Px-a3*Py-a4;//x + lineEndP[3] = a2*Py-a3*Px-a5;//y + lineEndpoints_.push_back(lineEndP); + lineDirection_.push_back(direction); + numOfLines++; + }else{ + offsetInLineArray = pLineSID[numOfLines];// line was not accepted, the offset is set back + } + }else{//x=ay+b, i.e. x-ay-b=0 + while(bExtended){ + tryTimes++; + if(bFirstTry){ + bFirstTry = false; + for(int i=0; i offsetInEdgeArrayS){ + pointToLineDis = fabs(pEdgeXCors[offsetInEdgeArrayS] - + lineEquation[0]*pEdgeYCors[offsetInEdgeArrayS] - lineEquation[1])*coef1; + pLineXCors[offsetInLineArray] = pEdgeXCors[offsetInEdgeArrayS]; + pLineYCors[offsetInLineArray++] = pEdgeYCors[offsetInEdgeArrayS++]; + if(pointToLineDis>lineFitErrThreshold_){ + numOfOutlier++; + if(numOfOutlier>3) break; + }else{//we count number of connective outliers. + numOfOutlier=0; + } + } + //pop back the last few outliers from lines and return them to edge chain + offsetInLineArray -= numOfOutlier; + offsetInEdgeArrayS -= numOfOutlier; + if(offsetInLineArray - newOffsetS>0&&tryTimes lineEqu= {1*coef1,-lineEquation[0]*coef1, -lineEquation[1]*coef1}; + if(LineValidation_(pLineXCors,pLineYCors,pLineSID[numOfLines],offsetInLineArray,lineEqu,direction)){//check the line + //store the line equation coefficients + lineEquations_.push_back(lineEqu); + /*At last, compute the line endpoints and store them. + *we project the first and last pixels in the pixelChain onto the best fit line + *to get the line endpoints. + *xp= (w2^2*x0-w1*w2*y0-w3*w1)/(w1^2+w2^2) + *yp= (w1^2*y0-w1*w2*x0-w3*w2)/(w1^2+w2^2) */ + std::array lineEndP;//line endpoints + double a1 = lineEqu[1]*lineEqu[1]; + double a2 = lineEqu[0]*lineEqu[0]; + double a3 = lineEqu[0]*lineEqu[1]; + double a4 = lineEqu[2]*lineEqu[0]; + double a5 = lineEqu[2]*lineEqu[1]; + unsigned int Px = pLineXCors[pLineSID[numOfLines] ];//first pixel + unsigned int Py = pLineYCors[pLineSID[numOfLines] ]; + lineEndP[0] = a1*Px-a3*Py-a4;//x + lineEndP[1] = a2*Py-a3*Px-a5;//y + Px = pLineXCors[offsetInLineArray -1 ];//last pixel + Py = pLineYCors[offsetInLineArray -1 ]; + lineEndP[2] = a1*Px-a3*Py-a4;//x + lineEndP[3] = a2*Py-a3*Px-a5;//y + lineEndpoints_.push_back(lineEndP); + lineDirection_.push_back(direction); + numOfLines++; + }else{ + offsetInLineArray = pLineSID[numOfLines];// line was not accepted, the offset is set back + } + } + //Extract line segments from the remaining pixel; Current chain has been shortened already. + } + }//end for(unsigned int edgeID=0; edgeIDx,iter->y); +// // char buf[10]; +// // sprintf( buf, "%d ", i); +// // cvPutText(cvColorImg,buf,point,&font,CV_RGB(r,g,b)); +// } +// cvNamedWindow("LineColorImage", CV_WINDOW_AUTOSIZE); +// cvShowImage("LineColorImage", cvColorImg); +// cvWaitKey(0); +// cvReleaseImage(&cvColorImg); +#endif + return 1; +} + + +double EDLineDetector::LeastSquaresLineFit_( unsigned int *xCors, unsigned int *yCors, + unsigned int offsetS, std::array &lineEquation) +{ + if(lineEquation.size()!=2){ + std::cout<<"SHOULD NOT BE != 2"<();//fitMatT = [x0, x1, ... xn; 1,1,...,1]; + for(int i=0; i(); + coef = 1.0/(double(pATA[0])*double(pATA[3]) - double(pATA[1])*double(pATA[2])); + // lineEquation = svd.Invert(ATA) * matT * vec; + lineEquation[0] = coef *( double(pATA[3])*double(ATV[0][0])-double(pATA[1])*double(ATV[0][1])); + lineEquation[1] = coef *( double(pATA[0])*double(ATV[0][1])-double(pATA[2])*double(ATV[0][0])); + /*compute line fit error */ + for(int i=0; i();//fitMatT = [y0, y1, ... yn; 1,1,...,1]; + for(int i=0; i(); + coef = 1.0/(double(pATA[0])*double(pATA[3]) - double(pATA[1])*double(pATA[2])); + // lineEquation = svd.Invert(ATA) * matT * vec; + lineEquation[0] = coef *( double(pATA[3])*double(ATV[0][0])-double(pATA[1])*double(ATV[0][1])); + lineEquation[1] = coef *( double(pATA[0])*double(ATV[0][1])-double(pATA[2])*double(ATV[0][0])); + /*compute line fit error */ + for(int i=0; i &lineEquation) +{ + int length = offsetE - offsetS; + int newLength = offsetE - newOffsetS; + if(length<=0||newLength<=0){ + cout<<"EDLineDetector::LeastSquaresLineFit_ Error:" + " the expected line index is wrong...offsetE = " + < matT(2,newLength); + cv::Mat_ vec(newLength,1); + float * pMatT; + float * pATA; + // double fitError = 0; + double coef; + unsigned char *pdirImg = dirImg_.data; + /*If the first pixel in this chain is horizontal, + *then we try to find a horizontal line, y=ax+b;*/ + if(pdirImg[yCors[offsetS]*imageWidth + xCors[offsetS] ]==Horizontal){ + /*Build the new system,and solve it using least square regression: mat * [a,b]^T = vec + * [x0',1] [y0'] + * [x1',1] [a] [y1'] + * . [b] = . + * [xn',1] [yn']*/ + pMatT = matT.ptr();//matT = [x0', x1', ... xn'; 1,1,...,1] + for(int i=0; i(); + coef = 1.0/(double(pATA[0])*double(pATA[3]) - double(pATA[1])*double(pATA[2])); + lineEquation[0] = coef *( double(pATA[3])*double(ATV[0][0])-double(pATA[1])*double(ATV[0][1])); + lineEquation[1] = coef *( double(pATA[0])*double(ATV[0][1])-double(pATA[2])*double(ATV[0][0])); + /*compute line fit error */ + // for(int i=0; i();//matT = [y0', y1', ... yn'; 1,1,...,1] + for(int i=0; i(); + coef = 1.0/(double(pATA[0])*double(pATA[3]) - double(pATA[1])*double(pATA[2])); + lineEquation[0] = coef *( double(pATA[3])*double(ATV[0][0])-double(pATA[1])*double(ATV[0][1])); + lineEquation[1] = coef *( double(pATA[0])*double(ATV[0][1])-double(pATA[2])*double(ATV[0][0])); + /*compute line fit error */ + // for(int i=0; i &lineEquation, float &direction) +{ + if(bValidate_){ + int n = offsetE - offsetS; + /*first compute the direction of line, make sure that the dark side always be the + *left side of a line.*/ + int meanGradientX=0, meanGradientY=0; + short *pdxImg = dxImg_.ptr(); + short *pdyImg = dyImg_.ptr(); + double dx, dy; + std::vector pointDirection; + int index; + for(int i=0; i0&&meanGradientY>=0){//first quadrant, and positive direction of X axis. + direction = atan2(-dy,dx);//line direction is in fourth quadrant + } + if(meanGradientX<=0&&meanGradientY>0){//second quadrant, and positive direction of Y axis. + direction = atan2(dy,dx);//line direction is in first quadrant + } + if(meanGradientX<0&&meanGradientY<=0){//third quadrant, and negative direction of X axis. + direction = atan2(dy,-dx);//line direction is in second quadrant + } + if(meanGradientX>=0&&meanGradientY<0){//fourth quadrant, and negative direction of Y axis. + direction = atan2(-dy,-dx);//line direction is in third quadrant + } + /*then check whether the line is on the border of the image. We don't keep the border line.*/ + if(fabs(direction)<0.15||M_PI-fabs(direction)<0.15){//Horizontal line + if(fabs(lineEquation[2])<10||fabs(imageHeight - fabs(lineEquation[2]))<10){//upper border or lower border + return false; + } + } + if(fabs(fabs(direction)-M_PI*0.5)<0.15){//Vertical line + if(fabs(lineEquation[2])<10||fabs(imageWidth - fabs(lineEquation[2]))<10){//left border or right border + return false; + } + } + //count the aligned points on the line which have the same direction as the line. + double disDirection; + int k = 0; + for(int i=0; i0); //0 corresponds to 1 mean false alarm + }else{ + return true; + } +} + +int EDLineDetector::EDline(cv::Mat &image, bool smoothed) +{ + if((EDline(image, lines_, smoothed)) != true){ + return -1; + } + lineSalience_.clear(); + lineSalience_.resize(lines_.numOfLines); + unsigned char *pgImg = gImgWO_.ptr(); + unsigned int indexInLineArray; + unsigned int *pXCor = lines_.xCors.data(); + unsigned int *pYCor = lines_.yCors.data(); + unsigned int *pSID = lines_.sId.data(); + for(unsigned int i=0; iEDline(blur,true))!= true){ + return -1; + } + + /* update number of total extracted lines */ + numOfFinalLine += edLineVec_[octaveCount]->lines_.numOfLines; + + /* resize image for next level of pyramid */ + cv::resize(blur, image, cv::Size(), (1.f/factor), (1.f/factor)); + + /* update sigma values */ + preSigma2 = curSigma2; + curSigma2 = curSigma2*2; + + } /* end of loop over number of octaves */ + + + /*lines which correspond to the same line in the octave images will be stored + in the same element of ScaleLines.*/ + + /* prepare a vector to store octave information associated to extracted lines */ + std::vector octaveLines(numOfFinalLine); + + /* set lines' counter to 0 for reuse */ + numOfFinalLine = 0; + + /* counter to give a unique ID to lines in LineVecs */ + unsigned int lineIDInScaleLineVec = 0; + + /* floats to compute lines' lengths */ + float dx, dy; + + /* loop over lines extracted from scale 0 (original image) */ + for(unsigned int lineCurId=0;lineCurIdlines_.numOfLines;lineCurId++){ + /* FOR CURRENT LINE: */ + + /* set octave from which it was extracted */ + octaveLines[numOfFinalLine].octaveCount = 0; + /* set ID within its octave */ + octaveLines[numOfFinalLine].lineIDInOctave = lineCurId; + /* set a unique ID among all lines extracted in all octaves */ + octaveLines[numOfFinalLine].lineIDInScaleLineVec = lineIDInScaleLineVec; + + /* compute absolute value of difference between X coordinates of line's extreme points */ + dx = fabs(edLineVec_[0]->lineEndpoints_[lineCurId][0]-edLineVec_[0]->lineEndpoints_[lineCurId][2]); + /* compute absolute value of difference between Y coordinates of line's extreme points */ + dy = fabs(edLineVec_[0]->lineEndpoints_[lineCurId][1]-edLineVec_[0]->lineEndpoints_[lineCurId][3]); + /* compute line's length */ + octaveLines[numOfFinalLine].lineLength = sqrt(dx*dx+dy*dy); + + /* update counters */ + numOfFinalLine++; + lineIDInScaleLineVec++; + } + + /* create and fill an array to store scale factors */ + float *scale = new float[numOfOctave_]; + scale[0] = 1; + for(unsigned int octaveCount = 1; octaveCount1){ + /* some other variables' declarations */ + float twoPI = 2*M_PI; + unsigned int closeLineID; + float endPointDis,minEndPointDis,minLocalDis,maxLocalDis; + float lp0,lp1, lp2, lp3, np0,np1, np2, np3; + + /* loop over list of octaves */ + for(unsigned int octaveCount = 1; octaveCountlines_.numOfLines;lineCurId++){ + /* get (scaled) known term from equation of current line */ + rho1 = scale[octaveCount] * fabs(edLineVec_[octaveCount]->lineEquations_[lineCurId][2]); + + /*nearThreshold depends on the distance of the image coordinate origin to current line. + *so nearThreshold = rho1 * nearThresholdRatio, where nearThresholdRatio = 1-cos(10*pi/180) = 0.0152*/ + tempValue = rho1 * 0.0152; + float nearThreshold = (tempValue>6)?(tempValue):6; + nearThreshold = (nearThreshold<12)?nearThreshold:12; + + /* compute scaled lenght of current line */ + dx = fabs(edLineVec_[octaveCount]->lineEndpoints_[lineCurId][0]-edLineVec_[octaveCount]->lineEndpoints_[lineCurId][2]);//x1-x2 + dy = fabs(edLineVec_[octaveCount]->lineEndpoints_[lineCurId][1]-edLineVec_[octaveCount]->lineEndpoints_[lineCurId][3]);//y1-y2 + length = scale[octaveCount] * sqrt(dx*dx+dy*dy); + + minEndPointDis = 12; + /* loop over the octave representations of all lines */ + for(unsigned int lineNextId=0; lineNextIdlineDirection_[lineCurId] - + edLineVec_[octaveID]->lineDirection_[lineIDInOctave]); + + /* the angle between two lines are larger than 10degrees + (i.e. 10*pi/180=0.1745), they are not close to parallel */ + if(direction>0.1745 && (twoPI - direction>0.1745)){ + continue; + } + /*now check whether current line and next line are near to each other. + *If line1:a1*x+b1*y+c1=0 and line2:a2*x+b2*y+c2=0 are near in image, then + *rho1 = |a1*0+b1*0+c1|/sqrt(a1^2+b1^2) and rho2 = |a2*0+b2*0+c2|/sqrt(a2^2+b2^2) should close. + *In our case, rho1 = |c1| and rho2 = |c2|, because sqrt(a1^2+b1^2) = sqrt(a2^2+b2^2) = 1; + *note that, lines are in different octave images, so we define near = fabs(scale*rho1 - rho2) or + *where scale is the scale factor between to octave images*/ + + /* get known term from equation to be compared */ + rho2 = scale[octaveID] * fabs(edLineVec_[octaveID]->lineEquations_[lineIDInOctave][2]); + /* compute difference between known ters */ + near = fabs(rho1 - rho2); + + /* two lines are not close in the image */ + if(near>nearThreshold){ + continue; + } + + /*now check the end points distance between two lines, the scale of distance is in the original image size. + * find the minimal and maximal end points distance*/ + + /* get the extreme points of the two lines */ + lp0 = scale[octaveCount] *edLineVec_[octaveCount]->lineEndpoints_[lineCurId][0]; + lp1 = scale[octaveCount] *edLineVec_[octaveCount]->lineEndpoints_[lineCurId][1]; + lp2 = scale[octaveCount] *edLineVec_[octaveCount]->lineEndpoints_[lineCurId][2]; + lp3 = scale[octaveCount] *edLineVec_[octaveCount]->lineEndpoints_[lineCurId][3]; + np0 = scale[octaveID] * edLineVec_[octaveID]->lineEndpoints_[lineIDInOctave][0]; + np1 = scale[octaveID] * edLineVec_[octaveID]->lineEndpoints_[lineIDInOctave][1]; + np2 = scale[octaveID] * edLineVec_[octaveID]->lineEndpoints_[lineIDInOctave][2]; + np3 = scale[octaveID] * edLineVec_[octaveID]->lineEndpoints_[lineIDInOctave][3]; + + /* get the distance between the two leftmost extremes of lines + L1(0,1)<->L2(0,1) */ + dx = lp0 - np0; + dy = lp1 - np1; + endPointDis = sqrt(dx*dx + dy*dy); + + /* set momentaneously min and max distance between lines to + the one between left extremes */ + minLocalDis = endPointDis; + maxLocalDis = endPointDis; + + /* compute distance between right extremes + L1(2,3)<->L2(2,3) */ + dx = lp2 - np2; + dy = lp3 - np3; + endPointDis = sqrt(dx*dx + dy*dy); + + /* update (if necessary) min and max distance between lines */ + minLocalDis = (endPointDismaxLocalDis)?endPointDis:maxLocalDis; + + + /* compute distance between left extreme of current line and + right extreme of line to be compared + L1(0,1)<->L2(2,3) */ + dx = lp0 - np2; + dy = lp1 - np3; + endPointDis = sqrt(dx*dx + dy*dy); + + /* update (if necessary) min and max distance between lines */ + minLocalDis = (endPointDismaxLocalDis)?endPointDis:maxLocalDis; + + /* compute distance between right extreme of current line and + left extreme of line to be compared + L1(2,3)<->L2(0,1) */ + dx = lp2 - np0; + dy = lp3 - np1; + endPointDis = sqrt(dx*dx + dy*dy); + + /* update (if necessary) min and max distance between lines */ + minLocalDis = (endPointDismaxLocalDis)?endPointDis:maxLocalDis; + + /* check whether conditions for considering line to be compared + worth to be inserted in the same LineVec are satisfied */ + if((maxLocalDis<0.8*(length+octaveLines[lineNextId].lineLength)) + &&(minLocalDis1) + + //////////////////////////////////// + //Reorganize the detected lines into keyLines + keyLines.clear(); + keyLines.resize(lineIDInScaleLineVec); + unsigned int tempID; + float s1,e1,s2,e2; + bool shouldChange; + OctaveSingleLine singleLine; + for(unsigned int lineID = 0;lineID < numOfFinalLine; lineID++){ + lineIDInOctave = octaveLines[lineID].lineIDInOctave; + octaveID = octaveLines[lineID].octaveCount; + direction = edLineVec_[octaveID]->lineDirection_[lineIDInOctave]; + singleLine.octaveCount = octaveID; + singleLine.direction = direction; + singleLine.lineLength = octaveLines[lineID].lineLength; + singleLine.salience = edLineVec_[octaveID]->lineSalience_[lineIDInOctave]; + singleLine.numOfPixels = edLineVec_[octaveID]->lines_.sId[lineIDInOctave+1]- + edLineVec_[octaveID]->lines_.sId[lineIDInOctave]; + //decide the start point and end point + shouldChange = false; + s1 = edLineVec_[octaveID]->lineEndpoints_[lineIDInOctave][0];//sx + s2 = edLineVec_[octaveID]->lineEndpoints_[lineIDInOctave][1];//sy + e1 = edLineVec_[octaveID]->lineEndpoints_[lineIDInOctave][2];//ex + e2 = edLineVec_[octaveID]->lineEndpoints_[lineIDInOctave][3];//ey + dx = e1 - s1;//ex-sx + dy = e2 - s2;//ey-sy + if(direction>=-0.75*M_PI&&direction<-0.25*M_PI){ + if(dy>0){shouldChange = true;} + } + if(direction>=-0.25*M_PI&&direction<0.25*M_PI){ + if(dx<0){shouldChange = true;} + } + if(direction>=0.25*M_PI&&direction<0.75*M_PI){ + if(dy<0){shouldChange = true;} + } + if((direction>=0.75*M_PI&&direction=-M_PI&&direction<-0.75*M_PI)){ + if(dx>0){shouldChange = true;} + } + tempValue = scale[octaveID]; + if(shouldChange){ + singleLine.sPointInOctaveX = e1; + singleLine.sPointInOctaveY = e2; + singleLine.ePointInOctaveX = s1; + singleLine.ePointInOctaveY = s2; + singleLine.startPointX = tempValue * e1; + singleLine.startPointY = tempValue * e2; + singleLine.endPointX = tempValue * s1; + singleLine.endPointY = tempValue * s2; + }else{ + singleLine.sPointInOctaveX = s1; + singleLine.sPointInOctaveY = s2; + singleLine.ePointInOctaveX = e1; + singleLine.ePointInOctaveY = e2; + singleLine.startPointX = tempValue * s1; + singleLine.startPointY = tempValue * s2; + singleLine.endPointX = tempValue * e1; + singleLine.endPointY = tempValue * e2; + } + tempID = octaveLines[lineID].lineIDInScaleLineVec; + keyLines[tempID].push_back(singleLine); + } + + //////////////////////////////////// + + delete [] scale; + return 1; +} + +/*The definitions of line descriptor,mean values of {g_dL>0},{g_dL<0},{g_dO>0},{g_dO<0} of each row in band + *and std values of sum{g_dL>0},sum{g_dL<0},sum{g_dO>0},sum{g_dO<0} of each row in band. + * With overlap region. */ +int LineDescriptor::ComputeLBD_(ScaleLines &keyLines) +{ + //the default length of the band is the line length. + short numOfFinalLine = keyLines.size(); + float *dL = new float[2];//line direction cos(dir), sin(dir) + float *dO = new float[2];//the clockwise orthogonal vector of line direction. + short heightOfLSP = widthOfBand_*numOfBand_;//the height of line support region; + short descriptorSize = numOfBand_ * 8;//each band, we compute the m( pgdL, ngdL, pgdO, ngdO) and std( pgdL, ngdL, pgdO, ngdO); + float pgdLRowSum;//the summation of {g_dL |g_dL>0 } for each row of the region; + float ngdLRowSum;//the summation of {g_dL |g_dL<0 } for each row of the region; + float pgdL2RowSum;//the summation of {g_dL^2 |g_dL>0 } for each row of the region; + float ngdL2RowSum;//the summation of {g_dL^2 |g_dL<0 } for each row of the region; + float pgdORowSum;//the summation of {g_dO |g_dO>0 } for each row of the region; + float ngdORowSum;//the summation of {g_dO |g_dO<0 } for each row of the region; + float pgdO2RowSum;//the summation of {g_dO^2 |g_dO>0 } for each row of the region; + float ngdO2RowSum;//the summation of {g_dO^2 |g_dO<0 } for each row of the region; + + float *pgdLBandSum = new float[numOfBand_];//the summation of {g_dL |g_dL>0 } for each band of the region; + float *ngdLBandSum = new float[numOfBand_];//the summation of {g_dL |g_dL<0 } for each band of the region; + float *pgdL2BandSum = new float[numOfBand_];//the summation of {g_dL^2 |g_dL>0 } for each band of the region; + float *ngdL2BandSum = new float[numOfBand_];//the summation of {g_dL^2 |g_dL<0 } for each band of the region; + float *pgdOBandSum = new float[numOfBand_];//the summation of {g_dO |g_dO>0 } for each band of the region; + float *ngdOBandSum = new float[numOfBand_];//the summation of {g_dO |g_dO<0 } for each band of the region; + float *pgdO2BandSum = new float[numOfBand_];//the summation of {g_dO^2 |g_dO>0 } for each band of the region; + float *ngdO2BandSum = new float[numOfBand_];//the summation of {g_dO^2 |g_dO<0 } for each band of the region; + + short numOfBitsBand = numOfBand_*sizeof(float); + short lengthOfLSP; //the length of line support region, varies with lines + short halfHeight = (heightOfLSP-1)/2; + short halfWidth; + short bandID; + float coefInGaussion; + float lineMiddlePointX, lineMiddlePointY; + float sCorX, sCorY,sCorX0, sCorY0; + short tempCor, xCor, yCor;//pixel coordinates in image plane + short dx, dy; + float gDL;//store the gradient projection of pixels in support region along dL vector + float gDO;//store the gradient projection of pixels in support region along dO vector + short imageWidth, imageHeight, realWidth; + short *pdxImg, *pdyImg; + float *desVec; + + short sameLineSize; + short octaveCount; + OctaveSingleLine *pSingleLine; + /* loop over list of LineVec */ + for(short lineIDInScaleVec = 0; lineIDInScaleVecoctaveCount; + + /* retrieve associated dxImg and dyImg */ + pdxImg = edLineVec_[octaveCount]->dxImg_.ptr(); + pdyImg = edLineVec_[octaveCount]->dyImg_.ptr(); + + /* get image size to work on from real one */ + realWidth = edLineVec_[octaveCount]->imageWidth; + imageWidth = realWidth -1; + imageHeight = edLineVec_[octaveCount]->imageHeight-1; + + + /* initialize memory areas */ + memset(pgdLBandSum, 0, numOfBitsBand); + memset(ngdLBandSum, 0, numOfBitsBand); + memset(pgdL2BandSum, 0, numOfBitsBand); + memset(ngdL2BandSum, 0, numOfBitsBand); + memset(pgdOBandSum, 0, numOfBitsBand); + memset(ngdOBandSum, 0, numOfBitsBand); + memset(pgdO2BandSum, 0, numOfBitsBand); + memset(ngdO2BandSum, 0, numOfBitsBand); + + /* get length of line and its half */ + lengthOfLSP = keyLines[lineIDInScaleVec][lineIDInSameLine].numOfPixels; + halfWidth = (lengthOfLSP-1)/2; + + /* get middlepoint of line */ + lineMiddlePointX = 0.5 * (pSingleLine->sPointInOctaveX + pSingleLine->ePointInOctaveX); + lineMiddlePointY = 0.5 * (pSingleLine->sPointInOctaveY + pSingleLine->ePointInOctaveY); + + /*1.rotate the local coordinate system to the line direction (direction is the angle + between positive line direction and positive X axis) + *2.compute the gradient projection of pixels in line support region*/ + + /* get the vector representing original image reference system after rotation to aligh with + line's direction */ + dL[0] = cos(pSingleLine->direction); + dL[1] = sin(pSingleLine->direction); + + /* set the clockwise orthogonal vector of line direction */ + dO[0] = -dL[1]; + dO[1] = dL[0]; + + /* get rotated reference frame */ + sCorX0= -dL[0]*halfWidth + dL[1]*halfHeight + lineMiddlePointX;//hID =0; wID = 0; + sCorY0= -dL[1]*halfWidth - dL[0]*halfHeight + lineMiddlePointY; + + + /* BIAS::Matrix gDLMat(heightOfLSP,lengthOfLSP) */ + for(short hID = 0; hID imageWidth)?imageWidth:tempCor; + tempCor = round(sCorY); + yCor = (tempCor<0)?0:(tempCor>imageHeight)?imageHeight:tempCor; + + /* To achieve rotation invariance, each simple gradient is rotated aligned with + * the line direction and clockwise orthogonal direction.*/ + dx = pdxImg[yCor*realWidth+xCor]; + dy = pdyImg[yCor*realWidth+xCor]; + gDL = dx * dL[0] + dy * dL[1]; + gDO = dx * dO[0] + dy * dO[1]; + if(gDL>0){ + pgdLRowSum += gDL; + }else{ + ngdLRowSum -= gDL; + } + if(gDO>0){ + pgdORowSum += gDO; + }else{ + ngdORowSum -= gDO; + } + sCorX +=dL[0]; + sCorY +=dL[1]; + /* gDLMat[hID][wID] = gDL; */ + } + sCorX0 -=dL[1]; + sCorY0 +=dL[0]; + coefInGaussion = gaussCoefG_[hID]; + pgdLRowSum = coefInGaussion * pgdLRowSum; + ngdLRowSum = coefInGaussion * ngdLRowSum; + pgdL2RowSum = pgdLRowSum * pgdLRowSum; + ngdL2RowSum = ngdLRowSum * ngdLRowSum; + pgdORowSum = coefInGaussion * pgdORowSum; + ngdORowSum = coefInGaussion * ngdORowSum; + pgdO2RowSum = pgdORowSum * pgdORowSum; + ngdO2RowSum = ngdORowSum * ngdORowSum; + + /* compute {g_dL |g_dL>0 }, {g_dL |g_dL<0 }, + {g_dO |g_dO>0 }, {g_dO |g_dO<0 } of each band in the line support region + first, current row belong to current band */ + bandID = hID/widthOfBand_; + coefInGaussion = gaussCoefL_[hID%widthOfBand_+widthOfBand_]; + pgdLBandSum[bandID] += coefInGaussion * pgdLRowSum; + ngdLBandSum[bandID] += coefInGaussion * ngdLRowSum; + pgdL2BandSum[bandID] += coefInGaussion * coefInGaussion * pgdL2RowSum; + ngdL2BandSum[bandID] += coefInGaussion * coefInGaussion * ngdL2RowSum; + pgdOBandSum[bandID] += coefInGaussion * pgdORowSum; + ngdOBandSum[bandID] += coefInGaussion * ngdORowSum; + pgdO2BandSum[bandID] += coefInGaussion * coefInGaussion * pgdO2RowSum; + ngdO2BandSum[bandID] += coefInGaussion * coefInGaussion * ngdO2RowSum; + + /* In order to reduce boundary effect along the line gradient direction, + * a row's gradient will contribute not only to its current band, but also + * to its nearest upper and down band with gaussCoefL_.*/ + bandID--; + if(bandID>=0){/* the band above the current band */ + coefInGaussion = gaussCoefL_[hID%widthOfBand_ + 2*widthOfBand_]; + pgdLBandSum[bandID] += coefInGaussion * pgdLRowSum; + ngdLBandSum[bandID] += coefInGaussion * ngdLRowSum; + pgdL2BandSum[bandID] += coefInGaussion * coefInGaussion * pgdL2RowSum; + ngdL2BandSum[bandID] += coefInGaussion * coefInGaussion * ngdL2RowSum; + pgdOBandSum[bandID] += coefInGaussion * pgdORowSum; + ngdOBandSum[bandID] += coefInGaussion * ngdORowSum; + pgdO2BandSum[bandID] += coefInGaussion * coefInGaussion * pgdO2RowSum; + ngdO2BandSum[bandID] += coefInGaussion * coefInGaussion * ngdO2RowSum; + } + bandID = bandID+2; + if(bandIDdescriptor.resize(descriptorSize); + desVec = pSingleLine->descriptor.data(); + + short desID; + + /*Note that the first and last bands only have (lengthOfLSP * widthOfBand_ * 2.0) pixels + * which are counted. */ + float invN2 = 1.0/(widthOfBand_ * 2.0); + float invN3 = 1.0/(widthOfBand_ * 3.0); + float invN, temp; + for(bandID = 0; bandIDdescriptor.data(); + + int base = 0; + for(short i=0; idescriptor.data(); + base = 0; + for(short i=0; idescriptor.data(); + for(short i=0; i0.4){ + desVec[i]=0.4; + } + } + + //re-normalize desVec; + temp = 0; + for(short i=0; if2[i]) + { +// std::cout<< " ------ 1 ------- "<f2[i]) +// { +//// std::cout<< " ------ 1 ------- "<& desc) +{ + uchar result=0; + for(int i = 0; i<8; i++) + { +// std::cout<<"f1[: "<desc[i+f2]) + { +// std::cout<< " ------ 1 ------- "< & oct_binaryDescMat, ScaleLines & keyLines) +{ + + /* std::cout<<"numOfOctave: "< rows_size; + for(int i = 0; i vec_binaryMat_p; + + /* loop on the number of the octaves */ + for(int i = 0; i(i, j) = (float)keyLines[i][0].descriptor[j]; +// } +// std::cout<= 3.12) + return true; + + return false; +} + + +void LineDescriptor::findNearestParallelLines(ScaleLines & keyLines) +{ + + std::cout<<"PARALLELLINES: size: "< parallels; + + /* loop over LineVecs */ + for(int j = 0; j::iterator it; + + /* scan map to searck for a line parallel to current one */ + bool foundParallel = false; + for(it = parallels.begin(); it != parallels.end(); it++) { + if(!areParallels(it->first, singleLine.direction)) + { + foundParallel = true; + break; + } + + } + + /* if a parallel line has not been found, add current line + to map, using its direction as a key */ + if(!foundParallel) + parallels[singleLine.direction] = singleLine; + + } + } + + /* create a vector of LineVecs, each one containing a line that is + not parallel to any other one inside a different LineVec */ + ScaleLines newKeyLines; + std::map::iterator it; + for(it = parallels.begin(); it != parallels.end(); it++) { + LinesVec lineScaleLs; + lineScaleLs.push_back(it->second); + newKeyLines.push_back(lineScaleLs); + } + + keyLines = newKeyLines; + +} + +int LineDescriptor::GetLineDescriptor(cv::Mat & image, ScaleLines & keyLines, bool lsd) +{ + + /*check whether image depth is different from 0 */ + if(image.depth() != 0) + { + std::cout << "Warning, depth image!= 0" << std::endl; + CV_Assert(false); + } + + /* make a clone of input image */ + cv::Mat original = image.clone(); + + /* get clock's TIC */ + double t = (double)cv::getTickCount(); + + /* compute LineVecs extraction and in case of failure, return an error code */ + if((OctaveKeyLines(image,keyLines))!=true){ + cout << "OctaveKeyLines failed" << endl; + return -1; + } + + /* get time lapse */ + t = ((double)cv::getTickCount() - t)/cv::getTickFrequency(); + std::cout << "time line extraction: " << t<< "s" < ls = cv::createLineSegmentDetector(cv::LSD_REFINE_STD); + + /* prepare a vectore to host extracted segments */ + std::vector lines_std; + + ScaleLines scaleLs; + + /* use detector to extract segments */ + ls->detect(original, lines_std); + + /* make a copy of input image */ + cv::Mat drawnLines(original); + + /* draw extracted segments on the copy of image */ + ls->drawSegments(drawnLines, lines_std); + + /* show extracted segments on image */ + cv::imshow("Standard refinement", drawnLines); + + /* get a matrix representation of segments */ + cv::Mat _lines; + _lines = ((cv::InputArray)lines_std).getMat(); + + // Draw segments + for(int i = 0; i < _lines.size().width; ++i) + { + + /* get current segments and store its extremes */ + const cv::Vec4i& v = _lines.at(i); + cv::Point b(v[0], v[1]); + cv::Point e(v[2], v[3]); + + /* create an object to store line information */ + OctaveSingleLine osl; + osl.startPointX = b.x; + osl.startPointY = b.y; + osl.endPointX = e.x; + osl.endPointY = e.y; + osl.sPointInOctaveX = b.x; + osl.sPointInOctaveY = b.y; + osl.ePointInOctaveX = e.x; + osl.ePointInOctaveY = e.y; + osl.direction = 0; + osl.salience = 0; + osl.lineLength = 0; + osl.numOfPixels = std::sqrt((b.x-e.x)*(b.x-e.x) + (b.y-e.y)*(b.y-e.y)); + osl.octaveCount = 0; + + /* store information about line */ + LinesVec lineScaleLs; + lineScaleLs.push_back(osl); + scaleLs.push_back(lineScaleLs); + + } + + + keyLines = scaleLs; + } + else + std::cout<<"GetLineDescriptor EDLINE"< &matchLeft, std::vector &matchRight, + int criteria) +{ + + /* check whether any input is void */ + int leftSize = keyLinesLeft.size(); + int rightSize = keyLinesRight.size(); + if(leftSize<1||rightSize<1){ + return -1; + } + + /* void vectors */ + matchLeft.clear(); + matchRight.clear(); + + + int desDim = keyLinesLeft[0][0].descriptor.size(); + float *desL, *desR, *desMax, *desOld; + + if(criteria==NearestNeighbor) + { + float minDis,dis,temp; + int corresId; + + /* loop over left list of LineVecs */ + for(int idL=0; idL