/*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; namespace cv { namespace line_descriptor { 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 ) ) throw std::runtime_error( "Mask error while detecting lines: please check its dimensions and that data type is CV_8UC1" ); 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 ) ) throw std::runtime_error( "Masks error while detecting lines: please check their dimensions and that data types are CV_8UC1" ); else 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 ) throw std::runtime_error( "Error, depth image!= 0" ); /* 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 */ int class_counter = -1; 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 = (float) extremes[0]; kl.startPointY = (float) extremes[1]; kl.endPointX = (float) extremes[2]; kl.endPointY = (float) extremes[3]; kl.sPointInOctaveX = (float) extremes[0]; kl.sPointInOctaveY = (float) extremes[1]; kl.ePointInOctaveX = (float) extremes[2]; kl.ePointInOctaveY = (float) extremes[3]; kl.lineLength = (float) 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 = ++class_counter; 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 = Point2f( ( 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>( (int) kl.startPointY, (int) kl.startPointX ) == 0 && mask.at<uchar>( (int) kl.endPointY, (int) kl.endPointX ) == 0 ) keylines.erase( keylines.begin() + keyCounter ); } } } } }