vendor: OpenCV 5.0.0 snapshot at 755e50675d97db9b7d449d8bd6b09888646f6c6e
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
set(the_description "Line descriptor")
|
||||
ocv_define_module(line_descriptor opencv_imgproc OPTIONAL opencv_features WRAP python)
|
||||
@@ -0,0 +1,12 @@
|
||||
Binary Descriptors for Line Segments
|
||||
====================================
|
||||
|
||||
This module shows how to extract line segments from an image by 2 different methods: First segmenting lines with Line Segment Detector LSDDetector and then (or just) using the Binary Descriptor to get the lines and give them a descriptor -- BinaryDescriptor. Finally, we can then match line segments using the BinaryDescriptorMatcher class.
|
||||
|
||||
## Two views of a builing
|
||||

|
||||
|
||||
## Line segments detected and matched
|
||||

|
||||
|
||||
* [Image examples from CSDN](https://blog.csdn.net/Small_Munich/article/details/87990946)
|
||||
@@ -0,0 +1,30 @@
|
||||
@article{LBD,
|
||||
title={An efficient and robust line segment matching approach based on LBD descriptor and pairwise geometric consistency},
|
||||
author={Zhang, Lilian and Koch, Reinhard},
|
||||
journal={Journal of Visual Communication and Image Representation},
|
||||
volume={24},
|
||||
number={7},
|
||||
pages={794--805},
|
||||
year={2013},
|
||||
publisher={Elsevier}
|
||||
}
|
||||
|
||||
@article{EDL,
|
||||
title={LSD: A fast line segment detector with a false detection control},
|
||||
author={Von Gioi, R Grompone and Jakubowicz, Jeremie and Morel, Jean-Michel and Randall, Gregory},
|
||||
journal={IEEE Transactions on Pattern Analysis and Machine Intelligence},
|
||||
volume={32},
|
||||
number={4},
|
||||
pages={722--732},
|
||||
year={2010},
|
||||
publisher={Institute of Electrical and Electronics Engineers, Inc., 345 E. 47 th St. NY NY 10017-2394 USA}
|
||||
}
|
||||
|
||||
@inproceedings{MIH,
|
||||
title={Fast search in hamming space with multi-index hashing},
|
||||
author={Norouzi, Mohammad and Punjani, Ali and Fleet, David J},
|
||||
booktitle={Computer Vision and Pattern Recognition (CVPR), 2012 IEEE Conference on},
|
||||
pages={3108--3115},
|
||||
year={2012},
|
||||
organization={IEEE}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 138 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 164 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 451 KiB |
@@ -0,0 +1,119 @@
|
||||
/*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:
|
||||
//
|
||||
// * 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*/
|
||||
|
||||
#ifndef __OPENCV_LINE_DESCRIPTOR_HPP__
|
||||
#define __OPENCV_LINE_DESCRIPTOR_HPP__
|
||||
|
||||
#include "opencv2/line_descriptor/descriptor.hpp"
|
||||
|
||||
/** @defgroup line_descriptor Binary descriptors for lines extracted from an image
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
One of the most challenging activities in computer vision is the extraction of useful information
|
||||
from a given image. Such information, usually comes in the form of points that preserve some kind of
|
||||
property (for instance, they are scale-invariant) and are actually representative of input image.
|
||||
|
||||
The goal of this module is seeking a new kind of representative information inside an image and
|
||||
providing the functionalities for its extraction and representation. In particular, differently from
|
||||
previous methods for detection of relevant elements inside an image, lines are extracted in place of
|
||||
points; a new class is defined ad hoc to summarize a line's properties, for reuse and plotting
|
||||
purposes.
|
||||
|
||||
Computation of binary descriptors
|
||||
---------------------------------
|
||||
|
||||
To obtatin a binary descriptor representing a certain line detected from a certain octave of an
|
||||
image, we first compute a non-binary descriptor as described in @cite LBD . Such algorithm works on
|
||||
lines extracted using EDLine detector, as explained in @cite EDL . Given a line, we consider a
|
||||
rectangular region centered at it and called *line support region (LSR)*. Such region is divided
|
||||
into a set of bands \f$\{B_1, B_2, ..., B_m\}\f$, whose length equals the one of line.
|
||||
|
||||
If we indicate with \f$\bf{d}_L\f$ the direction of line, the orthogonal and clockwise direction to line
|
||||
\f$\bf{d}_{\perp}\f$ can be determined; these two directions, are used to construct a reference frame
|
||||
centered in the middle point of line. The gradients of pixels \f$\bf{g'}\f$ inside LSR can be projected
|
||||
to the newly determined frame, obtaining their local equivalent
|
||||
\f$\bf{g'} = (\bf{g}^T \cdot \bf{d}_{\perp}, \bf{g}^T \cdot \bf{d}_L)^T \triangleq (\bf{g'}_{d_{\perp}}, \bf{g'}_{d_L})^T\f$.
|
||||
|
||||
Later on, a Gaussian function is applied to all LSR's pixels along \f$\bf{d}_\perp\f$ direction; first,
|
||||
we assign a global weighting coefficient \f$f_g(i) = (1/\sqrt{2\pi}\sigma_g)e^{-d^2_i/2\sigma^2_g}\f$ to
|
||||
*i*-th row in LSR, where \f$d_i\f$ is the distance of *i*-th row from the center row in LSR,
|
||||
\f$\sigma_g = 0.5(m \cdot w - 1)\f$ and \f$w\f$ is the width of bands (the same for every band). Secondly,
|
||||
considering a band \f$B_j\f$ and its neighbor bands \f$B_{j-1}, B_{j+1}\f$, we assign a local weighting
|
||||
\f$F_l(k) = (1/\sqrt{2\pi}\sigma_l)e^{-d'^2_k/2\sigma_l^2}\f$, where \f$d'_k\f$ is the distance of *k*-th
|
||||
row from the center row in \f$B_j\f$ and \f$\sigma_l = w\f$. Using the global and local weights, we obtain,
|
||||
at the same time, the reduction of role played by gradients far from line and of boundary effect,
|
||||
respectively.
|
||||
|
||||
Each band \f$B_j\f$ in LSR has an associated *band descriptor(BD)* which is computed considering
|
||||
previous and next band (top and bottom bands are ignored when computing descriptor for first and
|
||||
last band). Once each band has been assignen its BD, the LBD descriptor of line is simply given by
|
||||
|
||||
\f[LBD = (BD_1^T, BD_2^T, ... , BD^T_m)^T.\f]
|
||||
|
||||
To compute a band descriptor \f$B_j\f$, each *k*-th row in it is considered and the gradients in such
|
||||
row are accumulated:
|
||||
|
||||
\f[\begin{matrix} \bf{V1}^k_j = \lambda \sum\limits_{\bf{g}'_{d_\perp}>0}\bf{g}'_{d_\perp}, & \bf{V2}^k_j = \lambda \sum\limits_{\bf{g}'_{d_\perp}<0} -\bf{g}'_{d_\perp}, \\ \bf{V3}^k_j = \lambda \sum\limits_{\bf{g}'_{d_L}>0}\bf{g}'_{d_L}, & \bf{V4}^k_j = \lambda \sum\limits_{\bf{g}'_{d_L}<0} -\bf{g}'_{d_L}\end{matrix}.\f]
|
||||
|
||||
with \f$\lambda = f_g(k)f_l(k)\f$.
|
||||
|
||||
By stacking previous results, we obtain the *band description matrix (BDM)*
|
||||
|
||||
\f[BDM_j = \left(\begin{matrix} \bf{V1}_j^1 & \bf{V1}_j^2 & \ldots & \bf{V1}_j^n \\ \bf{V2}_j^1 & \bf{V2}_j^2 & \ldots & \bf{V2}_j^n \\ \bf{V3}_j^1 & \bf{V3}_j^2 & \ldots & \bf{V3}_j^n \\ \bf{V4}_j^1 & \bf{V4}_j^2 & \ldots & \bf{V4}_j^n \end{matrix} \right) \in \mathbb{R}^{4\times n},\f]
|
||||
|
||||
with \f$n\f$ the number of rows in band \f$B_j\f$:
|
||||
|
||||
\f[n = \begin{cases} 2w, & j = 1||m; \\ 3w, & \mbox{else}. \end{cases}\f]
|
||||
|
||||
Each \f$BD_j\f$ can be obtained using the standard deviation vector \f$S_j\f$ and mean vector \f$M_j\f$ of
|
||||
\f$BDM_J\f$. Thus, finally:
|
||||
|
||||
\f[LBD = (M_1^T, S_1^T, M_2^T, S_2^T, \ldots, M_m^T, S_m^T)^T \in \mathbb{R}^{8m}\f]
|
||||
|
||||
Once the LBD has been obtained, it must be converted into a binary form. For such purpose, we
|
||||
consider 32 possible pairs of BD inside it; each couple of BD is compared bit by bit and comparison
|
||||
generates an 8 bit string. Concatenating 32 comparison strings, we get the 256-bit final binary
|
||||
representation of a single LBD.
|
||||
*/
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
#include "opencv2/line_descriptor.hpp"
|
||||
|
||||
template<> struct pyopencvVecConverter<line_descriptor::KeyLine>
|
||||
{
|
||||
static bool to(PyObject* obj, std::vector<line_descriptor::KeyLine>& value, const ArgInfo& info)
|
||||
{
|
||||
return pyopencv_to_generic_vec(obj, value, info);
|
||||
}
|
||||
|
||||
static PyObject* from(const std::vector<line_descriptor::KeyLine>& value)
|
||||
{
|
||||
return pyopencv_from_generic_vec(value);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<line_descriptor::KeyLine> vector_KeyLine;
|
||||
typedef std::vector<std::vector<line_descriptor::KeyLine> > vector_vector_KeyLine;
|
||||
@@ -0,0 +1,74 @@
|
||||
/*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 "perf_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef perf::TestBaseWithParam<std::string> file_str;
|
||||
|
||||
#define IMAGES \
|
||||
"cv/line_descriptor/cameraman.jpg", "cv/shared/lena.png"
|
||||
|
||||
PERF_TEST_P(file_str, descriptors, testing::Values(IMAGES))
|
||||
{
|
||||
std::string filename = getDataPath( GetParam() );
|
||||
|
||||
Mat frame = imread( filename, 1 );
|
||||
|
||||
if( frame.empty() )
|
||||
FAIL()<< "Unable to load source image " << filename;
|
||||
|
||||
Mat descriptors;
|
||||
std::vector<KeyLine> keylines;
|
||||
Ptr<BinaryDescriptor> bd = BinaryDescriptor::createBinaryDescriptor();
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
bd->detect( frame, keylines );
|
||||
bd->compute( frame, keylines, descriptors );
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,135 @@
|
||||
/*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 "perf_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
typedef perf::TestBaseWithParam<std::string> file_str;
|
||||
|
||||
#define IMAGES \
|
||||
"cv/line_descriptor/cameraman.jpg", "cv/shared/lena.png"
|
||||
|
||||
void createMatFromVec( const std::vector<KeyLine>& linesVec, Mat& output );
|
||||
|
||||
void createMatFromVec( const std::vector<KeyLine>& linesVec, Mat& output )
|
||||
{
|
||||
output = Mat( (int) linesVec.size(), 17, CV_32FC1 );
|
||||
|
||||
for ( int i = 0; i < (int) linesVec.size(); i++ )
|
||||
{
|
||||
std::vector<float> klData;
|
||||
KeyLine kl = linesVec[i];
|
||||
klData.push_back( kl.angle );
|
||||
klData.push_back( (float) kl.class_id );
|
||||
klData.push_back( kl.ePointInOctaveX );
|
||||
klData.push_back( kl.ePointInOctaveY );
|
||||
klData.push_back( kl.endPointX );
|
||||
klData.push_back( kl.endPointY );
|
||||
klData.push_back( kl.lineLength );
|
||||
klData.push_back( (float) kl.numOfPixels );
|
||||
klData.push_back( (float) kl.octave );
|
||||
klData.push_back( kl.pt.x );
|
||||
klData.push_back( kl.pt.y );
|
||||
klData.push_back( kl.response );
|
||||
klData.push_back( kl.sPointInOctaveX );
|
||||
klData.push_back( kl.sPointInOctaveY );
|
||||
klData.push_back( kl.size );
|
||||
klData.push_back( kl.startPointX );
|
||||
klData.push_back( kl.startPointY );
|
||||
|
||||
float* pointerToRow = output.ptr<float>( i );
|
||||
for ( int j = 0; j < 17; j++ )
|
||||
{
|
||||
*pointerToRow = klData[j];
|
||||
pointerToRow++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PERF_TEST_P(file_str, detect, testing::Values(IMAGES))
|
||||
{
|
||||
std::string filename = getDataPath( GetParam() );
|
||||
|
||||
Mat frame = imread( filename, 1 );
|
||||
|
||||
if( frame.empty() )
|
||||
FAIL()<< "Unable to load source image " << filename;
|
||||
|
||||
Mat lines;
|
||||
std::vector<KeyLine> keylines;
|
||||
Ptr<BinaryDescriptor> bd = BinaryDescriptor::createBinaryDescriptor();
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
bd->detect( frame, keylines );
|
||||
createMatFromVec( keylines, lines );
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
|
||||
}
|
||||
|
||||
PERF_TEST_P(file_str, detect_lsd, testing::Values(IMAGES))
|
||||
{
|
||||
std::string filename = getDataPath( GetParam() );
|
||||
std::cout << filename.c_str() << std::endl;
|
||||
|
||||
Mat frame = imread( filename, 1 );
|
||||
|
||||
if( frame.empty() )
|
||||
FAIL()<< "Unable to load source image " << filename;
|
||||
|
||||
Mat lines;
|
||||
std::vector<KeyLine> keylines;
|
||||
Ptr<LSDDetector> lsd = LSDDetector::createLSDDetector();
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
lsd->detect( frame, keylines, 2, 1 );
|
||||
createMatFromVec( keylines, lines );
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,45 @@
|
||||
/*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 "perf_precomp.hpp"
|
||||
|
||||
CV_PERF_TEST_MAIN( line_descriptor )
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*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 "perf_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
#define QUERY_DES_COUNT 300
|
||||
#define DIM 32
|
||||
#define COUNT_FACTOR 4
|
||||
#define RADIUS 3
|
||||
|
||||
void generateData( Mat& query, Mat& train );
|
||||
uchar invertSingleBits( uchar dividend_char, int numBits );
|
||||
|
||||
/* invert numBits bits in input char */
|
||||
uchar invertSingleBits( uchar dividend_char, int numBits )
|
||||
{
|
||||
std::vector<int> bin_vector;
|
||||
long dividend;
|
||||
long bin_num;
|
||||
|
||||
/* convert input char to a long */
|
||||
dividend = (long) dividend_char;
|
||||
|
||||
/*if a 0 has been obtained, just generate a 8-bit long vector of zeros */
|
||||
if( dividend == 0 )
|
||||
bin_vector = std::vector<int>( 8, 0 );
|
||||
|
||||
/* else, apply classic decimal to binary conversion */
|
||||
else
|
||||
{
|
||||
while ( dividend >= 1 )
|
||||
{
|
||||
bin_num = dividend % 2;
|
||||
dividend /= 2;
|
||||
bin_vector.push_back( bin_num );
|
||||
}
|
||||
}
|
||||
|
||||
/* ensure that binary vector always has length 8 */
|
||||
if( bin_vector.size() < 8 )
|
||||
{
|
||||
std::vector<int> zeros( 8 - bin_vector.size(), 0 );
|
||||
bin_vector.insert( bin_vector.end(), zeros.begin(), zeros.end() );
|
||||
}
|
||||
|
||||
/* invert numBits bits */
|
||||
for ( int index = 0; index < numBits; index++ )
|
||||
{
|
||||
if( bin_vector[index] == 0 )
|
||||
bin_vector[index] = 1;
|
||||
|
||||
else
|
||||
bin_vector[index] = 0;
|
||||
}
|
||||
|
||||
/* reconvert to decimal */
|
||||
uchar result = 0;
|
||||
for ( int i = (int) bin_vector.size() - 1; i >= 0; i-- )
|
||||
result += (uchar) ( bin_vector[i] * ( 1 << i ) );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void generateData( Mat& query, Mat& train )
|
||||
{
|
||||
RNG& rng = theRNG();
|
||||
|
||||
Mat buf( QUERY_DES_COUNT, DIM, CV_8UC1 );
|
||||
rng.fill( buf, RNG::UNIFORM, Scalar( 0 ), Scalar( 255 ) );
|
||||
buf.convertTo( query, CV_8UC1 );
|
||||
|
||||
for ( int i = 0; i < query.rows; i++ )
|
||||
{
|
||||
for ( int j = 0; j < COUNT_FACTOR; j++ )
|
||||
{
|
||||
train.push_back( query.row( i ) );
|
||||
int randCol = rand() % 32;
|
||||
uchar u = query.at<uchar>( i, randCol );
|
||||
uchar modified_u = invertSingleBits( u, j + 1 );
|
||||
train.at<uchar>( i * COUNT_FACTOR + j, randCol ) = modified_u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PERF_TEST(matching, single_match)
|
||||
{
|
||||
Mat query, train;
|
||||
std::vector<DMatch> dm;
|
||||
Ptr<BinaryDescriptorMatcher> bd = BinaryDescriptorMatcher::createBinaryDescriptorMatcher();
|
||||
|
||||
generateData( query, train );
|
||||
|
||||
TEST_CYCLE()
|
||||
bd->match( query, train, dm );
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
|
||||
}
|
||||
|
||||
PERF_TEST(knn_matching, knn_match_distances_test)
|
||||
{
|
||||
Mat query, train, distances;
|
||||
std::vector<std::vector<DMatch> > dm;
|
||||
Ptr<BinaryDescriptorMatcher> bd = BinaryDescriptorMatcher::createBinaryDescriptorMatcher();
|
||||
|
||||
generateData( query, train );
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
bd->knnMatch( query, train, dm, QUERY_DES_COUNT );
|
||||
for ( int i = 0; i < (int) dm.size(); i++ )
|
||||
{
|
||||
for ( int j = 0; j < (int) dm[i].size(); j++ )
|
||||
distances.push_back( dm[i][j].distance );
|
||||
}
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
PERF_TEST(radius_match, radius_match_distances_test)
|
||||
{
|
||||
Mat query, train, distances;
|
||||
std::vector<std::vector<DMatch> > dm;
|
||||
Ptr<BinaryDescriptorMatcher> bd = BinaryDescriptorMatcher::createBinaryDescriptorMatcher();
|
||||
|
||||
generateData( query, train );
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
bd->radiusMatch( query, train, dm, RADIUS );
|
||||
for ( int i = 0; i < (int) dm.size(); i++ )
|
||||
{
|
||||
for ( int j = 0; j < (int) dm[i].size(); j++ )
|
||||
distances.push_back( dm[i][j].distance );
|
||||
}
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,52 @@
|
||||
/*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*/
|
||||
#ifndef __OPENCV_PERF_PRECOMP_HPP__
|
||||
#define __OPENCV_PERF_PRECOMP_HPP__
|
||||
|
||||
#include "opencv2/ts.hpp"
|
||||
#include "opencv2/highgui.hpp"
|
||||
#include "opencv2/line_descriptor.hpp"
|
||||
|
||||
namespace opencv_test {
|
||||
using namespace cv::line_descriptor;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/*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 <iostream>
|
||||
#include <opencv2/opencv_modules.hpp>
|
||||
|
||||
#ifdef HAVE_OPENCV_FEATURES
|
||||
|
||||
#include <opencv2/line_descriptor.hpp>
|
||||
#include <opencv2/core/utility.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/features.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::line_descriptor;
|
||||
|
||||
|
||||
static const char* keys =
|
||||
{ "{@image_path | | Image path }" };
|
||||
|
||||
static void help()
|
||||
{
|
||||
std::cout << "\nThis example shows the functionalities of lines extraction " << "and descriptors computation furnished by BinaryDescriptor class\n"
|
||||
<< "Please, run this sample using a command in the form\n" << "./example_line_descriptor_compute_descriptors <path_to_input_image>"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
/* get parameters from command line */
|
||||
CommandLineParser parser( argc, argv, keys );
|
||||
String image_path = parser.get<String>( 0 );
|
||||
|
||||
if( image_path.empty() )
|
||||
{
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* load image */
|
||||
cv::Mat imageMat = imread( image_path, 1 );
|
||||
if( imageMat.data == NULL )
|
||||
{
|
||||
std::cout << "Error, image could not be loaded. Please, check its path" << std::endl;
|
||||
}
|
||||
|
||||
/* create a binary mask */
|
||||
cv::Mat mask = Mat::ones( imageMat.size(), CV_8UC1 );
|
||||
|
||||
/* create a pointer to a BinaryDescriptor object with default parameters */
|
||||
Ptr<BinaryDescriptor> bd = BinaryDescriptor::createBinaryDescriptor();
|
||||
|
||||
/* compute lines */
|
||||
std::vector<KeyLine> keylines;
|
||||
bd->detect( imageMat, keylines, mask );
|
||||
|
||||
/* compute descriptors */
|
||||
cv::Mat descriptors;
|
||||
|
||||
bd->compute( imageMat, keylines, descriptors);
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cerr << "OpenCV was built without features module" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // HAVE_OPENCV_FEATURES
|
||||
@@ -0,0 +1,208 @@
|
||||
/*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 <iostream>
|
||||
#include <opencv2/opencv_modules.hpp>
|
||||
|
||||
#ifdef HAVE_OPENCV_FEATURES
|
||||
|
||||
#include <opencv2/line_descriptor.hpp>
|
||||
#include <opencv2/core/utility.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/features.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <time.h>
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::line_descriptor;
|
||||
|
||||
static const char* keys =
|
||||
{ "{@image_path1 | | Image path 1 }"
|
||||
"{@image_path2 | | Image path 2 }" };
|
||||
|
||||
static void help()
|
||||
{
|
||||
std::cout << "\nThis example shows the functionalities of descriptors matching\n" << "Please, run this sample using a command in the form\n"
|
||||
<< "./example_line_descriptor_matching <path_to_input_image 1>" << "<path_to_input_image 2>" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
uchar invertSingleBits( uchar dividend_char, int numBits );
|
||||
|
||||
/* invert numBits bits in input char */
|
||||
uchar invertSingleBits( uchar dividend_char, int numBits )
|
||||
{
|
||||
std::vector<int> bin_vector;
|
||||
long dividend;
|
||||
long bin_num;
|
||||
|
||||
/* convert input char to a long */
|
||||
dividend = (long) dividend_char;
|
||||
|
||||
/*if a 0 has been obtained, just generate a 8-bit long vector of zeros */
|
||||
if( dividend == 0 )
|
||||
bin_vector = std::vector<int>( 8, 0 );
|
||||
|
||||
/* else, apply classic decimal to binary conversion */
|
||||
else
|
||||
{
|
||||
while ( dividend >= 1 )
|
||||
{
|
||||
bin_num = dividend % 2;
|
||||
dividend /= 2;
|
||||
bin_vector.push_back( bin_num );
|
||||
}
|
||||
}
|
||||
|
||||
/* ensure that binary vector always has length 8 */
|
||||
if( bin_vector.size() < 8 )
|
||||
{
|
||||
std::vector<int> zeros( 8 - bin_vector.size(), 0 );
|
||||
bin_vector.insert( bin_vector.end(), zeros.begin(), zeros.end() );
|
||||
}
|
||||
|
||||
/* invert numBits bits */
|
||||
for ( int index = 0; index < numBits; index++ )
|
||||
{
|
||||
if( bin_vector[index] == 0 )
|
||||
bin_vector[index] = 1;
|
||||
|
||||
else
|
||||
bin_vector[index] = 0;
|
||||
}
|
||||
|
||||
/* reconvert to decimal */
|
||||
uchar result = 0;
|
||||
for ( int i = (int) bin_vector.size() - 1; i >= 0; i-- )
|
||||
result += (uchar) ( bin_vector[i] * (1 << i) );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
/* get parameters from comand line */
|
||||
CommandLineParser parser( argc, argv, keys );
|
||||
String image_path1 = parser.get<String>( 0 );
|
||||
String image_path2 = parser.get<String>( 1 );
|
||||
|
||||
if( image_path1.empty() || image_path2.empty() )
|
||||
{
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* load image */
|
||||
cv::Mat imageMat1 = imread( image_path1, 1 );
|
||||
cv::Mat imageMat2 = imread( image_path2, 1 );
|
||||
|
||||
if( imageMat1.data == NULL || imageMat2.data == NULL )
|
||||
{
|
||||
std::cout << "Error, images could not be loaded. Please, check their paths" << std::endl;
|
||||
}
|
||||
|
||||
/* create binary masks */
|
||||
cv::Mat mask1 = Mat::ones( imageMat1.size(), CV_8UC1 );
|
||||
cv::Mat mask2 = Mat::ones( imageMat2.size(), CV_8UC1 );
|
||||
|
||||
/* create a pointer to a BinaryDescriptor object with default parameters */
|
||||
Ptr<BinaryDescriptor> bd = BinaryDescriptor::createBinaryDescriptor();
|
||||
|
||||
/* compute lines */
|
||||
std::vector<KeyLine> keylines1, keylines2;
|
||||
bd->detect( imageMat1, keylines1, mask1 );
|
||||
bd->detect( imageMat2, keylines2, mask2 );
|
||||
|
||||
/* compute descriptors */
|
||||
cv::Mat descr1, descr2;
|
||||
bd->compute( imageMat1, keylines1, descr1 );
|
||||
bd->compute( imageMat2, keylines2, descr2 );
|
||||
|
||||
/* create a BinaryDescriptorMatcher object */
|
||||
Ptr<BinaryDescriptorMatcher> bdm = BinaryDescriptorMatcher::createBinaryDescriptorMatcher();
|
||||
|
||||
/* make a copy of descr2 mat */
|
||||
Mat descr2Copy = descr1.clone();
|
||||
|
||||
/* randomly change some bits in original descriptors */
|
||||
srand( (unsigned int) time( NULL ) );
|
||||
|
||||
for ( int j = 0; j < descr1.rows; j++ )
|
||||
{
|
||||
/* select a random column */
|
||||
int randCol = rand() % 32;
|
||||
|
||||
/* get correspondent data */
|
||||
uchar u = descr1.at<uchar>( j, randCol );
|
||||
|
||||
/* change bits */
|
||||
for ( int k = 1; k <= 5; k++ )
|
||||
{
|
||||
/* copy current row to train matrix */
|
||||
descr2Copy.push_back( descr1.row( j ) );
|
||||
|
||||
/* invert k bits */
|
||||
uchar uc = invertSingleBits( u, k );
|
||||
|
||||
/* update current row in train matrix */
|
||||
descr2Copy.at<uchar>( descr2Copy.rows - 1, randCol ) = uc;
|
||||
}
|
||||
}
|
||||
|
||||
/* prepare a structure to host matches */
|
||||
std::vector<std::vector<DMatch> > matches;
|
||||
|
||||
/* require knn match */
|
||||
bdm->knnMatch( descr1, descr2, matches, 6 );
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cerr << "OpenCV was built without features module" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // HAVE_OPENCV_FEATURES
|
||||
@@ -0,0 +1,135 @@
|
||||
/*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 <iostream>
|
||||
#include <opencv2/opencv_modules.hpp>
|
||||
|
||||
#ifdef HAVE_OPENCV_FEATURES
|
||||
|
||||
#include <opencv2/line_descriptor.hpp>
|
||||
#include <opencv2/core/utility.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/features.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::line_descriptor;
|
||||
using namespace std;
|
||||
|
||||
static const char* keys =
|
||||
{ "{@image_path | | Image path }" };
|
||||
|
||||
static void help()
|
||||
{
|
||||
cout << "\nThis example shows the functionalities of lines extraction " << "furnished by BinaryDescriptor class\n"
|
||||
<< "Please, run this sample using a command in the form\n" << "./example_line_descriptor_lines_extraction <path_to_input_image>" << endl;
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
/* get parameters from comand line */
|
||||
CommandLineParser parser( argc, argv, keys );
|
||||
String image_path = parser.get<String>( 0 );
|
||||
|
||||
if( image_path.empty() )
|
||||
{
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* load image */
|
||||
cv::Mat imageMat = imread( image_path, 1 );
|
||||
if( imageMat.data == NULL )
|
||||
{
|
||||
std::cout << "Error, image could not be loaded. Please, check its path" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create a random binary mask */
|
||||
cv::Mat mask = Mat::ones( imageMat.size(), CV_8UC1 );
|
||||
|
||||
/* create a pointer to a BinaryDescriptor object with deafult parameters */
|
||||
Ptr<BinaryDescriptor> bd = BinaryDescriptor::createBinaryDescriptor();
|
||||
|
||||
/* create a structure to store extracted lines */
|
||||
vector<KeyLine> lines;
|
||||
|
||||
/* extract lines */
|
||||
cv::Mat output = imageMat.clone();
|
||||
bd->detect( imageMat, lines, mask );
|
||||
|
||||
/* draw lines extracted from octave 0 */
|
||||
if( output.channels() == 1 )
|
||||
cvtColor( output, output, COLOR_GRAY2BGR );
|
||||
for ( size_t i = 0; i < lines.size(); i++ )
|
||||
{
|
||||
KeyLine kl = lines[i];
|
||||
if( kl.octave == 0)
|
||||
{
|
||||
/* get a random color */
|
||||
int R = ( rand() % (int) ( 255 + 1 ) );
|
||||
int G = ( rand() % (int) ( 255 + 1 ) );
|
||||
int B = ( rand() % (int) ( 255 + 1 ) );
|
||||
|
||||
/* get extremes of line */
|
||||
Point pt1 = Point2f( kl.startPointX, kl.startPointY );
|
||||
Point pt2 = Point2f( kl.endPointX, kl.endPointY );
|
||||
|
||||
/* draw line */
|
||||
line( output, pt1, pt2, Scalar( B, G, R ), 3 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* show lines on image */
|
||||
imshow( "Lines", output );
|
||||
waitKey();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cerr << "OpenCV was built without features module" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // HAVE_OPENCV_FEATURES
|
||||
@@ -0,0 +1,135 @@
|
||||
/*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 <iostream>
|
||||
#include <opencv2/opencv_modules.hpp>
|
||||
|
||||
#ifdef HAVE_OPENCV_FEATURES
|
||||
|
||||
#include <opencv2/line_descriptor.hpp>
|
||||
#include <opencv2/core/utility.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/features.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::line_descriptor;
|
||||
using namespace std;
|
||||
|
||||
static const char* keys =
|
||||
{ "{@image_path | | Image path }" };
|
||||
|
||||
static void help()
|
||||
{
|
||||
cout << "\nThis example shows the functionalities of lines extraction " << "furnished by BinaryDescriptor class\n"
|
||||
<< "Please, run this sample using a command in the form\n" << "./example_line_descriptor_lines_extraction <path_to_input_image>" << endl;
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
/* get parameters from comand line */
|
||||
CommandLineParser parser( argc, argv, keys );
|
||||
String image_path = parser.get<String>( 0 );
|
||||
|
||||
if( image_path.empty() )
|
||||
{
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* load image */
|
||||
cv::Mat imageMat = imread( image_path, 1 );
|
||||
if( imageMat.data == NULL )
|
||||
{
|
||||
std::cout << "Error, image could not be loaded. Please, check its path" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create a random binary mask */
|
||||
cv::Mat mask = Mat::ones( imageMat.size(), CV_8UC1 );
|
||||
|
||||
/* create a pointer to a BinaryDescriptor object with deafult parameters */
|
||||
Ptr<LSDDetector> bd = LSDDetector::createLSDDetector();
|
||||
|
||||
/* create a structure to store extracted lines */
|
||||
vector<KeyLine> lines;
|
||||
|
||||
/* extract lines */
|
||||
cv::Mat output = imageMat.clone();
|
||||
bd->detect( imageMat, lines, 2, 1, mask );
|
||||
|
||||
/* draw lines extracted from octave 0 */
|
||||
if( output.channels() == 1 )
|
||||
cvtColor( output, output, COLOR_GRAY2BGR );
|
||||
for ( size_t i = 0; i < lines.size(); i++ )
|
||||
{
|
||||
KeyLine kl = lines[i];
|
||||
if( kl.octave == 0)
|
||||
{
|
||||
/* get a random color */
|
||||
int R = ( rand() % (int) ( 255 + 1 ) );
|
||||
int G = ( rand() % (int) ( 255 + 1 ) );
|
||||
int B = ( rand() % (int) ( 255 + 1 ) );
|
||||
|
||||
/* get extremes of line */
|
||||
Point pt1 = Point2f( kl.startPointX, kl.startPointY );
|
||||
Point pt2 = Point2f( kl.endPointX, kl.endPointY );
|
||||
|
||||
/* draw line */
|
||||
line( output, pt1, pt2, Scalar( B, G, R ), 3 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* show lines on image */
|
||||
imshow( "LSD lines", output );
|
||||
waitKey();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cerr << "OpenCV was built without features module" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // HAVE_OPENCV_FEATURES
|
||||
@@ -0,0 +1,220 @@
|
||||
/*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 <iostream>
|
||||
#include <opencv2/opencv_modules.hpp>
|
||||
|
||||
#ifdef HAVE_OPENCV_FEATURES
|
||||
|
||||
#include <opencv2/line_descriptor.hpp>
|
||||
#include <opencv2/core/utility.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/features.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
#define MATCHES_DIST_THRESHOLD 25
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::line_descriptor;
|
||||
|
||||
static const char* keys =
|
||||
{ "{@image_path1 | | Image path 1 }"
|
||||
"{@image_path2 | | Image path 2 }" };
|
||||
|
||||
static void help()
|
||||
{
|
||||
std::cout << "\nThis example shows the functionalities of lines extraction " << "and descriptors computation furnished by BinaryDescriptor class\n"
|
||||
<< "Please, run this sample using a command in the form\n" << "./example_line_descriptor_compute_descriptors <path_to_input_image 1>"
|
||||
<< "<path_to_input_image 2>" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
/* get parameters from command line */
|
||||
CommandLineParser parser( argc, argv, keys );
|
||||
String image_path1 = parser.get<String>( 0 );
|
||||
String image_path2 = parser.get<String>( 1 );
|
||||
|
||||
if( image_path1.empty() || image_path2.empty() )
|
||||
{
|
||||
help();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* load image */
|
||||
cv::Mat imageMat1 = imread( image_path1, 1 );
|
||||
cv::Mat imageMat2 = imread( image_path2, 1 );
|
||||
|
||||
if( imageMat1.data == NULL || imageMat2.data == NULL )
|
||||
{
|
||||
std::cout << "Error, images could not be loaded. Please, check their path" << std::endl;
|
||||
}
|
||||
|
||||
/* create binary masks */
|
||||
cv::Mat mask1 = Mat::ones( imageMat1.size(), CV_8UC1 );
|
||||
cv::Mat mask2 = Mat::ones( imageMat2.size(), CV_8UC1 );
|
||||
|
||||
/* create a pointer to a BinaryDescriptor object with default parameters */
|
||||
Ptr<BinaryDescriptor> bd = BinaryDescriptor::createBinaryDescriptor( );
|
||||
|
||||
/* compute lines and descriptors */
|
||||
std::vector<KeyLine> keylines1, keylines2;
|
||||
cv::Mat descr1, descr2;
|
||||
|
||||
( *bd )( imageMat1, mask1, keylines1, descr1, false, false );
|
||||
( *bd )( imageMat2, mask2, keylines2, descr2, false, false );
|
||||
|
||||
/* select keylines from first octave and their descriptors */
|
||||
std::vector<KeyLine> lbd_octave1, lbd_octave2;
|
||||
Mat left_lbd, right_lbd;
|
||||
for ( int i = 0; i < (int) keylines1.size(); i++ )
|
||||
{
|
||||
if( keylines1[i].octave == 0 )
|
||||
{
|
||||
lbd_octave1.push_back( keylines1[i] );
|
||||
left_lbd.push_back( descr1.row( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
for ( int j = 0; j < (int) keylines2.size(); j++ )
|
||||
{
|
||||
if( keylines2[j].octave == 0 )
|
||||
{
|
||||
lbd_octave2.push_back( keylines2[j] );
|
||||
right_lbd.push_back( descr2.row( j ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* create a BinaryDescriptorMatcher object */
|
||||
Ptr<BinaryDescriptorMatcher> bdm = BinaryDescriptorMatcher::createBinaryDescriptorMatcher();
|
||||
|
||||
/* require match */
|
||||
std::vector<DMatch> matches;
|
||||
bdm->match( left_lbd, right_lbd, matches );
|
||||
|
||||
/* select best matches */
|
||||
std::vector<DMatch> good_matches;
|
||||
for ( int i = 0; i < (int) matches.size(); i++ )
|
||||
{
|
||||
if( matches[i].distance < MATCHES_DIST_THRESHOLD )
|
||||
good_matches.push_back( matches[i] );
|
||||
}
|
||||
|
||||
/* plot matches */
|
||||
cv::Mat outImg;
|
||||
cv::Mat scaled1, scaled2;
|
||||
std::vector<char> mask( matches.size(), 1 );
|
||||
drawLineMatches( imageMat1, lbd_octave1, imageMat2, lbd_octave2, good_matches, outImg, Scalar::all( -1 ), Scalar::all( -1 ), mask,
|
||||
DrawLinesMatchesFlags::DEFAULT );
|
||||
|
||||
imshow( "Matches", outImg );
|
||||
waitKey();
|
||||
imwrite("/home/ubisum/Desktop/images/env_match/matches.jpg", outImg);
|
||||
/* create an LSD detector */
|
||||
Ptr<LSDDetector> lsd = LSDDetector::createLSDDetector();
|
||||
|
||||
/* detect lines */
|
||||
std::vector<KeyLine> klsd1, klsd2;
|
||||
Mat lsd_descr1, lsd_descr2;
|
||||
lsd->detect( imageMat1, klsd1, 2, 2, mask1 );
|
||||
lsd->detect( imageMat2, klsd2, 2, 2, mask2 );
|
||||
|
||||
/* compute descriptors for lines from first octave */
|
||||
bd->compute( imageMat1, klsd1, lsd_descr1 );
|
||||
bd->compute( imageMat2, klsd2, lsd_descr2 );
|
||||
|
||||
/* select lines and descriptors from first octave */
|
||||
std::vector<KeyLine> octave0_1, octave0_2;
|
||||
Mat leftDEscr, rightDescr;
|
||||
for ( int i = 0; i < (int) klsd1.size(); i++ )
|
||||
{
|
||||
if( klsd1[i].octave == 1 )
|
||||
{
|
||||
octave0_1.push_back( klsd1[i] );
|
||||
leftDEscr.push_back( lsd_descr1.row( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
for ( int j = 0; j < (int) klsd2.size(); j++ )
|
||||
{
|
||||
if( klsd2[j].octave == 1 )
|
||||
{
|
||||
octave0_2.push_back( klsd2[j] );
|
||||
rightDescr.push_back( lsd_descr2.row( j ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* compute matches */
|
||||
std::vector<DMatch> lsd_matches;
|
||||
bdm->match( leftDEscr, rightDescr, lsd_matches );
|
||||
|
||||
/* select best matches */
|
||||
good_matches.clear();
|
||||
for ( int i = 0; i < (int) lsd_matches.size(); i++ )
|
||||
{
|
||||
if( lsd_matches[i].distance < MATCHES_DIST_THRESHOLD )
|
||||
good_matches.push_back( lsd_matches[i] );
|
||||
}
|
||||
|
||||
/* plot matches */
|
||||
cv::Mat lsd_outImg;
|
||||
resize( imageMat1, imageMat1, Size( imageMat1.cols / 2, imageMat1.rows / 2 ), 0, 0, INTER_LINEAR_EXACT );
|
||||
resize( imageMat2, imageMat2, Size( imageMat2.cols / 2, imageMat2.rows / 2 ), 0, 0, INTER_LINEAR_EXACT );
|
||||
std::vector<char> lsd_mask( matches.size(), 1 );
|
||||
drawLineMatches( imageMat1, octave0_1, imageMat2, octave0_2, good_matches, lsd_outImg, Scalar::all( -1 ), Scalar::all( -1 ), lsd_mask,
|
||||
DrawLinesMatchesFlags::DEFAULT );
|
||||
|
||||
imshow( "LSD matches", lsd_outImg );
|
||||
waitKey();
|
||||
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cerr << "OpenCV was built without features module" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // HAVE_OPENCV_FEATURES
|
||||
@@ -0,0 +1,155 @@
|
||||
/*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 <iostream>
|
||||
#include <opencv2/opencv_modules.hpp>
|
||||
|
||||
#ifdef HAVE_OPENCV_FEATURES
|
||||
|
||||
#include <opencv2/line_descriptor.hpp>
|
||||
#include <opencv2/core/utility.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/features.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::line_descriptor;
|
||||
|
||||
static const std::string images[] =
|
||||
{ "cameraman.jpg", "church.jpg", "church2.png", "einstein.jpg", "stuff.jpg" };
|
||||
|
||||
static const char* keys =
|
||||
{ "{@image_path | | Image path }" };
|
||||
|
||||
static void help()
|
||||
{
|
||||
std::cout << "\nThis example shows the functionalities of radius matching " << "Please, run this sample using a command in the form\n"
|
||||
<< "./example_line_descriptor_radius_matching <path_to_input_images>/" << std::endl;
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
/* get parameters from comand line */
|
||||
CommandLineParser parser( argc, argv, keys );
|
||||
String pathToImages = parser.get < String > ( 0 );
|
||||
|
||||
/* create structures for hosting KeyLines and descriptors */
|
||||
int num_elements = sizeof ( images ) / sizeof ( images[0] );
|
||||
std::vector < Mat > descriptorsMat;
|
||||
std::vector < std::vector<KeyLine> > linesMat;
|
||||
|
||||
/*create a pointer to a BinaryDescriptor object */
|
||||
Ptr < BinaryDescriptor > bd = BinaryDescriptor::createBinaryDescriptor();
|
||||
|
||||
/* compute lines and descriptors */
|
||||
for ( int i = 0; i < num_elements; i++ )
|
||||
{
|
||||
/* get path to image */
|
||||
std::stringstream image_path;
|
||||
image_path << pathToImages << images[i];
|
||||
std::cout << image_path.str().c_str() << std::endl;
|
||||
|
||||
/* load image */
|
||||
Mat loadedImage = imread( image_path.str().c_str(), 1 );
|
||||
if( loadedImage.data == NULL )
|
||||
{
|
||||
std::cout << "Could not load images." << std::endl;
|
||||
help();
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
/* compute lines and descriptors */
|
||||
std::vector < KeyLine > lines;
|
||||
Mat computedDescr;
|
||||
bd->detect( loadedImage, lines );
|
||||
bd->compute( loadedImage, lines, computedDescr );
|
||||
|
||||
descriptorsMat.push_back( computedDescr );
|
||||
linesMat.push_back( lines );
|
||||
|
||||
}
|
||||
|
||||
/* compose a queries matrix */
|
||||
Mat queries;
|
||||
for ( size_t j = 0; j < descriptorsMat.size(); j++ )
|
||||
{
|
||||
if( descriptorsMat[j].rows >= 5 )
|
||||
queries.push_back( descriptorsMat[j].rowRange( 0, 5 ) );
|
||||
|
||||
else if( descriptorsMat[j].rows > 0 && descriptorsMat[j].rows < 5 )
|
||||
queries.push_back( descriptorsMat[j] );
|
||||
}
|
||||
|
||||
std::cout << "It has been generated a matrix of " << queries.rows << " descriptors" << std::endl;
|
||||
|
||||
/* create a BinaryDescriptorMatcher object */
|
||||
Ptr < BinaryDescriptorMatcher > bdm = BinaryDescriptorMatcher::createBinaryDescriptorMatcher();
|
||||
|
||||
/* populate matcher */
|
||||
bdm->add( descriptorsMat );
|
||||
|
||||
/* compute matches */
|
||||
std::vector < std::vector<DMatch> > matches;
|
||||
bdm->radiusMatch( queries, matches, 30 );
|
||||
std::cout << "size matches sample " << matches.size() << std::endl;
|
||||
|
||||
for ( int i = 0; i < (int) matches.size(); i++ )
|
||||
{
|
||||
for ( int j = 0; j < (int) matches[i].size(); j++ )
|
||||
{
|
||||
std::cout << "match: " << matches[i][j].queryIdx << " " << matches[i][j].trainIdx << " " << matches[i][j].distance << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cerr << "OpenCV was built without features module" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // HAVE_OPENCV_FEATURES
|
||||
@@ -0,0 +1,226 @@
|
||||
/*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"
|
||||
#include "opencv2/geometry.hpp"
|
||||
|
||||
//using namespace cv;
|
||||
namespace cv
|
||||
{
|
||||
namespace line_descriptor
|
||||
{
|
||||
Ptr<LSDDetector> LSDDetector::createLSDDetector()
|
||||
{
|
||||
return Ptr<LSDDetector>( new LSDDetector() );
|
||||
}
|
||||
|
||||
Ptr<LSDDetector> LSDDetector::createLSDDetector(LSDParam params)
|
||||
{
|
||||
return Ptr<LSDDetector>( new LSDDetector(params) );
|
||||
}
|
||||
|
||||
/* 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::Vec4f& extremes, cv::Size imageSize )
|
||||
{
|
||||
|
||||
if( extremes[0] < 0 )
|
||||
extremes[0] = 0;
|
||||
|
||||
if( extremes[0] >= imageSize.width )
|
||||
extremes[0] = (float)imageSize.width - 1.0f;
|
||||
|
||||
if( extremes[2] < 0 )
|
||||
extremes[2] = 0;
|
||||
|
||||
if( extremes[2] >= imageSize.width )
|
||||
extremes[2] = (float)imageSize.width - 1.0f;
|
||||
|
||||
if( extremes[1] < 0 )
|
||||
extremes[1] = 0;
|
||||
|
||||
if( extremes[1] >= imageSize.height )
|
||||
extremes[1] = (float)imageSize.height - 1.0f;
|
||||
|
||||
if( extremes[3] < 0 )
|
||||
extremes[3] = 0;
|
||||
|
||||
if( extremes[3] >= imageSize.height )
|
||||
extremes[3] = (float)imageSize.height - 1.0f;
|
||||
}
|
||||
|
||||
/* 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 ) )
|
||||
CV_Error( Error::StsBadArg, "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 ) )
|
||||
CV_Error( Error::StsBadArg, "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 )
|
||||
CV_Error( Error::BadDepth, "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, params.scale, params.sigma_scale,
|
||||
params.quant, params.ang_th, params.log_eps,
|
||||
params.density_th, params.n_bins);
|
||||
|
||||
/* prepare a vector to host extracted segments */
|
||||
std::vector<std::vector<cv::Vec4f> > lines_lsd;
|
||||
|
||||
/* extract lines */
|
||||
for ( int i = 0; i < numOctaves; i++ )
|
||||
{
|
||||
std::vector<Vec4f> octave_lines;
|
||||
ls->detect( gaussianPyrs[i], octave_lines );
|
||||
lines_lsd.push_back( octave_lines );
|
||||
}
|
||||
|
||||
/* create keylines */
|
||||
int class_counter = -1;
|
||||
for ( int octaveIdx = 0; octaveIdx < (int) lines_lsd.size(); octaveIdx++ )
|
||||
{
|
||||
float octaveScale = std::pow((float)scale, (float)octaveIdx);
|
||||
for ( int k = 0; k < (int) lines_lsd[octaveIdx].size(); k++ )
|
||||
{
|
||||
KeyLine kl;
|
||||
cv::Vec4f extremes = lines_lsd[octaveIdx][k];
|
||||
|
||||
/* check data validity */
|
||||
checkLineExtremes( extremes, gaussianPyrs[octaveIdx].size() );
|
||||
|
||||
/* fill KeyLine's fields */
|
||||
kl.startPointX = extremes[0] * octaveScale;
|
||||
kl.startPointY = extremes[1] * octaveScale;
|
||||
kl.endPointX = extremes[2] * octaveScale;
|
||||
kl.endPointY = extremes[3] * octaveScale;
|
||||
kl.sPointInOctaveX = extremes[0];
|
||||
kl.sPointInOctaveY = extremes[1];
|
||||
kl.ePointInOctaveX = extremes[2];
|
||||
kl.ePointInOctaveY = 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[octaveIdx], Point2f( extremes[0], extremes[1] ), Point2f( 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 = octaveIdx;
|
||||
kl.size = ( kl.endPointX - kl.startPointX ) * ( kl.endPointY - kl.startPointY );
|
||||
kl.response = kl.lineLength / max( gaussianPyrs[octaveIdx].cols, gaussianPyrs[octaveIdx].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 );
|
||||
keyCounter--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,955 @@
|
||||
/*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"
|
||||
|
||||
#define MAX_B 37
|
||||
double ARRAY_RESIZE_FACTOR = 1.1; // minimum is 1.0
|
||||
double ARRAY_RESIZE_ADD_FACTOR = 4; // minimum is 1
|
||||
|
||||
//using namespace cv;
|
||||
namespace cv
|
||||
{
|
||||
namespace line_descriptor
|
||||
{
|
||||
|
||||
/* constructor */
|
||||
BinaryDescriptorMatcher::BinaryDescriptorMatcher()
|
||||
{
|
||||
dataset = Ptr<Mihasher>(new Mihasher( 256, 32 ));
|
||||
nextAddedIndex = 0;
|
||||
numImages = 0;
|
||||
descrInDS = 0;
|
||||
}
|
||||
|
||||
/* constructor with smart pointer */
|
||||
Ptr<BinaryDescriptorMatcher> BinaryDescriptorMatcher::createBinaryDescriptorMatcher()
|
||||
{
|
||||
return Ptr < BinaryDescriptorMatcher > ( new BinaryDescriptorMatcher() );
|
||||
}
|
||||
|
||||
/* store new descriptors to be inserted in dataset */
|
||||
void BinaryDescriptorMatcher::add( const std::vector<Mat>& descriptors )
|
||||
{
|
||||
for ( size_t i = 0; i < descriptors.size(); i++ )
|
||||
{
|
||||
descriptorsMat.push_back( descriptors[i] );
|
||||
|
||||
indexesMap.insert( std::pair<int, int>( nextAddedIndex, numImages ) );
|
||||
nextAddedIndex += descriptors[i].rows;
|
||||
numImages++;
|
||||
}
|
||||
}
|
||||
|
||||
/* store new descriptors into dataset */
|
||||
void BinaryDescriptorMatcher::train()
|
||||
{
|
||||
if( !dataset )
|
||||
dataset = Ptr<Mihasher>(new Mihasher( 256, 32 ));
|
||||
|
||||
if( descriptorsMat.rows > 0 )
|
||||
dataset->populate( descriptorsMat, descriptorsMat.rows, descriptorsMat.cols );
|
||||
|
||||
descrInDS = descriptorsMat.rows;
|
||||
descriptorsMat.release();
|
||||
}
|
||||
|
||||
/* clear dataset and internal data */
|
||||
void BinaryDescriptorMatcher::clear()
|
||||
{
|
||||
descriptorsMat.release();
|
||||
indexesMap.clear();
|
||||
dataset.release();
|
||||
nextAddedIndex = 0;
|
||||
numImages = 0;
|
||||
descrInDS = 0;
|
||||
}
|
||||
|
||||
/* retrieve Hamming distances */
|
||||
void BinaryDescriptorMatcher::checkKDistances( UINT32 * numres, int k, std::vector<int> & k_distances, int row, int string_length ) const
|
||||
{
|
||||
int k_to_found = k;
|
||||
|
||||
UINT32 * numres_tmp = numres + ( ( string_length + 1 ) * row );
|
||||
for ( int j = 0; j < ( string_length + 1 ) && k_to_found > 0; j++ )
|
||||
{
|
||||
if( ( * ( numres_tmp + j ) ) > 0 )
|
||||
{
|
||||
for ( int i = 0; i < (int) ( * ( numres_tmp + j ) ) && k_to_found > 0; i++ )
|
||||
{
|
||||
k_distances.push_back( j );
|
||||
k_to_found--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* for every input descriptor,
|
||||
find the best matching one (from one image to a set) */
|
||||
void BinaryDescriptorMatcher::match( const Mat& queryDescriptors, std::vector<DMatch>& matches, const std::vector<Mat>& masks )
|
||||
{
|
||||
/* check data validity */
|
||||
if( queryDescriptors.rows == 0 )
|
||||
{
|
||||
std::cout << "Error: query descriptors'matrix is empty" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if( masks.size() != 0 && (int) masks.size() != numImages )
|
||||
{
|
||||
std::cout << "Error: the number of images in dataset is " << numImages << " but match function received " << masks.size()
|
||||
<< " masks. Program will be terminated" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* add new descriptors to dataset, if needed */
|
||||
train();
|
||||
|
||||
/* set number of requested matches to return for each query */
|
||||
dataset->setK( 1 );
|
||||
|
||||
/* prepare structures for query */
|
||||
UINT32 *results = new UINT32[queryDescriptors.rows];
|
||||
UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )];
|
||||
|
||||
/* execute query */
|
||||
dataset->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols );
|
||||
/* compose matches */
|
||||
for ( int counter = 0; counter < queryDescriptors.rows; counter++ )
|
||||
{
|
||||
/* create a map iterator */
|
||||
std::map<int, int>::iterator itup;
|
||||
|
||||
/* get info about original image of each returned descriptor */
|
||||
itup = indexesMap.upper_bound( results[counter] - 1 );
|
||||
itup--;
|
||||
/* data validity check */
|
||||
if( !masks.empty() && ( masks[itup->second].rows != queryDescriptors.rows || masks[itup->second].cols != 1 ) )
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Error: mask " << itup->second << " in knnMatch function " << "should have " << queryDescriptors.rows << " and "
|
||||
<< "1 column. Program will be terminated";
|
||||
//throw std::runtime_error( ss.str() );
|
||||
}
|
||||
/* create a DMatch object if required by mask or if there is
|
||||
no mask at all */
|
||||
else if( masks.empty() || masks[itup->second].at < uchar > ( counter ) != 0 )
|
||||
{
|
||||
std::vector<int> k_distances;
|
||||
checkKDistances( numres, 1, k_distances, counter, 256 );
|
||||
|
||||
DMatch dm;
|
||||
dm.queryIdx = counter;
|
||||
dm.trainIdx = results[counter] - 1;
|
||||
dm.imgIdx = itup->second;
|
||||
dm.distance = (float) k_distances[0];
|
||||
|
||||
matches.push_back( dm );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* delete data */
|
||||
delete[] results;
|
||||
delete[] numres;
|
||||
}
|
||||
|
||||
/* for every input descriptor, find the best matching one (for a pair of images) */
|
||||
void BinaryDescriptorMatcher::match( const Mat& queryDescriptors, const Mat& trainDescriptors, std::vector<DMatch>& matches, const Mat& mask ) const
|
||||
{
|
||||
|
||||
/* check data validity */
|
||||
if( queryDescriptors.rows == 0 || trainDescriptors.rows == 0 )
|
||||
{
|
||||
std::cout << "Error: descriptors matrices cannot be void" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if( !mask.empty() && ( mask.rows != queryDescriptors.rows && mask.cols != 1 ) )
|
||||
{
|
||||
std::cout << "Error: input mask should have " << queryDescriptors.rows << " rows and 1 column. " << "Program will be terminated" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* create a new mihasher object */
|
||||
Mihasher *mh = new Mihasher( 256, 32 );
|
||||
|
||||
/* populate mihasher */
|
||||
cv::Mat copy = trainDescriptors.clone();
|
||||
mh->populate( copy, copy.rows, copy.cols );
|
||||
mh->setK( 1 );
|
||||
|
||||
/* prepare structures for query */
|
||||
UINT32 *results = new UINT32[queryDescriptors.rows];
|
||||
UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )];
|
||||
|
||||
/* execute query */
|
||||
mh->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols );
|
||||
|
||||
/* compose matches */
|
||||
for ( int counter = 0; counter < queryDescriptors.rows; counter++ )
|
||||
{
|
||||
/* create a DMatch object if required by mask or if there is
|
||||
no mask at all */
|
||||
if( mask.empty() || ( !mask.empty() && mask.at < uchar > ( counter ) != 0 ) )
|
||||
{
|
||||
std::vector<int> k_distances;
|
||||
checkKDistances( numres, 1, k_distances, counter, 256 );
|
||||
|
||||
DMatch dm;
|
||||
dm.queryIdx = counter;
|
||||
dm.trainIdx = results[counter] - 1;
|
||||
dm.imgIdx = 0;
|
||||
dm.distance = (float) k_distances[0];
|
||||
|
||||
matches.push_back( dm );
|
||||
}
|
||||
}
|
||||
|
||||
/* delete data */
|
||||
delete mh;
|
||||
delete[] results;
|
||||
delete[] numres;
|
||||
|
||||
}
|
||||
|
||||
/* for every input descriptor,
|
||||
find the best k matching descriptors (for a pair of images) */
|
||||
void BinaryDescriptorMatcher::knnMatch( const Mat& queryDescriptors, const Mat& trainDescriptors, std::vector<std::vector<DMatch> >& matches, int k,
|
||||
const Mat& mask, bool compactResult ) const
|
||||
|
||||
{
|
||||
/* check data validity */
|
||||
if( queryDescriptors.rows == 0 || trainDescriptors.rows == 0 )
|
||||
{
|
||||
std::cout << "Error: descriptors matrices cannot be void" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if( !mask.empty() && ( mask.rows != queryDescriptors.rows || mask.cols != 1 ) )
|
||||
{
|
||||
std::cout << "Error: input mask should have " << queryDescriptors.rows << " rows and 1 column. " << "Program will be terminated" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* create a new mihasher object */
|
||||
Mihasher *mh = new Mihasher( 256, 32 );
|
||||
|
||||
/* populate mihasher */
|
||||
cv::Mat copy = trainDescriptors.clone();
|
||||
mh->populate( copy, copy.rows, copy.cols );
|
||||
|
||||
/* set K */
|
||||
mh->setK( k );
|
||||
|
||||
/* prepare structures for query */
|
||||
UINT32 *results = new UINT32[k * queryDescriptors.rows];
|
||||
UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )];
|
||||
|
||||
/* execute query */
|
||||
mh->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols );
|
||||
|
||||
/* compose matches */
|
||||
int index = 0;
|
||||
for ( int counter = 0; counter < queryDescriptors.rows; counter++ )
|
||||
{
|
||||
/* initialize a vector of matches */
|
||||
std::vector < DMatch > tempVec;
|
||||
|
||||
/* chech whether query should be ignored */
|
||||
if( !mask.empty() && mask.at < uchar > ( counter ) == 0 )
|
||||
{
|
||||
/* if compact result is not requested, add an empty vector */
|
||||
if( !compactResult )
|
||||
matches.push_back( tempVec );
|
||||
}
|
||||
|
||||
/* query matches must be considered */
|
||||
else
|
||||
{
|
||||
std::vector<int> k_distances;
|
||||
checkKDistances( numres, k, k_distances, counter, 256 );
|
||||
for ( int j = index; j < index + k; j++ )
|
||||
{
|
||||
DMatch dm;
|
||||
dm.queryIdx = counter;
|
||||
dm.trainIdx = results[j] - 1;
|
||||
dm.imgIdx = 0;
|
||||
dm.distance = (float) k_distances[j - index];
|
||||
|
||||
tempVec.push_back( dm );
|
||||
}
|
||||
|
||||
matches.push_back( tempVec );
|
||||
}
|
||||
|
||||
/* increment pointer */
|
||||
index += k;
|
||||
}
|
||||
|
||||
/* delete data */
|
||||
delete mh;
|
||||
delete[] results;
|
||||
delete[] numres;
|
||||
}
|
||||
|
||||
/* for every input descriptor,
|
||||
find the best k matching descriptors (from one image to a set) */
|
||||
void BinaryDescriptorMatcher::knnMatch( const Mat& queryDescriptors, std::vector<std::vector<DMatch> >& matches, int k, const std::vector<Mat>& masks,
|
||||
bool compactResult )
|
||||
{
|
||||
|
||||
/* check data validity */
|
||||
if( queryDescriptors.rows == 0 )
|
||||
{
|
||||
std::cout << "Error: descriptors matrix cannot be void" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if( masks.size() != 0 && (int) masks.size() != numImages )
|
||||
{
|
||||
std::cout << "Error: the number of images in dataset is " << numImages << " but knnMatch function received " << masks.size()
|
||||
<< " masks. Program will be terminated" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* add new descriptors to dataset, if needed */
|
||||
train();
|
||||
|
||||
/* set number of requested matches to return for each query */
|
||||
dataset->setK( k );
|
||||
|
||||
/* prepare structures for query */
|
||||
UINT32 *results = new UINT32[k * queryDescriptors.rows];
|
||||
UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )];
|
||||
|
||||
/* execute query */
|
||||
dataset->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols );
|
||||
|
||||
/* compose matches */
|
||||
int index = 0;
|
||||
for ( int counter = 0; counter < queryDescriptors.rows; counter++ )
|
||||
{
|
||||
/* create a void vector of matches */
|
||||
std::vector < DMatch > tempVector;
|
||||
|
||||
/* loop over k results returned for every query */
|
||||
for ( int j = index; j < index + k; j++ )
|
||||
{
|
||||
/* retrieve which image returned index refers to */
|
||||
int currentIndex = results[j] - 1;
|
||||
std::map<int, int>::iterator itup;
|
||||
itup = indexesMap.upper_bound( currentIndex );
|
||||
itup--;
|
||||
|
||||
/* data validity check */
|
||||
if( !masks.empty() && ( masks[itup->second].rows != queryDescriptors.rows || masks[itup->second].cols != 1 ) )
|
||||
{
|
||||
std::cout << "Error: mask " << itup->second << " in knnMatch function " << "should have " << queryDescriptors.rows << " and "
|
||||
<< "1 column. Program will be terminated" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* decide if, according to relative mask, returned match should be
|
||||
considered */
|
||||
else if( masks.size() == 0 || masks[itup->second].at < uchar > ( counter ) != 0 )
|
||||
{
|
||||
std::vector<int> k_distances;
|
||||
checkKDistances( numres, k, k_distances, counter, 256 );
|
||||
|
||||
DMatch dm;
|
||||
dm.queryIdx = counter;
|
||||
dm.trainIdx = results[j] - 1;
|
||||
dm.imgIdx = itup->second;
|
||||
dm.distance = (float) k_distances[j - index];
|
||||
|
||||
tempVector.push_back( dm );
|
||||
}
|
||||
}
|
||||
|
||||
/* decide whether temporary vector should be saved */
|
||||
if( ( tempVector.size() == 0 && !compactResult ) || tempVector.size() > 0 )
|
||||
matches.push_back( tempVector );
|
||||
|
||||
/* increment pointer */
|
||||
index += k;
|
||||
}
|
||||
|
||||
/* delete data */
|
||||
delete[] results;
|
||||
delete[] numres;
|
||||
}
|
||||
|
||||
/* for every input desciptor, find all the ones falling in a
|
||||
certaing matching radius (for a pair of images) */
|
||||
void BinaryDescriptorMatcher::radiusMatch( const Mat& queryDescriptors, const Mat& trainDescriptors, std::vector<std::vector<DMatch> >& matches,
|
||||
float maxDistance, const Mat& mask, bool compactResult ) const
|
||||
|
||||
{
|
||||
|
||||
/* check data validity */
|
||||
if( queryDescriptors.rows == 0 || trainDescriptors.rows == 0 )
|
||||
{
|
||||
std::cout << "Error: descriptors matrices cannot be void" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if( !mask.empty() && ( mask.rows != queryDescriptors.rows && mask.cols != 1 ) )
|
||||
{
|
||||
std::cout << "Error: input mask should have " << queryDescriptors.rows << " rows and 1 column. " << "Program will be terminated" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* create a new Mihasher */
|
||||
Mihasher* mh = new Mihasher( 256, 32 );
|
||||
|
||||
/* populate Mihasher */
|
||||
//Mat copy = queryDescriptors.clone();
|
||||
Mat copy = trainDescriptors.clone();
|
||||
mh->populate( copy, copy.rows, copy.cols );
|
||||
|
||||
/* set K */
|
||||
mh->setK( trainDescriptors.rows );
|
||||
|
||||
/* prepare structures for query */
|
||||
UINT32 *results = new UINT32[trainDescriptors.rows * queryDescriptors.rows];
|
||||
UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )];
|
||||
|
||||
/* execute query */
|
||||
mh->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols );
|
||||
|
||||
/* compose matches */
|
||||
int index = 0;
|
||||
for ( int i = 0; i < queryDescriptors.rows; i++ )
|
||||
{
|
||||
std::vector<int> k_distances;
|
||||
checkKDistances( numres, trainDescriptors.rows, k_distances, i, 256 );
|
||||
|
||||
std::vector < DMatch > tempVector;
|
||||
for ( int j = index; j < index + trainDescriptors.rows; j++ )
|
||||
{
|
||||
// if( numres[j] <= maxDistance )
|
||||
if( k_distances[j - index] <= maxDistance )
|
||||
{
|
||||
if( mask.empty() || mask.at < uchar > ( i ) != 0 )
|
||||
{
|
||||
DMatch dm;
|
||||
dm.queryIdx = i;
|
||||
dm.trainIdx = (int) ( results[j] - 1 );
|
||||
dm.imgIdx = 0;
|
||||
dm.distance = (float) k_distances[j - index];
|
||||
|
||||
tempVector.push_back( dm );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* decide whether temporary vector should be saved */
|
||||
if( ( tempVector.size() == 0 && !compactResult ) || tempVector.size() > 0 )
|
||||
matches.push_back( tempVector );
|
||||
|
||||
/* increment pointer */
|
||||
index += trainDescriptors.rows;
|
||||
|
||||
}
|
||||
|
||||
/* delete data */
|
||||
delete mh;
|
||||
delete[] results;
|
||||
delete[] numres;
|
||||
}
|
||||
|
||||
/* for every input descriptor, find all the ones falling in a
|
||||
certain matching radius (from one image to a set) */
|
||||
void BinaryDescriptorMatcher::radiusMatch( const Mat& queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,
|
||||
const std::vector<Mat>& masks, bool compactResult )
|
||||
{
|
||||
|
||||
/* check data validity */
|
||||
if( queryDescriptors.rows == 0 )
|
||||
{
|
||||
std::cout << "Error: descriptors matrices cannot be void" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if( masks.size() != 0 && (int) masks.size() != numImages )
|
||||
{
|
||||
std::cout << "Error: the number of images in dataset is " << numImages << " but radiusMatch function received " << masks.size()
|
||||
<< " masks. Program will be terminated" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* populate dataset */
|
||||
train();
|
||||
|
||||
/* set K */
|
||||
dataset->setK( descrInDS );
|
||||
|
||||
/* prepare structures for query */
|
||||
UINT32 *results = new UINT32[descrInDS * queryDescriptors.rows];
|
||||
UINT32 * numres = new UINT32[ ( 256 + 1 ) * ( queryDescriptors.rows )];
|
||||
|
||||
/* execute query */
|
||||
dataset->batchquery( results, numres, queryDescriptors, queryDescriptors.rows, queryDescriptors.cols );
|
||||
|
||||
/* compose matches */
|
||||
int index = 0;
|
||||
for ( int counter = 0; counter < queryDescriptors.rows; counter++ )
|
||||
{
|
||||
std::vector < DMatch > tempVector;
|
||||
for ( int j = index; j < index + descrInDS; j++ )
|
||||
{
|
||||
std::vector<int> k_distances;
|
||||
checkKDistances( numres, descrInDS, k_distances, counter, 256 );
|
||||
|
||||
if( k_distances[j - index] <= maxDistance )
|
||||
{
|
||||
int currentIndex = results[j] - 1;
|
||||
std::map<int, int>::iterator itup;
|
||||
itup = indexesMap.upper_bound( currentIndex );
|
||||
itup--;
|
||||
|
||||
/* data validity check */
|
||||
if( !masks.empty() && ( masks[itup->second].rows != queryDescriptors.rows || masks[itup->second].cols != 1 ) )
|
||||
{
|
||||
std::cout << "Error: mask " << itup->second << " in radiusMatch function " << "should have " << queryDescriptors.rows << " and "
|
||||
<< "1 column. Program will be terminated" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* add match if necessary */
|
||||
else if( masks.empty() || masks[itup->second].at < uchar > ( counter ) != 0 )
|
||||
{
|
||||
|
||||
DMatch dm;
|
||||
dm.queryIdx = counter;
|
||||
dm.trainIdx = results[j] - 1;
|
||||
dm.imgIdx = itup->second;
|
||||
dm.distance = (float) k_distances[j - index];
|
||||
|
||||
tempVector.push_back( dm );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* decide whether temporary vector should be saved */
|
||||
if( ( tempVector.size() == 0 && !compactResult ) || tempVector.size() > 0 )
|
||||
matches.push_back( tempVector );
|
||||
|
||||
/* increment pointer */
|
||||
index += descrInDS;
|
||||
}
|
||||
|
||||
/* delete data */
|
||||
delete[] results;
|
||||
delete[] numres;
|
||||
|
||||
}
|
||||
|
||||
/* execute a batch query */
|
||||
void BinaryDescriptorMatcher::Mihasher::batchquery( UINT32 * results, UINT32 *numres, const cv::Mat & queries, UINT32 numq, int dim1queries )
|
||||
{
|
||||
/* create and initialize a bitarray */
|
||||
counter = makePtr<bitarray>();
|
||||
counter->init( N );
|
||||
|
||||
UINT32 *res = new UINT32[K * ( D + 1 )];
|
||||
UINT64 *chunks = new UINT64[m];
|
||||
UINT32 * presults = results;
|
||||
UINT32 *pnumres = numres;
|
||||
|
||||
/* make a copy of input queries */
|
||||
cv::Mat queries_clone = queries.clone();
|
||||
|
||||
/* set a pointer to first query (row) */
|
||||
UINT8 *pq = queries_clone.ptr();
|
||||
|
||||
/* loop over number of descriptors */
|
||||
for ( size_t i = 0; i < numq; i++ )
|
||||
{
|
||||
/* for every descriptor, query database */
|
||||
query( presults, pnumres, pq, chunks, res );
|
||||
|
||||
/* move pointer to write next K indeces */
|
||||
presults += K;
|
||||
pnumres += B + 1;
|
||||
|
||||
/* move forward pointer to current row in descriptors matrix */
|
||||
pq += dim1queries;
|
||||
|
||||
}
|
||||
|
||||
delete[] res;
|
||||
delete[] chunks;
|
||||
}
|
||||
|
||||
/* execute a single query */
|
||||
void BinaryDescriptorMatcher::Mihasher::query( UINT32* results, UINT32* numres, UINT8 * Query, UINT64 *chunks, UINT32 *res )
|
||||
{
|
||||
/* if K == 0 that means we want everything to be processed.
|
||||
So maxres = N in that case. Otherwise K limits the results processed */
|
||||
UINT32 maxres = K ? K : (UINT32) N;
|
||||
|
||||
/* number of results so far obtained (up to a distance of s per chunk) */
|
||||
UINT32 n = 0;
|
||||
|
||||
UINT32 *arr;
|
||||
int size = 0;
|
||||
UINT32 index;
|
||||
int hammd;
|
||||
|
||||
counter->erase();
|
||||
memset( numres, 0, ( B + 1 ) * sizeof ( *numres ) );
|
||||
|
||||
split( chunks, Query, m, mplus, b );
|
||||
|
||||
/* the growing search radius per substring */
|
||||
int s;
|
||||
|
||||
/* current b: for the first mplus substrings it is b, for the rest it is (b-1) */
|
||||
int curb = b;
|
||||
|
||||
for ( s = 0; s <= d && n < maxres; s++ )
|
||||
{
|
||||
for ( int k = 0; k < m; k++ )
|
||||
{
|
||||
if( k < mplus )
|
||||
curb = b;
|
||||
else
|
||||
curb = b - 1;
|
||||
UINT64 chunksk = chunks[k];
|
||||
|
||||
/* the bit-string with s number of 1s */
|
||||
UINT64 bitstr = 0;
|
||||
for ( int i = 0; i < s; i++ )
|
||||
/* power[i] stores the location of the i'th 1 */
|
||||
power[i] = i;
|
||||
/* used for stopping criterion (location of (s+1)th 1) */
|
||||
power[s] = curb + 1;
|
||||
|
||||
/* bit determines the 1 that should be moving to the left */
|
||||
int bit = s - 1;
|
||||
|
||||
/* start from the left-most 1, and move it to the left until
|
||||
it touches another one */
|
||||
|
||||
/* the loop for changing bitstr */
|
||||
bool infiniteWhile = true;
|
||||
while ( infiniteWhile )
|
||||
{
|
||||
if( bit != -1 )
|
||||
{
|
||||
bitstr ^= ( power[bit] == bit ) ? (UINT64) 1 << power[bit] : (UINT64) 3 << ( power[bit] - 1 );
|
||||
power[bit]++;
|
||||
bit--;
|
||||
}
|
||||
|
||||
else
|
||||
{ /* bit == -1 */
|
||||
/* the binary code bitstr is available for processing */
|
||||
arr = H[k].query( chunksk ^ bitstr, &size ); // lookup
|
||||
if( size )
|
||||
{ /* the corresponding bucket is not empty */
|
||||
for ( int c = 0; c < size; c++ )
|
||||
{
|
||||
index = arr[c];
|
||||
if( !counter->get( index ) )
|
||||
{ /* if it is not a duplicate */
|
||||
counter->set( index );
|
||||
hammd = cv::line_descriptor::match( codes.ptr() + (UINT64) index * ( B_over_8 ), Query, B_over_8 );
|
||||
|
||||
if( hammd <= D && numres[hammd] < maxres )
|
||||
res[hammd * K + numres[hammd]] = index + 1;
|
||||
|
||||
numres[hammd]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* end of processing */
|
||||
while ( ++bit < s && power[bit] == power[bit + 1] - 1 )
|
||||
{
|
||||
bitstr ^= (UINT64) 1 << ( power[bit] - 1 );
|
||||
power[bit] = bit;
|
||||
}
|
||||
if( bit == s )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
n = n + numres[s * m + k];
|
||||
if( n >= maxres )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
n = 0;
|
||||
for ( s = 0; s <= D && (int) n < K; s++ )
|
||||
{
|
||||
for ( int c = 0; c < (int) numres[s] && (int) n < K; c++ )
|
||||
results[n++] = res[s * K + c];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* constructor 2 */
|
||||
BinaryDescriptorMatcher::Mihasher::Mihasher( int B_val, int _m )
|
||||
{
|
||||
B = B_val;
|
||||
B_over_8 = B / 8;
|
||||
m = _m;
|
||||
b = (int) ceil( (double) B / m );
|
||||
|
||||
/* set radius to search for nearest neighbors to size of descriptor */
|
||||
D = (int) ceil( B );
|
||||
d = (int) ceil( (double) D / m );
|
||||
|
||||
/* mplus is the number of chunks with b bits
|
||||
(m-mplus) is the number of chunks with (b-1) bits */
|
||||
mplus = B - m * ( b - 1 );
|
||||
|
||||
xornum.resize(d + 2);
|
||||
xornum[0] = 0;
|
||||
for ( int i = 0; i <= d; i++ )
|
||||
xornum[i + 1] = xornum[i] + (UINT32) choose( b, i );
|
||||
|
||||
H.resize(m);
|
||||
|
||||
/* H[i].init might fail */
|
||||
for ( int i = 0; i < mplus; i++ )
|
||||
H[i].init( b );
|
||||
for ( int i = mplus; i < m; i++ )
|
||||
H[i].init( b - 1 );
|
||||
}
|
||||
|
||||
/* K setter */
|
||||
void BinaryDescriptorMatcher::Mihasher::setK( int K_val )
|
||||
{
|
||||
K = K_val;
|
||||
}
|
||||
|
||||
/* desctructor */
|
||||
BinaryDescriptorMatcher::Mihasher::~Mihasher()
|
||||
{
|
||||
}
|
||||
|
||||
/* populate tables */
|
||||
void BinaryDescriptorMatcher::Mihasher::populate( cv::Mat & _codes, UINT32 N_val, int dim1codes )
|
||||
{
|
||||
N = N_val;
|
||||
codes = _codes;
|
||||
UINT64 * chunks = new UINT64[m];
|
||||
|
||||
UINT8 * pcodes = codes.ptr();
|
||||
for ( UINT64 i = 0; i < N; i++, pcodes += dim1codes )
|
||||
{
|
||||
split( chunks, pcodes, m, mplus, b );
|
||||
|
||||
for ( int k = 0; k < m; k++ )
|
||||
H[k].insert( chunks[k], (UINT32) i );
|
||||
|
||||
if( i % (int) ceil( N / 1000.0 ) == 0 )
|
||||
fflush (stdout);
|
||||
}
|
||||
|
||||
delete[] chunks;
|
||||
}
|
||||
|
||||
/* constructor */
|
||||
BinaryDescriptorMatcher::SparseHashtable::SparseHashtable()
|
||||
{
|
||||
size = 0;
|
||||
b = 0;
|
||||
}
|
||||
|
||||
/* initializer */
|
||||
int BinaryDescriptorMatcher::SparseHashtable::init( int _b )
|
||||
{
|
||||
b = _b;
|
||||
|
||||
if( b < 5 || b > MAX_B || b > (int) ( sizeof(UINT64) * 8 ) )
|
||||
return 1;
|
||||
|
||||
size = UINT64_1 << ( b - 5 ); // size = 2 ^ b
|
||||
table = std::vector<BucketGroup>((size_t)size, BucketGroup(false));
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* destructor */
|
||||
BinaryDescriptorMatcher::SparseHashtable::~SparseHashtable()
|
||||
{
|
||||
}
|
||||
|
||||
/* insert data */
|
||||
void BinaryDescriptorMatcher::SparseHashtable::insert( UINT64 index, UINT32 data )
|
||||
{
|
||||
table[(size_t)(index >> 5)].insert( (int) ( index & 31 ), data );
|
||||
}
|
||||
|
||||
/* query data */
|
||||
UINT32* BinaryDescriptorMatcher::SparseHashtable::query( UINT64 index, int *Size )
|
||||
{
|
||||
return table[(size_t)(index >> 5)].query( (int) ( index & 31 ), Size );
|
||||
}
|
||||
|
||||
/* constructor */
|
||||
BinaryDescriptorMatcher::BucketGroup::BucketGroup(bool needAllocateGroup)
|
||||
{
|
||||
empty = 0;
|
||||
if (needAllocateGroup)
|
||||
group = std::vector < uint32_t > ( 2, 0 );
|
||||
else
|
||||
group = std::vector < uint32_t > ( 0, 0 );
|
||||
}
|
||||
|
||||
/* destructor */
|
||||
BinaryDescriptorMatcher::BucketGroup::~BucketGroup()
|
||||
{
|
||||
}
|
||||
|
||||
void BinaryDescriptorMatcher::BucketGroup::insert_value( std::vector<uint32_t>& vec, int index, UINT32 data )
|
||||
{
|
||||
if( vec.size() > 1 )
|
||||
{
|
||||
if( vec[0] == vec[1] )
|
||||
{
|
||||
vec[1] = (UINT32) ceil( vec[0] * 1.1 );
|
||||
for ( int i = 0; i < (int) ( 2 + vec[1] - vec.size() ); i++ )
|
||||
vec.push_back( 0 );
|
||||
|
||||
}
|
||||
|
||||
vec.insert( vec.begin() + 2 + index, data );
|
||||
vec[2 + index] = data;
|
||||
vec[0]++;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
vec = std::vector < uint32_t > ( 3, 0 );
|
||||
vec[0] = 1;
|
||||
vec[1] = 1;
|
||||
vec[2] = data;
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryDescriptorMatcher::BucketGroup::push_value( std::vector<uint32_t>& vec, UINT32 Data )
|
||||
{
|
||||
if( vec.size() > 0 )
|
||||
{
|
||||
if( vec[0] == vec[1] )
|
||||
{
|
||||
vec[1] = (UINT32) std::max( ceil( vec[1] * ARRAY_RESIZE_FACTOR ), vec[1] + ARRAY_RESIZE_ADD_FACTOR );
|
||||
for ( int i = 0; i < (int) ( 2 + vec[1] - vec.size() ); i++ )
|
||||
vec.push_back( 0 );
|
||||
}
|
||||
|
||||
vec[2 + vec[0]] = Data;
|
||||
vec[0]++;
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
vec = std::vector < uint32_t > ( 2 + (uint32_t) ARRAY_RESIZE_ADD_FACTOR, 0 );
|
||||
vec[0] = 1;
|
||||
vec[1] = 1;
|
||||
vec[2] = Data;
|
||||
}
|
||||
}
|
||||
|
||||
/* insert data into the bucket */
|
||||
void BinaryDescriptorMatcher::BucketGroup::insert( int subindex, UINT32 data )
|
||||
{
|
||||
if( group.size() == 0 )
|
||||
{
|
||||
push_value( group, 0 );
|
||||
}
|
||||
|
||||
UINT32 lowerbits = ( (UINT32) 1 << subindex ) - 1;
|
||||
int end = popcnt( empty & lowerbits );
|
||||
|
||||
if( ! ( empty & ( (UINT32) 1 << subindex ) ) )
|
||||
{
|
||||
insert_value( group, end, group[end + 2] );
|
||||
empty |= (UINT32) 1 << subindex;
|
||||
}
|
||||
|
||||
int totones = popcnt( empty );
|
||||
insert_value( group, totones + 1 + group[2 + end + 1], data );
|
||||
|
||||
for ( int i = end + 1; i < totones + 1; i++ )
|
||||
group[2 + i]++;
|
||||
}
|
||||
|
||||
/* perform a query to the bucket */
|
||||
UINT32* BinaryDescriptorMatcher::BucketGroup::query( int subindex, int *size )
|
||||
{
|
||||
if( empty & ( (UINT32) 1 << subindex ) )
|
||||
{
|
||||
UINT32 lowerbits = ( (UINT32) 1 << subindex ) - 1;
|
||||
int end = popcnt( empty & lowerbits );
|
||||
int totones = popcnt( empty );
|
||||
|
||||
*size = group[2 + end + 1] - group[2 + end];
|
||||
return & ( * ( group.begin() + 2 + totones + 1 + (int) group[2 + end] ) );
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*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, Mohammad Norouzi, Ali Punjani, David J. Fleet,
|
||||
// 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*/
|
||||
|
||||
#ifndef __OPENCV_BITARRAY_HPP
|
||||
#define __OPENCV_BITARRAY_HPP
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( disable : 4267 )
|
||||
#endif
|
||||
|
||||
#include "types.hpp"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
/* class defining a sequence of bits */
|
||||
class bitarray
|
||||
{
|
||||
|
||||
public:
|
||||
/* pointer to bits sequence and sequence's length */
|
||||
UINT32 *arr;
|
||||
UINT32 length;
|
||||
|
||||
/* constructor setting default values */
|
||||
bitarray()
|
||||
{
|
||||
arr = NULL;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
/* constructor setting sequence's length */
|
||||
bitarray( UINT64 _bits )
|
||||
{
|
||||
init( _bits );
|
||||
}
|
||||
|
||||
/* initializer of private fields */
|
||||
void init( UINT64 _bits )
|
||||
{
|
||||
length = (UINT32) ceil( _bits / 32.00 );
|
||||
arr = new UINT32[length];
|
||||
erase();
|
||||
}
|
||||
|
||||
/* destructor */
|
||||
~bitarray()
|
||||
{
|
||||
if( arr )
|
||||
delete[] arr;
|
||||
}
|
||||
|
||||
inline void flip( UINT64 index )
|
||||
{
|
||||
arr[index >> 5] ^= ( (UINT32) 0x01 ) << ( index % 32 );
|
||||
}
|
||||
|
||||
inline void set( UINT64 index )
|
||||
{
|
||||
arr[index >> 5] |= ( (UINT32) 0x01 ) << ( index % 32 );
|
||||
}
|
||||
|
||||
inline UINT8 get( UINT64 index )
|
||||
{
|
||||
return ( arr[index >> 5] & ( ( (UINT32) 0x01 ) << ( index % 32 ) ) ) != 0;
|
||||
}
|
||||
|
||||
/* reserve menory for an UINT32 */
|
||||
inline void erase()
|
||||
{
|
||||
memset( arr, 0, sizeof(UINT32) * length );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,175 @@
|
||||
/*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, Mohammad Norouzi, Ali Punjani, David J. Fleet,
|
||||
// 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*/
|
||||
|
||||
#ifndef __OPENCV_BITOPTS_HPP
|
||||
#define __OPENCV_BITOPTS_HPP
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_M_ARM) || defined(_M_ARM64)
|
||||
static inline UINT32 popcnt(UINT32 v)
|
||||
{
|
||||
v = v - ((v >> 1) & 0x55555555);
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
|
||||
return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
|
||||
}
|
||||
#else
|
||||
# include <intrin.h>
|
||||
# define popcnt __popcnt
|
||||
# pragma warning( disable : 4267 )
|
||||
#endif
|
||||
#else
|
||||
# define popcnt __builtin_popcount
|
||||
#endif
|
||||
|
||||
/* LUT */
|
||||
const int lookup[] =
|
||||
{
|
||||
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
|
||||
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
|
||||
};
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace line_descriptor
|
||||
{
|
||||
/*matching function */
|
||||
inline int match( UINT8*P, UINT8*Q, int codelb )
|
||||
{
|
||||
int i, output = 0;
|
||||
for( i = 0; i <= codelb - 16; i += 16 )
|
||||
{
|
||||
output += popcnt( *(UINT32*) (P+i) ^ *(UINT32*) (Q+i) ) +
|
||||
popcnt( *(UINT32*) (P+i+4) ^ *(UINT32*) (Q+i+4) ) +
|
||||
popcnt( *(UINT32*) (P+i+8) ^ *(UINT32*) (Q+i+8) ) +
|
||||
popcnt( *(UINT32*) (P+i+12) ^ *(UINT32*) (Q+i+12) );
|
||||
}
|
||||
for( ; i < codelb; i++ )
|
||||
output += lookup[P[i] ^ Q[i]];
|
||||
return output;
|
||||
}
|
||||
|
||||
/* splitting function (b <= 64) */
|
||||
inline void split( UINT64 *chunks, UINT8 *code, int m, int mplus, int b )
|
||||
{
|
||||
UINT64 temp = 0x0;
|
||||
int nbits = 0;
|
||||
int nbyte = 0;
|
||||
UINT64 mask = (b == 64) ? 0xFFFFFFFFFFFFFFFFull : ( ( UINT64_1 << b ) - UINT64_1 );
|
||||
|
||||
for ( int i = 0; i < m; i++ )
|
||||
{
|
||||
while ( nbits < b )
|
||||
{
|
||||
temp |= ( (UINT64) code[nbyte++] << nbits );
|
||||
nbits += 8;
|
||||
}
|
||||
|
||||
chunks[i] = temp & mask;
|
||||
temp = b == 64 ? 0x0 : temp >> b;
|
||||
nbits -= b;
|
||||
|
||||
if( i == mplus - 1 )
|
||||
{
|
||||
b--; /* b <= 63 */
|
||||
mask = ( ( UINT64_1 << b ) - UINT64_1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* generates the next binary code (in alphabetical order) with the
|
||||
same number of ones as the input x. Taken from
|
||||
http://www.geeksforgeeks.org/archives/10375 */
|
||||
inline UINT64 next_set_of_n_elements( UINT64 x )
|
||||
{
|
||||
UINT64 smallest, ripple, new_smallest;
|
||||
|
||||
smallest = x & -(signed) x;
|
||||
ripple = x + smallest;
|
||||
new_smallest = x ^ ripple;
|
||||
new_smallest = new_smallest / smallest;
|
||||
new_smallest >>= 2;
|
||||
return ripple | new_smallest;
|
||||
}
|
||||
|
||||
/* print code */
|
||||
inline void print_code( UINT64 tmp, int b )
|
||||
{
|
||||
for ( long long int j = ( b - 1 ); j >= 0; j-- )
|
||||
{
|
||||
printf( "%llu", (long long int) tmp / (UINT64) ( (UINT64)1 << j ) );
|
||||
tmp = tmp - ( tmp / (UINT64) ( (UINT64)1 << j ) ) * (UINT64) ( (UINT64)1 << j );
|
||||
}
|
||||
|
||||
printf( "\n" );
|
||||
}
|
||||
|
||||
inline UINT64 choose( int n, int r )
|
||||
{
|
||||
UINT64 nchooser = 1;
|
||||
for ( int k = 0; k < r; k++ )
|
||||
{
|
||||
nchooser *= n - k;
|
||||
nchooser /= k + 1;
|
||||
}
|
||||
|
||||
return nchooser;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,190 @@
|
||||
/*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"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
namespace line_descriptor
|
||||
{
|
||||
/* draw matches between two images */
|
||||
void drawLineMatches( const Mat& img1, const std::vector<KeyLine>& keylines1, const Mat& img2, const std::vector<KeyLine>& keylines2,
|
||||
const std::vector<DMatch>& matches1to2, Mat& outImg, const Scalar& matchColor, const Scalar& singleLineColor,
|
||||
const std::vector<char>& matchesMask, int flags )
|
||||
{
|
||||
|
||||
if(img1.type() != img2.type())
|
||||
{
|
||||
std::cout << "Input images have different types" << std::endl;
|
||||
CV_Assert(img1.type() == img2.type());
|
||||
}
|
||||
|
||||
/* initialize output matrix (if necessary) */
|
||||
if( flags == DrawLinesMatchesFlags::DEFAULT )
|
||||
{
|
||||
/* check how many rows are necessary for output matrix */
|
||||
int totalRows = img1.rows >= img2.rows ? img1.rows : img2.rows;
|
||||
|
||||
/* initialize output matrix */
|
||||
outImg = Mat::zeros( totalRows, img1.cols + img2.cols, img1.type() );
|
||||
|
||||
}
|
||||
|
||||
/* initialize random seed: */
|
||||
srand( (unsigned int) time( NULL ) );
|
||||
|
||||
Scalar singleLineColorRGB;
|
||||
if( singleLineColor == Scalar::all( -1 ) )
|
||||
{
|
||||
int R = ( rand() % (int) ( 255 + 1 ) );
|
||||
int G = ( rand() % (int) ( 255 + 1 ) );
|
||||
int B = ( rand() % (int) ( 255 + 1 ) );
|
||||
|
||||
singleLineColorRGB = Scalar( R, G, B );
|
||||
}
|
||||
|
||||
else
|
||||
singleLineColorRGB = singleLineColor;
|
||||
|
||||
/* copy input images to output images */
|
||||
Mat roi_left( outImg, Rect( 0, 0, img1.cols, img1.rows ) );
|
||||
Mat roi_right( outImg, Rect( img1.cols, 0, img2.cols, img2.rows ) );
|
||||
img1.copyTo( roi_left );
|
||||
img2.copyTo( roi_right );
|
||||
|
||||
/* get columns offset */
|
||||
int offset = img1.cols;
|
||||
|
||||
/* if requested, draw lines from both images */
|
||||
if( flags != DrawLinesMatchesFlags::NOT_DRAW_SINGLE_LINES )
|
||||
{
|
||||
for ( size_t i = 0; i < keylines1.size(); i++ )
|
||||
{
|
||||
KeyLine k1 = keylines1[i];
|
||||
//line( outImg, Point2f( k1.startPointX, k1.startPointY ), Point2f( k1.endPointX, k1.endPointY ), singleLineColorRGB, 2 );
|
||||
line( outImg, Point2f( k1.sPointInOctaveX, k1.sPointInOctaveY ), Point2f( k1.ePointInOctaveX, k1.ePointInOctaveY ), singleLineColorRGB, 2 );
|
||||
|
||||
}
|
||||
|
||||
for ( size_t j = 0; j < keylines2.size(); j++ )
|
||||
{
|
||||
KeyLine k2 = keylines2[j];
|
||||
line( outImg, Point2f( k2.sPointInOctaveX + offset, k2.sPointInOctaveY ), Point2f( k2.ePointInOctaveX + offset, k2.ePointInOctaveY ), singleLineColorRGB, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/* draw matches */
|
||||
for ( size_t counter = 0; counter < matches1to2.size(); counter++ )
|
||||
{
|
||||
if( matchesMask[counter] != 0 )
|
||||
{
|
||||
DMatch dm = matches1to2[counter];
|
||||
KeyLine left = keylines1[dm.queryIdx];
|
||||
KeyLine right = keylines2[dm.trainIdx];
|
||||
|
||||
Scalar matchColorRGB;
|
||||
if( matchColor == Scalar::all( -1 ) )
|
||||
{
|
||||
int R = ( rand() % (int) ( 255 + 1 ) );
|
||||
int G = ( rand() % (int) ( 255 + 1 ) );
|
||||
int B = ( rand() % (int) ( 255 + 1 ) );
|
||||
|
||||
matchColorRGB = Scalar( R, G, B );
|
||||
|
||||
if( singleLineColor == Scalar::all( -1 ) )
|
||||
singleLineColorRGB = matchColorRGB;
|
||||
}
|
||||
|
||||
else
|
||||
matchColorRGB = matchColor;
|
||||
|
||||
/* draw lines if necessary */
|
||||
// line( outImg, Point2f( left.startPointX, left.startPointY ), Point2f( left.endPointX, left.endPointY ), singleLineColorRGB, 2 );
|
||||
//
|
||||
// line( outImg, Point2f( right.startPointX + offset, right.startPointY ), Point2f( right.endPointX + offset, right.endPointY ), singleLineColorRGB,
|
||||
// 2 );
|
||||
//
|
||||
// /* link correspondent lines */
|
||||
// line( outImg, Point2f( left.startPointX, left.startPointY ), Point2f( right.startPointX + offset, right.startPointY ), matchColorRGB, 1 );
|
||||
|
||||
line( outImg, Point2f( left.sPointInOctaveX, left.sPointInOctaveY ), Point2f( left.ePointInOctaveX, left.ePointInOctaveY ), singleLineColorRGB, 2 );
|
||||
|
||||
line( outImg, Point2f( right.sPointInOctaveX + offset, right.sPointInOctaveY ), Point2f( right.ePointInOctaveX + offset, right.ePointInOctaveY ), singleLineColorRGB,
|
||||
2 );
|
||||
|
||||
/* link correspondent lines */
|
||||
line( outImg, Point2f( left.sPointInOctaveX, left.sPointInOctaveY ), Point2f( right.sPointInOctaveX + offset, right.sPointInOctaveY ), matchColorRGB, 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* draw extracted lines on original image */
|
||||
void drawKeylines( const Mat& image, const std::vector<KeyLine>& keylines, Mat& outImage, const Scalar& color, int flags )
|
||||
{
|
||||
if( flags == DrawLinesMatchesFlags::DEFAULT )
|
||||
outImage = image.clone();
|
||||
|
||||
for ( size_t i = 0; i < keylines.size(); i++ )
|
||||
{
|
||||
/* decide lines' color */
|
||||
Scalar lineColor;
|
||||
if( color == Scalar::all( -1 ) )
|
||||
{
|
||||
int R = ( rand() % (int) ( 255 + 1 ) );
|
||||
int G = ( rand() % (int) ( 255 + 1 ) );
|
||||
int B = ( rand() % (int) ( 255 + 1 ) );
|
||||
|
||||
lineColor = Scalar( R, G, B );
|
||||
}
|
||||
|
||||
else
|
||||
lineColor = color;
|
||||
|
||||
/* get line */
|
||||
KeyLine k = keylines[i];
|
||||
|
||||
/* draw line */
|
||||
line( outImage, Point2f( k.startPointX, k.startPointY ), Point2f( k.endPointX, k.endPointY ), lineColor, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*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*/
|
||||
|
||||
#ifndef __OPENCV_PRECOMP_H__
|
||||
#define __OPENCV_PRECOMP_H__
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( disable : 4267 )
|
||||
#endif
|
||||
|
||||
#ifndef _USE_MATH_DEFINES
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/core/private.hpp"
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include "opencv2/core.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <time.h>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "bitarray.hpp"
|
||||
#include "bitops.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
#include "opencv2/line_descriptor.hpp"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
/*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, Mohammad Norouzi, Ali Punjani, David J. Fleet,
|
||||
// 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*/
|
||||
|
||||
#if defined _MSC_VER && _MSC_VER <= 1700
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#ifndef __OPENCV_TYPES_HPP
|
||||
#define __OPENCV_TYPES_HPP
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( disable : 4267 )
|
||||
#endif
|
||||
|
||||
/* define data types */
|
||||
typedef uint64_t UINT64;
|
||||
typedef uint32_t UINT32;
|
||||
typedef uint16_t UINT16;
|
||||
typedef uint8_t UINT8;
|
||||
|
||||
/* define constants */
|
||||
#define UINT64_1 ((UINT64)0x01)
|
||||
#define UINT32_1 ((UINT32)0x01)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,364 @@
|
||||
/*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 "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
/****************************************************************************************\
|
||||
* Regression tests for line detector comparing keylines. *
|
||||
\****************************************************************************************/
|
||||
|
||||
const std::string LINE_DESCRIPTOR_DIR = "line_descriptor";
|
||||
const std::string IMAGE_FILENAME = "cameraman.jpg";
|
||||
|
||||
template<class Distance>
|
||||
class CV_BD_DescriptorsTest : public cvtest::BaseTest
|
||||
{
|
||||
|
||||
public:
|
||||
typedef typename Distance::ValueType ValueType;
|
||||
typedef typename Distance::ResultType DistanceType;
|
||||
|
||||
CV_BD_DescriptorsTest( std::string fs, DistanceType _maxDist ): maxDist(_maxDist)
|
||||
{
|
||||
bd = BinaryDescriptor::createBinaryDescriptor();
|
||||
fs_name = fs;
|
||||
}
|
||||
|
||||
protected:
|
||||
// void compareDescriptors( const Mat& validDescriptors, const Mat& calcDescriptors );
|
||||
// void createVecFromMat( Mat& inputMat, std::vector<KeyLine>& output );
|
||||
// virtual bool writeDescriptors( Mat& descs );
|
||||
// virtual Mat readDescriptors();
|
||||
// void emptyDataTest();
|
||||
// void regressionTest();
|
||||
// virtual void run( int );
|
||||
|
||||
Ptr<BinaryDescriptor> bd;
|
||||
std::string fs_name;
|
||||
const DistanceType maxDist;
|
||||
Distance distance;
|
||||
|
||||
//};
|
||||
|
||||
void compareDescriptors( const Mat& validDescriptors, const Mat& calcDescriptors )
|
||||
{
|
||||
if( validDescriptors.size != calcDescriptors.size || validDescriptors.type() != calcDescriptors.type() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Valid and computed descriptors matrices must have the same size and type.\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
return;
|
||||
}
|
||||
|
||||
CV_Assert( validDescriptors.type() == CV_8U );
|
||||
|
||||
int dimension = validDescriptors.cols;
|
||||
DistanceType curMaxDist = std::numeric_limits<DistanceType>::min();
|
||||
for ( int y = 0; y < validDescriptors.rows; y++ )
|
||||
{
|
||||
DistanceType dist = distance( validDescriptors.ptr<ValueType>( y ), calcDescriptors.ptr<ValueType>( y ), dimension );
|
||||
if( dist > curMaxDist )
|
||||
curMaxDist = dist;
|
||||
}
|
||||
|
||||
EXPECT_LT(curMaxDist, maxDist) << "Max distance between valid and computed descriptors";
|
||||
}
|
||||
|
||||
Mat readDescriptors()
|
||||
{
|
||||
Mat descriptors;
|
||||
FileStorage fs( std::string( ts->get_data_path() ) + LINE_DESCRIPTOR_DIR + "/" + fs_name, FileStorage::READ );
|
||||
fs["descriptors"] >> descriptors;
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
bool writeDescriptors( Mat& descs )
|
||||
{
|
||||
FileStorage fs( std::string( ts->get_data_path() ) + LINE_DESCRIPTOR_DIR + "/" + fs_name, FileStorage::WRITE );
|
||||
fs << "descriptors" << descs;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void createMatFromVec( const std::vector<KeyLine>& linesVec, Mat& output )
|
||||
{
|
||||
output = Mat( (int) linesVec.size(), 17, CV_32FC1 );
|
||||
|
||||
for ( int i = 0; i < (int) linesVec.size(); i++ )
|
||||
{
|
||||
std::vector<float> klData;
|
||||
KeyLine kl = linesVec[i];
|
||||
klData.push_back( kl.angle );
|
||||
klData.push_back( (float) kl.class_id );
|
||||
klData.push_back( kl.ePointInOctaveX );
|
||||
klData.push_back( kl.ePointInOctaveY );
|
||||
klData.push_back( kl.endPointX );
|
||||
klData.push_back( kl.endPointY );
|
||||
klData.push_back( kl.lineLength );
|
||||
klData.push_back( (float) kl.numOfPixels );
|
||||
klData.push_back( (float) kl.octave );
|
||||
klData.push_back( kl.pt.x );
|
||||
klData.push_back( kl.pt.y );
|
||||
klData.push_back( kl.response );
|
||||
klData.push_back( kl.sPointInOctaveX );
|
||||
klData.push_back( kl.sPointInOctaveY );
|
||||
klData.push_back( kl.size );
|
||||
klData.push_back( kl.startPointX );
|
||||
klData.push_back( kl.startPointY );
|
||||
|
||||
float* pointerToRow = output.ptr<float>( i );
|
||||
for ( int j = 0; j < 17; j++ )
|
||||
{
|
||||
*pointerToRow = klData[j];
|
||||
pointerToRow++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createVecFromMat( Mat& inputMat, std::vector<KeyLine>& output )
|
||||
{
|
||||
for ( int i = 0; i < inputMat.rows; i++ )
|
||||
{
|
||||
std::vector<float> tempFloat;
|
||||
KeyLine kl;
|
||||
float* pointerToRow = inputMat.ptr<float>( i );
|
||||
|
||||
for ( int j = 0; j < 17; j++ )
|
||||
{
|
||||
tempFloat.push_back( *pointerToRow );
|
||||
pointerToRow++;
|
||||
}
|
||||
|
||||
kl.angle = tempFloat[0];
|
||||
kl.class_id = (int) tempFloat[1];
|
||||
kl.ePointInOctaveX = tempFloat[2];
|
||||
kl.ePointInOctaveY = tempFloat[3];
|
||||
kl.endPointX = tempFloat[4];
|
||||
kl.endPointY = tempFloat[5];
|
||||
kl.lineLength = tempFloat[6];
|
||||
kl.numOfPixels = (int) tempFloat[7];
|
||||
kl.octave = (int) tempFloat[8];
|
||||
kl.pt.x = tempFloat[9];
|
||||
kl.pt.y = tempFloat[10];
|
||||
kl.response = tempFloat[11];
|
||||
kl.sPointInOctaveX = tempFloat[12];
|
||||
kl.sPointInOctaveY = tempFloat[13];
|
||||
kl.size = tempFloat[14];
|
||||
kl.startPointX = tempFloat[15];
|
||||
kl.startPointY = tempFloat[16];
|
||||
|
||||
output.push_back( kl );
|
||||
}
|
||||
}
|
||||
|
||||
void emptyDataTest()
|
||||
{
|
||||
assert( bd );
|
||||
|
||||
// One image.
|
||||
Mat image;
|
||||
std::vector<KeyLine> keypoints;
|
||||
Mat descriptors;
|
||||
|
||||
try
|
||||
{
|
||||
bd->compute( image, keypoints, descriptors );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "compute() on empty image and empty keypoints must not generate exception (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
}
|
||||
|
||||
image.create( 50, 50, CV_8UC3 );
|
||||
try
|
||||
{
|
||||
bd->compute( image, keypoints, descriptors );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "compute() on nonempty image and empty keylines must not generate exception (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
}
|
||||
|
||||
// Several images.
|
||||
std::vector<Mat> images;
|
||||
std::vector<std::vector<KeyLine> > keylinesCollection;
|
||||
std::vector<Mat> descriptorsCollection;
|
||||
try
|
||||
{
|
||||
bd->compute( images, keylinesCollection, descriptorsCollection );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "compute() on empty images and empty keylines collection must not generate exception (2).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void regressionTest()
|
||||
{
|
||||
assert( bd );
|
||||
|
||||
// Read the test image.
|
||||
std::string imgFilename = std::string( ts->get_data_path() ) + LINE_DESCRIPTOR_DIR + "/" + IMAGE_FILENAME;
|
||||
|
||||
Mat img = imread( imgFilename );
|
||||
if( img.empty() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Image %s can not be read.\n", imgFilename.c_str() );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<KeyLine> keylines;
|
||||
FileStorage fs( std::string( ts->get_data_path() ) + LINE_DESCRIPTOR_DIR + "/edl_detector_keylines_cameraman.yaml", FileStorage::READ );
|
||||
if( fs.isOpened() )
|
||||
{
|
||||
//read( fs.getFirstTopLevelNode(), keypoints );
|
||||
|
||||
/* load keylines */
|
||||
Mat loadedKeylines;
|
||||
fs["keylines"] >> loadedKeylines;
|
||||
createVecFromMat( loadedKeylines, keylines );
|
||||
|
||||
/* compute descriptors */
|
||||
Mat calcDescriptors;
|
||||
double t = (double) getTickCount();
|
||||
bd->compute( img, keylines, calcDescriptors );
|
||||
t = getTickCount() - t;
|
||||
ts->printf( cvtest::TS::LOG, "\nAverage time of computing one descriptor = %g ms.\n",
|
||||
t / ( (double) getTickFrequency() * 1000. ) / calcDescriptors.rows );
|
||||
|
||||
ASSERT_EQ((int)keylines.size(), calcDescriptors.rows)
|
||||
<< "Count of computed descriptors and keylines count must be equal";
|
||||
|
||||
ASSERT_EQ(bd->descriptorSize() / 8, calcDescriptors.cols);
|
||||
ASSERT_EQ(bd->descriptorType(), calcDescriptors.type());
|
||||
|
||||
// TODO read and write descriptor extractor parameters and check them
|
||||
Mat validDescriptors = readDescriptors();
|
||||
if( !validDescriptors.empty() )
|
||||
compareDescriptors( validDescriptors, calcDescriptors );
|
||||
else
|
||||
{
|
||||
if( !writeDescriptors( calcDescriptors ) )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Descriptors can not be written.\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Compute and write keylines.\n" );
|
||||
fs.open( std::string( ts->get_data_path() ) + LINE_DESCRIPTOR_DIR + "/edl_detector_keylines_cameraman.yaml", FileStorage::WRITE );
|
||||
if( fs.isOpened() )
|
||||
{
|
||||
bd->detect( img, keylines );
|
||||
Mat keyLinesToYaml;
|
||||
createMatFromVec( keylines, keyLinesToYaml );
|
||||
fs << "keylines" << keyLinesToYaml;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "File for writting keylines can not be opened.\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void run( int )
|
||||
{
|
||||
if( !bd )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Feature detector is empty.\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
return;
|
||||
}
|
||||
|
||||
emptyDataTest();
|
||||
regressionTest();
|
||||
|
||||
ts->set_failed_test_info( cvtest::TS::OK );
|
||||
}
|
||||
|
||||
private:
|
||||
CV_BD_DescriptorsTest& operator=( const CV_BD_DescriptorsTest& )
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
/****************************************************************************************\
|
||||
* Tests registrations *
|
||||
\****************************************************************************************/
|
||||
|
||||
TEST( BinaryDescriptor_Descriptors, regression )
|
||||
{
|
||||
CV_BD_DescriptorsTest<Hamming> test( std::string( "lbd_descriptors_cameraman" ), 1 );
|
||||
test.safe_run();
|
||||
}
|
||||
|
||||
/****************************************************************************************\
|
||||
* Other tests *
|
||||
\****************************************************************************************/
|
||||
|
||||
TEST( BinaryDescriptor, no_lines_found )
|
||||
{
|
||||
Mat Image = Mat::zeros(100, 100, CV_8U);
|
||||
Ptr<line_descriptor::BinaryDescriptor> binDescriptor =
|
||||
line_descriptor::BinaryDescriptor::createBinaryDescriptor();
|
||||
|
||||
std::vector<cv::line_descriptor::KeyLine> keyLines;
|
||||
binDescriptor->detect(Image, keyLines);
|
||||
ASSERT_EQ(keyLines.size(), 0u);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,340 @@
|
||||
/*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 "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
/****************************************************************************************\
|
||||
* Regression tests for line detector comparing keylines. *
|
||||
\****************************************************************************************/
|
||||
|
||||
const std::string LINE_DESCRIPTOR_DIR = "line_descriptor";
|
||||
const std::string IMAGE_FILENAME = "cameraman.jpg";
|
||||
|
||||
class CV_BinaryDescriptorDetectorTest : public cvtest::BaseTest
|
||||
{
|
||||
|
||||
public:
|
||||
CV_BinaryDescriptorDetectorTest( std::string fs )
|
||||
{
|
||||
bd = BinaryDescriptor::createBinaryDescriptor();
|
||||
fs_name = fs;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool isSimilarKeylines( const KeyLine& k1, const KeyLine& k2 );
|
||||
void compareKeylineSets( const std::vector<KeyLine>& validKeylines, const std::vector<KeyLine>& calcKeylines );
|
||||
void createMatFromVec( const std::vector<KeyLine>& linesVec, Mat& output );
|
||||
void createVecFromMat( Mat& inputMat, std::vector<KeyLine>& output );
|
||||
|
||||
void emptyDataTest();
|
||||
void regressionTest();
|
||||
virtual void run( int );
|
||||
|
||||
Ptr<BinaryDescriptor> bd;
|
||||
std::string fs_name;
|
||||
|
||||
};
|
||||
|
||||
void CV_BinaryDescriptorDetectorTest::emptyDataTest()
|
||||
{
|
||||
/* one image */
|
||||
Mat image;
|
||||
std::vector<KeyLine> keylines;
|
||||
|
||||
try
|
||||
{
|
||||
bd->detect( image, keylines );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "detect() on empty image must return empty keylines vector (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
if( !keylines.empty() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "detect() on empty image must return empty keylines vector (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
return;
|
||||
}
|
||||
|
||||
/* more than one image */
|
||||
std::vector<Mat> images;
|
||||
std::vector<std::vector<KeyLine> > keylineCollection;
|
||||
|
||||
try
|
||||
{
|
||||
bd->detect( images, keylineCollection );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "detect() on empty image vector must not generate exception (2).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CV_BinaryDescriptorDetectorTest::createMatFromVec( const std::vector<KeyLine>& linesVec, Mat& output )
|
||||
{
|
||||
output = Mat( (int) linesVec.size(), 17, CV_32FC1 );
|
||||
|
||||
for ( int i = 0; i < (int) linesVec.size(); i++ )
|
||||
{
|
||||
std::vector<float> klData;
|
||||
KeyLine kl = linesVec[i];
|
||||
klData.push_back( kl.angle );
|
||||
klData.push_back( (float) kl.class_id );
|
||||
klData.push_back( kl.ePointInOctaveX );
|
||||
klData.push_back( kl.ePointInOctaveY );
|
||||
klData.push_back( kl.endPointX );
|
||||
klData.push_back( kl.endPointY );
|
||||
klData.push_back( kl.lineLength );
|
||||
klData.push_back( (float) kl.numOfPixels );
|
||||
klData.push_back( (float) kl.octave );
|
||||
klData.push_back( kl.pt.x );
|
||||
klData.push_back( kl.pt.y );
|
||||
klData.push_back( kl.response );
|
||||
klData.push_back( kl.sPointInOctaveX );
|
||||
klData.push_back( kl.sPointInOctaveY );
|
||||
klData.push_back( kl.size );
|
||||
klData.push_back( kl.startPointX );
|
||||
klData.push_back( kl.startPointY );
|
||||
|
||||
float* pointerToRow = output.ptr<float>( i );
|
||||
for ( int j = 0; j < 17; j++ )
|
||||
{
|
||||
*pointerToRow = klData[j];
|
||||
pointerToRow++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CV_BinaryDescriptorDetectorTest::createVecFromMat( Mat& inputMat, std::vector<KeyLine>& output )
|
||||
{
|
||||
for ( int i = 0; i < inputMat.rows; i++ )
|
||||
{
|
||||
std::vector<float> tempFloat;
|
||||
KeyLine kl;
|
||||
float* pointerToRow = inputMat.ptr<float>( i );
|
||||
|
||||
for ( int j = 0; j < 17; j++ )
|
||||
{
|
||||
tempFloat.push_back( *pointerToRow );
|
||||
pointerToRow++;
|
||||
}
|
||||
|
||||
kl.angle = tempFloat[0];
|
||||
kl.class_id = (int) tempFloat[1];
|
||||
kl.ePointInOctaveX = tempFloat[2];
|
||||
kl.ePointInOctaveY = tempFloat[3];
|
||||
kl.endPointX = tempFloat[4];
|
||||
kl.endPointY = tempFloat[5];
|
||||
kl.lineLength = tempFloat[6];
|
||||
kl.numOfPixels = (int) tempFloat[7];
|
||||
kl.octave = (int) tempFloat[8];
|
||||
kl.pt.x = tempFloat[9];
|
||||
kl.pt.y = tempFloat[10];
|
||||
kl.response = tempFloat[11];
|
||||
kl.sPointInOctaveX = tempFloat[12];
|
||||
kl.sPointInOctaveY = tempFloat[13];
|
||||
kl.size = tempFloat[14];
|
||||
kl.startPointX = tempFloat[15];
|
||||
kl.startPointY = tempFloat[16];
|
||||
|
||||
output.push_back( kl );
|
||||
}
|
||||
}
|
||||
|
||||
bool CV_BinaryDescriptorDetectorTest::isSimilarKeylines( const KeyLine& k1, const KeyLine& k2 )
|
||||
{
|
||||
const float maxPtDif = 1.f;
|
||||
const float maxSizeDif = 1.f;
|
||||
const float maxAngleDif = 2.f;
|
||||
const float maxResponseDif = 0.1f;
|
||||
|
||||
float dist = (float)cv::norm(k1.pt - k2.pt);
|
||||
return ( dist < maxPtDif && fabs( k1.size - k2.size ) < maxSizeDif && abs( k1.angle - k2.angle ) < maxAngleDif
|
||||
&& abs( k1.response - k2.response ) < maxResponseDif && k1.octave == k2.octave && k1.class_id == k2.class_id );
|
||||
}
|
||||
|
||||
void CV_BinaryDescriptorDetectorTest::compareKeylineSets( const std::vector<KeyLine>& validKeylines, const std::vector<KeyLine>& calcKeylines )
|
||||
{
|
||||
const float maxCountRatioDif = 0.01f;
|
||||
|
||||
// Compare counts of validation and calculated keylines.
|
||||
float countRatio = (float) validKeylines.size() / (float) calcKeylines.size();
|
||||
if( countRatio < 1 - maxCountRatioDif || countRatio > 1.f + maxCountRatioDif )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Bad keylines count ratio (validCount = %d, calcCount = %d).\n", validKeylines.size(), calcKeylines.size() );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
return;
|
||||
}
|
||||
|
||||
int progress = 0;
|
||||
int progressCount = (int) ( validKeylines.size() * calcKeylines.size() );
|
||||
int badLineCount = 0;
|
||||
int commonLineCount = max( (int) validKeylines.size(), (int) calcKeylines.size() );
|
||||
for ( size_t v = 0; v < validKeylines.size(); v++ )
|
||||
{
|
||||
int nearestIdx = -1;
|
||||
float minDist = std::numeric_limits<float>::max();
|
||||
|
||||
for ( size_t c = 0; c < calcKeylines.size(); c++ )
|
||||
{
|
||||
progress = update_progress( progress, (int) ( v * calcKeylines.size() + c ), progressCount, 0 );
|
||||
float curDist = (float)cv::norm(calcKeylines[c].pt - validKeylines[v].pt);
|
||||
if( curDist < minDist )
|
||||
{
|
||||
minDist = curDist;
|
||||
nearestIdx = (int) c;
|
||||
}
|
||||
}
|
||||
|
||||
assert( minDist >= 0 );
|
||||
if( !isSimilarKeylines( validKeylines[v], calcKeylines[nearestIdx] ) )
|
||||
badLineCount++;
|
||||
}
|
||||
|
||||
ts->printf( cvtest::TS::LOG, "badLineCount = %d; validLineCount = %d; calcLineCount = %d\n", badLineCount, validKeylines.size(),
|
||||
calcKeylines.size() );
|
||||
|
||||
if( badLineCount > 0.9 * commonLineCount )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, " - Bad accuracy!\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
|
||||
return;
|
||||
}
|
||||
|
||||
ts->printf( cvtest::TS::LOG, " - OK\n" );
|
||||
}
|
||||
|
||||
void CV_BinaryDescriptorDetectorTest::regressionTest()
|
||||
{
|
||||
assert( bd );
|
||||
std::string imgFilename = std::string( ts->get_data_path() ) + LINE_DESCRIPTOR_DIR + "/" + IMAGE_FILENAME;
|
||||
std::string resFilename = std::string( ts->get_data_path() ) + LINE_DESCRIPTOR_DIR + "/" + fs_name + ".yaml";
|
||||
|
||||
// Read the test image.
|
||||
Mat image = imread( imgFilename );
|
||||
if( image.empty() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Image %s can not be read.\n", imgFilename.c_str() );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
return;
|
||||
}
|
||||
|
||||
// open a storage for reading
|
||||
FileStorage fs( resFilename, FileStorage::READ );
|
||||
|
||||
// Compute keylines.
|
||||
std::vector<KeyLine> calcKeylines;
|
||||
bd->detect( image, calcKeylines );
|
||||
|
||||
if( fs.isOpened() ) // Compare computed and valid keylines.
|
||||
{
|
||||
// Read validation keylines set.
|
||||
std::vector<KeyLine> validKeylines;
|
||||
Mat storedKeylines;
|
||||
fs["keylines"] >> storedKeylines;
|
||||
createVecFromMat( storedKeylines, validKeylines );
|
||||
|
||||
if( validKeylines.empty() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "keylines can not be read.\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
return;
|
||||
}
|
||||
|
||||
compareKeylineSets( validKeylines, calcKeylines );
|
||||
}
|
||||
|
||||
else // Write detector parameters and computed keylines as validation data.
|
||||
{
|
||||
fs.open( resFilename, FileStorage::WRITE );
|
||||
if( !fs.isOpened() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "File %s can not be opened to write.\n", resFilename.c_str() );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
return;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
fs << "detector_params" << "{";
|
||||
bd->write( fs );
|
||||
fs << "}";
|
||||
Mat lines;
|
||||
createMatFromVec( calcKeylines, lines );
|
||||
fs << "keylines" << lines;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CV_BinaryDescriptorDetectorTest::run( int )
|
||||
{
|
||||
if( !bd )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Feature detector is empty.\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
return;
|
||||
}
|
||||
|
||||
emptyDataTest();
|
||||
regressionTest();
|
||||
|
||||
ts->set_failed_test_info( cvtest::TS::OK );
|
||||
}
|
||||
|
||||
/****************************************************************************************\
|
||||
* Tests registrations *
|
||||
\****************************************************************************************/
|
||||
|
||||
TEST( BinaryDescriptor_Detector, regression )
|
||||
{
|
||||
CV_BinaryDescriptorDetectorTest test( std::string( "edl_detector_keylines_cameraman" ) );
|
||||
test.safe_run();
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,6 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
CV_TEST_MAIN("cv")
|
||||
@@ -0,0 +1,580 @@
|
||||
/*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 "test_precomp.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
class CV_BinaryDescriptorMatcherTest : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
CV_BinaryDescriptorMatcherTest( float _badPart ) :
|
||||
badPart( _badPart )
|
||||
{
|
||||
dmatcher = BinaryDescriptorMatcher::createBinaryDescriptorMatcher();
|
||||
}
|
||||
|
||||
protected:
|
||||
static const int dim = 32;
|
||||
static const int queryDescCount = 300; // must be even number because we split train data in some cases in two
|
||||
static const int countFactor = 4; // do not change it
|
||||
const float badPart;
|
||||
|
||||
virtual void run( int );
|
||||
void generateData( Mat& query, Mat& train );
|
||||
uchar invertSingleBits( uchar dividend_char, int numBits );
|
||||
void emptyDataTest();
|
||||
void matchTest( const Mat& query, const Mat& train );
|
||||
void knnMatchTest( const Mat& query, const Mat& train );
|
||||
void radiusMatchTest( const Mat& query, const Mat& train );
|
||||
|
||||
std::string name;
|
||||
Ptr<BinaryDescriptorMatcher> dmatcher;
|
||||
|
||||
private:
|
||||
CV_BinaryDescriptorMatcherTest& operator=( const CV_BinaryDescriptorMatcherTest& )
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* invert numBits bits in input char */
|
||||
uchar CV_BinaryDescriptorMatcherTest::invertSingleBits( uchar dividend_char, int numBits )
|
||||
{
|
||||
std::vector<int> bin_vector;
|
||||
long dividend;
|
||||
long bin_num;
|
||||
|
||||
/* convert input char to a long */
|
||||
dividend = (long) dividend_char;
|
||||
|
||||
/*if a 0 has been obtained, just generate a 8-bit long vector of zeros */
|
||||
if( dividend == 0 )
|
||||
bin_vector = std::vector<int>( 8, 0 );
|
||||
|
||||
/* else, apply classic decimal to binary conversion */
|
||||
else
|
||||
{
|
||||
while ( dividend >= 1 )
|
||||
{
|
||||
bin_num = dividend % 2;
|
||||
dividend /= 2;
|
||||
bin_vector.push_back( bin_num );
|
||||
}
|
||||
}
|
||||
|
||||
/* ensure that binary vector always has length 8 */
|
||||
if( bin_vector.size() < 8 )
|
||||
{
|
||||
std::vector<int> zeros( 8 - bin_vector.size(), 0 );
|
||||
bin_vector.insert( bin_vector.end(), zeros.begin(), zeros.end() );
|
||||
}
|
||||
|
||||
/* invert numBits bits */
|
||||
for ( int index = 0; index < numBits; index++ )
|
||||
{
|
||||
if( bin_vector[index] == 0 )
|
||||
bin_vector[index] = 1;
|
||||
|
||||
else
|
||||
bin_vector[index] = 0;
|
||||
}
|
||||
|
||||
/* reconvert to decimal */
|
||||
uchar result = 0;
|
||||
for ( int i = (int) bin_vector.size() - 1; i >= 0; i-- )
|
||||
result += (uchar) ( bin_vector[i] * ( 1 << i ) );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CV_BinaryDescriptorMatcherTest::emptyDataTest()
|
||||
{
|
||||
Mat queryDescriptors, trainDescriptors, mask;
|
||||
std::vector<Mat> trainDescriptorCollection, masks;
|
||||
std::vector<DMatch> matches;
|
||||
std::vector<std::vector<DMatch> > vmatches;
|
||||
|
||||
try
|
||||
{
|
||||
dmatcher->match( queryDescriptors, trainDescriptors, matches, mask );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "match() on empty descriptors must not generate exception (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
dmatcher->knnMatch( queryDescriptors, trainDescriptors, vmatches, 2, mask );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "knnMatch() on empty descriptors must not generate exception (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
dmatcher->radiusMatch( queryDescriptors, trainDescriptors, vmatches, 10.f, mask );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "radiusMatch() on empty descriptors must not generate exception (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
dmatcher->add( trainDescriptorCollection );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "add() on empty descriptors must not generate exception.\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
dmatcher->match( queryDescriptors, matches, masks );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "match() on empty descriptors must not generate exception (2).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
dmatcher->knnMatch( queryDescriptors, vmatches, 2, masks );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "knnMatch() on empty descriptors must not generate exception (2).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
dmatcher->radiusMatch( queryDescriptors, vmatches, 10.f, masks );
|
||||
}
|
||||
|
||||
catch ( ... )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "radiusMatch() on empty descriptors must not generate exception (2).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CV_BinaryDescriptorMatcherTest::generateData( Mat& query, Mat& train )
|
||||
{
|
||||
RNG& rng = theRNG();
|
||||
|
||||
/* Generate query descriptors randomly.
|
||||
Descriptor vector elements are binary values. */
|
||||
Mat buf( queryDescCount, dim, CV_8UC1 );
|
||||
rng.fill( buf, RNG::UNIFORM, Scalar( 0 ), Scalar( 255 ) );
|
||||
buf.convertTo( query, CV_8UC1 );
|
||||
|
||||
for ( int i = 0; i < query.rows; i++ )
|
||||
{
|
||||
for ( int j = 0; j < countFactor; j++ )
|
||||
{
|
||||
train.push_back( query.row( i ) );
|
||||
int randCol = rand() % 32;
|
||||
uchar u = query.at<uchar>( i, randCol );
|
||||
uchar modified_u = invertSingleBits( u, j + 1 );
|
||||
train.at<uchar>( i * countFactor + j, randCol ) = modified_u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CV_BinaryDescriptorMatcherTest::matchTest( const Mat& query, const Mat& train )
|
||||
{
|
||||
dmatcher->clear();
|
||||
|
||||
// test const version of match()
|
||||
{
|
||||
std::vector<DMatch> matches;
|
||||
dmatcher->match( query, train, matches );
|
||||
|
||||
if( (int) matches.size() != queryDescCount )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Incorrect matches count while test match() function (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
int badCount = 0;
|
||||
for ( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
DMatch& match = matches[i];
|
||||
if( ( match.queryIdx != (int) i ) || ( match.trainIdx != (int) i * countFactor ) || ( match.imgIdx != 0 ) )
|
||||
badCount++;
|
||||
}
|
||||
if( (float) badCount > (float) queryDescCount * badPart )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test match() function (1).\n",
|
||||
(float) badCount / (float) queryDescCount );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test const version of match() for the same query and test descriptors
|
||||
{
|
||||
std::vector<DMatch> matches;
|
||||
dmatcher->match( query, query, matches );
|
||||
|
||||
if( (int) matches.size() != query.rows )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Incorrect matches count while test match() function for the same query and test descriptors (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
DMatch& match = matches[i];
|
||||
if( match.queryIdx != (int) i || match.trainIdx != (int) i || std::abs( match.distance ) > FLT_EPSILON )
|
||||
{
|
||||
ts->printf(
|
||||
cvtest::TS::LOG,
|
||||
"Bad match (i=%d, queryIdx=%d, trainIdx=%d, distance=%f) while test match() function for the same query and test descriptors (1).\n", i,
|
||||
match.queryIdx, match.trainIdx, match.distance );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// test version of match() with add()
|
||||
{
|
||||
dmatcher->clear();
|
||||
std::vector<DMatch> matches;
|
||||
|
||||
// make add() twice to test such case
|
||||
dmatcher->add( std::vector<Mat>( 1, train.rowRange( 0, train.rows / 2 ) ) );
|
||||
dmatcher->add( std::vector<Mat>( 1, train.rowRange( train.rows / 2, train.rows ) ) );
|
||||
|
||||
// prepare masks (make first nearest match illegal)
|
||||
std::vector<Mat> masks( 2 );
|
||||
for ( int mi = 0; mi < 2; mi++ )
|
||||
masks[mi] = Mat::ones( query.rows, 1/*train.rows / 2*/, CV_8UC1 );
|
||||
|
||||
dmatcher->match( query, matches, masks );
|
||||
if( (int) matches.size() != queryDescCount )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Incorrect matches count while test match() function (2).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
int badCount = 0;
|
||||
for ( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
DMatch& match = matches[i];
|
||||
|
||||
if( ( match.queryIdx != (int) i ) || ( match.trainIdx != (int) i * countFactor /*+ shift*/) || ( match.imgIdx > 1 ) )
|
||||
badCount++;
|
||||
}
|
||||
|
||||
if( (float) badCount > (float) queryDescCount * badPart )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test match() function (2).\n",
|
||||
(float) badCount / (float) queryDescCount );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CV_BinaryDescriptorMatcherTest::knnMatchTest( const Mat& query, const Mat& train )
|
||||
{
|
||||
dmatcher->clear();
|
||||
|
||||
// test const version of knnMatch()
|
||||
{
|
||||
const int knn = 3;
|
||||
|
||||
std::vector<std::vector<DMatch> > matches;
|
||||
dmatcher->knnMatch( query, train, matches, knn );
|
||||
|
||||
if( (int) matches.size() != queryDescCount )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Incorrect matches count while test knnMatch() function (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
int badCount = 0;
|
||||
for ( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
if( (int) matches[i].size() != knn )
|
||||
badCount++;
|
||||
|
||||
else
|
||||
{
|
||||
int localBadCount = 0;
|
||||
for ( int k = 0; k < knn; k++ )
|
||||
{
|
||||
DMatch& match = matches[i][k];
|
||||
if( ( match.queryIdx != (int) i ) || ( match.trainIdx != (int) i * countFactor + k ) || ( match.imgIdx != 0 ) )
|
||||
localBadCount++;
|
||||
}
|
||||
badCount += localBadCount > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( (float) badCount > (float) queryDescCount * badPart )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test knnMatch() function (1).\n",
|
||||
(float) badCount / (float) queryDescCount );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // test version of knnMatch() with add()
|
||||
{
|
||||
const int knn = 2;
|
||||
std::vector<std::vector<DMatch> > matches;
|
||||
|
||||
// make add() twice to test such case
|
||||
dmatcher->add( std::vector<Mat>( 1, train.rowRange( 0, train.rows / 2 ) ) );
|
||||
dmatcher->add( std::vector<Mat>( 1, train.rowRange( train.rows / 2, train.rows ) ) );
|
||||
|
||||
// prepare masks (make first nearest match illegal)
|
||||
std::vector<Mat> masks( 2 );
|
||||
for ( int mi = 0; mi < 2; mi++ )
|
||||
{
|
||||
masks[mi] = Mat::ones( query.rows, 1, CV_8UC1 );
|
||||
}
|
||||
|
||||
dmatcher->knnMatch( query, matches, knn, masks );
|
||||
|
||||
if( (int) matches.size() != queryDescCount )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Incorrect matches count while test knnMatch() function (2).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
int badCount = 0;
|
||||
for ( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
if( (int) matches[i].size() != knn )
|
||||
badCount++;
|
||||
|
||||
else
|
||||
{
|
||||
int localBadCount = 0;
|
||||
for ( int k = 0; k < knn; k++ )
|
||||
{
|
||||
DMatch& match = matches[i][k];
|
||||
{
|
||||
if( i < queryDescCount / 2 )
|
||||
{
|
||||
if( ( match.queryIdx != (int) i ) || ( match.trainIdx != (int) i * countFactor + k ) || ( match.imgIdx != 0 ) )
|
||||
localBadCount++;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if( ( match.queryIdx != (int) i ) || ( match.trainIdx != (int) i * countFactor + k ) || ( match.imgIdx != 1 ) )
|
||||
localBadCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
badCount += localBadCount > 0 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( (float) badCount > (float) queryDescCount * badPart )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test knnMatch() function (2).\n",
|
||||
(float) badCount / (float) queryDescCount );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CV_BinaryDescriptorMatcherTest::radiusMatchTest( const Mat& query, const Mat& train )
|
||||
{
|
||||
dmatcher->clear();
|
||||
// test const version of match()
|
||||
{
|
||||
const float radius = 1;
|
||||
std::vector<std::vector<DMatch> > matches;
|
||||
dmatcher->radiusMatch( query, train, matches, radius );
|
||||
|
||||
if( (int) matches.size() != queryDescCount )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Incorrect matches count while test radiusMatch() function (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
else
|
||||
{
|
||||
int badCount = 0;
|
||||
for ( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
|
||||
if( (int) matches[i].size() != 1 )
|
||||
{
|
||||
badCount++;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
DMatch& match = matches[i][0];
|
||||
if( ( match.queryIdx != (int) i ) || ( match.trainIdx != (int) i * countFactor ) || ( match.imgIdx != 0 ) )
|
||||
badCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if( (float) badCount > (float) queryDescCount * badPart )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test radiusMatch() function (1).\n",
|
||||
(float) badCount / (float) queryDescCount );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const float radius = 3;
|
||||
std::vector<std::vector<DMatch> > matches;
|
||||
// make add() twice to test such case
|
||||
dmatcher->add( std::vector<Mat>( 1, train.rowRange( 0, train.rows / 2 ) ) );
|
||||
dmatcher->add( std::vector<Mat>( 1, train.rowRange( train.rows / 2, train.rows ) ) );
|
||||
|
||||
// prepare masks
|
||||
std::vector<Mat> masks( 2 );
|
||||
for ( int mi = 0; mi < 2; mi++ )
|
||||
masks[mi] = Mat::ones( query.rows, 1, CV_8UC1 );
|
||||
|
||||
dmatcher->radiusMatch( query, matches, radius, masks );
|
||||
|
||||
//int curRes = cvtest::TS::OK;
|
||||
if( (int) matches.size() != queryDescCount )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Incorrect matches count while test radiusMatch() function (1).\n" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
|
||||
}
|
||||
|
||||
int badCount = 0;
|
||||
for ( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
if( (int) matches[i].size() != radius )
|
||||
badCount++;
|
||||
|
||||
else
|
||||
{
|
||||
int localBadCount = 0;
|
||||
for ( int k = 0; k < radius; k++ )
|
||||
{
|
||||
DMatch& match = matches[i][k];
|
||||
{
|
||||
if( i < queryDescCount / 2 )
|
||||
{
|
||||
if( ( match.queryIdx != (int) i ) || ( match.trainIdx != (int) i * countFactor + k ) || ( match.imgIdx != 0 ) )
|
||||
localBadCount++;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if( ( match.queryIdx != (int) i ) || ( match.trainIdx != (int) i * countFactor + k ) || ( match.imgIdx != 1 ) )
|
||||
localBadCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
badCount += localBadCount > 0 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( (float) badCount > (float) queryDescCount * badPart )
|
||||
{
|
||||
//curRes = cvtest::TS::FAIL_INVALID_OUTPUT;
|
||||
ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test radiusMatch() function (2).\n",
|
||||
(float) badCount / (float) queryDescCount );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CV_BinaryDescriptorMatcherTest::run( int )
|
||||
{
|
||||
Mat query, train;
|
||||
emptyDataTest();
|
||||
generateData( query, train );
|
||||
matchTest( query, train );
|
||||
knnMatchTest( query, train );
|
||||
radiusMatchTest( query, train );
|
||||
}
|
||||
|
||||
/****************************************************************************************\
|
||||
* Tests registrations *
|
||||
\****************************************************************************************/
|
||||
|
||||
TEST( BinaryDescriptor_Matcher, regression)
|
||||
{
|
||||
CV_BinaryDescriptorMatcherTest test( 0.01f );
|
||||
test.safe_run();
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
@@ -0,0 +1,14 @@
|
||||
// This file is part of OpenCV project.
|
||||
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
||||
// of this distribution and at http://opencv.org/license.html.
|
||||
#ifndef __OPENCV_TEST_PRECOMP_HPP__
|
||||
#define __OPENCV_TEST_PRECOMP_HPP__
|
||||
|
||||
#include "opencv2/ts.hpp"
|
||||
#include "opencv2/line_descriptor.hpp"
|
||||
|
||||
namespace opencv_test {
|
||||
using namespace cv::line_descriptor;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
Line Features Tutorial {#tutorial_line_descriptor_main}
|
||||
======================
|
||||
|
||||
In this tutorial it will be shown how to:
|
||||
|
||||
- Use the *BinaryDescriptor* interface to extract the lines and store them in *KeyLine* objects
|
||||
- Use the same interface to compute descriptors for every extracted line
|
||||
- Use the *BynaryDescriptorMatcher* to determine matches among descriptors obtained from different
|
||||
images
|
||||
|
||||
Lines extraction and descriptors computation
|
||||
--------------------------------------------
|
||||
|
||||
In the following snippet of code, it is shown how to detect lines from an image. The LSD extractor
|
||||
is initialized with *LSD\_REFINE\_ADV* option; remaining parameters are left to their default
|
||||
values. A mask of ones is used in order to accept all extracted lines, which, at the end, are
|
||||
displayed using random colors for octave 0.
|
||||
|
||||
@includelineno line_descriptor/samples/lsd_lines_extraction.cpp
|
||||
|
||||
This is the result obtained from the famous cameraman image:
|
||||
|
||||

|
||||
|
||||
Another way to extract lines is using *LSDDetector* class; such class uses the LSD extractor to
|
||||
compute lines. To obtain this result, it is sufficient to use the snippet code seen above, just
|
||||
modifying it by the rows
|
||||
|
||||
@code{.cpp}
|
||||
// create a pointer to an LSDDetector object
|
||||
Ptr<LSDDetector> lsd = LSDDetector::createLSDDetector();
|
||||
|
||||
// compute lines
|
||||
std::vector<KeyLine> keylines;
|
||||
lsd->detect( imageMat, keylines, mask );
|
||||
@endcode
|
||||
|
||||
Here's the result returned by LSD detector again on cameraman picture:
|
||||
|
||||

|
||||
|
||||
Once keylines have been detected, it is possible to compute their descriptors as shown in the
|
||||
following:
|
||||
|
||||
@includelineno line_descriptor/samples/compute_descriptors.cpp
|
||||
|
||||
Matching among descriptors
|
||||
--------------------------
|
||||
|
||||
If we have extracted descriptors from two different images, it is possible to search for matches
|
||||
among them. One way of doing it is matching exactly a descriptor to each input query descriptor,
|
||||
choosing the one at closest distance:
|
||||
|
||||
@includelineno line_descriptor/samples/matching.cpp
|
||||
|
||||
Sometimes, we could be interested in searching for the closest *k* descriptors, given an input one.
|
||||
This requires modifying previous code slightly:
|
||||
|
||||
@code{.cpp}
|
||||
// prepare a structure to host matches
|
||||
std::vector<std::vector<DMatch> > matches;
|
||||
|
||||
// require knn match
|
||||
bdm->knnMatch( descr1, descr2, matches, 6 );
|
||||
@endcode
|
||||
|
||||
In the above example, the closest 6 descriptors are returned for every query. In some cases, we
|
||||
could have a search radius and look for all descriptors distant at the most *r* from input query.
|
||||
Previous code must be modified like:
|
||||
|
||||
@code{.cpp}
|
||||
// prepare a structure to host matches
|
||||
std::vector<std::vector<DMatch> > matches;
|
||||
|
||||
// compute matches
|
||||
bdm->radiusMatch( queries, matches, 30 );
|
||||
@endcode
|
||||
|
||||
Here's an example of matching among descriptors extracted from original cameraman image and its
|
||||
downsampled (and blurred) version:
|
||||
|
||||

|
||||
|
||||
Querying internal database
|
||||
--------------------------
|
||||
|
||||
The *BynaryDescriptorMatcher* class owns an internal database that can be populated with
|
||||
descriptors extracted from different images and queried using one of the modalities described in the
|
||||
previous section. Population of internal dataset can be done using the *add* function; such function
|
||||
doesn't directly add new data to the database, but it just stores it them locally. The real update
|
||||
happens when the function *train* is invoked or when any querying function is executed, since each of
|
||||
them invokes *train* before querying. When queried, internal database not only returns required
|
||||
descriptors, but for every returned match, it is able to tell which image matched descriptor was
|
||||
extracted from. An example of internal dataset usage is described in the following code; after
|
||||
adding locally new descriptors, a radius search is invoked. This provokes local data to be
|
||||
transferred to dataset which in turn, is then queried.
|
||||
|
||||
@includelineno line_descriptor/samples/radius_matching.cpp
|
||||
Reference in New Issue
Block a user