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