博主研究生阶段一直在研究LSD算法,先马出 LSD基于opencv的源代码。
另外链接:http://demo.ipol.im/demo/gjmr_line_segment_detector/
给出了LSD论文的demo和article。
/*M///
//
// 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) 2013, OpenCV Foundation, 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.
//
//M*/
#include "precomp.hpp"
#include <vector>
/
// Default LSD parameters
// SIGMA_SCALE 0.6 - Sigma for Gaussian filter is computed as sigma = sigma_scale/scale.
// QUANT 2.0 - Bound to the quantization error on the gradient norm.
// ANG_TH 22.5 - Gradient angle tolerance in degrees.
// LOG_EPS 0.0 - Detection threshold: -log10(NFA) > log_eps
// DENSITY_TH 0.7 - Minimal density of region points in rectangle.
// N_BINS 1024 - Number of bins in pseudo-ordering of gradient modulus.
#define M_3_2_PI (3 * CV_PI) / 2 // 3/2 pi
#define M_2__PI (2 * CV_PI) // 2 pi
#ifndef M_LN10
#define M_LN10 2.30258509299404568402
#endif
#define NOTDEF double(-1024.0) // Label for pixels with undefined gradient.
#define NOTUSED 0 // Label for pixels not used in yet.
#define USED 1 // Label for pixels already used in detection.
#define RELATIVE_ERROR_FACTOR 100.0
const double DEG_TO_RADS = CV_PI / 180;
#define log_gamma(x) ((x)>15.0?log_gamma_windschitl(x):log_gamma_lanczos(x))
struct edge
{
cv::Point p;
bool taken;
};
/
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)
{
return sqrt(distSq(x1, y1, x2, y2));
}
// Signed angle difference
inline double angle_diff_signed(const double& a, const double& b)
{
double diff = a - b;
while(diff <= -CV_PI) diff += M_2__PI;
while(diff > CV_PI) diff -= M_2__PI;
return diff;
}
// Absolute value angle difference
inline double angle_diff(const double& a, const double& b)
{
return std::fabs(angle_diff_signed(a, b));
}
// Compare doubles by relative error.
inline bool double_equal(const double& a, const double& b)
{
// trivial case
if(a == b) return true;
double abs_diff = fabs(a - b);
double aa = fabs(a);
double bb = fabs(b);
double abs_max = (aa > bb)? aa : bb;
if(abs_max < DBL_MIN) abs_max = DBL_MIN;
return (abs_diff / abs_max) <= (RELATIVE_ERROR_FACTOR * DBL_EPSILON);
}
inline bool AsmallerB_XoverY(const edge& a, const edge& b)
{
if (a.p.x == b.p.x) return a.p.y < b.p.y;
else return a.p.x < b.p.x;
}
/**
* Computes the natural logarithm of the absolute value of
* the gamma function of x using Windschitl method.
* See http://www.rskey.org/gamma.htm
*/
inline double log_gamma_windschitl(const 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 the natural logarithm of the absolute value of
* the gamma function of x using the Lanczos approximation.
* See http://www.rskey.org/gamma.htm
*/
inline double log_gamma_lanczos(const 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;
for(int n = 0; n < 7; ++n)
{
a -= log(x + double(n));
b += q[n] * pow(x, double(n));
}
return a + log(b);
}
///
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.
*
* @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 or Vec4f elements specifying the beginning and ending point of a line.
* Where Vec4i/Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 - end.
* Returned lines are strictly oriented depending on the gradient.
* @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(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, InputArray lines);
/**
* Draw both vectors on the image canvas. Uses blue for lines 1 and red for lines 2.
*
* @param size The size of the image, where lines1 and lines2 were found.
* @param lines1 The first lines that need to be drawn. Color - Blue.