Commit d191729b authored by biagio montesano's avatar biagio montesano

Matcher functionalities' tests completed

parent 3b207a77
......@@ -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 */
......
#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++;
// }
/* write matrices */
writeMat(descr1, "descr1", 0);
writeMat(result, "result", 0);
}
/* 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);
std::cout << "num dmatch " << matches.size() << std::endl;
imshow("Matches", outImg);
waitKey();
}
#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,13 +434,16 @@ 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);
}
}
}
......@@ -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 */
......
#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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment