parent
b433ac58c5
commit
43f3eb9ffc
14 changed files with 1778 additions and 2151 deletions
@ -0,0 +1,52 @@ |
|||||||
|
.. _LSDDetector: |
||||||
|
|
||||||
|
Line Segments Detector |
||||||
|
====================== |
||||||
|
|
||||||
|
|
||||||
|
Lines extraction methodology |
||||||
|
---------------------------- |
||||||
|
|
||||||
|
The lines extraction methodology described in the following is mainly based on [EDL]_. |
||||||
|
The extraction starts with a Gaussian pyramid generated from an original image, downsampled N-1 times, blurred N times, to obtain N layers (one for each octave), with layer 0 corresponding to input image. Then, from each layer (octave) in the pyramid, lines are extracted using LSD algorithm. |
||||||
|
|
||||||
|
Differently from EDLine lines extractor used in original article, LSD furnishes information only about lines extremes; thus, additional information regarding slope and equation of line are computed via analytic methods. The number of pixels is obtained using `LineIterator <http://docs.opencv.org/modules/core/doc/drawing_functions.html#lineiterator>`_. Extracted lines are returned in the form of KeyLine objects, but since extraction is based on a method different from the one used in `BinaryDescriptor <binary_descriptor.html>`_ class, data associated to a line's extremes in original image and in octave it was extracted from, coincide. KeyLine's field *class_id* is used as an index to indicate the order of extraction of a line inside a single octave. |
||||||
|
|
||||||
|
|
||||||
|
LSDDetector::createLSDDetector |
||||||
|
------------------------------ |
||||||
|
|
||||||
|
Creates ad LSDDetector object, using smart pointers. |
||||||
|
|
||||||
|
.. ocv:function:: Ptr<LSDDetector> LSDDetector::createLSDDetector() |
||||||
|
|
||||||
|
|
||||||
|
LSDDetector::detect |
||||||
|
------------------- |
||||||
|
|
||||||
|
Detect lines inside an image. |
||||||
|
|
||||||
|
.. ocv:function:: void LSDDetector::detect( const Mat& image, std::vector<KeyLine>& keylines, int scale, int numOctaves, const Mat& mask=Mat()) |
||||||
|
|
||||||
|
.. ocv:function:: void LSDDetector::detect( const std::vector<Mat>& images, std::vector<std::vector<KeyLine> >& keylines, int scale, int numOctaves, const std::vector<Mat>& masks=std::vector<Mat>() ) const |
||||||
|
|
||||||
|
:param image: input image |
||||||
|
|
||||||
|
:param images: input images |
||||||
|
|
||||||
|
:param keylines: vector or set of vectors that will store extracted lines for one or more images |
||||||
|
|
||||||
|
:param mask: mask matrix to detect only KeyLines of interest |
||||||
|
|
||||||
|
:param masks: vector of mask matrices to detect only KeyLines of interest from each input image |
||||||
|
|
||||||
|
:param scale: scale factor used in pyramids generation |
||||||
|
|
||||||
|
:param numOctaves: number of octaves inside pyramid |
||||||
|
|
||||||
|
|
||||||
|
References |
||||||
|
---------- |
||||||
|
|
||||||
|
.. [EDL] Von Gioi, R. Grompone, et al. *LSD: A fast line segment detector with a false detection control*, IEEE Transactions on Pattern Analysis and Machine Intelligence 32.4 (2010): 722-732. |
||||||
|
|
After Width: | Height: | Size: 164 KiB |
@ -0,0 +1,215 @@ |
|||||||
|
/*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) 2014, Biagio Montesano, 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:
|
||||||
|
//
|
||||||
|
// * Redistribution's of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// * Redistribution's 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" |
||||||
|
|
||||||
|
using namespace cv; |
||||||
|
|
||||||
|
Ptr<LSDDetector> LSDDetector::createLSDDetector() |
||||||
|
{ |
||||||
|
return Ptr<LSDDetector>( new LSDDetector() ); |
||||||
|
} |
||||||
|
|
||||||
|
/* compute Gaussian pyramid of input image */ |
||||||
|
void LSDDetector::computeGaussianPyramid( const Mat& image, int numOctaves, int scale ) |
||||||
|
{ |
||||||
|
/* clear class fields */ |
||||||
|
gaussianPyrs.clear(); |
||||||
|
|
||||||
|
/* insert input image into pyramid */ |
||||||
|
cv::Mat currentMat = image.clone(); |
||||||
|
cv::GaussianBlur( currentMat, currentMat, cv::Size( 5, 5 ), 1 ); |
||||||
|
gaussianPyrs.push_back( currentMat ); |
||||||
|
|
||||||
|
/* fill Gaussian pyramid */ |
||||||
|
for ( int pyrCounter = 1; pyrCounter < numOctaves; pyrCounter++ ) |
||||||
|
{ |
||||||
|
/* compute and store next image in pyramid and its size */ |
||||||
|
pyrDown( currentMat, currentMat, Size( currentMat.cols / scale, currentMat.rows / scale ) ); |
||||||
|
gaussianPyrs.push_back( currentMat ); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* check lines' extremes */ |
||||||
|
inline void checkLineExtremes( cv::Vec4i& extremes, cv::Size imageSize ) |
||||||
|
{ |
||||||
|
|
||||||
|
if( extremes[0] < 0 ) |
||||||
|
extremes[0] = 0; |
||||||
|
|
||||||
|
if( extremes[0] >= imageSize.width ) |
||||||
|
extremes[0] = imageSize.width - 1; |
||||||
|
|
||||||
|
if( extremes[2] < 0 ) |
||||||
|
extremes[2] = 0; |
||||||
|
|
||||||
|
if( extremes[2] >= imageSize.width ) |
||||||
|
extremes[2] = imageSize.width - 1; |
||||||
|
|
||||||
|
if( extremes[1] < 0 ) |
||||||
|
extremes[1] = 0; |
||||||
|
|
||||||
|
if( extremes[1] >= imageSize.height ) |
||||||
|
extremes[1] = imageSize.height - 1; |
||||||
|
|
||||||
|
if( extremes[3] < 0 ) |
||||||
|
extremes[3] = 0; |
||||||
|
|
||||||
|
if( extremes[3] >= imageSize.height ) |
||||||
|
extremes[3] = imageSize.height - 1; |
||||||
|
} |
||||||
|
|
||||||
|
/* requires line detection (only one image) */ |
||||||
|
void LSDDetector::detect( const Mat& image, CV_OUT std::vector<KeyLine>& keylines, int scale, int numOctaves, const Mat& mask ) |
||||||
|
{ |
||||||
|
if( mask.data != NULL && ( mask.size() != image.size() || mask.type() != CV_8UC1 ) ) |
||||||
|
{ |
||||||
|
std::cout << "Mask error while detecting lines: " << "please check its dimensions and that data type is CV_8UC1" << std::endl; |
||||||
|
CV_Assert( false ); |
||||||
|
} |
||||||
|
|
||||||
|
else |
||||||
|
detectImpl( image, keylines, numOctaves, scale, mask ); |
||||||
|
} |
||||||
|
|
||||||
|
/* requires line detection (more than one image) */ |
||||||
|
void LSDDetector::detect( const std::vector<Mat>& images, std::vector<std::vector<KeyLine> >& keylines, int scale, int numOctaves, |
||||||
|
const std::vector<Mat>& masks ) const |
||||||
|
{ |
||||||
|
/* detect lines from each image */ |
||||||
|
for ( size_t counter = 0; counter < images.size(); counter++ ) |
||||||
|
{ |
||||||
|
if( masks[counter].data != NULL && ( masks[counter].size() != images[counter].size() || masks[counter].type() != CV_8UC1 ) ) |
||||||
|
{ |
||||||
|
std::cout << "Masks error while detecting lines: " << "please check their dimensions and that data types are CV_8UC1" << std::endl; |
||||||
|
CV_Assert( false ); |
||||||
|
} |
||||||
|
|
||||||
|
detectImpl( images[counter], keylines[counter], numOctaves, scale, masks[counter] ); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* implementation of line detection */ |
||||||
|
void LSDDetector::detectImpl( const Mat& imageSrc, std::vector<KeyLine>& keylines, int numOctaves, int scale, const Mat& mask ) const |
||||||
|
{ |
||||||
|
cv::Mat image; |
||||||
|
if( imageSrc.channels() != 1 ) |
||||||
|
cvtColor( imageSrc, image, COLOR_BGR2GRAY ); |
||||||
|
else |
||||||
|
image = imageSrc.clone(); |
||||||
|
|
||||||
|
/*check whether image depth is different from 0 */ |
||||||
|
if( image.depth() != 0 ) |
||||||
|
{ |
||||||
|
std::cout << "Warning, depth image!= 0" << std::endl; |
||||||
|
CV_Assert( false ); |
||||||
|
} |
||||||
|
|
||||||
|
/* create a pointer to self */ |
||||||
|
LSDDetector *lsd = const_cast<LSDDetector*>( this ); |
||||||
|
|
||||||
|
/* compute Gaussian pyramids */ |
||||||
|
lsd->computeGaussianPyramid( image, numOctaves, scale ); |
||||||
|
|
||||||
|
/* create an LSD extractor */ |
||||||
|
cv::Ptr<cv::LineSegmentDetector> ls = cv::createLineSegmentDetector( cv::LSD_REFINE_ADV ); |
||||||
|
|
||||||
|
/* prepare a vector to host extracted segments */ |
||||||
|
std::vector<std::vector<cv::Vec4i> > lines_lsd; |
||||||
|
|
||||||
|
/* extract lines */ |
||||||
|
for ( int i = 0; i < numOctaves; i++ ) |
||||||
|
{ |
||||||
|
std::vector<Vec4i> octave_lines; |
||||||
|
ls->detect( gaussianPyrs[i], octave_lines ); |
||||||
|
lines_lsd.push_back( octave_lines ); |
||||||
|
} |
||||||
|
|
||||||
|
/* create keylines */ |
||||||
|
for ( int j = 0; j < (int) lines_lsd.size(); j++ ) |
||||||
|
{ |
||||||
|
for ( int k = 0; k < (int) lines_lsd[j].size(); k++ ) |
||||||
|
{ |
||||||
|
KeyLine kl; |
||||||
|
cv::Vec4i extremes = lines_lsd[j][k]; |
||||||
|
|
||||||
|
/* check data validity */ |
||||||
|
checkLineExtremes( extremes, gaussianPyrs[j].size() ); |
||||||
|
|
||||||
|
/* fill KeyLine's fields */ |
||||||
|
kl.startPointX = extremes[0]; |
||||||
|
kl.startPointY = extremes[1]; |
||||||
|
kl.endPointX = extremes[2]; |
||||||
|
kl.endPointY = extremes[3]; |
||||||
|
kl.sPointInOctaveX = extremes[0]; |
||||||
|
kl.sPointInOctaveY = extremes[1]; |
||||||
|
kl.ePointInOctaveX = extremes[2]; |
||||||
|
kl.ePointInOctaveY = extremes[3]; |
||||||
|
kl.lineLength = sqrt( pow( extremes[0] - extremes[2], 2 ) + pow( extremes[1] - extremes[3], 2 ) ); |
||||||
|
|
||||||
|
/* compute number of pixels covered by line */ |
||||||
|
LineIterator li( gaussianPyrs[j], Point( extremes[0], extremes[1] ), Point( extremes[2], extremes[3] ) ); |
||||||
|
kl.numOfPixels = li.count; |
||||||
|
|
||||||
|
kl.angle = atan2( ( kl.endPointY - kl.startPointY ), ( kl.endPointX - kl.startPointX ) ); |
||||||
|
kl.class_id = k; |
||||||
|
kl.octave = j; |
||||||
|
kl.size = ( kl.endPointX - kl.startPointX ) * ( kl.endPointY - kl.startPointY ); |
||||||
|
kl.response = kl.lineLength / max( gaussianPyrs[j].cols, gaussianPyrs[j].rows ); |
||||||
|
kl.pt = Point( ( kl.endPointX + kl.startPointX ) / 2, ( kl.endPointY + kl.startPointY ) / 2 ); |
||||||
|
|
||||||
|
keylines.push_back( kl ); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* delete undesired KeyLines, according to input mask */ |
||||||
|
if( !mask.empty() ) |
||||||
|
{ |
||||||
|
for ( size_t keyCounter = 0; keyCounter < keylines.size(); keyCounter++ ) |
||||||
|
{ |
||||||
|
KeyLine kl = keylines[keyCounter]; |
||||||
|
if( mask.at<uchar>( kl.startPointY, kl.startPointX ) == 0 && mask.at<uchar>( kl.endPointY, kl.endPointX ) == 0 ) |
||||||
|
keylines.erase( keylines.begin() + keyCounter ); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue