mirror of
https://github.com/opencv/opencv_contrib.git
synced 2025-10-19 02:16:34 +08:00
Matcher functionalities' tests completed
This commit is contained in:
@@ -55,7 +55,6 @@
|
||||
#include "sparse_hashtable.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
@@ -195,17 +194,17 @@ namespace cv
|
||||
|
||||
protected:
|
||||
/* implementation of line detection */
|
||||
virtual void detectImpl( const Mat& image,
|
||||
virtual void detectImpl( const Mat& imageSrc,
|
||||
std::vector<KeyLine>& keylines,
|
||||
const Mat& mask=Mat() ) const;
|
||||
|
||||
|
||||
/* implementation of descriptors' computation */
|
||||
virtual void computeImpl( const Mat& image,
|
||||
virtual void computeImpl( const Mat& imageSrc,
|
||||
std::vector<KeyLine>& keylines,
|
||||
Mat& descriptors ) const;
|
||||
|
||||
/* function inherited by Algorithm */
|
||||
/* function inherited from Algorithm */
|
||||
AlgorithmInfo* info() const;
|
||||
|
||||
private:
|
||||
@@ -302,25 +301,99 @@ namespace cv
|
||||
const std::vector<Mat>& masks=std::vector<Mat>(),
|
||||
bool compactResult=false );
|
||||
|
||||
/* store new descriptors to be inserted in dataset */
|
||||
void add( const std::vector<Mat>& descriptors );
|
||||
|
||||
/* store new descriptors into dataset */
|
||||
void train();
|
||||
|
||||
/* constructor with smart pointer */
|
||||
static Ptr<BinaryDescriptorMatcher> createBinaryDescriptorMatcher();
|
||||
|
||||
|
||||
/* write/read data to/from file */
|
||||
virtual void read( const FileNode& );
|
||||
virtual void write( FileStorage& ) const;
|
||||
/* clear dataset and internal data */
|
||||
void clear();
|
||||
|
||||
/* constructor */
|
||||
BinaryDescriptorMatcher(){};
|
||||
BinaryDescriptorMatcher();
|
||||
|
||||
/* desctructor */
|
||||
~BinaryDescriptorMatcher(){};
|
||||
~BinaryDescriptorMatcher(){}
|
||||
|
||||
protected:
|
||||
/* function inherited from Algorithm */
|
||||
AlgorithmInfo* info() const;
|
||||
|
||||
private:
|
||||
/* vector to store new desciptors */
|
||||
std::vector<Mat> descriptorsVector;
|
||||
/* retrieve Hamming distances */
|
||||
void checkKDistances(UINT32 * numres,
|
||||
int k,
|
||||
std::vector<int>& k_distances,
|
||||
int row,
|
||||
int string_length) const;
|
||||
|
||||
/* matrix to store new descriptors */
|
||||
Mat descriptorsMat;
|
||||
|
||||
/* map storing where each bunch of descriptors benins in DS */
|
||||
std::map<int, int> indexesMap;
|
||||
|
||||
/* internal MiHaser representing dataset */
|
||||
Mihasher* dataset;
|
||||
|
||||
/* index from which next added descriptors' bunch must begin */
|
||||
int nextAddedIndex;
|
||||
|
||||
/* number of images whose descriptors are stored in DS */
|
||||
int numImages;
|
||||
|
||||
/* number of descriptors in dataset */
|
||||
int descrInDS;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------------------------
|
||||
UTILITY FUNCTIONS
|
||||
-------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* struct for drawing options */
|
||||
struct CV_EXPORTS DrawLinesMatchesFlags
|
||||
{
|
||||
enum
|
||||
{
|
||||
DEFAULT = 0, // Output image matrix will be created (Mat::create),
|
||||
// i.e. existing memory of output image may be reused.
|
||||
// Two source images, matches, and single keylines
|
||||
// will be drawn.
|
||||
DRAW_OVER_OUTIMG = 1, // Output image matrix will not be
|
||||
// created (using Mat::create). Matches will be drawn
|
||||
// on existing content of output image.
|
||||
NOT_DRAW_SINGLE_LINES = 2 // Single keylines will not be drawn.
|
||||
};
|
||||
};
|
||||
|
||||
/* draw matches between two images */
|
||||
CV_EXPORTS_W 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=Scalar::all(-1),
|
||||
const Scalar& singleLineColor=Scalar::all(-1),
|
||||
const std::vector<char>& matchesMask=std::vector<char>(),
|
||||
int flags=DrawLinesMatchesFlags::DEFAULT );
|
||||
|
||||
/* draw extracted lines on original image */
|
||||
CV_EXPORTS_W void drawKeylines( const Mat& image,
|
||||
const std::vector<KeyLine>& keylines,
|
||||
Mat& outImage,
|
||||
const Scalar& color=Scalar::all(-1),
|
||||
int flags=DrawLinesMatchesFlags::DEFAULT );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@@ -58,8 +58,6 @@ int main( int argc, char** argv )
|
||||
}
|
||||
|
||||
/* create a random binary mask */
|
||||
// cv::Mat mask(imageMat.size(), CV_8UC1);
|
||||
// cv::randu(mask, Scalar::all(0), Scalar::all(1));
|
||||
cv::Mat mask = Mat::ones(imageMat.size(), CV_8UC1);
|
||||
|
||||
/* create a pointer to a BinaryDescriptor object with default parameters */
|
||||
|
BIN
modules/line_descriptor/samples/images/cameraman.jpg
Normal file
BIN
modules/line_descriptor/samples/images/cameraman.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
modules/line_descriptor/samples/images/church.jpg
Normal file
BIN
modules/line_descriptor/samples/images/church.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
BIN
modules/line_descriptor/samples/images/church2.png
Normal file
BIN
modules/line_descriptor/samples/images/church2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 792 KiB |
BIN
modules/line_descriptor/samples/images/einstein.jpg
Normal file
BIN
modules/line_descriptor/samples/images/einstein.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
BIN
modules/line_descriptor/samples/images/stuff.jpg
Normal file
BIN
modules/line_descriptor/samples/images/stuff.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
169
modules/line_descriptor/samples/knn_matching.cpp
Normal file
169
modules/line_descriptor/samples/knn_matching.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
#include <opencv2/line_descriptor.hpp>
|
||||
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/core/private.hpp"
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/features2d.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
/* 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;
|
||||
for(int i = (int)bin_vector.size()-1; i>=0; i--)
|
||||
result += bin_vector[i]*pow(2, 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 (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);
|
||||
|
||||
/* visualize matches and Hamming distances */
|
||||
for(size_t v = 0; v<matches.size(); v++)
|
||||
{
|
||||
for(size_t m = 0; m<matches[v].size(); m++)
|
||||
{
|
||||
DMatch dm = matches[v][m];
|
||||
std::cout << dm.queryIdx << " " << dm.trainIdx << " "
|
||||
<< dm.distance << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -45,8 +45,6 @@ int main( int argc, char** argv )
|
||||
}
|
||||
|
||||
/* create a ramdom binary mask */
|
||||
// cv::Mat mask(imageMat.size(), CV_8UC1);
|
||||
// cv::randu(mask, Scalar::all(0), Scalar::all(1));
|
||||
cv::Mat mask = Mat::ones(imageMat.size(), CV_8UC1);
|
||||
|
||||
/* create a pointer to a BinaryDescriptor object with deafult parameters */
|
||||
|
@@ -26,19 +26,6 @@ static void help()
|
||||
|
||||
}
|
||||
|
||||
inline void writeMat(cv::Mat m, std::string name, int n)
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::string s;
|
||||
ss << n;
|
||||
ss >> s;
|
||||
std::string fileNameConf = name + s;
|
||||
cv::FileStorage fsConf(fileNameConf, cv::FileStorage::WRITE);
|
||||
fsConf << "m" << m;
|
||||
|
||||
fsConf.release();
|
||||
}
|
||||
|
||||
int main( int argc, char** argv )
|
||||
{
|
||||
/* get parameters from comand line */
|
||||
@@ -54,8 +41,10 @@ int main( int argc, char** argv )
|
||||
|
||||
|
||||
/* load image */
|
||||
cv::Mat imageMat1 = imread(image_path1, 0);
|
||||
cv::Mat imageMat2 = imread(image_path2, 0);
|
||||
cv::Mat imageMat1 = imread(image_path1, 1);
|
||||
cv::Mat imageMat2 = imread(image_path2, 1);
|
||||
|
||||
waitKey();
|
||||
if(imageMat1.data == NULL || imageMat2.data == NULL)
|
||||
{
|
||||
std::cout << "Error, images could not be loaded. Please, check their path"
|
||||
@@ -74,9 +63,6 @@ int main( int argc, char** argv )
|
||||
bd->detect(imageMat1, keylines1, mask1);
|
||||
bd->detect(imageMat2, keylines2, mask2);
|
||||
|
||||
std::cout << "lines " << keylines1.size() << " " << keylines2.size()
|
||||
<< std::endl;
|
||||
|
||||
/* compute descriptors */
|
||||
cv::Mat descr1, descr2;
|
||||
bd->compute(imageMat1, keylines1, descr1);
|
||||
@@ -88,58 +74,17 @@ int main( int argc, char** argv )
|
||||
/* require match */
|
||||
std::vector<DMatch> matches;
|
||||
bdm->match(descr1, descr2, matches);
|
||||
for(int x = 0; x<matches.size(); x++)
|
||||
std::cout << matches[x].queryIdx << " " << matches[x].trainIdx << std::endl;
|
||||
|
||||
/* result checkout */
|
||||
cv::Mat result(descr1.size(), CV_8UC1);
|
||||
std::cout << "size " << descr1.rows << " " << descr1.cols
|
||||
<< " " << descr2.rows << " " << descr2.cols << std::endl;
|
||||
// for(size_t i = 0; i<matches.size(); i++){
|
||||
// uchar* pointer = result.ptr(i);
|
||||
// uchar* trainPointer = descr2.ptr(matches[i].trainIdx);
|
||||
// *pointer = *trainPointer;
|
||||
// pointer++;
|
||||
// }
|
||||
/* plot matches */
|
||||
cv::Mat outImg;
|
||||
std::vector<char> mask (matches.size(), 1);
|
||||
drawLineMatches(imageMat1, keylines1, imageMat2, keylines2, matches,
|
||||
outImg, Scalar::all(-1), Scalar::all(-1), mask,
|
||||
DrawLinesMatchesFlags::DEFAULT);
|
||||
|
||||
|
||||
/* write matrices */
|
||||
writeMat(descr1, "descr1", 0);
|
||||
writeMat(result, "result", 0);
|
||||
std::cout << "num dmatch " << matches.size() << std::endl;
|
||||
imshow("Matches", outImg);
|
||||
waitKey();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
111
modules/line_descriptor/samples/radius_matching.cpp
Normal file
111
modules/line_descriptor/samples/radius_matching.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
#include <opencv2/line_descriptor.hpp>
|
||||
|
||||
#include "opencv2/core/utility.hpp"
|
||||
#include "opencv2/core/private.hpp"
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <opencv2/features2d.hpp>
|
||||
#include <opencv2/highgui.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using namespace cv;
|
||||
|
||||
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];
|
||||
|
||||
/* 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);
|
||||
|
||||
/* print matches */
|
||||
for(size_t q = 0; q<matches.size(); q++)
|
||||
{
|
||||
for(size_t m = 0; m<matches[q].size(); m++)
|
||||
{
|
||||
DMatch dm = matches[q][m];
|
||||
std::cout << "Descriptor: " << q << " Image: " << dm.imgIdx
|
||||
<< " Distance: " << dm.distance << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
@@ -306,6 +306,7 @@ void BinaryDescriptor::computeGaussianPyramid(const Mat& image)
|
||||
/* clear class fields */
|
||||
images_sizes.clear();
|
||||
octaveImages.clear();
|
||||
extractedLines.clear();
|
||||
|
||||
/* insert input image into pyramid */
|
||||
cv::Mat currentMat = image.clone();
|
||||
@@ -330,6 +331,17 @@ void BinaryDescriptor::detect( const Mat& image,
|
||||
CV_OUT std::vector<KeyLine>& keylines,
|
||||
const Mat& mask )
|
||||
{
|
||||
if(mask.data!=NULL && (mask.size() != image.size() || mask.type()!=CV_8UC1))
|
||||
{
|
||||
|
||||
std::cout << "Mask error while detecting lines: "
|
||||
<< "please check its dimensions and that data type is CV_8UC1"
|
||||
<< std::endl;
|
||||
|
||||
CV_Assert(false);
|
||||
}
|
||||
|
||||
else
|
||||
detectImpl(image, keylines, mask);
|
||||
}
|
||||
|
||||
@@ -342,15 +354,29 @@ void BinaryDescriptor::detect( const std::vector<Mat>& images,
|
||||
/* detect lines from each image */
|
||||
for(size_t counter = 0; counter<images.size(); counter++)
|
||||
{
|
||||
if(masks[counter].data!=NULL &&
|
||||
(masks[counter].size() != images[counter].size() ||
|
||||
masks[counter].type()!=CV_8UC1))
|
||||
{
|
||||
|
||||
std::cout << "Masks error while detecting lines: "
|
||||
<< "please check their dimensions and that data types are CV_8UC1"
|
||||
<< std::endl;
|
||||
|
||||
CV_Assert(false);
|
||||
}
|
||||
|
||||
detectImpl(images[counter],keylines[counter], masks[counter]);
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryDescriptor::detectImpl( const Mat& image,
|
||||
void BinaryDescriptor::detectImpl( const Mat& imageSrc,
|
||||
std::vector<KeyLine>& keylines,
|
||||
const Mat& mask ) const
|
||||
{
|
||||
|
||||
cv::Mat image;
|
||||
cvtColor(imageSrc, image, COLOR_BGR2GRAY);
|
||||
/*check whether image depth is different from 0 */
|
||||
if(image.depth() != 0)
|
||||
{
|
||||
@@ -408,15 +434,18 @@ void BinaryDescriptor::detectImpl( const Mat& image,
|
||||
|
||||
|
||||
/* delete undesired KeyLines, according to input mask */
|
||||
if(!mask.empty()){
|
||||
for(size_t keyCounter = 0; keyCounter<keylines.size(); keyCounter++)
|
||||
{
|
||||
KeyLine kl = keylines[keyCounter];
|
||||
if(mask.at<uchar>(kl.startPointX, kl.startPointY) == 0 &&
|
||||
mask.at<uchar>(kl.endPointX, kl.endPointY) == 0)
|
||||
if(mask.at<uchar>(kl.startPointY, kl.startPointX) == 0 &&
|
||||
mask.at<uchar>(kl.endPointY, kl.endPointX) == 0)
|
||||
keylines.erase(keylines.begin() + keyCounter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* requires descriptors computation (only one image) */
|
||||
@@ -438,10 +467,14 @@ void BinaryDescriptor::compute( const std::vector<Mat>& images,
|
||||
}
|
||||
|
||||
/* implementation of descriptors computation */
|
||||
void BinaryDescriptor::computeImpl( const Mat& image,
|
||||
void BinaryDescriptor::computeImpl( const Mat& imageSrc,
|
||||
std::vector<KeyLine>& keylines,
|
||||
Mat& descriptors ) const
|
||||
{
|
||||
/* convert input image to gray scale */
|
||||
cv::Mat image;
|
||||
cvtColor(imageSrc, image, COLOR_BGR2GRAY);
|
||||
|
||||
/*check whether image's depth is different from 0 */
|
||||
if(image.depth() != 0)
|
||||
{
|
||||
@@ -521,7 +554,7 @@ void BinaryDescriptor::computeImpl( const Mat& image,
|
||||
/* compute Gaussian pyramid, if image is new or pyramid was not
|
||||
computed before */
|
||||
BinaryDescriptor *bn = const_cast<BinaryDescriptor*>(this);
|
||||
if(octaveImages.size() == 0 || cv::countNonZero(image != octaveImages[0]) != 0)
|
||||
/* all structures cleared in computeGaussianPyramid */
|
||||
bn->computeGaussianPyramid(image);
|
||||
|
||||
/* compute Sobel's derivatives */
|
||||
@@ -588,7 +621,7 @@ int BinaryDescriptor::OctaveKeyLines(ScaleLines &keyLines)
|
||||
cv::Mat currentScaledImage = octaveImages[scaleCounter];
|
||||
|
||||
/* create an LSD detector and store a pointer to it */
|
||||
cv::Ptr<cv::LineSegmentDetector> ls = cv::createLineSegmentDetector(cv::LSD_REFINE_STD);
|
||||
cv::Ptr<cv::LineSegmentDetector> ls = cv::createLineSegmentDetector(cv::LSD_REFINE_ADV);
|
||||
|
||||
/* prepare a vector to host extracted segments */
|
||||
std::vector<cv::Vec4i> lines_std;
|
||||
@@ -602,6 +635,7 @@ int BinaryDescriptor::OctaveKeyLines(ScaleLines &keyLines)
|
||||
/* update lines counter */
|
||||
numOfFinalLine += lines_std.size();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* prepare a vector to store octave information associated to extracted lines */
|
||||
|
@@ -2,14 +2,154 @@
|
||||
|
||||
using namespace cv;
|
||||
|
||||
/* constructor */
|
||||
BinaryDescriptorMatcher::BinaryDescriptorMatcher()
|
||||
{
|
||||
dataset = new Mihasher(256, 32);
|
||||
nextAddedIndex = 0;
|
||||
numImages = 0;
|
||||
descrInDS = 0;
|
||||
}
|
||||
|
||||
/* constructor with smart pointer */
|
||||
Ptr<BinaryDescriptorMatcher> BinaryDescriptorMatcher::createBinaryDescriptorMatcher()
|
||||
{
|
||||
return Ptr<BinaryDescriptorMatcher>(new BinaryDescriptorMatcher());
|
||||
}
|
||||
|
||||
void BinaryDescriptorMatcher::read( const FileNode& ){}
|
||||
void BinaryDescriptorMatcher::write( FileStorage& ) const{}
|
||||
/* 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 = 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 = 0;
|
||||
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<(*(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(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;
|
||||
}
|
||||
|
||||
/* set number of requested matches to return for each query */
|
||||
dataset->setK(1);
|
||||
|
||||
/* add new descriptors to dataset, if needed */
|
||||
train();
|
||||
|
||||
/* 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::cout << "Error: mask " << itup->second << " in knnMatch function "
|
||||
<< "should have " << queryDescriptors.rows << " and "
|
||||
<< "1 column. Program will be terminated"
|
||||
<< std::endl;
|
||||
|
||||
CV_Assert(false);
|
||||
}
|
||||
|
||||
/* create a DMatch object if required by mask of 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 = 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,
|
||||
@@ -17,6 +157,17 @@ void BinaryDescriptorMatcher::match( const Mat& queryDescriptors,
|
||||
std::vector<DMatch>& matches,
|
||||
const Mat& mask ) const
|
||||
{
|
||||
|
||||
/* check data validity */
|
||||
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);
|
||||
|
||||
@@ -30,28 +181,378 @@ void BinaryDescriptorMatcher::match( const Mat& queryDescriptors,
|
||||
UINT32 * numres = new UINT32[(256+1)*(queryDescriptors.rows)];
|
||||
|
||||
/* execute query */
|
||||
mh->batchquery(results,
|
||||
numres,
|
||||
queryDescriptors,
|
||||
queryDescriptors.rows,
|
||||
queryDescriptors.cols);
|
||||
mh->batchquery(results, numres, queryDescriptors,
|
||||
queryDescriptors.rows, queryDescriptors.cols);
|
||||
|
||||
/* compose matches */
|
||||
for(size_t counter = 0; counter<queryDescriptors.rows; counter++)
|
||||
for(int counter = 0; counter<queryDescriptors.rows; counter++)
|
||||
{
|
||||
/* create a DMatch object if required by mask of if there is
|
||||
no mask at all */
|
||||
if( mask.empty() || (!mask.empty() && mask.at<int>(counter)!=0))
|
||||
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];
|
||||
dm.trainIdx = results[counter] - 1;
|
||||
dm.imgIdx = 0;
|
||||
dm.distance = numres[counter];
|
||||
dm.distance = 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(!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 = 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(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;
|
||||
}
|
||||
|
||||
/* set number of requested matches to return for each query */
|
||||
dataset->setK(k);
|
||||
|
||||
/* add new descriptors to dataset, if needed */
|
||||
train();
|
||||
|
||||
/* 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 = 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(!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();
|
||||
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 = 0; j<index+trainDescriptors.rows; j++)
|
||||
{
|
||||
if(numres[j] <= maxDistance)
|
||||
{
|
||||
if(mask.empty() || mask.at<uchar>(i) != 0){
|
||||
DMatch dm;
|
||||
dm.queryIdx = i;
|
||||
dm.trainIdx = results[j] - 1;
|
||||
dm.imgIdx = 0;
|
||||
dm.distance = 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 desciptor, find all the ones falling in a
|
||||
certaing atching 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(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 = 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;
|
||||
|
||||
}
|
||||
|
142
modules/line_descriptor/src/draw.cpp
Normal file
142
modules/line_descriptor/src/draw.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
#include "precomp.hpp"
|
||||
|
||||
namespace cv
|
||||
{
|
||||
/* 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 )
|
||||
{
|
||||
|
||||
/* 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 (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,Point(k1.startPointX, k1.startPointY),
|
||||
Point(k1.endPointX, k1.endPointY), singleLineColorRGB, 2);
|
||||
}
|
||||
|
||||
for(size_t j = 0; j<keylines2.size(); j++)
|
||||
{
|
||||
KeyLine k2 = keylines2[j];
|
||||
line(outImg,Point(k2.startPointX+offset, k2.startPointY),
|
||||
Point(k2.endPointX+offset, k2.endPointY), 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, Point(left.startPointX, left.startPointY),
|
||||
Point(left.endPointX, left.endPointY), singleLineColorRGB, 2);
|
||||
|
||||
line(outImg, Point(right.startPointX+offset, right.startPointY),
|
||||
Point(right.endPointX+offset, right.endPointY), singleLineColorRGB, 2);
|
||||
|
||||
/* link correspondent lines */
|
||||
line(outImg, Point(left.startPointX, left.startPointY),
|
||||
Point(right.startPointX+offset, right.startPointY), 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, Point(k.startPointX, k.startPointY),
|
||||
Point(k.endPointX, k.endPointY), lineColor, 1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -45,11 +45,13 @@ namespace cv
|
||||
{
|
||||
|
||||
CV_INIT_ALGORITHM(BinaryDescriptor, "BINARY.DESCRIPTOR",);
|
||||
CV_INIT_ALGORITHM(BinaryDescriptorMatcher, "BINARY.DESCRIPTOR.MATCHER",);
|
||||
|
||||
bool initModule_line_descriptor(void)
|
||||
{
|
||||
bool all = true;
|
||||
all &= !BinaryDescriptor_info_auto.name().empty();
|
||||
all &= !BinaryDescriptorMatcher_info_auto.name().empty();
|
||||
|
||||
return all;
|
||||
}
|
||||
|
Reference in New Issue
Block a user