From: Daniel Angelov Date: Sat, 20 Jul 2013 22:31:51 +0000 (+0300) Subject: Update on the class to reflect the review. Split the class into virtual and implement... X-Git-Tag: accepted/tizen/6.0/unified/20201030.111113~3832^2~7 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=965b3759b11956ca29e2246efe85ee20dfcbcc30;p=platform%2Fupstream%2Fopencv.git Update on the class to reflect the review. Split the class into virtual and implementation. change of name to LineSegmentDetector, using Input/Output-Arrays, general clean ups. --- diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index b4a5efb..1dec4ce 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -835,34 +835,16 @@ protected: Point2f bottomRight; }; -class CV_EXPORTS_W LSD +class LineSegmentDetector : public Algorithm { public: - -/** - * Create an LSD object. Specifying scale, number of subdivisions for the image, should the lines be refined and other constants as follows: - * - * @param _refine How should the lines found be refined? - * LSD_REFINE_NONE - No refinement applied. - * LSD_REFINE_STD - Standard refinement is applied. E.g. breaking arches into smaller line approximations. - * LSD_REFINE_ADV - Advanced refinement. Number of false alarms is calculated, - * lines are refined through increase of precision, decrement in size, etc. - * @param _scale The scale of the image that will be used to find the lines. Range (0..1]. - * @param _sigma_scale Sigma for Gaussian filter is computed as sigma = _sigma_scale/_scale. - * @param _quant Bound to the quantization error on the gradient norm. - * @param _ang_th Gradient angle tolerance in degrees. - * @param _log_eps Detection threshold: -log10(NFA) > _log_eps - * @param _density_th Minimal density of aligned region points in rectangle. - * @param _n_bins Number of bins in pseudo-ordering of gradient modulus. - */ - LSD(int _refine = LSD_REFINE_STD, double _scale = 0.8, - double _sigma_scale = 0.6, double _quant = 2.0, double _ang_th = 22.5, - double _log_eps = 0, double _density_th = 0.7, int _n_bins = 1024); - /** * Detect lines in the input image with the specified ROI. * * @param _image A grayscale(CV_8UC1) input image. + * If only a roi needs to be selected, use + * lsd_ptr->detect(image(roi), ..., lines); + * lines += Scalar(roi.x, roi.y, roi.x, roi.y); * @param _lines Return: A vector of Vec4i elements specifying the beginning and ending point of a line. * Where Vec4i is (x1, y1, x2, y2), point 1 is the start, point 2 - end. * Returned lines are strictly oriented depending on the gradient. @@ -875,10 +857,11 @@ public: * * -1 corresponds to 10 mean false alarms * * 0 corresponds to 1 mean false alarm * * 1 corresponds to 0.1 mean false alarms + * This vector will be calculated _only_ when the objects type is REFINE_ADV */ - void detect(const cv::InputArray _image, cv::OutputArray _lines, cv::Rect _roi = cv::Rect(), - cv::OutputArray width = cv::noArray(), cv::OutputArray prec = cv::noArray(), - cv::OutputArray nfa = cv::noArray()); + virtual void detect(const InputArray _image, OutputArray _lines, + OutputArray width = noArray(), OutputArray prec = noArray(), + OutputArray nfa = noArray()) = 0; /** * Draw lines on the given canvas. @@ -887,7 +870,7 @@ public: * Should have the size of the image, where the lines were found * @param lines The lines that need to be drawn */ - static void drawSegments(cv::Mat& image, const std::vector& lines); + virtual void drawSegments(InputOutputArray image, const InputArray lines) = 0; /** * Draw both vectors on the image canvas. Uses blue for lines 1 and red for lines 2. @@ -898,163 +881,23 @@ public: * @param lines2 The second lines that need to be drawn. Color - Red. * @return The number of mismatching pixels between lines1 and lines2. */ - static int compareSegments(const cv::Size& size, const std::vector& lines1, const std::vector lines2, cv::Mat* image = 0); - -private: - cv::Mat image; - cv::Mat_ scaled_image; - double *scaled_image_data; - cv::Mat_ angles; // in rads - double *angles_data; - cv::Mat_ modgrad; - double *modgrad_data; - cv::Mat_ used; - - int img_width; - int img_height; - double LOG_NT; - - cv::Rect roi; - int roix, roiy; - - const double SCALE; - const int doRefine; - const double SIGMA_SCALE; - const double QUANT; - const double ANG_TH; - const double LOG_EPS; - const double DENSITY_TH; - const int N_BINS; - - struct RegionPoint { - int x; - int y; - uchar* used; - double angle; - double modgrad; - }; - - struct coorlist - { - cv::Point2i p; - struct coorlist* next; - }; - - struct rect - { - double x1, y1, x2, y2; // first and second point of the line segment - double width; // rectangle width - double x, y; // center of the rectangle - double theta; // angle - double dx,dy; // (dx,dy) is vector oriented as the line segment - double prec; // tolerance angle - double p; // probability of a point with angle within 'prec' - }; - -/** - * Detect lines in the whole input image. - * - * @param lines Return: A vector of Vec4i elements specifying the beginning and ending point of a line. - * Where Vec4i is (x1, y1, x2, y2), point 1 is the start, point 2 - end. - * Returned lines are strictly oriented depending on the gradient. - * @param widths Return: Vector of widths of the regions, where the lines are found. E.g. Width of line. - * @param precisions Return: Vector of precisions with which the lines are found. - * @param nfas Return: Vector containing number of false alarms in the line region, with precision of 10%. - * The bigger the value, logarithmically better the detection. - * * -1 corresponds to 10 mean false alarms - * * 0 corresponds to 1 mean false alarm - * * 1 corresponds to 0.1 mean false alarms - */ - void flsd(std::vector& lines, - std::vector* widths, std::vector* precisions, - std::vector* nfas); - -/** - * Finds the angles and the gradients of the image. Generates a list of pseudo ordered points. - * - * @param threshold The minimum value of the angle that is considered defined, otherwise NOTDEF - * @param n_bins The number of bins with which gradients are ordered by, using bucket sort. - * @param list Return: Vector of coordinate points that are pseudo ordered by magnitude. - * Pixels would be ordered by norm value, up to a precision given by max_grad/n_bins. - */ - void ll_angle(const double& threshold, const unsigned int& n_bins, std::vector& list); - -/** - * Grow a region starting from point s with a defined precision, - * returning the containing points size and the angle of the gradients. - * - * @param s Starting point for the region. - * @param reg Return: Vector of points, that are part of the region - * @param reg_size Return: The size of the region. - * @param reg_angle Return: The mean angle of the region. - * @param prec The precision by which each region angle should be aligned to the mean. - */ - void region_grow(const cv::Point2i& s, std::vector& reg, - int& reg_size, double& reg_angle, const double& prec); + virtual int compareSegments(const Size& size, const InputArray lines1, const InputArray lines2, Mat* image = 0) = 0; -/** - * Finds the bounding rotated rectangle of a region. - * - * @param reg The region of points, from which the rectangle to be constructed from. - * @param reg_size The number of points in the region. - * @param reg_angle The mean angle of the region. - * @param prec The precision by which points were found. - * @param p Probability of a point with angle within 'prec'. - * @param rec Return: The generated rectangle. - */ - void region2rect(const std::vector& reg, const int reg_size, const double reg_angle, - const double prec, const double p, rect& rec) const; - -/** - * Compute region's angle as the principal inertia axis of the region. - * @return Regions angle. - */ - double get_theta(const std::vector& reg, const int& reg_size, const double& x, - const double& y, const double& reg_angle, const double& prec) const; - -/** - * An estimation of the angle tolerance is performed by the standard deviation of the angle at points - * near the region's starting point. Then, a new region is grown starting from the same point, but using the - * estimated angle tolerance. If this fails to produce a rectangle with the right density of region points, - * 'reduce_region_radius' is called to try to satisfy this condition. - */ - bool refine(std::vector& reg, int& reg_size, double reg_angle, - const double prec, double p, rect& rec, const double& density_th); - -/** - * Reduce the region size, by elimination the points far from the starting point, until that leads to - * rectangle with the right density of region points or to discard the region if too small. - */ - bool reduce_region_radius(std::vector& reg, int& reg_size, double reg_angle, - const double prec, double p, rect& rec, double density, const double& density_th); - -/** - * Try some rectangles variations to improve NFA value. Only if the rectangle is not meaningful (i.e., log_nfa <= log_eps). - * @return The new NFA value. - */ - double rect_improve(rect& rec) const; - -/** - * Calculates the number of correctly aligned points within the rectangle. - * @return The new NFA value. - */ - double rect_nfa(const rect& rec) const; - -/** - * Computes the NFA values based on the total number of points, points that agree. - * n, k, p are the binomial parameters. - * @return The new NFA value. - */ - double nfa(const int& n, const int& k, const double& p) const; - -/** - * Is the point at place 'address' aligned to angle theta, up to precision 'prec'? - * @return Whether the point is aligned. - */ - bool isAligned(const int& address, const double& theta, const double& prec) const; + ~LineSegmentDetector() {}; +protected: + LineSegmentDetector() {}; }; +//! Returns a pointer to a LineSegmentDetector class. +CV_EXPORTS Ptr createLineSegmentDetectorSmrtPtr( + int _refine = LSD_REFINE_STD, double _scale = 0.8, + double _sigma_scale = 0.6, double _quant = 2.0, double _ang_th = 22.5, + double _log_eps = 0, double _density_th = 0.7, int _n_bins = 1024); +CV_EXPORTS LineSegmentDetector* createLineSegmentDetectorPtr( + int _refine = LSD_REFINE_STD, double _scale = 0.8, + double _sigma_scale = 0.6, double _quant = 2.0, double _ang_th = 22.5, + double _log_eps = 0, double _density_th = 0.7, int _n_bins = 1024); //! returns type (one of KERNEL_*) of 1D or 2D kernel specified by its coefficients. CV_EXPORTS int getKernelType(InputArray kernel, Point anchor); diff --git a/modules/imgproc/src/lsd.cpp b/modules/imgproc/src/lsd.cpp index aa56e02..8b653a2 100644 --- a/modules/imgproc/src/lsd.cpp +++ b/modules/imgproc/src/lsd.cpp @@ -40,11 +40,8 @@ //M*/ #include "precomp.hpp" - #include -using namespace cv; - ///////////////////////////////////////////////////////////////////////////////////////// // Default LSD parameters // SIGMA_SCALE 0.6 - Sigma for Gaussian filter is computed as sigma = sigma_scale/scale. @@ -54,10 +51,6 @@ using namespace cv; // DENSITY_TH 0.7 - Minimal density of region points in rectangle. // N_BINS 1024 - Number of bins in pseudo-ordering of gradient modulus. -// PI -#ifndef M_PI -#define M_PI CV_PI -#endif #define M_3_2_PI (3 * CV_PI) / 2 // 3/2 pi #define M_2__PI (2 * CV_PI) // 2 pi @@ -72,7 +65,7 @@ using namespace cv; #define RELATIVE_ERROR_FACTOR 100.0 -const double DEG_TO_RADS = M_PI / 180; +const double DEG_TO_RADS = CV_PI / 180; #define log_gamma(x) ((x)>15.0?log_gamma_windschitl(x):log_gamma_lanczos(x)) @@ -84,12 +77,14 @@ struct edge ///////////////////////////////////////////////////////////////////////////////////////// -inline double distSq(const double x1, const double y1, const double x2, const double y2) +inline double distSq(const double x1, const double y1, + const double x2, const double y2) { return (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1); } -inline double dist(const double x1, const double y1, const double x2, const double y2) +inline double dist(const double x1, const double y1, + const double x2, const double y2) { return sqrt(distSq(x1, y1, x2, y2)); } @@ -163,7 +158,256 @@ inline double log_gamma_lanczos(const double& x) } /////////////////////////////////////////////////////////////////////////////////////////////////////////////// -LSD::LSD(int _refine, double _scale, double _sigma_scale, double _quant, +namespace cv{ + +class LineSegmentDetectorImpl : public LineSegmentDetector +{ +public: + +/** + * Create a LineSegmentDetectorImpl object. Specifying scale, number of subdivisions for the image, should the lines be refined and other constants as follows: + * + * @param _refine How should the lines found be refined? + * LSD_REFINE_NONE - No refinement applied. + * LSD_REFINE_STD - Standard refinement is applied. E.g. breaking arches into smaller line approximations. + * LSD_REFINE_ADV - Advanced refinement. Number of false alarms is calculated, + * lines are refined through increase of precision, decrement in size, etc. + * @param _scale The scale of the image that will be used to find the lines. Range (0..1]. + * @param _sigma_scale Sigma for Gaussian filter is computed as sigma = _sigma_scale/_scale. + * @param _quant Bound to the quantization error on the gradient norm. + * @param _ang_th Gradient angle tolerance in degrees. + * @param _log_eps Detection threshold: -log10(NFA) > _log_eps + * @param _density_th Minimal density of aligned region points in rectangle. + * @param _n_bins Number of bins in pseudo-ordering of gradient modulus. + */ + LineSegmentDetectorImpl(int _refine = LSD_REFINE_STD, double _scale = 0.8, + double _sigma_scale = 0.6, double _quant = 2.0, double _ang_th = 22.5, + double _log_eps = 0, double _density_th = 0.7, int _n_bins = 1024); + +/** + * Detect lines in the input image with the specified ROI. + * + * @param _image A grayscale(CV_8UC1) input image. + * If only a roi needs to be selected, use + * lsd_ptr->detect(image(roi), ..., lines); + * lines += Scalar(roi.x, roi.y, roi.x, roi.y); + * @param _lines Return: A vector of Vec4i elements specifying the beginning and ending point of a line. + * Where Vec4i is (x1, y1, x2, y2), point 1 is the start, point 2 - end. + * Returned lines are strictly oriented depending on the gradient. + * @param _roi Return: ROI of the image, where lines are to be found. If specified, the returning + * lines coordinates are image wise. + * @param width Return: Vector of widths of the regions, where the lines are found. E.g. Width of line. + * @param prec Return: Vector of precisions with which the lines are found. + * @param nfa Return: Vector containing number of false alarms in the line region, with precision of 10%. + * The bigger the value, logarithmically better the detection. + * * -1 corresponds to 10 mean false alarms + * * 0 corresponds to 1 mean false alarm + * * 1 corresponds to 0.1 mean false alarms + * This vector will be calculated _only_ when the objects type is REFINE_ADV + */ + void detect(const InputArray _image, OutputArray _lines, + OutputArray width = noArray(), OutputArray prec = noArray(), + OutputArray nfa = noArray()); + +/** + * Draw lines on the given canvas. + * + * @param image The image, where lines will be drawn. + * Should have the size of the image, where the lines were found + * @param lines The lines that need to be drawn + */ + void drawSegments(InputOutputArray image, const InputArray lines); + +/** + * Draw both vectors on the image canvas. Uses blue for lines 1 and red for lines 2. + * + * @param image The image, where lines will be drawn. + * Should have the size of the image, where the lines were found + * @param lines1 The first lines that need to be drawn. Color - Blue. + * @param lines2 The second lines that need to be drawn. Color - Red. + * @return The number of mismatching pixels between lines1 and lines2. + */ + int compareSegments(const Size& size, const InputArray lines1, const InputArray lines2, Mat* image = 0); + +private: + Mat image; + Mat_ scaled_image; + double *scaled_image_data; + Mat_ angles; // in rads + double *angles_data; + Mat_ modgrad; + double *modgrad_data; + Mat_ used; + + int img_width; + int img_height; + double LOG_NT; + + bool w_needed; + bool p_needed; + bool n_needed; + + const double SCALE; + const int doRefine; + const double SIGMA_SCALE; + const double QUANT; + const double ANG_TH; + const double LOG_EPS; + const double DENSITY_TH; + const int N_BINS; + + struct RegionPoint { + int x; + int y; + uchar* used; + double angle; + double modgrad; + }; + + + struct coorlist + { + Point2i p; + struct coorlist* next; + }; + + struct rect + { + double x1, y1, x2, y2; // first and second point of the line segment + double width; // rectangle width + double x, y; // center of the rectangle + double theta; // angle + double dx,dy; // (dx,dy) is vector oriented as the line segment + double prec; // tolerance angle + double p; // probability of a point with angle within 'prec' + }; + +/** + * Detect lines in the whole input image. + * + * @param lines Return: A vector of Vec4i elements specifying the beginning and ending point of a line. + * Where Vec4i is (x1, y1, x2, y2), point 1 is the start, point 2 - end. + * Returned lines are strictly oriented depending on the gradient. + * @param widths Return: Vector of widths of the regions, where the lines are found. E.g. Width of line. + * @param precisions Return: Vector of precisions with which the lines are found. + * @param nfas Return: Vector containing number of false alarms in the line region, with precision of 10%. + * The bigger the value, logarithmically better the detection. + * * -1 corresponds to 10 mean false alarms + * * 0 corresponds to 1 mean false alarm + * * 1 corresponds to 0.1 mean false alarms + */ + void flsd(std::vector& lines, + std::vector& widths, std::vector& precisions, + std::vector& nfas); + +/** + * Finds the angles and the gradients of the image. Generates a list of pseudo ordered points. + * + * @param threshold The minimum value of the angle that is considered defined, otherwise NOTDEF + * @param n_bins The number of bins with which gradients are ordered by, using bucket sort. + * @param list Return: Vector of coordinate points that are pseudo ordered by magnitude. + * Pixels would be ordered by norm value, up to a precision given by max_grad/n_bins. + */ + void ll_angle(const double& threshold, const unsigned int& n_bins, std::vector& list); + +/** + * Grow a region starting from point s with a defined precision, + * returning the containing points size and the angle of the gradients. + * + * @param s Starting point for the region. + * @param reg Return: Vector of points, that are part of the region + * @param reg_size Return: The size of the region. + * @param reg_angle Return: The mean angle of the region. + * @param prec The precision by which each region angle should be aligned to the mean. + */ + void region_grow(const Point2i& s, std::vector& reg, + int& reg_size, double& reg_angle, const double& prec); + +/** + * Finds the bounding rotated rectangle of a region. + * + * @param reg The region of points, from which the rectangle to be constructed from. + * @param reg_size The number of points in the region. + * @param reg_angle The mean angle of the region. + * @param prec The precision by which points were found. + * @param p Probability of a point with angle within 'prec'. + * @param rec Return: The generated rectangle. + */ + void region2rect(const std::vector& reg, const int reg_size, const double reg_angle, + const double prec, const double p, rect& rec) const; + +/** + * Compute region's angle as the principal inertia axis of the region. + * @return Regions angle. + */ + double get_theta(const std::vector& reg, const int& reg_size, const double& x, + const double& y, const double& reg_angle, const double& prec) const; + +/** + * An estimation of the angle tolerance is performed by the standard deviation of the angle at points + * near the region's starting point. Then, a new region is grown starting from the same point, but using the + * estimated angle tolerance. If this fails to produce a rectangle with the right density of region points, + * 'reduce_region_radius' is called to try to satisfy this condition. + */ + bool refine(std::vector& reg, int& reg_size, double reg_angle, + const double prec, double p, rect& rec, const double& density_th); + +/** + * Reduce the region size, by elimination the points far from the starting point, until that leads to + * rectangle with the right density of region points or to discard the region if too small. + */ + bool reduce_region_radius(std::vector& reg, int& reg_size, double reg_angle, + const double prec, double p, rect& rec, double density, const double& density_th); + +/** + * Try some rectangles variations to improve NFA value. Only if the rectangle is not meaningful (i.e., log_nfa <= log_eps). + * @return The new NFA value. + */ + double rect_improve(rect& rec) const; + +/** + * Calculates the number of correctly aligned points within the rectangle. + * @return The new NFA value. + */ + double rect_nfa(const rect& rec) const; + +/** + * Computes the NFA values based on the total number of points, points that agree. + * n, k, p are the binomial parameters. + * @return The new NFA value. + */ + double nfa(const int& n, const int& k, const double& p) const; + +/** + * Is the point at place 'address' aligned to angle theta, up to precision 'prec'? + * @return Whether the point is aligned. + */ + bool isAligned(const int& address, const double& theta, const double& prec) const; +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +CV_EXPORTS Ptr createLineSegmentDetectorSmrtPtr( + int _refine, double _scale, double _sigma_scale, double _quant, double _ang_th, + double _log_eps, double _density_th, int _n_bins) +{ + return Ptr(new LineSegmentDetectorImpl( + _refine, _scale, _sigma_scale, _quant, _ang_th, + _log_eps, _density_th, _n_bins)); +} + +CV_EXPORTS LineSegmentDetector* createLineSegmentDetectorPtr( + int _refine, double _scale, double _sigma_scale, double _quant, double _ang_th, + double _log_eps, double _density_th, int _n_bins) +{ + return new LineSegmentDetectorImpl( + _refine, _scale, _sigma_scale, _quant, _ang_th, + _log_eps, _density_th, _n_bins); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +LineSegmentDetectorImpl::LineSegmentDetectorImpl(int _refine, double _scale, double _sigma_scale, double _quant, double _ang_th, double _log_eps, double _density_th, int _n_bins) :SCALE(_scale), doRefine(_refine), SIGMA_SCALE(_sigma_scale), QUANT(_quant), ANG_TH(_ang_th), LOG_EPS(_log_eps), DENSITY_TH(_density_th), N_BINS(_n_bins) @@ -173,46 +417,35 @@ LSD::LSD(int _refine, double _scale, double _sigma_scale, double _quant, _n_bins > 0); } -void LSD::detect(const cv::InputArray _image, cv::OutputArray _lines, cv::Rect _roi, - cv::OutputArray _width, cv::OutputArray _prec, - cv::OutputArray _nfa) +void LineSegmentDetectorImpl::detect(const InputArray _image, OutputArray _lines, + OutputArray _width, OutputArray _prec, OutputArray _nfa) { Mat_ img = _image.getMat(); CV_Assert(!img.empty() && img.channels() == 1); - // If default, then convert the whole image, else just the specified by roi - roi = _roi; - if (roi.area() == 0) - { - img.convertTo(image, CV_64FC1); - } - else - { - roix = roi.x; - roiy = roi.y; - img(roi).convertTo(image, CV_64FC1); - } + // Convert image to double + img.convertTo(image, CV_64FC1); std::vector lines; - std::vector* w = (_width.needed())?(new std::vector()) : 0; - std::vector* p = (_prec.needed())?(new std::vector()) : 0; - std::vector* n = (_nfa.needed())?(new std::vector()) : 0; + std::vector w, p, n; + w_needed = _width.needed(); + p_needed = _prec.needed(); + n_needed = _nfa.needed(); + + CV_Assert((!_nfa.needed()) || // NFA InputArray will be filled _only_ when + (_nfa.needed() && doRefine >= LSD_REFINE_ADV)); // REFINE_ADV type LineSegmentDetectorImpl object is created. flsd(lines, w, p, n); Mat(lines).copyTo(_lines); - if(w) Mat(*w).copyTo(_width); - if(p) Mat(*p).copyTo(_prec); - if(n) Mat(*n).copyTo(_nfa); - - delete w; - delete p; - delete n; + if(w_needed) Mat(w).copyTo(_width); + if(p_needed) Mat(p).copyTo(_prec); + if(n_needed) Mat(n).copyTo(_nfa); } -void LSD::flsd(std::vector& lines, - std::vector* widths, std::vector* precisions, - std::vector* nfas) +void LineSegmentDetectorImpl::flsd(std::vector& lines, + std::vector& widths, std::vector& precisions, + std::vector& nfas) { // Angle tolerance const double prec = M_PI * ANG_TH / 180; @@ -293,19 +526,12 @@ void LSD::flsd(std::vector& lines, rec.width /= SCALE; } - if(roi.area()) // if a roi has been given by the user, adjust coordinates - { - rec.x1 += roix; - rec.y1 += roiy; - rec.x2 += roix; - rec.y2 += roiy; - } - //Store the relevant data lines.push_back(Vec4i(int(rec.x1), int(rec.y1), int(rec.x2), int(rec.y2))); - if (widths) widths->push_back(rec.width); - if (precisions) precisions->push_back(rec.p); - if (nfas && doRefine >= LSD_REFINE_ADV) nfas->push_back(log_nfa); + if(w_needed) widths.push_back(rec.width); + if(p_needed) precisions.push_back(rec.p); + if(n_needed && doRefine >= LSD_REFINE_ADV) nfas.push_back(log_nfa); + // //Add the linesID to the region on the image // for(unsigned int el = 0; el < reg_size; el++) @@ -316,11 +542,13 @@ void LSD::flsd(std::vector& lines, } } -void LSD::ll_angle(const double& threshold, const unsigned int& n_bins, std::vector& list) +void LineSegmentDetectorImpl::ll_angle(const double& threshold, + const unsigned int& n_bins, + std::vector& list) { //Initialize data - angles = cv::Mat_(scaled_image.size()); - modgrad = cv::Mat_(scaled_image.size()); + angles = Mat_(scaled_image.size()); + modgrad = Mat_(scaled_image.size()); angles_data = angles.ptr(0); modgrad_data = modgrad.ptr(0); @@ -357,7 +585,7 @@ void LSD::ll_angle(const double& threshold, const unsigned int& n_bins, std::vec } else { - angles_data[addr] = cv::fastAtan2(float(gx), float(-gy)) * DEG_TO_RADS; // gradient angle computation + angles_data[addr] = fastAtan2(float(gx), float(-gy)) * DEG_TO_RADS; // gradient angle computation if (norm > max_grad) { max_grad = norm; } } @@ -389,7 +617,7 @@ void LSD::ll_angle(const double& threshold, const unsigned int& n_bins, std::vec range_e[i] = &list[count]; ++count; } - range_e[i]->p = cv::Point(x, y); + range_e[i]->p = Point(x, y); range_e[i]->next = 0; } } @@ -413,8 +641,8 @@ void LSD::ll_angle(const double& threshold, const unsigned int& n_bins, std::vec } } -void LSD::region_grow(const cv::Point2i& s, std::vector& reg, - int& reg_size, double& reg_angle, const double& prec) +void LineSegmentDetectorImpl::region_grow(const Point2i& s, std::vector& reg, + int& reg_size, double& reg_angle, const double& prec) { // Point to this region reg_size = 1; @@ -459,15 +687,15 @@ void LSD::region_grow(const cv::Point2i& s, std::vector& reg, sumdx += cos(float(angle)); sumdy += sin(float(angle)); // reg_angle is used in the isAligned, so it needs to be updates? - reg_angle = cv::fastAtan2(sumdy, sumdx) * DEG_TO_RADS; + reg_angle = fastAtan2(sumdy, sumdx) * DEG_TO_RADS; } } } } } -void LSD::region2rect(const std::vector& reg, const int reg_size, const double reg_angle, - const double prec, const double p, rect& rec) const +void LineSegmentDetectorImpl::region2rect(const std::vector& reg, const int reg_size, + const double reg_angle, const double prec, const double p, rect& rec) const { double x = 0, y = 0, sum = 0; for(int i = 0; i < reg_size; ++i) @@ -524,8 +752,8 @@ void LSD::region2rect(const std::vector& reg, const int reg_size, c if(rec.width < 1.0) rec.width = 1.0; } -double LSD::get_theta(const std::vector& reg, const int& reg_size, const double& x, - const double& y, const double& reg_angle, const double& prec) const +double LineSegmentDetectorImpl::get_theta(const std::vector& reg, const int& reg_size, const double& x, + const double& y, const double& reg_angle, const double& prec) const { double Ixx = 0.0; double Iyy = 0.0; @@ -552,8 +780,8 @@ double LSD::get_theta(const std::vector& reg, const int& reg_size, // Compute angle double theta = (fabs(Ixx)>fabs(Iyy))? - double(cv::fastAtan2(float(lambda - Ixx), float(Ixy))): - double(cv::fastAtan2(float(Ixy), float(lambda - Iyy))); // in degs + double(fastAtan2(float(lambda - Ixx), float(Ixy))): + double(fastAtan2(float(Ixy), float(lambda - Iyy))); // in degs theta *= DEG_TO_RADS; // Correct angle by 180 deg if necessary @@ -562,8 +790,8 @@ double LSD::get_theta(const std::vector& reg, const int& reg_size, return theta; } -bool LSD::refine(std::vector& reg, int& reg_size, double reg_angle, - const double prec, double p, rect& rec, const double& density_th) +bool LineSegmentDetectorImpl::refine(std::vector& reg, int& reg_size, double reg_angle, + const double prec, double p, rect& rec, const double& density_th) { double density = double(reg_size) / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width); @@ -610,7 +838,7 @@ bool LSD::refine(std::vector& reg, int& reg_size, double reg_angle, } } -bool LSD::reduce_region_radius(std::vector& reg, int& reg_size, double reg_angle, +bool LineSegmentDetectorImpl::reduce_region_radius(std::vector& reg, int& reg_size, double reg_angle, const double prec, double p, rect& rec, double density, const double& density_th) { // Compute region's radius @@ -642,13 +870,14 @@ bool LSD::reduce_region_radius(std::vector& reg, int& reg_size, dou region2rect(reg, reg_size ,reg_angle, prec, p, rec); // Re-compute region points density - density = double(reg_size) / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width); + density = double(reg_size) / + (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width); } return true; } -double LSD::rect_improve(rect& rec) const +double LineSegmentDetectorImpl::rect_improve(rect& rec) const { double delta = 0.5; double delta_2 = delta / 2.0; @@ -752,7 +981,7 @@ double LSD::rect_improve(rect& rec) const return log_nfa; } -double LSD::rect_nfa(const rect& rec) const +double LineSegmentDetectorImpl::rect_nfa(const rect& rec) const { int total_pts = 0, alg_pts = 0; double half_width = rec.width / 2.0; @@ -871,7 +1100,7 @@ double LSD::rect_nfa(const rect& rec) const return nfa(total_pts, alg_pts, rec.p); } -double LSD::nfa(const int& n, const int& k, const double& p) const +double LineSegmentDetectorImpl::nfa(const int& n, const int& k, const double& p) const { // Trivial cases if(n == 0 || k == 0) { return -LOG_NT; } @@ -909,7 +1138,7 @@ double LSD::nfa(const int& n, const int& k, const double& p) const return -log10(bin_tail) - LOG_NT; } -inline bool LSD::isAligned(const int& address, const double& theta, const double& prec) const +inline bool LineSegmentDetectorImpl::isAligned(const int& address, const double& theta, const double& prec) const { if(address < 0) { return false; } const double& a = angles_data[address]; @@ -928,18 +1157,18 @@ inline bool LSD::isAligned(const int& address, const double& theta, const double } -void LSD::drawSegments(cv::Mat& image, const std::vector& lines) +void LineSegmentDetectorImpl::drawSegments(InputOutputArray _image, const InputArray lines) { - CV_Assert(!image.empty() && (image.channels() == 1 || image.channels() == 3)); + CV_Assert(!_image.empty() && (_image.channels() == 1 || _image.channels() == 3)); Mat gray; - if (image.channels() == 1) + if (_image.channels() == 1) { - gray = image; + gray = _image.getMatRef(); } - else if (image.channels() == 3) + else if (_image.channels() == 3) { - cv::cvtColor(image, gray, CV_BGR2GRAY); + cvtColor(_image, gray, CV_BGR2GRAY); } // Create a 3 channel image in order to draw colored lines @@ -948,38 +1177,47 @@ void LSD::drawSegments(cv::Mat& image, const std::vector& lines) planes.push_back(gray); planes.push_back(gray); - merge(planes, image); + merge(planes, _image); + + Mat _lines; + _lines = lines.getMat(); // Draw segments - for(unsigned int i = 0; i < lines.size(); ++i) + for(int i = 0; i < _lines.size().width; ++i) { - Point b(lines[i][0], lines[i][1]); - Point e(lines[i][2], lines[i][3]); - line(image, b, e, Scalar(0, 0, 255), 1); + const Vec4i& v = _lines.at(i); + Point b(v[0], v[1]); + Point e(v[2], v[3]); + line(_image.getMatRef(), b, e, Scalar(0, 0, 255), 1); } } -int LSD::compareSegments(const cv::Size& size, const std::vector& lines1, const std::vector lines2, cv::Mat* image) +int LineSegmentDetectorImpl::compareSegments(const Size& size, const InputArray lines1, const InputArray lines2, Mat* _image) { Size sz = size; - if (image && image->size() != size) sz = image->size(); + if (_image && _image->size() != size) sz = _image->size(); CV_Assert(sz.area()); Mat_ I1 = Mat_::zeros(sz); Mat_ I2 = Mat_::zeros(sz); + Mat _lines1; + Mat _lines2; + _lines1 = lines1.getMat(); + _lines2 = lines2.getMat(); // Draw segments - for(unsigned int i = 0; i < lines1.size(); ++i) + std::vector _lines; + for(int i = 0; i < _lines1.size().width; ++i) { - Point b(lines1[i][0], lines1[i][1]); - Point e(lines1[i][2], lines1[i][3]); + Point b(_lines1.at(i)[0], _lines1.at(i)[1]); + Point e(_lines1.at(i)[2], _lines1.at(i)[3]); line(I1, b, e, Scalar::all(255), 1); } - for(unsigned int i = 0; i < lines2.size(); ++i) + for(int i = 0; i < _lines2.size().width; ++i) { - Point b(lines2[i][0], lines2[i][1]); - Point e(lines2[i][2], lines2[i][3]); + Point b(_lines2.at(i)[0], _lines2.at(i)[1]); + Point e(_lines2.at(i)[2], _lines2.at(i)[3]); line(I2, b, e, Scalar::all(255), 1); } @@ -988,14 +1226,14 @@ int LSD::compareSegments(const cv::Size& size, const std::vector& lin bitwise_xor(I1, I2, Ixor); int N = countNonZero(Ixor); - if (image) + if (_image) { Mat Ig; - if (image->channels() == 1) + if (_image->channels() == 1) { - cv::cvtColor(*image, *image, CV_GRAY2BGR); + cvtColor(*_image, *_image, CV_GRAY2BGR); } - CV_Assert(image->isContinuous() && I1.isContinuous() && I2.isContinuous()); + CV_Assert(_image->isContinuous() && I1.isContinuous() && I2.isContinuous()); for (unsigned int i = 0; i < I1.total(); ++i) { @@ -1003,14 +1241,16 @@ int LSD::compareSegments(const cv::Size& size, const std::vector& lin uchar i2 = I2.data[i]; if (i1 || i2) { - image->data[3*i + 1] = 0; - if (i1) image->data[3*i] = 255; - else image->data[3*i] = 0; - if (i2) image->data[3*i + 2] = 255; - else image->data[3*i + 2] = 0; + _image->data[3*i + 1] = 0; + if (i1) _image->data[3*i] = 255; + else _image->data[3*i] = 0; + if (i2) _image->data[3*i + 2] = 255; + else _image->data[3*i + 2] = 0; } } } return N; } + +} // namespace cv diff --git a/modules/imgproc/test/test_lsd.cpp b/modules/imgproc/test/test_lsd.cpp index ea9bf86..e79d86e 100644 --- a/modules/imgproc/test/test_lsd.cpp +++ b/modules/imgproc/test/test_lsd.cpp @@ -23,26 +23,26 @@ protected: virtual void SetUp(); }; -class LSD_ADV: public LSDBase +class Imgproc_LSD_ADV: public LSDBase { public: - LSD_ADV() {}; + Imgproc_LSD_ADV() {}; protected: }; -class LSD_STD: public LSDBase +class Imgproc_LSD_STD: public LSDBase { public: - LSD_STD() {}; + Imgproc_LSD_STD() {}; protected: }; -class LSD_NONE: public LSDBase +class Imgproc_LSD_NONE: public LSDBase { public: - LSD_NONE() {}; + Imgproc_LSD_NONE() {}; protected: }; @@ -92,7 +92,7 @@ void LSDBase::GenerateRotatedRect(Mat& image) rRect.points(vertices); for (int i = 0; i < 4; i++) { - line(image, vertices[i], vertices[(i + 1) % 4], Scalar(255)); + line(image, vertices[i], vertices[(i + 1) % 4], Scalar(255), 3); } } @@ -103,110 +103,113 @@ void LSDBase::SetUp() } -TEST_F(LSD_ADV, whiteNoise) +TEST_F(Imgproc_LSD_ADV, whiteNoise) { GenerateWhiteNoise(test_image); - LSD detector(LSD_REFINE_ADV); - detector.detect(test_image, lines); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_ADV); + detector->detect(test_image, lines); ASSERT_GE((unsigned int)(40), lines.size()); } -TEST_F(LSD_ADV, constColor) +TEST_F(Imgproc_LSD_ADV, constColor) { GenerateConstColor(test_image); - LSD detector(LSD_REFINE_ADV); - detector.detect(test_image, lines); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_ADV); + detector->detect(test_image, lines); ASSERT_EQ((unsigned int)(0), lines.size()); } -TEST_F(LSD_ADV, lines) +TEST_F(Imgproc_LSD_ADV, lines) { const unsigned int numOfLines = 3; GenerateLines(test_image, numOfLines); - LSD detector(LSD_REFINE_ADV); - detector.detect(test_image, lines); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_ADV); + detector->detect(test_image, lines); ASSERT_EQ(numOfLines * 2, lines.size()); // * 2 because of Gibbs effect } -TEST_F(LSD_ADV, rotatedRect) +TEST_F(Imgproc_LSD_ADV, rotatedRect) { GenerateRotatedRect(test_image); - LSD detector(LSD_REFINE_ADV); - detector.detect(test_image, lines); - ASSERT_LE((unsigned int)(4), lines.size()); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_ADV); + detector->detect(test_image, lines); + + ASSERT_LE((unsigned int)(2), lines.size()); } -TEST_F(LSD_STD, whiteNoise) +TEST_F(Imgproc_LSD_STD, whiteNoise) { GenerateWhiteNoise(test_image); - LSD detector(LSD_REFINE_STD); - detector.detect(test_image, lines); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_STD); + detector->detect(test_image, lines); ASSERT_GE((unsigned int)(50), lines.size()); } -TEST_F(LSD_STD, constColor) +TEST_F(Imgproc_LSD_STD, constColor) { GenerateConstColor(test_image); - LSD detector(LSD_REFINE_STD); - detector.detect(test_image, lines); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_STD); + detector->detect(test_image, lines); ASSERT_EQ((unsigned int)(0), lines.size()); } -TEST_F(LSD_STD, lines) +TEST_F(Imgproc_LSD_STD, lines) { const unsigned int numOfLines = 3; //1 GenerateLines(test_image, numOfLines); - LSD detector(LSD_REFINE_STD); - detector.detect(test_image, lines); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_STD); + detector->detect(test_image, lines); ASSERT_EQ(numOfLines * 2, lines.size()); // * 2 because of Gibbs effect } -TEST_F(LSD_STD, rotatedRect) +TEST_F(Imgproc_LSD_STD, rotatedRect) { GenerateRotatedRect(test_image); - LSD detector(LSD_REFINE_STD); - detector.detect(test_image, lines); - ASSERT_EQ((unsigned int)(8), lines.size()); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_STD); + detector->detect(test_image, lines); + + ASSERT_LE((unsigned int)(4), lines.size()); } -TEST_F(LSD_NONE, whiteNoise) +TEST_F(Imgproc_LSD_NONE, whiteNoise) { GenerateWhiteNoise(test_image); - LSD detector(LSD_REFINE_NONE); - detector.detect(test_image, lines); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_STD); + detector->detect(test_image, lines); ASSERT_GE((unsigned int)(50), lines.size()); } -TEST_F(LSD_NONE, constColor) +TEST_F(Imgproc_LSD_NONE, constColor) { GenerateConstColor(test_image); - LSD detector(LSD_REFINE_NONE); - detector.detect(test_image, lines); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_NONE); + detector->detect(test_image, lines); ASSERT_EQ((unsigned int)(0), lines.size()); } -TEST_F(LSD_NONE, lines) +TEST_F(Imgproc_LSD_NONE, lines) { const unsigned int numOfLines = 3; //1 GenerateLines(test_image, numOfLines); - LSD detector(LSD_REFINE_NONE); - detector.detect(test_image, lines); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_NONE); + detector->detect(test_image, lines); ASSERT_EQ(numOfLines * 2, lines.size()); // * 2 because of Gibbs effect } -TEST_F(LSD_NONE, rotatedRect) +TEST_F(Imgproc_LSD_NONE, rotatedRect) { GenerateRotatedRect(test_image); - LSD detector(LSD_REFINE_NONE); - detector.detect(test_image, lines); - ASSERT_EQ((unsigned int)(8), lines.size()); + LineSegmentDetector* detector = createLineSegmentDetectorPtr(LSD_REFINE_NONE); + detector->detect(test_image, lines); + + ASSERT_LE((unsigned int)(8), lines.size()); } diff --git a/samples/cpp/lsd_lines.cpp b/samples/cpp/lsd_lines.cpp index f74c7d9..08807e6 100644 --- a/samples/cpp/lsd_lines.cpp +++ b/samples/cpp/lsd_lines.cpp @@ -22,28 +22,28 @@ int main(int argc, char** argv) Mat image = imread(in, IMREAD_GRAYSCALE); // Create and LSD detector with std refinement. - LSD lsd_std(LSD_REFINE_STD); + LineSegmentDetector* lsd_std = createLineSegmentDetectorPtr(LSD_REFINE_STD); double start = double(getTickCount()); vector lines_std; - lsd_std.detect(image, lines_std); + lsd_std->detect(image, lines_std); double duration_ms = (double(getTickCount()) - start) * 1000 / getTickFrequency(); std::cout << "OpenCV STD (blue) - " << duration_ms << " ms." << std::endl; // Create an LSD detector with no refinement applied. - LSD lsd_none(LSD_REFINE_NONE); + LineSegmentDetector* lsd_none = createLineSegmentDetectorPtr(LSD_REFINE_NONE); start = double(getTickCount()); vector lines_none; - lsd_none.detect(image, lines_none); + lsd_none->detect(image, lines_none); duration_ms = (double(getTickCount()) - start) * 1000 / getTickFrequency(); std::cout << "OpenCV NONE (red)- " << duration_ms << " ms." << std::endl; std::cout << "Overlapping pixels are shown in purple." << std::endl; Mat difference = Mat::zeros(image.size(), CV_8UC1); - LSD::compareSegments(image.size(), lines_std, lines_none, &difference); + lsd_none->compareSegments(image.size(), lines_std, lines_none, &difference); imshow("Line difference", difference); Mat drawnLines(image); - LSD::drawSegments(drawnLines, lines_std); + lsd_none->drawSegments(drawnLines, lines_std); imshow("Standard refinement", drawnLines); waitKey();