refactored features2d and sample on matching to many images
This commit is contained in:
parent
cf0d9da643
commit
e406dfee44
File diff suppressed because it is too large
Load Diff
@ -46,6 +46,12 @@ using namespace std;
|
|||||||
namespace cv
|
namespace cv
|
||||||
{
|
{
|
||||||
|
|
||||||
|
BOWTrainer::BOWTrainer()
|
||||||
|
{}
|
||||||
|
|
||||||
|
BOWTrainer::~BOWTrainer()
|
||||||
|
{}
|
||||||
|
|
||||||
void BOWTrainer::add( const Mat& _descriptors )
|
void BOWTrainer::add( const Mat& _descriptors )
|
||||||
{
|
{
|
||||||
CV_Assert( !_descriptors.empty() );
|
CV_Assert( !_descriptors.empty() );
|
||||||
@ -63,6 +69,16 @@ void BOWTrainer::add( const Mat& _descriptors )
|
|||||||
descriptors.push_back(_descriptors);
|
descriptors.push_back(_descriptors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const vector<Mat>& BOWTrainer::getDescriptors() const
|
||||||
|
{
|
||||||
|
return descriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BOWTrainer::descripotorsCount() const
|
||||||
|
{
|
||||||
|
return descriptors.empty() ? 0 : size;
|
||||||
|
}
|
||||||
|
|
||||||
void BOWTrainer::clear()
|
void BOWTrainer::clear()
|
||||||
{
|
{
|
||||||
descriptors.clear();
|
descriptors.clear();
|
||||||
@ -91,6 +107,9 @@ Mat BOWKMeansTrainer::cluster() const
|
|||||||
return cluster( mergedDescriptors );
|
return cluster( mergedDescriptors );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOWKMeansTrainer::~BOWKMeansTrainer()
|
||||||
|
{}
|
||||||
|
|
||||||
Mat BOWKMeansTrainer::cluster( const Mat& descriptors ) const
|
Mat BOWKMeansTrainer::cluster( const Mat& descriptors ) const
|
||||||
{
|
{
|
||||||
Mat labels, vocabulary;
|
Mat labels, vocabulary;
|
||||||
@ -104,6 +123,9 @@ BOWImgDescriptorExtractor::BOWImgDescriptorExtractor( const Ptr<DescriptorExtrac
|
|||||||
dextractor(_dextractor), dmatcher(_dmatcher)
|
dextractor(_dextractor), dmatcher(_dmatcher)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
BOWImgDescriptorExtractor::~BOWImgDescriptorExtractor()
|
||||||
|
{}
|
||||||
|
|
||||||
void BOWImgDescriptorExtractor::setVocabulary( const Mat& _vocabulary )
|
void BOWImgDescriptorExtractor::setVocabulary( const Mat& _vocabulary )
|
||||||
{
|
{
|
||||||
dmatcher->clear();
|
dmatcher->clear();
|
||||||
@ -111,6 +133,11 @@ void BOWImgDescriptorExtractor::setVocabulary( const Mat& _vocabulary )
|
|||||||
dmatcher->add( vector<Mat>(1, vocabulary) );
|
dmatcher->add( vector<Mat>(1, vocabulary) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Mat& BOWImgDescriptorExtractor::getVocabulary() const
|
||||||
|
{
|
||||||
|
return vocabulary;
|
||||||
|
}
|
||||||
|
|
||||||
void BOWImgDescriptorExtractor::compute( const Mat& image, vector<KeyPoint>& keypoints, Mat& imgDescriptor,
|
void BOWImgDescriptorExtractor::compute( const Mat& image, vector<KeyPoint>& keypoints, Mat& imgDescriptor,
|
||||||
vector<vector<int> >* pointIdxsOfClusters, Mat* _descriptors )
|
vector<vector<int> >* pointIdxsOfClusters, Mat* _descriptors )
|
||||||
{
|
{
|
||||||
@ -153,4 +180,14 @@ void BOWImgDescriptorExtractor::compute( const Mat& image, vector<KeyPoint>& key
|
|||||||
imgDescriptor /= descriptors.rows;
|
imgDescriptor /= descriptors.rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int BOWImgDescriptorExtractor::descriptorSize() const
|
||||||
|
{
|
||||||
|
return vocabulary.empty() ? 0 : vocabulary.rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BOWImgDescriptorExtractor::descriptorType() const
|
||||||
|
{
|
||||||
|
return CV_32FC1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -44,78 +44,101 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace cv;
|
||||||
|
|
||||||
|
inline int smoothedSum(const Mat& sum, const KeyPoint& pt, int y, int x)
|
||||||
|
{
|
||||||
|
static const int HALF_KERNEL = BriefDescriptorExtractor::KERNEL_SIZE / 2;
|
||||||
|
|
||||||
|
int img_y = (int)(pt.pt.y + 0.5) + y;
|
||||||
|
int img_x = (int)(pt.pt.x + 0.5) + x;
|
||||||
|
return sum.at<int>(img_y + HALF_KERNEL + 1, img_x + HALF_KERNEL + 1)
|
||||||
|
- sum.at<int>(img_y + HALF_KERNEL + 1, img_x - HALF_KERNEL)
|
||||||
|
- sum.at<int>(img_y - HALF_KERNEL, img_x + HALF_KERNEL + 1)
|
||||||
|
+ sum.at<int>(img_y - HALF_KERNEL, img_x - HALF_KERNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pixelTests16(const Mat& sum, const std::vector<KeyPoint>& keypoints, Mat& descriptors)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)keypoints.size(); ++i)
|
||||||
|
{
|
||||||
|
uchar* desc = descriptors.ptr(i);
|
||||||
|
const KeyPoint& pt = keypoints[i];
|
||||||
|
#include "generated_16.i"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pixelTests32(const Mat& sum, const std::vector<KeyPoint>& keypoints, Mat& descriptors)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)keypoints.size(); ++i)
|
||||||
|
{
|
||||||
|
uchar* desc = descriptors.ptr(i);
|
||||||
|
const KeyPoint& pt = keypoints[i];
|
||||||
|
|
||||||
|
#include "generated_32.i"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pixelTests64(const Mat& sum, const std::vector<KeyPoint>& keypoints, Mat& descriptors)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)keypoints.size(); ++i)
|
||||||
|
{
|
||||||
|
uchar* desc = descriptors.ptr(i);
|
||||||
|
const KeyPoint& pt = keypoints[i];
|
||||||
|
|
||||||
|
#include "generated_64.i"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace cv
|
namespace cv
|
||||||
{
|
{
|
||||||
|
|
||||||
BriefDescriptorExtractor::BriefDescriptorExtractor(int bytes) :
|
BriefDescriptorExtractor::BriefDescriptorExtractor(int bytes) :
|
||||||
bytes_(bytes), test_fn_(NULL)
|
bytes_(bytes), test_fn_(NULL)
|
||||||
{
|
{
|
||||||
switch (bytes)
|
switch (bytes)
|
||||||
{
|
{
|
||||||
case 16:
|
case 16:
|
||||||
test_fn_ = pixelTests16;
|
test_fn_ = pixelTests16;
|
||||||
break;
|
break;
|
||||||
case 32:
|
case 32:
|
||||||
test_fn_ = pixelTests32;
|
test_fn_ = pixelTests32;
|
||||||
break;
|
break;
|
||||||
case 64:
|
case 64:
|
||||||
test_fn_ = pixelTests64;
|
test_fn_ = pixelTests64;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
CV_Error(CV_StsBadArg, "bytes must be 16, 32, or 64");
|
CV_Error(CV_StsBadArg, "bytes must be 16, 32, or 64");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BriefDescriptorExtractor::compute(const Mat& image, std::vector<KeyPoint>& keypoints, Mat& descriptors) const
|
int BriefDescriptorExtractor::descriptorSize() const
|
||||||
{
|
{
|
||||||
// Construct integral image for fast smoothing (box filter)
|
return bytes_;
|
||||||
Mat sum;
|
|
||||||
|
|
||||||
///TODO allow the user to pass in a precomputed integral image
|
|
||||||
//if(image.type() == CV_32S)
|
|
||||||
// sum = image;
|
|
||||||
//else
|
|
||||||
|
|
||||||
integral(image, sum, CV_32S);
|
|
||||||
|
|
||||||
//Remove keypoints very close to the border
|
|
||||||
removeBorderKeypoints(keypoints, image.size(), PATCH_SIZE/2 + KERNEL_SIZE/2);
|
|
||||||
|
|
||||||
descriptors = Mat::zeros(keypoints.size(), bytes_, CV_8U);
|
|
||||||
test_fn_(sum, keypoints, descriptors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BriefDescriptorExtractor::pixelTests16(const Mat& sum, const std::vector<KeyPoint>& keypoints, Mat& descriptors)
|
int BriefDescriptorExtractor::descriptorType() const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < (int)keypoints.size(); ++i)
|
return CV_8UC1;
|
||||||
{
|
|
||||||
uchar* desc = descriptors.ptr(i);
|
|
||||||
const KeyPoint& pt = keypoints[i];
|
|
||||||
|
|
||||||
#include "generated_16.i"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BriefDescriptorExtractor::pixelTests32(const Mat& sum, const std::vector<KeyPoint>& keypoints, Mat& descriptors)
|
void BriefDescriptorExtractor::computeImpl(const Mat& image, std::vector<KeyPoint>& keypoints, Mat& descriptors) const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < (int)keypoints.size(); ++i)
|
// Construct integral image for fast smoothing (box filter)
|
||||||
{
|
Mat sum;
|
||||||
uchar* desc = descriptors.ptr(i);
|
|
||||||
const KeyPoint& pt = keypoints[i];
|
|
||||||
|
|
||||||
#include "generated_32.i"
|
///TODO allow the user to pass in a precomputed integral image
|
||||||
}
|
//if(image.type() == CV_32S)
|
||||||
}
|
// sum = image;
|
||||||
|
//else
|
||||||
|
|
||||||
void BriefDescriptorExtractor::pixelTests64(const Mat& sum, const std::vector<KeyPoint>& keypoints, Mat& descriptors)
|
integral(image, sum, CV_32S);
|
||||||
{
|
|
||||||
for (int i = 0; i < (int)keypoints.size(); ++i)
|
|
||||||
{
|
|
||||||
uchar* desc = descriptors.ptr(i);
|
|
||||||
const KeyPoint& pt = keypoints[i];
|
|
||||||
|
|
||||||
#include "generated_64.i"
|
//Remove keypoints very close to the border
|
||||||
}
|
removeBorderKeypoints(keypoints, image.size(), PATCH_SIZE/2 + KERNEL_SIZE/2);
|
||||||
|
|
||||||
|
descriptors = Mat::zeros(keypoints.size(), bytes_, CV_8U);
|
||||||
|
test_fn_(sum, keypoints, descriptors);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -125,282 +148,285 @@ void BriefDescriptorExtractor::pixelTests64(const Mat& sum, const std::vector<Ke
|
|||||||
template<unsigned char b>
|
template<unsigned char b>
|
||||||
struct ByteBits
|
struct ByteBits
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* number of bits in the byte given by the template constant
|
* number of bits in the byte given by the template constant
|
||||||
*/
|
*/
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
COUNT = ((b >> 0) & 1) +
|
COUNT = ((b >> 0) & 1) +
|
||||||
((b >> 1) & 1) +
|
((b >> 1) & 1) +
|
||||||
((b >> 2) & 1) +
|
((b >> 2) & 1) +
|
||||||
((b >> 3) & 1) +
|
((b >> 3) & 1) +
|
||||||
((b >> 4) & 1) +
|
((b >> 4) & 1) +
|
||||||
((b >> 5) & 1) +
|
((b >> 5) & 1) +
|
||||||
((b >> 6) & 1) +
|
((b >> 6) & 1) +
|
||||||
((b >> 7) & 1)
|
((b >> 7) & 1)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
unsigned char HammingLUT::byteBitsLookUp(unsigned char b){
|
|
||||||
static const unsigned char table[256] =
|
unsigned char HammingLUT::byteBitsLookUp(unsigned char b)
|
||||||
{
|
{
|
||||||
ByteBits<0>::COUNT,
|
static const unsigned char table[256] =
|
||||||
ByteBits<1>::COUNT,
|
{
|
||||||
ByteBits<2>::COUNT,
|
ByteBits<0>::COUNT,
|
||||||
ByteBits<3>::COUNT,
|
ByteBits<1>::COUNT,
|
||||||
ByteBits<4>::COUNT,
|
ByteBits<2>::COUNT,
|
||||||
ByteBits<5>::COUNT,
|
ByteBits<3>::COUNT,
|
||||||
ByteBits<6>::COUNT,
|
ByteBits<4>::COUNT,
|
||||||
ByteBits<7>::COUNT,
|
ByteBits<5>::COUNT,
|
||||||
ByteBits<8>::COUNT,
|
ByteBits<6>::COUNT,
|
||||||
ByteBits<9>::COUNT,
|
ByteBits<7>::COUNT,
|
||||||
ByteBits<10>::COUNT,
|
ByteBits<8>::COUNT,
|
||||||
ByteBits<11>::COUNT,
|
ByteBits<9>::COUNT,
|
||||||
ByteBits<12>::COUNT,
|
ByteBits<10>::COUNT,
|
||||||
ByteBits<13>::COUNT,
|
ByteBits<11>::COUNT,
|
||||||
ByteBits<14>::COUNT,
|
ByteBits<12>::COUNT,
|
||||||
ByteBits<15>::COUNT,
|
ByteBits<13>::COUNT,
|
||||||
ByteBits<16>::COUNT,
|
ByteBits<14>::COUNT,
|
||||||
ByteBits<17>::COUNT,
|
ByteBits<15>::COUNT,
|
||||||
ByteBits<18>::COUNT,
|
ByteBits<16>::COUNT,
|
||||||
ByteBits<19>::COUNT,
|
ByteBits<17>::COUNT,
|
||||||
ByteBits<20>::COUNT,
|
ByteBits<18>::COUNT,
|
||||||
ByteBits<21>::COUNT,
|
ByteBits<19>::COUNT,
|
||||||
ByteBits<22>::COUNT,
|
ByteBits<20>::COUNT,
|
||||||
ByteBits<23>::COUNT,
|
ByteBits<21>::COUNT,
|
||||||
ByteBits<24>::COUNT,
|
ByteBits<22>::COUNT,
|
||||||
ByteBits<25>::COUNT,
|
ByteBits<23>::COUNT,
|
||||||
ByteBits<26>::COUNT,
|
ByteBits<24>::COUNT,
|
||||||
ByteBits<27>::COUNT,
|
ByteBits<25>::COUNT,
|
||||||
ByteBits<28>::COUNT,
|
ByteBits<26>::COUNT,
|
||||||
ByteBits<29>::COUNT,
|
ByteBits<27>::COUNT,
|
||||||
ByteBits<30>::COUNT,
|
ByteBits<28>::COUNT,
|
||||||
ByteBits<31>::COUNT,
|
ByteBits<29>::COUNT,
|
||||||
ByteBits<32>::COUNT,
|
ByteBits<30>::COUNT,
|
||||||
ByteBits<33>::COUNT,
|
ByteBits<31>::COUNT,
|
||||||
ByteBits<34>::COUNT,
|
ByteBits<32>::COUNT,
|
||||||
ByteBits<35>::COUNT,
|
ByteBits<33>::COUNT,
|
||||||
ByteBits<36>::COUNT,
|
ByteBits<34>::COUNT,
|
||||||
ByteBits<37>::COUNT,
|
ByteBits<35>::COUNT,
|
||||||
ByteBits<38>::COUNT,
|
ByteBits<36>::COUNT,
|
||||||
ByteBits<39>::COUNT,
|
ByteBits<37>::COUNT,
|
||||||
ByteBits<40>::COUNT,
|
ByteBits<38>::COUNT,
|
||||||
ByteBits<41>::COUNT,
|
ByteBits<39>::COUNT,
|
||||||
ByteBits<42>::COUNT,
|
ByteBits<40>::COUNT,
|
||||||
ByteBits<43>::COUNT,
|
ByteBits<41>::COUNT,
|
||||||
ByteBits<44>::COUNT,
|
ByteBits<42>::COUNT,
|
||||||
ByteBits<45>::COUNT,
|
ByteBits<43>::COUNT,
|
||||||
ByteBits<46>::COUNT,
|
ByteBits<44>::COUNT,
|
||||||
ByteBits<47>::COUNT,
|
ByteBits<45>::COUNT,
|
||||||
ByteBits<48>::COUNT,
|
ByteBits<46>::COUNT,
|
||||||
ByteBits<49>::COUNT,
|
ByteBits<47>::COUNT,
|
||||||
ByteBits<50>::COUNT,
|
ByteBits<48>::COUNT,
|
||||||
ByteBits<51>::COUNT,
|
ByteBits<49>::COUNT,
|
||||||
ByteBits<52>::COUNT,
|
ByteBits<50>::COUNT,
|
||||||
ByteBits<53>::COUNT,
|
ByteBits<51>::COUNT,
|
||||||
ByteBits<54>::COUNT,
|
ByteBits<52>::COUNT,
|
||||||
ByteBits<55>::COUNT,
|
ByteBits<53>::COUNT,
|
||||||
ByteBits<56>::COUNT,
|
ByteBits<54>::COUNT,
|
||||||
ByteBits<57>::COUNT,
|
ByteBits<55>::COUNT,
|
||||||
ByteBits<58>::COUNT,
|
ByteBits<56>::COUNT,
|
||||||
ByteBits<59>::COUNT,
|
ByteBits<57>::COUNT,
|
||||||
ByteBits<60>::COUNT,
|
ByteBits<58>::COUNT,
|
||||||
ByteBits<61>::COUNT,
|
ByteBits<59>::COUNT,
|
||||||
ByteBits<62>::COUNT,
|
ByteBits<60>::COUNT,
|
||||||
ByteBits<63>::COUNT,
|
ByteBits<61>::COUNT,
|
||||||
ByteBits<64>::COUNT,
|
ByteBits<62>::COUNT,
|
||||||
ByteBits<65>::COUNT,
|
ByteBits<63>::COUNT,
|
||||||
ByteBits<66>::COUNT,
|
ByteBits<64>::COUNT,
|
||||||
ByteBits<67>::COUNT,
|
ByteBits<65>::COUNT,
|
||||||
ByteBits<68>::COUNT,
|
ByteBits<66>::COUNT,
|
||||||
ByteBits<69>::COUNT,
|
ByteBits<67>::COUNT,
|
||||||
ByteBits<70>::COUNT,
|
ByteBits<68>::COUNT,
|
||||||
ByteBits<71>::COUNT,
|
ByteBits<69>::COUNT,
|
||||||
ByteBits<72>::COUNT,
|
ByteBits<70>::COUNT,
|
||||||
ByteBits<73>::COUNT,
|
ByteBits<71>::COUNT,
|
||||||
ByteBits<74>::COUNT,
|
ByteBits<72>::COUNT,
|
||||||
ByteBits<75>::COUNT,
|
ByteBits<73>::COUNT,
|
||||||
ByteBits<76>::COUNT,
|
ByteBits<74>::COUNT,
|
||||||
ByteBits<77>::COUNT,
|
ByteBits<75>::COUNT,
|
||||||
ByteBits<78>::COUNT,
|
ByteBits<76>::COUNT,
|
||||||
ByteBits<79>::COUNT,
|
ByteBits<77>::COUNT,
|
||||||
ByteBits<80>::COUNT,
|
ByteBits<78>::COUNT,
|
||||||
ByteBits<81>::COUNT,
|
ByteBits<79>::COUNT,
|
||||||
ByteBits<82>::COUNT,
|
ByteBits<80>::COUNT,
|
||||||
ByteBits<83>::COUNT,
|
ByteBits<81>::COUNT,
|
||||||
ByteBits<84>::COUNT,
|
ByteBits<82>::COUNT,
|
||||||
ByteBits<85>::COUNT,
|
ByteBits<83>::COUNT,
|
||||||
ByteBits<86>::COUNT,
|
ByteBits<84>::COUNT,
|
||||||
ByteBits<87>::COUNT,
|
ByteBits<85>::COUNT,
|
||||||
ByteBits<88>::COUNT,
|
ByteBits<86>::COUNT,
|
||||||
ByteBits<89>::COUNT,
|
ByteBits<87>::COUNT,
|
||||||
ByteBits<90>::COUNT,
|
ByteBits<88>::COUNT,
|
||||||
ByteBits<91>::COUNT,
|
ByteBits<89>::COUNT,
|
||||||
ByteBits<92>::COUNT,
|
ByteBits<90>::COUNT,
|
||||||
ByteBits<93>::COUNT,
|
ByteBits<91>::COUNT,
|
||||||
ByteBits<94>::COUNT,
|
ByteBits<92>::COUNT,
|
||||||
ByteBits<95>::COUNT,
|
ByteBits<93>::COUNT,
|
||||||
ByteBits<96>::COUNT,
|
ByteBits<94>::COUNT,
|
||||||
ByteBits<97>::COUNT,
|
ByteBits<95>::COUNT,
|
||||||
ByteBits<98>::COUNT,
|
ByteBits<96>::COUNT,
|
||||||
ByteBits<99>::COUNT,
|
ByteBits<97>::COUNT,
|
||||||
ByteBits<100>::COUNT,
|
ByteBits<98>::COUNT,
|
||||||
ByteBits<101>::COUNT,
|
ByteBits<99>::COUNT,
|
||||||
ByteBits<102>::COUNT,
|
ByteBits<100>::COUNT,
|
||||||
ByteBits<103>::COUNT,
|
ByteBits<101>::COUNT,
|
||||||
ByteBits<104>::COUNT,
|
ByteBits<102>::COUNT,
|
||||||
ByteBits<105>::COUNT,
|
ByteBits<103>::COUNT,
|
||||||
ByteBits<106>::COUNT,
|
ByteBits<104>::COUNT,
|
||||||
ByteBits<107>::COUNT,
|
ByteBits<105>::COUNT,
|
||||||
ByteBits<108>::COUNT,
|
ByteBits<106>::COUNT,
|
||||||
ByteBits<109>::COUNT,
|
ByteBits<107>::COUNT,
|
||||||
ByteBits<110>::COUNT,
|
ByteBits<108>::COUNT,
|
||||||
ByteBits<111>::COUNT,
|
ByteBits<109>::COUNT,
|
||||||
ByteBits<112>::COUNT,
|
ByteBits<110>::COUNT,
|
||||||
ByteBits<113>::COUNT,
|
ByteBits<111>::COUNT,
|
||||||
ByteBits<114>::COUNT,
|
ByteBits<112>::COUNT,
|
||||||
ByteBits<115>::COUNT,
|
ByteBits<113>::COUNT,
|
||||||
ByteBits<116>::COUNT,
|
ByteBits<114>::COUNT,
|
||||||
ByteBits<117>::COUNT,
|
ByteBits<115>::COUNT,
|
||||||
ByteBits<118>::COUNT,
|
ByteBits<116>::COUNT,
|
||||||
ByteBits<119>::COUNT,
|
ByteBits<117>::COUNT,
|
||||||
ByteBits<120>::COUNT,
|
ByteBits<118>::COUNT,
|
||||||
ByteBits<121>::COUNT,
|
ByteBits<119>::COUNT,
|
||||||
ByteBits<122>::COUNT,
|
ByteBits<120>::COUNT,
|
||||||
ByteBits<123>::COUNT,
|
ByteBits<121>::COUNT,
|
||||||
ByteBits<124>::COUNT,
|
ByteBits<122>::COUNT,
|
||||||
ByteBits<125>::COUNT,
|
ByteBits<123>::COUNT,
|
||||||
ByteBits<126>::COUNT,
|
ByteBits<124>::COUNT,
|
||||||
ByteBits<127>::COUNT,
|
ByteBits<125>::COUNT,
|
||||||
ByteBits<128>::COUNT,
|
ByteBits<126>::COUNT,
|
||||||
ByteBits<129>::COUNT,
|
ByteBits<127>::COUNT,
|
||||||
ByteBits<130>::COUNT,
|
ByteBits<128>::COUNT,
|
||||||
ByteBits<131>::COUNT,
|
ByteBits<129>::COUNT,
|
||||||
ByteBits<132>::COUNT,
|
ByteBits<130>::COUNT,
|
||||||
ByteBits<133>::COUNT,
|
ByteBits<131>::COUNT,
|
||||||
ByteBits<134>::COUNT,
|
ByteBits<132>::COUNT,
|
||||||
ByteBits<135>::COUNT,
|
ByteBits<133>::COUNT,
|
||||||
ByteBits<136>::COUNT,
|
ByteBits<134>::COUNT,
|
||||||
ByteBits<137>::COUNT,
|
ByteBits<135>::COUNT,
|
||||||
ByteBits<138>::COUNT,
|
ByteBits<136>::COUNT,
|
||||||
ByteBits<139>::COUNT,
|
ByteBits<137>::COUNT,
|
||||||
ByteBits<140>::COUNT,
|
ByteBits<138>::COUNT,
|
||||||
ByteBits<141>::COUNT,
|
ByteBits<139>::COUNT,
|
||||||
ByteBits<142>::COUNT,
|
ByteBits<140>::COUNT,
|
||||||
ByteBits<143>::COUNT,
|
ByteBits<141>::COUNT,
|
||||||
ByteBits<144>::COUNT,
|
ByteBits<142>::COUNT,
|
||||||
ByteBits<145>::COUNT,
|
ByteBits<143>::COUNT,
|
||||||
ByteBits<146>::COUNT,
|
ByteBits<144>::COUNT,
|
||||||
ByteBits<147>::COUNT,
|
ByteBits<145>::COUNT,
|
||||||
ByteBits<148>::COUNT,
|
ByteBits<146>::COUNT,
|
||||||
ByteBits<149>::COUNT,
|
ByteBits<147>::COUNT,
|
||||||
ByteBits<150>::COUNT,
|
ByteBits<148>::COUNT,
|
||||||
ByteBits<151>::COUNT,
|
ByteBits<149>::COUNT,
|
||||||
ByteBits<152>::COUNT,
|
ByteBits<150>::COUNT,
|
||||||
ByteBits<153>::COUNT,
|
ByteBits<151>::COUNT,
|
||||||
ByteBits<154>::COUNT,
|
ByteBits<152>::COUNT,
|
||||||
ByteBits<155>::COUNT,
|
ByteBits<153>::COUNT,
|
||||||
ByteBits<156>::COUNT,
|
ByteBits<154>::COUNT,
|
||||||
ByteBits<157>::COUNT,
|
ByteBits<155>::COUNT,
|
||||||
ByteBits<158>::COUNT,
|
ByteBits<156>::COUNT,
|
||||||
ByteBits<159>::COUNT,
|
ByteBits<157>::COUNT,
|
||||||
ByteBits<160>::COUNT,
|
ByteBits<158>::COUNT,
|
||||||
ByteBits<161>::COUNT,
|
ByteBits<159>::COUNT,
|
||||||
ByteBits<162>::COUNT,
|
ByteBits<160>::COUNT,
|
||||||
ByteBits<163>::COUNT,
|
ByteBits<161>::COUNT,
|
||||||
ByteBits<164>::COUNT,
|
ByteBits<162>::COUNT,
|
||||||
ByteBits<165>::COUNT,
|
ByteBits<163>::COUNT,
|
||||||
ByteBits<166>::COUNT,
|
ByteBits<164>::COUNT,
|
||||||
ByteBits<167>::COUNT,
|
ByteBits<165>::COUNT,
|
||||||
ByteBits<168>::COUNT,
|
ByteBits<166>::COUNT,
|
||||||
ByteBits<169>::COUNT,
|
ByteBits<167>::COUNT,
|
||||||
ByteBits<170>::COUNT,
|
ByteBits<168>::COUNT,
|
||||||
ByteBits<171>::COUNT,
|
ByteBits<169>::COUNT,
|
||||||
ByteBits<172>::COUNT,
|
ByteBits<170>::COUNT,
|
||||||
ByteBits<173>::COUNT,
|
ByteBits<171>::COUNT,
|
||||||
ByteBits<174>::COUNT,
|
ByteBits<172>::COUNT,
|
||||||
ByteBits<175>::COUNT,
|
ByteBits<173>::COUNT,
|
||||||
ByteBits<176>::COUNT,
|
ByteBits<174>::COUNT,
|
||||||
ByteBits<177>::COUNT,
|
ByteBits<175>::COUNT,
|
||||||
ByteBits<178>::COUNT,
|
ByteBits<176>::COUNT,
|
||||||
ByteBits<179>::COUNT,
|
ByteBits<177>::COUNT,
|
||||||
ByteBits<180>::COUNT,
|
ByteBits<178>::COUNT,
|
||||||
ByteBits<181>::COUNT,
|
ByteBits<179>::COUNT,
|
||||||
ByteBits<182>::COUNT,
|
ByteBits<180>::COUNT,
|
||||||
ByteBits<183>::COUNT,
|
ByteBits<181>::COUNT,
|
||||||
ByteBits<184>::COUNT,
|
ByteBits<182>::COUNT,
|
||||||
ByteBits<185>::COUNT,
|
ByteBits<183>::COUNT,
|
||||||
ByteBits<186>::COUNT,
|
ByteBits<184>::COUNT,
|
||||||
ByteBits<187>::COUNT,
|
ByteBits<185>::COUNT,
|
||||||
ByteBits<188>::COUNT,
|
ByteBits<186>::COUNT,
|
||||||
ByteBits<189>::COUNT,
|
ByteBits<187>::COUNT,
|
||||||
ByteBits<190>::COUNT,
|
ByteBits<188>::COUNT,
|
||||||
ByteBits<191>::COUNT,
|
ByteBits<189>::COUNT,
|
||||||
ByteBits<192>::COUNT,
|
ByteBits<190>::COUNT,
|
||||||
ByteBits<193>::COUNT,
|
ByteBits<191>::COUNT,
|
||||||
ByteBits<194>::COUNT,
|
ByteBits<192>::COUNT,
|
||||||
ByteBits<195>::COUNT,
|
ByteBits<193>::COUNT,
|
||||||
ByteBits<196>::COUNT,
|
ByteBits<194>::COUNT,
|
||||||
ByteBits<197>::COUNT,
|
ByteBits<195>::COUNT,
|
||||||
ByteBits<198>::COUNT,
|
ByteBits<196>::COUNT,
|
||||||
ByteBits<199>::COUNT,
|
ByteBits<197>::COUNT,
|
||||||
ByteBits<200>::COUNT,
|
ByteBits<198>::COUNT,
|
||||||
ByteBits<201>::COUNT,
|
ByteBits<199>::COUNT,
|
||||||
ByteBits<202>::COUNT,
|
ByteBits<200>::COUNT,
|
||||||
ByteBits<203>::COUNT,
|
ByteBits<201>::COUNT,
|
||||||
ByteBits<204>::COUNT,
|
ByteBits<202>::COUNT,
|
||||||
ByteBits<205>::COUNT,
|
ByteBits<203>::COUNT,
|
||||||
ByteBits<206>::COUNT,
|
ByteBits<204>::COUNT,
|
||||||
ByteBits<207>::COUNT,
|
ByteBits<205>::COUNT,
|
||||||
ByteBits<208>::COUNT,
|
ByteBits<206>::COUNT,
|
||||||
ByteBits<209>::COUNT,
|
ByteBits<207>::COUNT,
|
||||||
ByteBits<210>::COUNT,
|
ByteBits<208>::COUNT,
|
||||||
ByteBits<211>::COUNT,
|
ByteBits<209>::COUNT,
|
||||||
ByteBits<212>::COUNT,
|
ByteBits<210>::COUNT,
|
||||||
ByteBits<213>::COUNT,
|
ByteBits<211>::COUNT,
|
||||||
ByteBits<214>::COUNT,
|
ByteBits<212>::COUNT,
|
||||||
ByteBits<215>::COUNT,
|
ByteBits<213>::COUNT,
|
||||||
ByteBits<216>::COUNT,
|
ByteBits<214>::COUNT,
|
||||||
ByteBits<217>::COUNT,
|
ByteBits<215>::COUNT,
|
||||||
ByteBits<218>::COUNT,
|
ByteBits<216>::COUNT,
|
||||||
ByteBits<219>::COUNT,
|
ByteBits<217>::COUNT,
|
||||||
ByteBits<220>::COUNT,
|
ByteBits<218>::COUNT,
|
||||||
ByteBits<221>::COUNT,
|
ByteBits<219>::COUNT,
|
||||||
ByteBits<222>::COUNT,
|
ByteBits<220>::COUNT,
|
||||||
ByteBits<223>::COUNT,
|
ByteBits<221>::COUNT,
|
||||||
ByteBits<224>::COUNT,
|
ByteBits<222>::COUNT,
|
||||||
ByteBits<225>::COUNT,
|
ByteBits<223>::COUNT,
|
||||||
ByteBits<226>::COUNT,
|
ByteBits<224>::COUNT,
|
||||||
ByteBits<227>::COUNT,
|
ByteBits<225>::COUNT,
|
||||||
ByteBits<228>::COUNT,
|
ByteBits<226>::COUNT,
|
||||||
ByteBits<229>::COUNT,
|
ByteBits<227>::COUNT,
|
||||||
ByteBits<230>::COUNT,
|
ByteBits<228>::COUNT,
|
||||||
ByteBits<231>::COUNT,
|
ByteBits<229>::COUNT,
|
||||||
ByteBits<232>::COUNT,
|
ByteBits<230>::COUNT,
|
||||||
ByteBits<233>::COUNT,
|
ByteBits<231>::COUNT,
|
||||||
ByteBits<234>::COUNT,
|
ByteBits<232>::COUNT,
|
||||||
ByteBits<235>::COUNT,
|
ByteBits<233>::COUNT,
|
||||||
ByteBits<236>::COUNT,
|
ByteBits<234>::COUNT,
|
||||||
ByteBits<237>::COUNT,
|
ByteBits<235>::COUNT,
|
||||||
ByteBits<238>::COUNT,
|
ByteBits<236>::COUNT,
|
||||||
ByteBits<239>::COUNT,
|
ByteBits<237>::COUNT,
|
||||||
ByteBits<240>::COUNT,
|
ByteBits<238>::COUNT,
|
||||||
ByteBits<241>::COUNT,
|
ByteBits<239>::COUNT,
|
||||||
ByteBits<242>::COUNT,
|
ByteBits<240>::COUNT,
|
||||||
ByteBits<243>::COUNT,
|
ByteBits<241>::COUNT,
|
||||||
ByteBits<244>::COUNT,
|
ByteBits<242>::COUNT,
|
||||||
ByteBits<245>::COUNT,
|
ByteBits<243>::COUNT,
|
||||||
ByteBits<246>::COUNT,
|
ByteBits<244>::COUNT,
|
||||||
ByteBits<247>::COUNT,
|
ByteBits<245>::COUNT,
|
||||||
ByteBits<248>::COUNT,
|
ByteBits<246>::COUNT,
|
||||||
ByteBits<249>::COUNT,
|
ByteBits<247>::COUNT,
|
||||||
ByteBits<250>::COUNT,
|
ByteBits<248>::COUNT,
|
||||||
ByteBits<251>::COUNT,
|
ByteBits<249>::COUNT,
|
||||||
ByteBits<252>::COUNT,
|
ByteBits<250>::COUNT,
|
||||||
ByteBits<253>::COUNT,
|
ByteBits<251>::COUNT,
|
||||||
ByteBits<254>::COUNT,
|
ByteBits<252>::COUNT,
|
||||||
ByteBits<255>::COUNT
|
ByteBits<253>::COUNT,
|
||||||
};
|
ByteBits<254>::COUNT,
|
||||||
return table[b];
|
ByteBits<255>::COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
return table[b];
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace cv
|
} // namespace cv
|
||||||
|
@ -67,6 +67,21 @@ struct RoiPredicate
|
|||||||
float minX, minY, maxX, maxY;
|
float minX, minY, maxX, maxY;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DescriptorExtractor::~DescriptorExtractor()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void DescriptorExtractor::compute( const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors ) const
|
||||||
|
{
|
||||||
|
if( image.empty() || keypoints.empty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check keypoints are in image. Do filter bad points here?
|
||||||
|
//for( size_t i = 0; i < keypoints.size(); i++ )
|
||||||
|
// CV_Assert( Rect(0,0, image.cols, image.rows).contains(keypoints[i].pt) );
|
||||||
|
|
||||||
|
computeImpl( image, keypoints, descriptors );
|
||||||
|
}
|
||||||
|
|
||||||
void DescriptorExtractor::compute( const vector<Mat>& imageCollection, vector<vector<KeyPoint> >& pointCollection, vector<Mat>& descCollection ) const
|
void DescriptorExtractor::compute( const vector<Mat>& imageCollection, vector<vector<KeyPoint> >& pointCollection, vector<Mat>& descCollection ) const
|
||||||
{
|
{
|
||||||
descCollection.resize( imageCollection.size() );
|
descCollection.resize( imageCollection.size() );
|
||||||
@ -74,27 +89,42 @@ void DescriptorExtractor::compute( const vector<Mat>& imageCollection, vector<ve
|
|||||||
compute( imageCollection[i], pointCollection[i], descCollection[i] );
|
compute( imageCollection[i], pointCollection[i], descCollection[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DescriptorExtractor::read( const FileNode& )
|
||||||
|
{}
|
||||||
|
|
||||||
|
void DescriptorExtractor::write( FileStorage& ) const
|
||||||
|
{}
|
||||||
|
|
||||||
void DescriptorExtractor::removeBorderKeypoints( vector<KeyPoint>& keypoints,
|
void DescriptorExtractor::removeBorderKeypoints( vector<KeyPoint>& keypoints,
|
||||||
Size imageSize, int borderPixels )
|
Size imageSize, int borderSize )
|
||||||
{
|
{
|
||||||
keypoints.erase( remove_if(keypoints.begin(), keypoints.end(),
|
if( borderSize > 0)
|
||||||
RoiPredicate((float)borderPixels, (float)borderPixels,
|
{
|
||||||
(float)(imageSize.width - borderPixels),
|
keypoints.erase( remove_if(keypoints.begin(), keypoints.end(),
|
||||||
(float)(imageSize.height - borderPixels))),
|
RoiPredicate((float)borderSize, (float)borderSize,
|
||||||
keypoints.end());
|
(float)(imageSize.width - borderSize),
|
||||||
|
(float)(imageSize.height - borderSize))),
|
||||||
|
keypoints.end() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************\
|
/****************************************************************************************\
|
||||||
* SiftDescriptorExtractor *
|
* SiftDescriptorExtractor *
|
||||||
\****************************************************************************************/
|
\****************************************************************************************/
|
||||||
|
SiftDescriptorExtractor::SiftDescriptorExtractor(const SIFT::DescriptorParams& descriptorParams,
|
||||||
|
const SIFT::CommonParams& commonParams)
|
||||||
|
: sift( descriptorParams.magnification, descriptorParams.isNormalize, descriptorParams.recalculateAngles,
|
||||||
|
commonParams.nOctaves, commonParams.nOctaveLayers, commonParams.firstOctave, commonParams.angleMode )
|
||||||
|
{}
|
||||||
|
|
||||||
SiftDescriptorExtractor::SiftDescriptorExtractor( double magnification, bool isNormalize, bool recalculateAngles,
|
SiftDescriptorExtractor::SiftDescriptorExtractor( double magnification, bool isNormalize, bool recalculateAngles,
|
||||||
int nOctaves, int nOctaveLayers, int firstOctave, int angleMode )
|
int nOctaves, int nOctaveLayers, int firstOctave, int angleMode )
|
||||||
: sift( magnification, isNormalize, recalculateAngles, nOctaves, nOctaveLayers, firstOctave, angleMode )
|
: sift( magnification, isNormalize, recalculateAngles, nOctaves, nOctaveLayers, firstOctave, angleMode )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void SiftDescriptorExtractor::compute( const Mat& image,
|
void SiftDescriptorExtractor::computeImpl( const Mat& image,
|
||||||
vector<KeyPoint>& keypoints,
|
vector<KeyPoint>& keypoints,
|
||||||
Mat& descriptors) const
|
Mat& descriptors) const
|
||||||
{
|
{
|
||||||
bool useProvidedKeypoints = true;
|
bool useProvidedKeypoints = true;
|
||||||
Mat grayImage = image;
|
Mat grayImage = image;
|
||||||
@ -131,6 +161,16 @@ void SiftDescriptorExtractor::write (FileStorage &fs) const
|
|||||||
fs << "angleMode" << commParams.angleMode;
|
fs << "angleMode" << commParams.angleMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SiftDescriptorExtractor::descriptorSize() const
|
||||||
|
{
|
||||||
|
return sift.descriptorSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SiftDescriptorExtractor::descriptorType() const
|
||||||
|
{
|
||||||
|
return CV_32FC1;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************************\
|
/****************************************************************************************\
|
||||||
* SurfDescriptorExtractor *
|
* SurfDescriptorExtractor *
|
||||||
\****************************************************************************************/
|
\****************************************************************************************/
|
||||||
@ -139,9 +179,9 @@ SurfDescriptorExtractor::SurfDescriptorExtractor( int nOctaves,
|
|||||||
: surf( 0.0, nOctaves, nOctaveLayers, extended )
|
: surf( 0.0, nOctaves, nOctaveLayers, extended )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void SurfDescriptorExtractor::compute( const Mat& image,
|
void SurfDescriptorExtractor::computeImpl( const Mat& image,
|
||||||
vector<KeyPoint>& keypoints,
|
vector<KeyPoint>& keypoints,
|
||||||
Mat& descriptors) const
|
Mat& descriptors) const
|
||||||
{
|
{
|
||||||
// Compute descriptors for given keypoints
|
// Compute descriptors for given keypoints
|
||||||
vector<float> _descriptors;
|
vector<float> _descriptors;
|
||||||
@ -175,11 +215,21 @@ void SurfDescriptorExtractor::write( FileStorage &fs ) const
|
|||||||
fs << "extended" << surf.extended;
|
fs << "extended" << surf.extended;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SurfDescriptorExtractor::descriptorSize() const
|
||||||
|
{
|
||||||
|
return surf.descriptorSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SurfDescriptorExtractor::descriptorType() const
|
||||||
|
{
|
||||||
|
return CV_32FC1;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************************\
|
/****************************************************************************************\
|
||||||
* OpponentColorDescriptorExtractor *
|
* OpponentColorDescriptorExtractor *
|
||||||
\****************************************************************************************/
|
\****************************************************************************************/
|
||||||
OpponentColorDescriptorExtractor::OpponentColorDescriptorExtractor( const Ptr<DescriptorExtractor>& _dextractor ) :
|
OpponentColorDescriptorExtractor::OpponentColorDescriptorExtractor( const Ptr<DescriptorExtractor>& _descriptorExtractor ) :
|
||||||
dextractor(_dextractor)
|
descriptorExtractor(_descriptorExtractor)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void convertBGRImageToOpponentColorSpace( const Mat& bgrImage, vector<Mat>& opponentChannels )
|
void convertBGRImageToOpponentColorSpace( const Mat& bgrImage, vector<Mat>& opponentChannels )
|
||||||
@ -246,33 +296,42 @@ void convertBGRImageToOpponentColorSpace( const Mat& bgrImage, vector<Mat>& oppo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpponentColorDescriptorExtractor::compute( const Mat& bgrImage, vector<KeyPoint>& keypoints, Mat& descriptors ) const
|
void OpponentColorDescriptorExtractor::computeImpl( const Mat& bgrImage, vector<KeyPoint>& keypoints, Mat& descriptors ) const
|
||||||
{
|
{
|
||||||
vector<Mat> opponentChannels;
|
vector<Mat> opponentChannels;
|
||||||
convertBGRImageToOpponentColorSpace( bgrImage, opponentChannels );
|
convertBGRImageToOpponentColorSpace( bgrImage, opponentChannels );
|
||||||
|
|
||||||
// Compute descriptors three times, once for each Opponent channel
|
// Compute descriptors three times, once for each Opponent channel
|
||||||
// and concatenate into a single color surf descriptor
|
// and concatenate into a single color surf descriptor
|
||||||
int descriptorSize = dextractor->descriptorSize();
|
int descriptorSize = descriptorExtractor->descriptorSize();
|
||||||
descriptors.create( static_cast<int>(keypoints.size()), 3*descriptorSize, CV_32FC1 );
|
descriptors.create( static_cast<int>(keypoints.size()), 3*descriptorSize, CV_32FC1 );
|
||||||
for( int i = 0; i < 3/*channel count*/; i++ )
|
for( int i = 0; i < 3/*channel count*/; i++ )
|
||||||
{
|
{
|
||||||
CV_Assert( opponentChannels[i].type() == CV_8UC1 );
|
CV_Assert( opponentChannels[i].type() == CV_8UC1 );
|
||||||
Mat opponentDescriptors = descriptors.colRange( i*descriptorSize, (i+1)*descriptorSize );
|
Mat opponentDescriptors = descriptors.colRange( i*descriptorSize, (i+1)*descriptorSize );
|
||||||
dextractor->compute( opponentChannels[i], keypoints, opponentDescriptors );
|
descriptorExtractor->compute( opponentChannels[i], keypoints, opponentDescriptors );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpponentColorDescriptorExtractor::read( const FileNode& fn )
|
void OpponentColorDescriptorExtractor::read( const FileNode& fn )
|
||||||
{
|
{
|
||||||
dextractor->read( fn );
|
descriptorExtractor->read(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpponentColorDescriptorExtractor::write( FileStorage& fs ) const
|
void OpponentColorDescriptorExtractor::write( FileStorage& fs ) const
|
||||||
{
|
{
|
||||||
dextractor->write( fs );
|
descriptorExtractor->write(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int OpponentColorDescriptorExtractor::descriptorSize() const
|
||||||
|
{
|
||||||
|
return 3*descriptorExtractor->descriptorSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
int OpponentColorDescriptorExtractor::descriptorType() const
|
||||||
|
{
|
||||||
|
return descriptorExtractor->descriptorType();
|
||||||
|
}
|
||||||
/****************************************************************************************\
|
/****************************************************************************************\
|
||||||
* Factory function for descriptor extractor creating *
|
* Factory function for descriptor extractor creating *
|
||||||
\****************************************************************************************/
|
\****************************************************************************************/
|
||||||
|
@ -61,6 +61,21 @@ struct MaskPredicate
|
|||||||
const Mat& mask;
|
const Mat& mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
FeatureDetector::~FeatureDetector()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void FeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||||
|
{
|
||||||
|
keypoints.clear();
|
||||||
|
|
||||||
|
if( image.empty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) );
|
||||||
|
|
||||||
|
detectImpl( image, keypoints, mask );
|
||||||
|
}
|
||||||
|
|
||||||
void FeatureDetector::detect(const vector<Mat>& imageCollection, vector<vector<KeyPoint> >& pointCollection, const vector<Mat>& masks ) const
|
void FeatureDetector::detect(const vector<Mat>& imageCollection, vector<vector<KeyPoint> >& pointCollection, const vector<Mat>& masks ) const
|
||||||
{
|
{
|
||||||
pointCollection.resize( imageCollection.size() );
|
pointCollection.resize( imageCollection.size() );
|
||||||
@ -76,6 +91,12 @@ void FeatureDetector::removeInvalidPoints( const Mat& mask, vector<KeyPoint>& ke
|
|||||||
keypoints.erase(remove_if(keypoints.begin(), keypoints.end(), MaskPredicate(mask)), keypoints.end());
|
keypoints.erase(remove_if(keypoints.begin(), keypoints.end(), MaskPredicate(mask)), keypoints.end());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void FeatureDetector::read( const FileNode& )
|
||||||
|
{}
|
||||||
|
|
||||||
|
void FeatureDetector::write( FileStorage& ) const
|
||||||
|
{}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FastFeatureDetector
|
* FastFeatureDetector
|
||||||
*/
|
*/
|
||||||
@ -95,7 +116,7 @@ void FastFeatureDetector::write (FileStorage& fs) const
|
|||||||
fs << "nonmaxSuppression" << nonmaxSuppression;
|
fs << "nonmaxSuppression" << nonmaxSuppression;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FastFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
void FastFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||||
{
|
{
|
||||||
Mat grayImage = image;
|
Mat grayImage = image;
|
||||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||||
@ -106,14 +127,13 @@ void FastFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints,
|
|||||||
/*
|
/*
|
||||||
* GoodFeaturesToTrackDetector
|
* GoodFeaturesToTrackDetector
|
||||||
*/
|
*/
|
||||||
GoodFeaturesToTrackDetector::GoodFeaturesToTrackDetector( int _maxCorners, double _qualityLevel, \
|
GoodFeaturesToTrackDetector::Params::Params( int _maxCorners, double _qualityLevel, double _minDistance,
|
||||||
double _minDistance, int _blockSize,
|
int _blockSize, bool _useHarrisDetector, double _k ) :
|
||||||
bool _useHarrisDetector, double _k )
|
maxCorners(_maxCorners), qualityLevel(_qualityLevel), minDistance(_minDistance),
|
||||||
: maxCorners(_maxCorners), qualityLevel(_qualityLevel), minDistance(_minDistance),
|
blockSize(_blockSize), useHarrisDetector(_useHarrisDetector), k(_k)
|
||||||
blockSize(_blockSize), useHarrisDetector(_useHarrisDetector), k(_k)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void GoodFeaturesToTrackDetector::read (const FileNode& fn)
|
void GoodFeaturesToTrackDetector::Params::read (const FileNode& fn)
|
||||||
{
|
{
|
||||||
maxCorners = fn["maxCorners"];
|
maxCorners = fn["maxCorners"];
|
||||||
qualityLevel = fn["qualityLevel"];
|
qualityLevel = fn["qualityLevel"];
|
||||||
@ -123,7 +143,7 @@ void GoodFeaturesToTrackDetector::read (const FileNode& fn)
|
|||||||
k = fn["k"];
|
k = fn["k"];
|
||||||
}
|
}
|
||||||
|
|
||||||
void GoodFeaturesToTrackDetector::write (FileStorage& fs) const
|
void GoodFeaturesToTrackDetector::Params::write (FileStorage& fs) const
|
||||||
{
|
{
|
||||||
fs << "maxCorners" << maxCorners;
|
fs << "maxCorners" << maxCorners;
|
||||||
fs << "qualityLevel" << qualityLevel;
|
fs << "qualityLevel" << qualityLevel;
|
||||||
@ -133,20 +153,40 @@ void GoodFeaturesToTrackDetector::write (FileStorage& fs) const
|
|||||||
fs << "k" << k;
|
fs << "k" << k;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GoodFeaturesToTrackDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask) const
|
GoodFeaturesToTrackDetector::GoodFeaturesToTrackDetector( const Params& _params ) : params(_params)
|
||||||
|
{}
|
||||||
|
|
||||||
|
GoodFeaturesToTrackDetector::GoodFeaturesToTrackDetector( int maxCorners, double qualityLevel,
|
||||||
|
double minDistance, int blockSize,
|
||||||
|
bool useHarrisDetector, double k )
|
||||||
|
{
|
||||||
|
params = Params( maxCorners, qualityLevel, minDistance, blockSize, useHarrisDetector, k );
|
||||||
|
}
|
||||||
|
|
||||||
|
void GoodFeaturesToTrackDetector::read (const FileNode& fn)
|
||||||
|
{
|
||||||
|
params.read(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GoodFeaturesToTrackDetector::write (FileStorage& fs) const
|
||||||
|
{
|
||||||
|
params.write(fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GoodFeaturesToTrackDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask) const
|
||||||
{
|
{
|
||||||
Mat grayImage = image;
|
Mat grayImage = image;
|
||||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||||
|
|
||||||
vector<Point2f> corners;
|
vector<Point2f> corners;
|
||||||
goodFeaturesToTrack( grayImage, corners, maxCorners, qualityLevel, minDistance, mask,
|
goodFeaturesToTrack( grayImage, corners, params.maxCorners, params.qualityLevel, params.minDistance, mask,
|
||||||
blockSize, useHarrisDetector, k );
|
params.blockSize, params.useHarrisDetector, params.k );
|
||||||
keypoints.resize(corners.size());
|
keypoints.resize(corners.size());
|
||||||
vector<Point2f>::const_iterator corner_it = corners.begin();
|
vector<Point2f>::const_iterator corner_it = corners.begin();
|
||||||
vector<KeyPoint>::iterator keypoint_it = keypoints.begin();
|
vector<KeyPoint>::iterator keypoint_it = keypoints.begin();
|
||||||
for( ; corner_it != corners.end(); ++corner_it, ++keypoint_it )
|
for( ; corner_it != corners.end(); ++corner_it, ++keypoint_it )
|
||||||
{
|
{
|
||||||
*keypoint_it = KeyPoint( *corner_it, (float)blockSize );
|
*keypoint_it = KeyPoint( *corner_it, (float)params.blockSize );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,13 +238,12 @@ void MserFeatureDetector::write (FileStorage& fs) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MserFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
void MserFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||||
{
|
{
|
||||||
vector<vector<Point> > msers;
|
vector<vector<Point> > msers;
|
||||||
|
|
||||||
mser(image, msers, mask);
|
mser(image, msers, mask);
|
||||||
|
|
||||||
keypoints.clear();
|
|
||||||
vector<vector<Point> >::const_iterator contour_it = msers.begin();
|
vector<vector<Point> >::const_iterator contour_it = msers.begin();
|
||||||
for( ; contour_it != msers.end(); ++contour_it )
|
for( ; contour_it != msers.end(); ++contour_it )
|
||||||
{
|
{
|
||||||
@ -220,6 +259,12 @@ void MserFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints,
|
|||||||
/*
|
/*
|
||||||
* StarFeatureDetector
|
* StarFeatureDetector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
StarFeatureDetector::StarFeatureDetector( const CvStarDetectorParams& params )
|
||||||
|
: star( params.maxSize, params.responseThreshold, params.lineThresholdProjected,
|
||||||
|
params.lineThresholdBinarized, params.suppressNonmaxSize)
|
||||||
|
{}
|
||||||
|
|
||||||
StarFeatureDetector::StarFeatureDetector(int maxSize, int responseThreshold,
|
StarFeatureDetector::StarFeatureDetector(int maxSize, int responseThreshold,
|
||||||
int lineThresholdProjected,
|
int lineThresholdProjected,
|
||||||
int lineThresholdBinarized,
|
int lineThresholdBinarized,
|
||||||
@ -251,7 +296,7 @@ void StarFeatureDetector::write (FileStorage& fs) const
|
|||||||
fs << "suppressNonmaxSize" << star.suppressNonmaxSize;
|
fs << "suppressNonmaxSize" << star.suppressNonmaxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StarFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
void StarFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||||
{
|
{
|
||||||
Mat grayImage = image;
|
Mat grayImage = image;
|
||||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||||
@ -263,13 +308,20 @@ void StarFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints,
|
|||||||
/*
|
/*
|
||||||
* SiftFeatureDetector
|
* SiftFeatureDetector
|
||||||
*/
|
*/
|
||||||
SiftFeatureDetector::SiftFeatureDetector(double threshold, double edgeThreshold,
|
SiftFeatureDetector::SiftFeatureDetector( const SIFT::DetectorParams &detectorParams,
|
||||||
int nOctaves, int nOctaveLayers, int firstOctave, int angleMode) :
|
const SIFT::CommonParams &commonParams )
|
||||||
|
: sift(detectorParams.threshold, detectorParams.edgeThreshold,
|
||||||
|
commonParams.nOctaves, commonParams.nOctaveLayers, commonParams.firstOctave, commonParams.angleMode)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SiftFeatureDetector::SiftFeatureDetector( double threshold, double edgeThreshold,
|
||||||
|
int nOctaves, int nOctaveLayers, int firstOctave, int angleMode ) :
|
||||||
sift(threshold, edgeThreshold, nOctaves, nOctaveLayers, firstOctave, angleMode)
|
sift(threshold, edgeThreshold, nOctaves, nOctaveLayers, firstOctave, angleMode)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void SiftFeatureDetector::read (const FileNode& fn)
|
void SiftFeatureDetector::read( const FileNode& fn )
|
||||||
{
|
{
|
||||||
double threshold = fn["threshold"];
|
double threshold = fn["threshold"];
|
||||||
double edgeThreshold = fn["edgeThreshold"];
|
double edgeThreshold = fn["edgeThreshold"];
|
||||||
@ -296,7 +348,7 @@ void SiftFeatureDetector::write (FileStorage& fs) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SiftFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
void SiftFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||||
{
|
{
|
||||||
Mat grayImage = image;
|
Mat grayImage = image;
|
||||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||||
@ -329,7 +381,7 @@ void SurfFeatureDetector::write (FileStorage& fs) const
|
|||||||
fs << "octaveLayers" << surf.nOctaveLayers;
|
fs << "octaveLayers" << surf.nOctaveLayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
void SurfFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||||
{
|
{
|
||||||
Mat grayImage = image;
|
Mat grayImage = image;
|
||||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||||
@ -340,14 +392,24 @@ void SurfFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints,
|
|||||||
/*
|
/*
|
||||||
* DenseFeatureDetector
|
* DenseFeatureDetector
|
||||||
*/
|
*/
|
||||||
void DenseFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
DenseFeatureDetector::Params::Params( float _initFeatureScale, int _featureScaleLevels,
|
||||||
{
|
float _featureScaleMul, int _initXyStep,
|
||||||
keypoints.clear();
|
int _initImgBound, bool _varyXyStepWithScale,
|
||||||
|
bool _varyImgBoundWithScale ) :
|
||||||
|
initFeatureScale(_initFeatureScale), featureScaleLevels(_featureScaleLevels),
|
||||||
|
featureScaleMul(_featureScaleMul), initXyStep(_initXyStep), initImgBound(_initImgBound),
|
||||||
|
varyXyStepWithScale(_varyXyStepWithScale), varyImgBoundWithScale(_varyImgBoundWithScale)
|
||||||
|
{}
|
||||||
|
|
||||||
float curScale = initFeatureScale;
|
DenseFeatureDetector::DenseFeatureDetector(const DenseFeatureDetector::Params &_params) : params(_params)
|
||||||
int curStep = initXyStep;
|
{}
|
||||||
int curBound = initImgBound;
|
|
||||||
for( int curLevel = 0; curLevel < featureScaleLevels; curLevel++ )
|
void DenseFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||||
|
{
|
||||||
|
float curScale = params.initFeatureScale;
|
||||||
|
int curStep = params.initXyStep;
|
||||||
|
int curBound = params.initImgBound;
|
||||||
|
for( int curLevel = 0; curLevel < params.featureScaleLevels; curLevel++ )
|
||||||
{
|
{
|
||||||
for( int x = curBound; x < image.cols - curBound; x += curStep )
|
for( int x = curBound; x < image.cols - curBound; x += curStep )
|
||||||
{
|
{
|
||||||
@ -357,9 +419,9 @@ void DenseFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
curScale = curScale * featureScaleMul;
|
curScale = curScale * params.featureScaleMul;
|
||||||
if( varyXyStepWithScale ) curStep = static_cast<int>( curStep * featureScaleMul + 0.5f );
|
if( params.varyXyStepWithScale ) curStep = static_cast<int>( curStep * params.featureScaleMul + 0.5f );
|
||||||
if( varyImgBoundWithScale ) curBound = static_cast<int>( curBound * featureScaleMul + 0.5f );
|
if( params.varyImgBoundWithScale ) curBound = static_cast<int>( curBound * params.featureScaleMul + 0.5f );
|
||||||
}
|
}
|
||||||
|
|
||||||
removeInvalidPoints( mask, keypoints );
|
removeInvalidPoints( mask, keypoints );
|
||||||
@ -391,9 +453,8 @@ void keepStrongest( int N, vector<KeyPoint>& keypoints )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GridAdaptedFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
void GridAdaptedFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||||
{
|
{
|
||||||
keypoints.clear();
|
|
||||||
keypoints.reserve(maxTotalKeypoints);
|
keypoints.reserve(maxTotalKeypoints);
|
||||||
|
|
||||||
int maxPerCell = maxTotalKeypoints / (gridRows * gridCols);
|
int maxPerCell = maxTotalKeypoints / (gridRows * gridCols);
|
||||||
@ -430,7 +491,7 @@ PyramidAdaptedFeatureDetector::PyramidAdaptedFeatureDetector( const Ptr<FeatureD
|
|||||||
: detector(_detector), levels(_levels)
|
: detector(_detector), levels(_levels)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void PyramidAdaptedFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
void PyramidAdaptedFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||||
{
|
{
|
||||||
Mat src = image;
|
Mat src = image;
|
||||||
for( int l = 0, multiplier = 1; l <= levels; ++l, multiplier *= 2 )
|
for( int l = 0, multiplier = 1; l <= levels; ++l, multiplier *= 2 )
|
||||||
@ -463,12 +524,11 @@ Ptr<FeatureDetector> createFeatureDetector( const string& detectorType )
|
|||||||
FeatureDetector* fd = 0;
|
FeatureDetector* fd = 0;
|
||||||
if( !detectorType.compare( "FAST" ) )
|
if( !detectorType.compare( "FAST" ) )
|
||||||
{
|
{
|
||||||
fd = new FastFeatureDetector( 10/*threshold*/, true/*nonmax_suppression*/ );
|
fd = new FastFeatureDetector();
|
||||||
}
|
}
|
||||||
else if( !detectorType.compare( "STAR" ) )
|
else if( !detectorType.compare( "STAR" ) )
|
||||||
{
|
{
|
||||||
fd = new StarFeatureDetector( 16/*max_size*/, 5/*response_threshold*/, 10/*line_threshold_projected*/,
|
fd = new StarFeatureDetector();
|
||||||
8/*line_threshold_binarized*/, 5/*suppress_nonmax_size*/ );
|
|
||||||
}
|
}
|
||||||
else if( !detectorType.compare( "SIFT" ) )
|
else if( !detectorType.compare( "SIFT" ) )
|
||||||
{
|
{
|
||||||
@ -477,23 +537,21 @@ Ptr<FeatureDetector> createFeatureDetector( const string& detectorType )
|
|||||||
}
|
}
|
||||||
else if( !detectorType.compare( "SURF" ) )
|
else if( !detectorType.compare( "SURF" ) )
|
||||||
{
|
{
|
||||||
fd = new SurfFeatureDetector( 400./*hessian_threshold*/, 3 /*octaves*/, 4/*octave_layers*/ );
|
fd = new SurfFeatureDetector();
|
||||||
}
|
}
|
||||||
else if( !detectorType.compare( "MSER" ) )
|
else if( !detectorType.compare( "MSER" ) )
|
||||||
{
|
{
|
||||||
fd = new MserFeatureDetector( 5/*delta*/, 60/*min_area*/, 14400/*_max_area*/, 0.25f/*max_variation*/,
|
fd = new MserFeatureDetector();
|
||||||
0.2/*min_diversity*/, 200/*max_evolution*/, 1.01/*area_threshold*/, 0.003/*min_margin*/,
|
|
||||||
5/*edge_blur_size*/ );
|
|
||||||
}
|
}
|
||||||
else if( !detectorType.compare( "GFTT" ) )
|
else if( !detectorType.compare( "GFTT" ) )
|
||||||
{
|
{
|
||||||
fd = new GoodFeaturesToTrackDetector( 1000/*maxCorners*/, 0.01/*qualityLevel*/, 1./*minDistance*/,
|
fd = new GoodFeaturesToTrackDetector();
|
||||||
3/*int _blockSize*/, false/*useHarrisDetector*/, 0.04/*k*/ );
|
|
||||||
}
|
}
|
||||||
else if( !detectorType.compare( "HARRIS" ) )
|
else if( !detectorType.compare( "HARRIS" ) )
|
||||||
{
|
{
|
||||||
fd = new GoodFeaturesToTrackDetector( 1000/*maxCorners*/, 0.01/*qualityLevel*/, 1./*minDistance*/,
|
GoodFeaturesToTrackDetector::Params params;
|
||||||
3/*int _blockSize*/, true/*useHarrisDetector*/, 0.04/*k*/ );
|
params.useHarrisDetector = true;
|
||||||
|
fd = new GoodFeaturesToTrackDetector(params);
|
||||||
}
|
}
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
@ -71,11 +71,23 @@ Mat windowedMatchingMask( const vector<KeyPoint>& keypoints1, const vector<KeyPo
|
|||||||
/****************************************************************************************\
|
/****************************************************************************************\
|
||||||
* DescriptorMatcher *
|
* DescriptorMatcher *
|
||||||
\****************************************************************************************/
|
\****************************************************************************************/
|
||||||
void DescriptorMatcher::DescriptorCollection::set( const vector<Mat>& descCollection )
|
DescriptorMatcher::DescriptorCollection::DescriptorCollection()
|
||||||
|
{}
|
||||||
|
|
||||||
|
DescriptorMatcher::DescriptorCollection::DescriptorCollection( const DescriptorCollection& collection )
|
||||||
|
{
|
||||||
|
mergedDescriptors = collection.mergedDescriptors.clone();
|
||||||
|
copy( collection.startIdxs.begin(), collection.startIdxs.begin(), startIdxs.begin() );
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptorMatcher::DescriptorCollection::~DescriptorCollection()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void DescriptorMatcher::DescriptorCollection::set( const vector<Mat>& descriptors )
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
size_t imageCount = descCollection.size();
|
size_t imageCount = descriptors.size();
|
||||||
CV_Assert( imageCount > 0 );
|
CV_Assert( imageCount > 0 );
|
||||||
|
|
||||||
startIdxs.resize( imageCount );
|
startIdxs.resize( imageCount );
|
||||||
@ -86,35 +98,35 @@ void DescriptorMatcher::DescriptorCollection::set( const vector<Mat>& descCollec
|
|||||||
for( size_t i = 1; i < imageCount; i++ )
|
for( size_t i = 1; i < imageCount; i++ )
|
||||||
{
|
{
|
||||||
int s = 0;
|
int s = 0;
|
||||||
if( !descCollection[i-1].empty() )
|
if( !descriptors[i-1].empty() )
|
||||||
{
|
{
|
||||||
dim = descCollection[i-1].cols;
|
dim = descriptors[i-1].cols;
|
||||||
type = descCollection[i-1].type();
|
type = descriptors[i-1].type();
|
||||||
s = descCollection[i-1].rows;
|
s = descriptors[i-1].rows;
|
||||||
}
|
}
|
||||||
startIdxs[i] = startIdxs[i-1] + s;
|
startIdxs[i] = startIdxs[i-1] + s;
|
||||||
}
|
}
|
||||||
if( imageCount == 1 )
|
if( imageCount == 1 )
|
||||||
{
|
{
|
||||||
if( descCollection[0].empty() ) return;
|
if( descriptors[0].empty() ) return;
|
||||||
|
|
||||||
dim = descCollection[0].cols;
|
dim = descriptors[0].cols;
|
||||||
type = descCollection[0].type();
|
type = descriptors[0].type();
|
||||||
}
|
}
|
||||||
assert( dim > 0 );
|
assert( dim > 0 );
|
||||||
|
|
||||||
int count = startIdxs[imageCount-1] + descCollection[imageCount-1].rows;
|
int count = startIdxs[imageCount-1] + descriptors[imageCount-1].rows;
|
||||||
|
|
||||||
if( count > 0 )
|
if( count > 0 )
|
||||||
{
|
{
|
||||||
dmatrix.create( count, dim, type );
|
mergedDescriptors.create( count, dim, type );
|
||||||
for( size_t i = 0; i < imageCount; i++ )
|
for( size_t i = 0; i < imageCount; i++ )
|
||||||
{
|
{
|
||||||
if( !descCollection[i].empty() )
|
if( !descriptors[i].empty() )
|
||||||
{
|
{
|
||||||
CV_Assert( descCollection[i].cols == dim && descCollection[i].type() == type );
|
CV_Assert( descriptors[i].cols == dim && descriptors[i].type() == type );
|
||||||
Mat m = dmatrix.rowRange( startIdxs[i], startIdxs[i] + descCollection[i].rows );
|
Mat m = mergedDescriptors.rowRange( startIdxs[i], startIdxs[i] + descriptors[i].rows );
|
||||||
descCollection[i].copyTo(m);
|
descriptors[i].copyTo(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +135,7 @@ void DescriptorMatcher::DescriptorCollection::set( const vector<Mat>& descCollec
|
|||||||
void DescriptorMatcher::DescriptorCollection::clear()
|
void DescriptorMatcher::DescriptorCollection::clear()
|
||||||
{
|
{
|
||||||
startIdxs.clear();
|
startIdxs.clear();
|
||||||
dmatrix.release();
|
mergedDescriptors.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int imgIdx, int localDescIdx ) const
|
const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int imgIdx, int localDescIdx ) const
|
||||||
@ -135,10 +147,15 @@ const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int imgIdx, in
|
|||||||
return getDescriptor( globalIdx );
|
return getDescriptor( globalIdx );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Mat& DescriptorMatcher::DescriptorCollection::getDescriptors() const
|
||||||
|
{
|
||||||
|
return mergedDescriptors;
|
||||||
|
}
|
||||||
|
|
||||||
const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int globalDescIdx ) const
|
const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int globalDescIdx ) const
|
||||||
{
|
{
|
||||||
CV_Assert( globalDescIdx < size() );
|
CV_Assert( globalDescIdx < size() );
|
||||||
return dmatrix.row( globalDescIdx );
|
return mergedDescriptors.row( globalDescIdx );
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorMatcher::DescriptorCollection::getLocalIdx( int globalDescIdx, int& imgIdx, int& localDescIdx ) const
|
void DescriptorMatcher::DescriptorCollection::getLocalIdx( int globalDescIdx, int& imgIdx, int& localDescIdx ) const
|
||||||
@ -157,6 +174,11 @@ void DescriptorMatcher::DescriptorCollection::getLocalIdx( int globalDescIdx, in
|
|||||||
localDescIdx = globalDescIdx - startIdxs[imgIdx];
|
localDescIdx = globalDescIdx - startIdxs[imgIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DescriptorMatcher::DescriptorCollection::size() const
|
||||||
|
{
|
||||||
|
return mergedDescriptors.rows;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DescriptorMatcher
|
* DescriptorMatcher
|
||||||
*/
|
*/
|
||||||
@ -172,9 +194,17 @@ void convertMatches( const vector<vector<DMatch> >& knnMatches, vector<DMatch>&
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorMatcher::add( const vector<Mat>& descCollection )
|
DescriptorMatcher::~DescriptorMatcher()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void DescriptorMatcher::add( const vector<Mat>& descriptors )
|
||||||
{
|
{
|
||||||
trainDescCollection.insert( trainDescCollection.end(), descCollection.begin(), descCollection.end() );
|
trainDescCollection.insert( trainDescCollection.end(), descriptors.begin(), descriptors.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
const vector<Mat>& DescriptorMatcher::getTrainDescriptors() const
|
||||||
|
{
|
||||||
|
return trainDescCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorMatcher::clear()
|
void DescriptorMatcher::clear()
|
||||||
@ -182,67 +212,134 @@ void DescriptorMatcher::clear()
|
|||||||
trainDescCollection.clear();
|
trainDescCollection.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorMatcher::match( const Mat& queryDescs, const Mat& trainDescs, vector<DMatch>& matches, const Mat& mask ) const
|
bool DescriptorMatcher::empty() const
|
||||||
{
|
{
|
||||||
Ptr<DescriptorMatcher> tempMatcher = cloneWithoutData();
|
return trainDescCollection.size() == 0;
|
||||||
tempMatcher->add( vector<Mat>(1, trainDescs) );
|
|
||||||
tempMatcher->match( queryDescs, matches, vector<Mat>(1, mask) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorMatcher::knnMatch( const Mat& queryDescs, const Mat& trainDescs, vector<vector<DMatch> >& matches, int knn,
|
void DescriptorMatcher::train()
|
||||||
|
{}
|
||||||
|
|
||||||
|
void DescriptorMatcher::match( const Mat& queryDescriptors, const Mat& trainDescriptors, vector<DMatch>& matches, const Mat& mask ) const
|
||||||
|
{
|
||||||
|
Ptr<DescriptorMatcher> tempMatcher = clone(true);
|
||||||
|
tempMatcher->add( vector<Mat>(1, trainDescriptors) );
|
||||||
|
tempMatcher->match( queryDescriptors, matches, vector<Mat>(1, mask) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void DescriptorMatcher::knnMatch( const Mat& queryDescriptors, const Mat& trainDescriptors, vector<vector<DMatch> >& matches, int knn,
|
||||||
const Mat& mask, bool compactResult ) const
|
const Mat& mask, bool compactResult ) const
|
||||||
{
|
{
|
||||||
Ptr<DescriptorMatcher> tempMatcher = cloneWithoutData();
|
Ptr<DescriptorMatcher> tempMatcher = clone(true);
|
||||||
tempMatcher->add( vector<Mat>(1, trainDescs) );
|
tempMatcher->add( vector<Mat>(1, trainDescriptors) );
|
||||||
tempMatcher->knnMatch( queryDescs, matches, knn, vector<Mat>(1, mask), compactResult );
|
tempMatcher->knnMatch( queryDescriptors, matches, knn, vector<Mat>(1, mask), compactResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorMatcher::radiusMatch( const Mat& queryDescs, const Mat& trainDescs, vector<vector<DMatch> >& matches, float maxDistance,
|
void DescriptorMatcher::radiusMatch( const Mat& queryDescriptors, const Mat& trainDescriptors, vector<vector<DMatch> >& matches, float maxDistance,
|
||||||
const Mat& mask, bool compactResult ) const
|
const Mat& mask, bool compactResult ) const
|
||||||
{
|
{
|
||||||
Ptr<DescriptorMatcher> tempMatcher = cloneWithoutData();
|
Ptr<DescriptorMatcher> tempMatcher = clone(true);
|
||||||
tempMatcher->add( vector<Mat>(1, trainDescs) );
|
tempMatcher->add( vector<Mat>(1, trainDescriptors) );
|
||||||
tempMatcher->radiusMatch( queryDescs, matches, maxDistance, vector<Mat>(1, mask), compactResult );
|
tempMatcher->radiusMatch( queryDescriptors, matches, maxDistance, vector<Mat>(1, mask), compactResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorMatcher::match( const Mat& queryDescs, vector<DMatch>& matches, const vector<Mat>& masks )
|
void DescriptorMatcher::match( const Mat& queryDescriptors, vector<DMatch>& matches, const vector<Mat>& masks )
|
||||||
{
|
{
|
||||||
vector<vector<DMatch> > knnMatches;
|
vector<vector<DMatch> > knnMatches;
|
||||||
knnMatch( queryDescs, knnMatches, 1, masks, true /*compactResult*/ );
|
knnMatch( queryDescriptors, knnMatches, 1, masks, true /*compactResult*/ );
|
||||||
convertMatches( knnMatches, matches );
|
convertMatches( knnMatches, matches );
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorMatcher::knnMatch( const Mat& queryDescs, vector<vector<DMatch> >& matches, int knn,
|
void DescriptorMatcher::checkMasks( const vector<Mat>& masks, int queryDescriptorsCount ) const
|
||||||
|
{
|
||||||
|
if( isMaskSupported() && !masks.empty() )
|
||||||
|
{
|
||||||
|
// Check masks
|
||||||
|
size_t imageCount = trainDescCollection.size();
|
||||||
|
CV_Assert( masks.size() == imageCount );
|
||||||
|
for( size_t i = 0; i < imageCount; i++ )
|
||||||
|
{
|
||||||
|
if( !masks[i].empty() && !trainDescCollection[i].empty() )
|
||||||
|
{
|
||||||
|
CV_Assert( masks[i].rows == queryDescriptorsCount &&
|
||||||
|
masks[i].cols == trainDescCollection[i].rows &&
|
||||||
|
masks[i].type() == CV_8UC1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DescriptorMatcher::knnMatch( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, int knn,
|
||||||
const vector<Mat>& masks, bool compactResult )
|
const vector<Mat>& masks, bool compactResult )
|
||||||
{
|
{
|
||||||
|
matches.empty();
|
||||||
|
if( empty() || queryDescriptors.empty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
CV_Assert( knn > 0 );
|
||||||
|
|
||||||
|
checkMasks( masks, queryDescriptors.rows );
|
||||||
|
|
||||||
train();
|
train();
|
||||||
knnMatchImpl( queryDescs, matches, knn, masks, compactResult );
|
knnMatchImpl( queryDescriptors, matches, knn, masks, compactResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorMatcher::radiusMatch( const Mat& queryDescs, vector<vector<DMatch> >& matches, float maxDistance,
|
void DescriptorMatcher::radiusMatch( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, float maxDistance,
|
||||||
const vector<Mat>& masks, bool compactResult )
|
const vector<Mat>& masks, bool compactResult )
|
||||||
{
|
{
|
||||||
|
matches.empty();
|
||||||
|
if( empty() || queryDescriptors.empty() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
CV_Assert( maxDistance > std::numeric_limits<float>::epsilon() );
|
||||||
|
|
||||||
|
checkMasks( masks, queryDescriptors.rows );
|
||||||
|
|
||||||
train();
|
train();
|
||||||
radiusMatchImpl( queryDescs, matches, maxDistance, masks, compactResult );
|
radiusMatchImpl( queryDescriptors, matches, maxDistance, masks, compactResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DescriptorMatcher::read( const FileNode& )
|
||||||
|
{}
|
||||||
|
|
||||||
|
void DescriptorMatcher::write( FileStorage& ) const
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool DescriptorMatcher::isPossibleMatch( const Mat& mask, int queryIdx, int trainIdx )
|
||||||
|
{
|
||||||
|
return mask.empty() || mask.at<uchar>(queryIdx, trainIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DescriptorMatcher::isMaskedOut( const vector<Mat>& masks, int queryIdx )
|
||||||
|
{
|
||||||
|
size_t outCount = 0;
|
||||||
|
for( size_t i = 0; i < masks.size(); i++ )
|
||||||
|
{
|
||||||
|
if( !masks[i].empty() && (countNonZero(masks[i].row(queryIdx)) == 0) )
|
||||||
|
outCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !masks.empty() && outCount == masks.size() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescs, vector<vector<DMatch> >& matches, int knn,
|
void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, int knn,
|
||||||
const vector<Mat>& masks, bool compactResult )
|
const vector<Mat>& masks, bool compactResult )
|
||||||
{
|
{
|
||||||
#ifndef HAVE_EIGEN2
|
#ifndef HAVE_EIGEN2
|
||||||
bfKnnMatchImpl( *this, queryDescs, matches, knn, masks, compactResult );
|
commonKnnMatchImpl( *this, queryDescriptors, matches, knn, masks, compactResult );
|
||||||
#else
|
#else
|
||||||
CV_Assert( queryDescs.type() == CV_32FC1 || queryDescs.empty() );
|
CV_Assert( queryDescriptors.type() == CV_32FC1 || queryDescriptors.empty() );
|
||||||
CV_Assert( masks.empty() || masks.size() == trainDescCollection.size() );
|
CV_Assert( masks.empty() || masks.size() == trainDescCollection.size() );
|
||||||
|
|
||||||
matches.reserve(queryDescs.rows);
|
matches.reserve(queryDescriptors.rows);
|
||||||
size_t imgCount = trainDescCollection.size();
|
size_t imgCount = trainDescCollection.size();
|
||||||
|
|
||||||
Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> e_query_t;
|
Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> e_query_t;
|
||||||
vector<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> > e_trainCollection(trainDescCollection.size());
|
vector<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> > e_trainCollection(trainDescCollection.size());
|
||||||
vector<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> > e_trainNorms2(trainDescCollection.size());
|
vector<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> > e_trainNorms2(trainDescCollection.size());
|
||||||
cv2eigen( queryDescs.t(), e_query_t);
|
cv2eigen( queryDescriptors.t(), e_query_t);
|
||||||
for( size_t i = 0; i < trainDescCollection.size(); i++ )
|
for( size_t i = 0; i < trainDescCollection.size(); i++ )
|
||||||
{
|
{
|
||||||
cv2eigen( trainDescCollection[i], e_trainCollection[i] );
|
cv2eigen( trainDescCollection[i], e_trainCollection[i] );
|
||||||
@ -251,7 +348,7 @@ void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescs, vector<
|
|||||||
|
|
||||||
vector<Eigen::Matrix<float, Eigen::Dynamic, 1> > e_allDists( imgCount ); // distances between one query descriptor and all train descriptors
|
vector<Eigen::Matrix<float, Eigen::Dynamic, 1> > e_allDists( imgCount ); // distances between one query descriptor and all train descriptors
|
||||||
|
|
||||||
for( int qIdx = 0; qIdx < queryDescs.rows; qIdx++ )
|
for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
|
||||||
{
|
{
|
||||||
if( maskedOut( masks, qIdx ) )
|
if( maskedOut( masks, qIdx ) )
|
||||||
{
|
{
|
||||||
@ -265,10 +362,10 @@ void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescs, vector<
|
|||||||
for( size_t iIdx = 0; iIdx < imgCount; iIdx++ )
|
for( size_t iIdx = 0; iIdx < imgCount; iIdx++ )
|
||||||
{
|
{
|
||||||
CV_Assert( masks.empty() || masks[iIdx].empty() ||
|
CV_Assert( masks.empty() || masks[iIdx].empty() ||
|
||||||
( masks[iIdx].rows == queryDescs.rows && masks[iIdx].cols == trainDescCollection[iIdx].rows &&
|
( masks[iIdx].rows == queryDescriptors.rows && masks[iIdx].cols == trainDescCollection[iIdx].rows &&
|
||||||
masks[iIdx].type() == CV_8UC1 ) );
|
masks[iIdx].type() == CV_8UC1 ) );
|
||||||
CV_Assert( trainDescCollection[iIdx].type() == CV_32FC1 || trainDescCollection[iIdx].empty() );
|
CV_Assert( trainDescCollection[iIdx].type() == CV_32FC1 || trainDescCollection[iIdx].empty() );
|
||||||
CV_Assert( queryDescs.cols == trainDescCollection[iIdx].cols );
|
CV_Assert( queryDescriptors.cols == trainDescCollection[iIdx].cols );
|
||||||
|
|
||||||
e_allDists[iIdx] = e_trainCollection[iIdx] *e_query_t.col(qIdx);
|
e_allDists[iIdx] = e_trainCollection[iIdx] *e_query_t.col(qIdx);
|
||||||
e_allDists[iIdx] -= e_trainNorms2[iIdx];
|
e_allDists[iIdx] -= e_trainNorms2[iIdx];
|
||||||
@ -315,22 +412,22 @@ void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescs, vector<
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescs, vector<vector<DMatch> >& matches, float maxDistance,
|
void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, float maxDistance,
|
||||||
const vector<Mat>& masks, bool compactResult )
|
const vector<Mat>& masks, bool compactResult )
|
||||||
{
|
{
|
||||||
#ifndef HAVE_EIGEN2
|
#ifndef HAVE_EIGEN2
|
||||||
bfRadiusMatchImpl( *this, queryDescs, matches, maxDistance, masks, compactResult );
|
commonRadiusMatchImpl( *this, queryDescriptors, matches, maxDistance, masks, compactResult );
|
||||||
#else
|
#else
|
||||||
CV_Assert( queryDescs.type() == CV_32FC1 || queryDescs.empty() );
|
CV_Assert( queryDescriptors.type() == CV_32FC1 || queryDescriptors.empty() );
|
||||||
CV_Assert( masks.empty() || masks.size() == trainDescCollection.size() );
|
CV_Assert( masks.empty() || masks.size() == trainDescCollection.size() );
|
||||||
|
|
||||||
matches.reserve(queryDescs.rows);
|
matches.reserve(queryDescriptors.rows);
|
||||||
size_t imgCount = trainDescCollection.size();
|
size_t imgCount = trainDescCollection.size();
|
||||||
|
|
||||||
Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> e_query_t;
|
Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> e_query_t;
|
||||||
vector<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> > e_trainCollection(trainDescCollection.size());
|
vector<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> > e_trainCollection(trainDescCollection.size());
|
||||||
vector<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> > e_trainNorms2(trainDescCollection.size());
|
vector<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> > e_trainNorms2(trainDescCollection.size());
|
||||||
cv2eigen( queryDescs.t(), e_query_t);
|
cv2eigen( queryDescriptors.t(), e_query_t);
|
||||||
for( size_t i = 0; i < trainDescCollection.size(); i++ )
|
for( size_t i = 0; i < trainDescCollection.size(); i++ )
|
||||||
{
|
{
|
||||||
cv2eigen( trainDescCollection[i], e_trainCollection[i] );
|
cv2eigen( trainDescCollection[i], e_trainCollection[i] );
|
||||||
@ -339,7 +436,7 @@ void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescs, vect
|
|||||||
|
|
||||||
vector<Eigen::Matrix<float, Eigen::Dynamic, 1> > e_allDists( imgCount ); // distances between one query descriptor and all train descriptors
|
vector<Eigen::Matrix<float, Eigen::Dynamic, 1> > e_allDists( imgCount ); // distances between one query descriptor and all train descriptors
|
||||||
|
|
||||||
for( int qIdx = 0; qIdx < queryDescs.rows; qIdx++ )
|
for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
|
||||||
{
|
{
|
||||||
if( maskedOut( masks, qIdx ) )
|
if( maskedOut( masks, qIdx ) )
|
||||||
{
|
{
|
||||||
@ -353,10 +450,10 @@ void BruteForceMatcher<L2<float> >::radiusMatchImpl( const Mat& queryDescs, vect
|
|||||||
for( size_t iIdx = 0; iIdx < imgCount; iIdx++ )
|
for( size_t iIdx = 0; iIdx < imgCount; iIdx++ )
|
||||||
{
|
{
|
||||||
CV_Assert( masks.empty() || masks[iIdx].empty() ||
|
CV_Assert( masks.empty() || masks[iIdx].empty() ||
|
||||||
( masks[iIdx].rows == queryDescs.rows && masks[iIdx].cols == trainDescCollection[iIdx].rows &&
|
( masks[iIdx].rows == queryDescriptors.rows && masks[iIdx].cols == trainDescCollection[iIdx].rows &&
|
||||||
masks[iIdx].type() == CV_8UC1 ) );
|
masks[iIdx].type() == CV_8UC1 ) );
|
||||||
CV_Assert( trainDescCollection[iIdx].type() == CV_32FC1 || trainDescCollection[iIdx].empty() );
|
CV_Assert( trainDescCollection[iIdx].type() == CV_32FC1 || trainDescCollection[iIdx].empty() );
|
||||||
CV_Assert( queryDescs.cols == trainDescCollection[iIdx].cols );
|
CV_Assert( queryDescriptors.cols == trainDescCollection[iIdx].cols );
|
||||||
|
|
||||||
e_allDists[iIdx] = e_trainCollection[iIdx] *e_query_t.col(qIdx);
|
e_allDists[iIdx] = e_trainCollection[iIdx] *e_query_t.col(qIdx);
|
||||||
e_allDists[iIdx] -= e_trainNorms2[iIdx];
|
e_allDists[iIdx] -= e_trainNorms2[iIdx];
|
||||||
@ -393,12 +490,12 @@ FlannBasedMatcher::FlannBasedMatcher( const Ptr<flann::IndexParams>& _indexParam
|
|||||||
CV_Assert( !_searchParams.empty() );
|
CV_Assert( !_searchParams.empty() );
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlannBasedMatcher::add( const vector<Mat>& descCollection )
|
void FlannBasedMatcher::add( const vector<Mat>& descriptors )
|
||||||
{
|
{
|
||||||
DescriptorMatcher::add( descCollection );
|
DescriptorMatcher::add( descriptors );
|
||||||
for( size_t i = 0; i < descCollection.size(); i++ )
|
for( size_t i = 0; i < descriptors.size(); i++ )
|
||||||
{
|
{
|
||||||
addedDescCount += descCollection[i].rows;
|
addedDescCount += descriptors[i].rows;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,6 +518,27 @@ void FlannBasedMatcher::train()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FlannBasedMatcher::isMaskSupported() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr<DescriptorMatcher> FlannBasedMatcher::clone( bool emptyTrainData ) const
|
||||||
|
{
|
||||||
|
FlannBasedMatcher* matcher = new FlannBasedMatcher(indexParams, searchParams);
|
||||||
|
if( !emptyTrainData )
|
||||||
|
{
|
||||||
|
CV_Error( CV_StsNotImplemented, "deep clone functionality is not implemented, because "
|
||||||
|
"Flann::Index has not copy constructor or clone method ");
|
||||||
|
//matcher->flannIndex;
|
||||||
|
matcher->addedDescCount = addedDescCount;
|
||||||
|
matcher->mergedDescriptors = DescriptorCollection( mergedDescriptors );
|
||||||
|
transform( trainDescCollection.begin(), trainDescCollection.end(),
|
||||||
|
matcher->trainDescCollection.begin(), clone_op );
|
||||||
|
}
|
||||||
|
return matcher;
|
||||||
|
}
|
||||||
|
|
||||||
void FlannBasedMatcher::convertToDMatches( const DescriptorCollection& collection, const Mat& indices, const Mat& dists,
|
void FlannBasedMatcher::convertToDMatches( const DescriptorCollection& collection, const Mat& indices, const Mat& dists,
|
||||||
vector<vector<DMatch> >& matches )
|
vector<vector<DMatch> >& matches )
|
||||||
{
|
{
|
||||||
@ -440,28 +558,28 @@ void FlannBasedMatcher::convertToDMatches( const DescriptorCollection& collectio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlannBasedMatcher::knnMatchImpl( const Mat& queryDescs, vector<vector<DMatch> >& matches, int knn,
|
void FlannBasedMatcher::knnMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, int knn,
|
||||||
const vector<Mat>& /*masks*/, bool /*compactResult*/ )
|
const vector<Mat>& /*masks*/, bool /*compactResult*/ )
|
||||||
{
|
{
|
||||||
Mat indices( queryDescs.rows, knn, CV_32SC1 );
|
Mat indices( queryDescriptors.rows, knn, CV_32SC1 );
|
||||||
Mat dists( queryDescs.rows, knn, CV_32FC1);
|
Mat dists( queryDescriptors.rows, knn, CV_32FC1);
|
||||||
flannIndex->knnSearch( queryDescs, indices, dists, knn, *searchParams );
|
flannIndex->knnSearch( queryDescriptors, indices, dists, knn, *searchParams );
|
||||||
|
|
||||||
convertToDMatches( mergedDescriptors, indices, dists, matches );
|
convertToDMatches( mergedDescriptors, indices, dists, matches );
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlannBasedMatcher::radiusMatchImpl( const Mat& queryDescs, vector<vector<DMatch> >& matches, float maxDistance,
|
void FlannBasedMatcher::radiusMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, float maxDistance,
|
||||||
const vector<Mat>& /*masks*/, bool /*compactResult*/ )
|
const vector<Mat>& /*masks*/, bool /*compactResult*/ )
|
||||||
{
|
{
|
||||||
const int count = mergedDescriptors.size(); // TODO do count as param?
|
const int count = mergedDescriptors.size(); // TODO do count as param?
|
||||||
Mat indices( queryDescs.rows, count, CV_32SC1, Scalar::all(-1) );
|
Mat indices( queryDescriptors.rows, count, CV_32SC1, Scalar::all(-1) );
|
||||||
Mat dists( queryDescs.rows, count, CV_32FC1, Scalar::all(-1) );
|
Mat dists( queryDescriptors.rows, count, CV_32FC1, Scalar::all(-1) );
|
||||||
for( int qIdx = 0; qIdx < queryDescs.rows; qIdx++ )
|
for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
|
||||||
{
|
{
|
||||||
Mat queryDescsRow = queryDescs.row(qIdx);
|
Mat queryDescriptorsRow = queryDescriptors.row(qIdx);
|
||||||
Mat indicesRow = indices.row(qIdx);
|
Mat indicesRow = indices.row(qIdx);
|
||||||
Mat distsRow = dists.row(qIdx);
|
Mat distsRow = dists.row(qIdx);
|
||||||
flannIndex->radiusSearch( queryDescsRow, indicesRow, distsRow, maxDistance*maxDistance, *searchParams );
|
flannIndex->radiusSearch( queryDescriptorsRow, indicesRow, distsRow, maxDistance*maxDistance, *searchParams );
|
||||||
}
|
}
|
||||||
|
|
||||||
convertToDMatches( mergedDescriptors, indices, dists, matches );
|
convertToDMatches( mergedDescriptors, indices, dists, matches );
|
||||||
@ -507,6 +625,22 @@ Ptr<DescriptorMatcher> createDescriptorMatcher( const string& descriptorMatcherT
|
|||||||
/*
|
/*
|
||||||
* KeyPointCollection
|
* KeyPointCollection
|
||||||
*/
|
*/
|
||||||
|
GenericDescriptorMatcher::KeyPointCollection::KeyPointCollection() : pointCount(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
GenericDescriptorMatcher::KeyPointCollection::KeyPointCollection( const KeyPointCollection& collection )
|
||||||
|
{
|
||||||
|
pointCount = collection.pointCount;
|
||||||
|
|
||||||
|
transform( collection.images.begin(), collection.images.end(), images.begin(), clone_op );
|
||||||
|
|
||||||
|
keypoints.resize( collection.keypoints.size() );
|
||||||
|
for( size_t i = 0; i < keypoints.size(); i++ )
|
||||||
|
copy( collection.keypoints[i].begin(), collection.keypoints[i].end(), keypoints[i].begin() );
|
||||||
|
|
||||||
|
copy( collection.startIndices.begin(), collection.startIndices.end(), startIndices.begin() );
|
||||||
|
}
|
||||||
|
|
||||||
void GenericDescriptorMatcher::KeyPointCollection::add( const vector<Mat>& _images,
|
void GenericDescriptorMatcher::KeyPointCollection::add( const vector<Mat>& _images,
|
||||||
const vector<vector<KeyPoint> >& _points )
|
const vector<vector<KeyPoint> >& _points )
|
||||||
{
|
{
|
||||||
@ -514,9 +648,9 @@ void GenericDescriptorMatcher::KeyPointCollection::add( const vector<Mat>& _imag
|
|||||||
CV_Assert( _images.size() == _points.size() );
|
CV_Assert( _images.size() == _points.size() );
|
||||||
|
|
||||||
images.insert( images.end(), _images.begin(), _images.end() );
|
images.insert( images.end(), _images.begin(), _images.end() );
|
||||||
points.insert( points.end(), _points.begin(), _points.end() );
|
keypoints.insert( keypoints.end(), _points.begin(), _points.end() );
|
||||||
for( size_t i = 0; i < _points.size(); i++ )
|
for( size_t i = 0; i < _points.size(); i++ )
|
||||||
size += _points[i].size();
|
pointCount += _points[i].size();
|
||||||
|
|
||||||
size_t prevSize = startIndices.size(), addSize = _images.size();
|
size_t prevSize = startIndices.size(), addSize = _images.size();
|
||||||
startIndices.resize( prevSize + addSize );
|
startIndices.resize( prevSize + addSize );
|
||||||
@ -524,37 +658,58 @@ void GenericDescriptorMatcher::KeyPointCollection::add( const vector<Mat>& _imag
|
|||||||
if( prevSize == 0 )
|
if( prevSize == 0 )
|
||||||
startIndices[prevSize] = 0; //first
|
startIndices[prevSize] = 0; //first
|
||||||
else
|
else
|
||||||
startIndices[prevSize] = startIndices[prevSize-1] + points[prevSize-1].size();
|
startIndices[prevSize] = startIndices[prevSize-1] + keypoints[prevSize-1].size();
|
||||||
|
|
||||||
for( size_t i = prevSize + 1; i < prevSize + addSize; i++ )
|
for( size_t i = prevSize + 1; i < prevSize + addSize; i++ )
|
||||||
{
|
{
|
||||||
startIndices[i] = startIndices[i - 1] + points[i - 1].size();
|
startIndices[i] = startIndices[i - 1] + keypoints[i - 1].size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericDescriptorMatcher::KeyPointCollection::clear()
|
void GenericDescriptorMatcher::KeyPointCollection::clear()
|
||||||
{
|
{
|
||||||
points.clear();
|
keypoints.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GenericDescriptorMatcher::KeyPointCollection::keypointCount() const
|
||||||
|
{
|
||||||
|
return pointCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GenericDescriptorMatcher::KeyPointCollection::imageCount() const
|
||||||
|
{
|
||||||
|
return images.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const vector<vector<KeyPoint> >& GenericDescriptorMatcher::KeyPointCollection::getKeypoints() const
|
||||||
|
{
|
||||||
|
return keypoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vector<KeyPoint>& GenericDescriptorMatcher::KeyPointCollection::getKeypoints( int imgIdx ) const
|
||||||
|
{
|
||||||
|
CV_Assert( imgIdx < (int)imageCount() );
|
||||||
|
return keypoints[imgIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
const KeyPoint& GenericDescriptorMatcher::KeyPointCollection::getKeyPoint( int imgIdx, int localPointIdx ) const
|
const KeyPoint& GenericDescriptorMatcher::KeyPointCollection::getKeyPoint( int imgIdx, int localPointIdx ) const
|
||||||
{
|
{
|
||||||
CV_Assert( imgIdx < (int)images.size() );
|
CV_Assert( imgIdx < (int)images.size() );
|
||||||
CV_Assert( localPointIdx < (int)points[imgIdx].size() );
|
CV_Assert( localPointIdx < (int)keypoints[imgIdx].size() );
|
||||||
return points[imgIdx][localPointIdx];
|
return keypoints[imgIdx][localPointIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
const KeyPoint& GenericDescriptorMatcher::KeyPointCollection::getKeyPoint( int globalPointIdx ) const
|
const KeyPoint& GenericDescriptorMatcher::KeyPointCollection::getKeyPoint( int globalPointIdx ) const
|
||||||
{
|
{
|
||||||
int imgIdx, localPointIdx;
|
int imgIdx, localPointIdx;
|
||||||
getLocalIdx( globalPointIdx, imgIdx, localPointIdx );
|
getLocalIdx( globalPointIdx, imgIdx, localPointIdx );
|
||||||
return points[imgIdx][localPointIdx];
|
return keypoints[imgIdx][localPointIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericDescriptorMatcher::KeyPointCollection::getLocalIdx( int globalPointIdx, int& imgIdx, int& localPointIdx ) const
|
void GenericDescriptorMatcher::KeyPointCollection::getLocalIdx( int globalPointIdx, int& imgIdx, int& localPointIdx ) const
|
||||||
{
|
{
|
||||||
imgIdx = -1;
|
imgIdx = -1;
|
||||||
CV_Assert( globalPointIdx < (int)pointCount() );
|
CV_Assert( globalPointIdx < (int)keypointCount() );
|
||||||
for( size_t i = 1; i < startIndices.size(); i++ )
|
for( size_t i = 1; i < startIndices.size(); i++ )
|
||||||
{
|
{
|
||||||
if( globalPointIdx < startIndices[i] )
|
if( globalPointIdx < startIndices[i] )
|
||||||
@ -567,20 +722,50 @@ void GenericDescriptorMatcher::KeyPointCollection::getLocalIdx( int globalPointI
|
|||||||
localPointIdx = globalPointIdx - startIndices[imgIdx];
|
localPointIdx = globalPointIdx - startIndices[imgIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const vector<Mat>& GenericDescriptorMatcher::KeyPointCollection::getImages() const
|
||||||
|
{
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Mat& GenericDescriptorMatcher::KeyPointCollection::getImage( int imgIdx ) const
|
||||||
|
{
|
||||||
|
CV_Assert( imgIdx < (int)imageCount() );
|
||||||
|
return images[imgIdx];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GenericDescriptorMatcher
|
* GenericDescriptorMatcher
|
||||||
*/
|
*/
|
||||||
|
GenericDescriptorMatcher::GenericDescriptorMatcher()
|
||||||
|
{}
|
||||||
|
|
||||||
|
GenericDescriptorMatcher::~GenericDescriptorMatcher()
|
||||||
|
{}
|
||||||
|
|
||||||
void GenericDescriptorMatcher::add( const vector<Mat>& imgCollection,
|
void GenericDescriptorMatcher::add( const vector<Mat>& imgCollection,
|
||||||
vector<vector<KeyPoint> >& pointCollection )
|
vector<vector<KeyPoint> >& pointCollection )
|
||||||
{
|
{
|
||||||
trainPointCollection.add( imgCollection, pointCollection );
|
trainPointCollection.add( imgCollection, pointCollection );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const vector<Mat>& GenericDescriptorMatcher::getTrainImages() const
|
||||||
|
{
|
||||||
|
return trainPointCollection.getImages();
|
||||||
|
}
|
||||||
|
|
||||||
|
const vector<vector<KeyPoint> >& GenericDescriptorMatcher::getTrainKeypoints() const
|
||||||
|
{
|
||||||
|
return trainPointCollection.getKeypoints();
|
||||||
|
}
|
||||||
|
|
||||||
void GenericDescriptorMatcher::clear()
|
void GenericDescriptorMatcher::clear()
|
||||||
{
|
{
|
||||||
trainPointCollection.clear();
|
trainPointCollection.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GenericDescriptorMatcher::train()
|
||||||
|
{}
|
||||||
|
|
||||||
void GenericDescriptorMatcher::classify( const Mat& queryImage, vector<KeyPoint>& queryPoints,
|
void GenericDescriptorMatcher::classify( const Mat& queryImage, vector<KeyPoint>& queryPoints,
|
||||||
const Mat& trainImage, vector<KeyPoint>& trainPoints ) const
|
const Mat& trainImage, vector<KeyPoint>& trainPoints ) const
|
||||||
{
|
{
|
||||||
@ -606,7 +791,7 @@ void GenericDescriptorMatcher::match( const Mat& queryImg, vector<KeyPoint>& que
|
|||||||
const Mat& trainImg, vector<KeyPoint>& trainPoints,
|
const Mat& trainImg, vector<KeyPoint>& trainPoints,
|
||||||
vector<DMatch>& matches, const Mat& mask ) const
|
vector<DMatch>& matches, const Mat& mask ) const
|
||||||
{
|
{
|
||||||
Ptr<GenericDescriptorMatcher> tempMatcher = createEmptyMatcherCopy();
|
Ptr<GenericDescriptorMatcher> tempMatcher = clone( true );
|
||||||
vector<vector<KeyPoint> > vecTrainPoints(1, trainPoints);
|
vector<vector<KeyPoint> > vecTrainPoints(1, trainPoints);
|
||||||
tempMatcher->add( vector<Mat>(1, trainImg), vecTrainPoints );
|
tempMatcher->add( vector<Mat>(1, trainImg), vecTrainPoints );
|
||||||
tempMatcher->match( queryImg, queryPoints, matches, vector<Mat>(1, mask) );
|
tempMatcher->match( queryImg, queryPoints, matches, vector<Mat>(1, mask) );
|
||||||
@ -617,7 +802,7 @@ void GenericDescriptorMatcher::knnMatch( const Mat& queryImg, vector<KeyPoint>&
|
|||||||
const Mat& trainImg, vector<KeyPoint>& trainPoints,
|
const Mat& trainImg, vector<KeyPoint>& trainPoints,
|
||||||
vector<vector<DMatch> >& matches, int knn, const Mat& mask, bool compactResult ) const
|
vector<vector<DMatch> >& matches, int knn, const Mat& mask, bool compactResult ) const
|
||||||
{
|
{
|
||||||
Ptr<GenericDescriptorMatcher> tempMatcher = createEmptyMatcherCopy();
|
Ptr<GenericDescriptorMatcher> tempMatcher = clone( true );
|
||||||
vector<vector<KeyPoint> > vecTrainPoints(1, trainPoints);
|
vector<vector<KeyPoint> > vecTrainPoints(1, trainPoints);
|
||||||
tempMatcher->add( vector<Mat>(1, trainImg), vecTrainPoints );
|
tempMatcher->add( vector<Mat>(1, trainImg), vecTrainPoints );
|
||||||
tempMatcher->knnMatch( queryImg, queryPoints, matches, knn, vector<Mat>(1, mask), compactResult );
|
tempMatcher->knnMatch( queryImg, queryPoints, matches, knn, vector<Mat>(1, mask), compactResult );
|
||||||
@ -629,7 +814,7 @@ void GenericDescriptorMatcher::radiusMatch( const Mat& queryImg, vector<KeyPoint
|
|||||||
vector<vector<DMatch> >& matches, float maxDistance,
|
vector<vector<DMatch> >& matches, float maxDistance,
|
||||||
const Mat& mask, bool compactResult ) const
|
const Mat& mask, bool compactResult ) const
|
||||||
{
|
{
|
||||||
Ptr<GenericDescriptorMatcher> tempMatcher = createEmptyMatcherCopy();
|
Ptr<GenericDescriptorMatcher> tempMatcher = clone( true );
|
||||||
vector<vector<KeyPoint> > vecTrainPoints(1, trainPoints);
|
vector<vector<KeyPoint> > vecTrainPoints(1, trainPoints);
|
||||||
tempMatcher->add( vector<Mat>(1, trainImg), vecTrainPoints );
|
tempMatcher->add( vector<Mat>(1, trainImg), vecTrainPoints );
|
||||||
tempMatcher->radiusMatch( queryImg, queryPoints, matches, maxDistance, vector<Mat>(1, mask), compactResult );
|
tempMatcher->radiusMatch( queryImg, queryPoints, matches, maxDistance, vector<Mat>(1, mask), compactResult );
|
||||||
@ -660,9 +845,25 @@ void GenericDescriptorMatcher::radiusMatch( const Mat& queryImg, vector<KeyPoint
|
|||||||
radiusMatchImpl( queryImg, queryPoints, matches, maxDistance, masks, compactResult );
|
radiusMatchImpl( queryImg, queryPoints, matches, maxDistance, masks, compactResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GenericDescriptorMatcher::read( const FileNode& )
|
||||||
|
{}
|
||||||
|
|
||||||
|
void GenericDescriptorMatcher::write( FileStorage& ) const
|
||||||
|
{}
|
||||||
|
|
||||||
/****************************************************************************************\
|
/****************************************************************************************\
|
||||||
* OneWayDescriptorMatcher *
|
* OneWayDescriptorMatcher *
|
||||||
\****************************************************************************************/
|
\****************************************************************************************/
|
||||||
|
|
||||||
|
OneWayDescriptorMatcher::Params::Params( int _poseCount, Size _patchSize, string _pcaFilename,
|
||||||
|
string _trainPath, string _trainImagesList,
|
||||||
|
float _minScale, float _maxScale, float _stepScale ) :
|
||||||
|
poseCount(_poseCount), patchSize(_patchSize), pcaFilename(_pcaFilename),
|
||||||
|
trainPath(_trainPath), trainImagesList(_trainImagesList),
|
||||||
|
minScale(_minScale), maxScale(_maxScale), stepScale(_stepScale)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
OneWayDescriptorMatcher::OneWayDescriptorMatcher( const Params& _params)
|
OneWayDescriptorMatcher::OneWayDescriptorMatcher( const Params& _params)
|
||||||
{
|
{
|
||||||
initialize(_params);
|
initialize(_params);
|
||||||
@ -691,13 +892,13 @@ void OneWayDescriptorMatcher::clear()
|
|||||||
|
|
||||||
void OneWayDescriptorMatcher::train()
|
void OneWayDescriptorMatcher::train()
|
||||||
{
|
{
|
||||||
if( base.empty() || prevTrainCount < (int)trainPointCollection.pointCount() )
|
if( base.empty() || prevTrainCount < (int)trainPointCollection.keypointCount() )
|
||||||
{
|
{
|
||||||
base = new OneWayDescriptorObject( params.patchSize, params.poseCount, params.pcaFilename,
|
base = new OneWayDescriptorObject( params.patchSize, params.poseCount, params.pcaFilename,
|
||||||
params.trainPath, params.trainImagesList, params.minScale, params.maxScale, params.stepScale );
|
params.trainPath, params.trainImagesList, params.minScale, params.maxScale, params.stepScale );
|
||||||
|
|
||||||
base->Allocate( trainPointCollection.pointCount() );
|
base->Allocate( trainPointCollection.keypointCount() );
|
||||||
prevTrainCount = trainPointCollection.pointCount();
|
prevTrainCount = trainPointCollection.keypointCount();
|
||||||
|
|
||||||
const vector<vector<KeyPoint> >& points = trainPointCollection.getKeypoints();
|
const vector<vector<KeyPoint> >& points = trainPointCollection.getKeypoints();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@ -714,6 +915,11 @@ void OneWayDescriptorMatcher::train()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OneWayDescriptorMatcher::isMaskSupported()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void OneWayDescriptorMatcher::knnMatchImpl( const Mat& queryImg, vector<KeyPoint>& queryPoints,
|
void OneWayDescriptorMatcher::knnMatchImpl( const Mat& queryImg, vector<KeyPoint>& queryPoints,
|
||||||
vector<vector<DMatch> >& matches, int knn,
|
vector<vector<DMatch> >& matches, int knn,
|
||||||
const vector<Mat>& /*masks*/, bool /*compactResult*/ )
|
const vector<Mat>& /*masks*/, bool /*compactResult*/ )
|
||||||
@ -763,6 +969,23 @@ void OneWayDescriptorMatcher::write( FileStorage& fs ) const
|
|||||||
base->Write (fs);
|
base->Write (fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ptr<GenericDescriptorMatcher> OneWayDescriptorMatcher::clone( bool emptyTrainData ) const
|
||||||
|
{
|
||||||
|
OneWayDescriptorMatcher* matcher = new OneWayDescriptorMatcher( params );
|
||||||
|
|
||||||
|
if( !emptyTrainData )
|
||||||
|
{
|
||||||
|
CV_Error( CV_StsNotImplemented, "deep clone dunctionality is not implemented, because "
|
||||||
|
"OneWayDescriptorBase has not copy constructor or clone method ");
|
||||||
|
|
||||||
|
//matcher->base;
|
||||||
|
matcher->params = params;
|
||||||
|
matcher->prevTrainCount = prevTrainCount;
|
||||||
|
matcher->trainPointCollection = trainPointCollection;
|
||||||
|
}
|
||||||
|
return matcher;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************************\
|
/****************************************************************************************\
|
||||||
* FernDescriptorMatcher *
|
* FernDescriptorMatcher *
|
||||||
\****************************************************************************************/
|
\****************************************************************************************/
|
||||||
@ -805,7 +1028,7 @@ void FernDescriptorMatcher::clear()
|
|||||||
|
|
||||||
void FernDescriptorMatcher::train()
|
void FernDescriptorMatcher::train()
|
||||||
{
|
{
|
||||||
if( classifier.empty() || prevTrainCount < (int)trainPointCollection.pointCount() )
|
if( classifier.empty() || prevTrainCount < (int)trainPointCollection.keypointCount() )
|
||||||
{
|
{
|
||||||
assert( params.filename.empty() );
|
assert( params.filename.empty() );
|
||||||
|
|
||||||
@ -819,6 +1042,11 @@ void FernDescriptorMatcher::train()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FernDescriptorMatcher::isMaskSupported()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void FernDescriptorMatcher::calcBestProbAndMatchIdx( const Mat& image, const Point2f& pt,
|
void FernDescriptorMatcher::calcBestProbAndMatchIdx( const Mat& image, const Point2f& pt,
|
||||||
float& bestProb, int& bestMatchIdx, vector<float>& signature )
|
float& bestProb, int& bestMatchIdx, vector<float>& signature )
|
||||||
{
|
{
|
||||||
@ -921,16 +1149,42 @@ void FernDescriptorMatcher::write( FileStorage& fs ) const
|
|||||||
// classifier->write(fs);
|
// classifier->write(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ptr<GenericDescriptorMatcher> FernDescriptorMatcher::clone( bool emptyTrainData ) const
|
||||||
|
{
|
||||||
|
FernDescriptorMatcher* matcher = new FernDescriptorMatcher( params );
|
||||||
|
if( !emptyTrainData )
|
||||||
|
{
|
||||||
|
CV_Error( CV_StsNotImplemented, "deep clone dunctionality is not implemented, because "
|
||||||
|
"FernClassifier has not copy constructor or clone method ");
|
||||||
|
|
||||||
|
//matcher->classifier;
|
||||||
|
matcher->params = params;
|
||||||
|
matcher->prevTrainCount = prevTrainCount;
|
||||||
|
matcher->trainPointCollection = trainPointCollection;
|
||||||
|
}
|
||||||
|
return matcher;
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************************\
|
/****************************************************************************************\
|
||||||
* VectorDescriptorMatcher *
|
* VectorDescriptorMatcher *
|
||||||
\****************************************************************************************/
|
\****************************************************************************************/
|
||||||
|
VectorDescriptorMatcher::VectorDescriptorMatcher( const Ptr<DescriptorExtractor>& _extractor,
|
||||||
|
const Ptr<DescriptorMatcher>& _matcher )
|
||||||
|
: extractor( _extractor ), matcher( _matcher )
|
||||||
|
{
|
||||||
|
CV_Assert( !extractor.empty() && !matcher.empty() );
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorDescriptorMatcher::~VectorDescriptorMatcher()
|
||||||
|
{}
|
||||||
|
|
||||||
void VectorDescriptorMatcher::add( const vector<Mat>& imgCollection,
|
void VectorDescriptorMatcher::add( const vector<Mat>& imgCollection,
|
||||||
vector<vector<KeyPoint> >& pointCollection )
|
vector<vector<KeyPoint> >& pointCollection )
|
||||||
{
|
{
|
||||||
vector<Mat> descCollection;
|
vector<Mat> descriptors;
|
||||||
extractor->compute( imgCollection, pointCollection, descCollection );
|
extractor->compute( imgCollection, pointCollection, descriptors );
|
||||||
|
|
||||||
matcher->add( descCollection );
|
matcher->add( descriptors );
|
||||||
|
|
||||||
trainPointCollection.add( imgCollection, pointCollection );
|
trainPointCollection.add( imgCollection, pointCollection );
|
||||||
}
|
}
|
||||||
@ -947,28 +1201,33 @@ void VectorDescriptorMatcher::train()
|
|||||||
matcher->train();
|
matcher->train();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VectorDescriptorMatcher::isMaskSupported()
|
||||||
|
{
|
||||||
|
return matcher->isMaskSupported();
|
||||||
|
}
|
||||||
|
|
||||||
void VectorDescriptorMatcher::knnMatchImpl( const Mat& queryImg, vector<KeyPoint>& queryPoints,
|
void VectorDescriptorMatcher::knnMatchImpl( const Mat& queryImg, vector<KeyPoint>& queryPoints,
|
||||||
vector<vector<DMatch> >& matches, int knn,
|
vector<vector<DMatch> >& matches, int knn,
|
||||||
const vector<Mat>& masks, bool compactResult )
|
const vector<Mat>& masks, bool compactResult )
|
||||||
{
|
{
|
||||||
Mat queryDescs;
|
Mat queryDescriptors;
|
||||||
extractor->compute( queryImg, queryPoints, queryDescs );
|
extractor->compute( queryImg, queryPoints, queryDescriptors );
|
||||||
matcher->knnMatch( queryDescs, matches, knn, masks, compactResult );
|
matcher->knnMatch( queryDescriptors, matches, knn, masks, compactResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
void VectorDescriptorMatcher::radiusMatchImpl( const Mat& queryImg, vector<KeyPoint>& queryPoints,
|
void VectorDescriptorMatcher::radiusMatchImpl( const Mat& queryImg, vector<KeyPoint>& queryPoints,
|
||||||
vector<vector<DMatch> >& matches, float maxDistance,
|
vector<vector<DMatch> >& matches, float maxDistance,
|
||||||
const vector<Mat>& masks, bool compactResult )
|
const vector<Mat>& masks, bool compactResult )
|
||||||
{
|
{
|
||||||
Mat queryDescs;
|
Mat queryDescriptors;
|
||||||
extractor->compute( queryImg, queryPoints, queryDescs );
|
extractor->compute( queryImg, queryPoints, queryDescriptors );
|
||||||
matcher->radiusMatch( queryDescs, matches, maxDistance, masks, compactResult );
|
matcher->radiusMatch( queryDescriptors, matches, maxDistance, masks, compactResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
void VectorDescriptorMatcher::read( const FileNode& fn )
|
void VectorDescriptorMatcher::read( const FileNode& fn )
|
||||||
{
|
{
|
||||||
GenericDescriptorMatcher::read(fn);
|
GenericDescriptorMatcher::read(fn);
|
||||||
extractor->read (fn);
|
extractor->read(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VectorDescriptorMatcher::write (FileStorage& fs) const
|
void VectorDescriptorMatcher::write (FileStorage& fs) const
|
||||||
@ -977,6 +1236,12 @@ void VectorDescriptorMatcher::write (FileStorage& fs) const
|
|||||||
extractor->write (fs);
|
extractor->write (fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ptr<GenericDescriptorMatcher> VectorDescriptorMatcher::clone( bool emptyTrainData ) const
|
||||||
|
{
|
||||||
|
// TODO clone extractor
|
||||||
|
return new VectorDescriptorMatcher( extractor, matcher->clone(emptyTrainData) );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Factory function for GenericDescriptorMatch creating
|
* Factory function for GenericDescriptorMatch creating
|
||||||
*/
|
*/
|
||||||
|
@ -7,103 +7,22 @@
|
|||||||
using namespace cv;
|
using namespace cv;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
void maskMatchesByTrainImgIdx( const vector<DMatch>& matches, int trainImgIdx, vector<char>& mask );
|
/*
|
||||||
void readTrainFilenames( const string& filename, string& dirName, vector<string>& trainFilenames );
|
* This is a sample on matching descriptors detected on one image to descriptors detected in image set.
|
||||||
|
* So we have one query image and several train images. For each keypoint descriptor of query image
|
||||||
int main(int argc, char** argv)
|
* the one nearest train descriptor is found the entire collection of train images. To visualize the result
|
||||||
{
|
* of matching we save images, each of which combines query and train image with matches between them (if they exist).
|
||||||
Mat queryImg;
|
* Match is drawn as line between corresponding points. Count of all matches is equel to count of
|
||||||
vector<KeyPoint> queryPoints;
|
* query keypoints, so we have the same count of lines in all set of result images (but not for each result
|
||||||
Mat queryDescs;
|
* (train) image).
|
||||||
|
*/
|
||||||
vector<Mat> trainImgCollection;
|
|
||||||
vector<vector<KeyPoint> > trainPointCollection;
|
|
||||||
vector<Mat> trainDescCollection;
|
|
||||||
|
|
||||||
vector<DMatch> matches;
|
|
||||||
|
|
||||||
if( argc != 7 )
|
|
||||||
{
|
|
||||||
cout << "Format:" << endl;
|
|
||||||
cout << argv[0] << "[detectorType] [descriptorType] [matcherType] [queryImage] [fileWithTrainImages] [dirToSaveResImages]" << endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "< 1.) Creating feature detector, descriptor extractor and descriptor matcher ..." << endl;
|
|
||||||
Ptr<FeatureDetector> detector = createFeatureDetector( argv[1] );
|
|
||||||
Ptr<DescriptorExtractor> descriptorExtractor = createDescriptorExtractor( argv[2] );
|
|
||||||
Ptr<DescriptorMatcher> descriptorMatcher = createDescriptorMatcher( argv[3] );
|
|
||||||
cout << ">" << endl;
|
|
||||||
if( detector.empty() || descriptorExtractor.empty() || descriptorMatcher.empty() )
|
|
||||||
{
|
|
||||||
cout << "Can not create feature detector or descriptor exstractor or descriptor matcher of given types." << endl << ">" << endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "< 2.) Reading the images..." << endl;
|
|
||||||
queryImg = imread( argv[4], CV_LOAD_IMAGE_GRAYSCALE);
|
|
||||||
if( queryImg.empty() )
|
|
||||||
{
|
|
||||||
cout << "Query image can not be read." << endl << ">" << endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
string trainDirName;
|
|
||||||
vector<string> trainFilenames;
|
|
||||||
vector<int> usedTrainImgIdxs;
|
|
||||||
readTrainFilenames( argv[5], trainDirName, trainFilenames );
|
|
||||||
if( trainFilenames.empty() )
|
|
||||||
{
|
|
||||||
cout << "Train image filenames can not be read." << endl << ">" << endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
for( size_t i = 0; i < trainFilenames.size(); i++ )
|
|
||||||
{
|
|
||||||
Mat img = imread( trainDirName + trainFilenames[i], CV_LOAD_IMAGE_GRAYSCALE );
|
|
||||||
if( img.empty() ) cout << "Train image " << trainDirName + trainFilenames[i] << " can not be read." << endl;
|
|
||||||
trainImgCollection.push_back( img );
|
|
||||||
usedTrainImgIdxs.push_back( i );
|
|
||||||
}
|
|
||||||
if( trainImgCollection.empty() )
|
|
||||||
{
|
|
||||||
cout << "All train images can not be read." << endl << ">" << endl;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cout << trainImgCollection.size() << " train images were read." << endl;
|
|
||||||
cout << ">" << endl;
|
|
||||||
|
|
||||||
cout << endl << "< 3.) Extracting keypoints from images..." << endl;
|
|
||||||
detector->detect( queryImg, queryPoints );
|
|
||||||
detector->detect( trainImgCollection, trainPointCollection );
|
|
||||||
cout << ">" << endl;
|
|
||||||
|
|
||||||
cout << "< 4.) Computing descriptors for keypoints..." << endl;
|
|
||||||
descriptorExtractor->compute( queryImg, queryPoints, queryDescs );
|
|
||||||
descriptorExtractor->compute( trainImgCollection, trainPointCollection, trainDescCollection );
|
|
||||||
cout << ">" << endl;
|
|
||||||
|
|
||||||
cout << "< 5.) Set train descriptors collection in the matcher and match query descriptors to them..." << endl;
|
|
||||||
descriptorMatcher->add( trainDescCollection );
|
|
||||||
descriptorMatcher->match( queryDescs, matches );
|
|
||||||
CV_Assert( queryPoints.size() == matches.size() );
|
|
||||||
cout << ">" << endl;
|
|
||||||
|
|
||||||
cout << "< 6.) Save results..." << endl;
|
|
||||||
Mat drawImg;
|
|
||||||
vector<char> mask;
|
|
||||||
for( size_t i = 0; i < trainImgCollection.size(); i++ )
|
|
||||||
{
|
|
||||||
maskMatchesByTrainImgIdx( matches, i, mask );
|
|
||||||
drawMatches( queryImg, queryPoints, trainImgCollection[i], trainPointCollection[i],
|
|
||||||
matches, drawImg, Scalar::all(-1), Scalar::all(-1), mask );
|
|
||||||
|
|
||||||
imwrite( string(argv[6]) + "/res_" + trainFilenames[usedTrainImgIdxs[i]] + ".png", drawImg );
|
|
||||||
}
|
|
||||||
cout << ">" << endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const string defaultDetectorType = "SURF";
|
||||||
|
const string defaultDescriptorType = "SURF";
|
||||||
|
const string defaultMatcherType = "FlannBased";
|
||||||
|
const string defaultQueryImageName = "../../opencv/samples/cpp/matching_to_many_images/query.png";
|
||||||
|
const string defaultFileWithTrainImages = "../../opencv/samples/cpp/matching_to_many_images/train/trainImages.txt";
|
||||||
|
const string defaultDirToSaveResImages = "../../opencv/samples/cpp/matching_to_many_images/results";
|
||||||
|
|
||||||
void maskMatchesByTrainImgIdx( const vector<DMatch>& matches, int trainImgIdx, vector<char>& mask )
|
void maskMatchesByTrainImgIdx( const vector<DMatch>& matches, int trainImgIdx, vector<char>& mask )
|
||||||
{
|
{
|
||||||
@ -136,3 +55,180 @@ void readTrainFilenames( const string& filename, string& dirName, vector<string>
|
|||||||
}
|
}
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool createDetectorDescriptorMatcher( const string& detectorType, const string& descriptorType, const string& matcherType,
|
||||||
|
Ptr<FeatureDetector>& featureDetector,
|
||||||
|
Ptr<DescriptorExtractor>& descriptorExtractor,
|
||||||
|
Ptr<DescriptorMatcher>& descriptorMatcher )
|
||||||
|
{
|
||||||
|
cout << "< Creating feature detector, descriptor extractor and descriptor matcher ..." << endl;
|
||||||
|
featureDetector = createFeatureDetector( detectorType );
|
||||||
|
descriptorExtractor = createDescriptorExtractor( descriptorType );
|
||||||
|
descriptorMatcher = createDescriptorMatcher( matcherType );
|
||||||
|
cout << ">" << endl;
|
||||||
|
|
||||||
|
bool isCreated = !( featureDetector.empty() || descriptorExtractor.empty() || descriptorMatcher.empty() );
|
||||||
|
if( !isCreated )
|
||||||
|
cout << "Can not create feature detector or descriptor exstractor or descriptor matcher of given types." << endl << ">" << endl;
|
||||||
|
|
||||||
|
return isCreated;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readImages( const string& queryImageName, const string& trainFilename,
|
||||||
|
Mat& queryImage, vector <Mat>& trainImages, vector<string>& trainImageNames )
|
||||||
|
{
|
||||||
|
cout << "< Reading the images..." << endl;
|
||||||
|
queryImage = imread( queryImageName, CV_LOAD_IMAGE_GRAYSCALE);
|
||||||
|
if( queryImage.empty() )
|
||||||
|
{
|
||||||
|
cout << "Query image can not be read." << endl << ">" << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
string trainDirName;
|
||||||
|
readTrainFilenames( trainFilename, trainDirName, trainImageNames );
|
||||||
|
if( trainImageNames.empty() )
|
||||||
|
{
|
||||||
|
cout << "Train image filenames can not be read." << endl << ">" << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int readImageCount = 0;
|
||||||
|
for( size_t i = 0; i < trainImageNames.size(); i++ )
|
||||||
|
{
|
||||||
|
string filename = trainDirName + trainImageNames[i];
|
||||||
|
Mat img = imread( filename, CV_LOAD_IMAGE_GRAYSCALE );
|
||||||
|
if( img.empty() )
|
||||||
|
cout << "Train image " << filename << " can not be read." << endl;
|
||||||
|
else
|
||||||
|
readImageCount++;
|
||||||
|
trainImages.push_back( img );
|
||||||
|
}
|
||||||
|
if( !readImageCount )
|
||||||
|
{
|
||||||
|
cout << "All train images can not be read." << endl << ">" << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cout << readImageCount << " train images were read." << endl;
|
||||||
|
cout << ">" << endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void detectKeypoints( const Mat& queryImage, vector<KeyPoint>& queryKeypoints,
|
||||||
|
const vector<Mat>& trainImages, vector<vector<KeyPoint> >& trainKeypoints,
|
||||||
|
Ptr<FeatureDetector>& featureDetector )
|
||||||
|
{
|
||||||
|
cout << endl << "< Extracting keypoints from images..." << endl;
|
||||||
|
featureDetector->detect( queryImage, queryKeypoints );
|
||||||
|
featureDetector->detect( trainImages, trainKeypoints );
|
||||||
|
cout << ">" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void computeDescriptors( const Mat& queryImage, vector<KeyPoint>& queryKeypoints, Mat& queryDescriptors,
|
||||||
|
const vector<Mat>& trainImages, vector<vector<KeyPoint> >& trainKeypoints, vector<Mat>& trainDescriptors,
|
||||||
|
Ptr<DescriptorExtractor>& descriptorExtractor )
|
||||||
|
{
|
||||||
|
cout << "< Computing descriptors for keypoints..." << endl;
|
||||||
|
descriptorExtractor->compute( queryImage, queryKeypoints, queryDescriptors );
|
||||||
|
descriptorExtractor->compute( trainImages, trainKeypoints, trainDescriptors );
|
||||||
|
cout << ">" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void matchDescriptors( const Mat& queryDescriptors, const vector<Mat>& trainDescriptors,
|
||||||
|
vector<DMatch>& matches, Ptr<DescriptorMatcher>& descriptorMatcher )
|
||||||
|
{
|
||||||
|
cout << "< Set train descriptors collection in the matcher and match query descriptors to them..." << endl;
|
||||||
|
descriptorMatcher->add( trainDescriptors );
|
||||||
|
descriptorMatcher->match( queryDescriptors, matches );
|
||||||
|
CV_Assert( queryDescriptors.rows == (int)matches.size() || matches.empty() );
|
||||||
|
cout << ">" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveResultImages( const Mat& queryImage, const vector<KeyPoint>& queryKeypoints,
|
||||||
|
const vector<Mat>& trainImages, const vector<vector<KeyPoint> >& trainKeypoints,
|
||||||
|
const vector<DMatch>& matches, const vector<string>& trainImagesNames, const string& resultDir )
|
||||||
|
{
|
||||||
|
cout << "< Save results..." << endl;
|
||||||
|
Mat drawImg;
|
||||||
|
vector<char> mask;
|
||||||
|
for( size_t i = 0; i < trainImages.size(); i++ )
|
||||||
|
{
|
||||||
|
if( !trainImages[i].empty() )
|
||||||
|
{
|
||||||
|
maskMatchesByTrainImgIdx( matches, i, mask );
|
||||||
|
drawMatches( queryImage, queryKeypoints, trainImages[i], trainKeypoints[i],
|
||||||
|
matches, drawImg, Scalar::all(-1), Scalar::all(-1), mask );
|
||||||
|
string filename = resultDir + "/res_" + trainImagesNames[i];
|
||||||
|
if( !imwrite( filename, drawImg ) )
|
||||||
|
cout << "Image " << filename << " can not be saved (may be because directory " << resultDir << " does not exist)." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cout << ">" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printPrompt( const string& applName )
|
||||||
|
{
|
||||||
|
cout << endl << "Format:" << endl;
|
||||||
|
cout << applName << " [detectorType] [descriptorType] [matcherType] [queryImage] [fileWithTrainImages] [dirToSaveResImages]" << endl;
|
||||||
|
cout << endl << "Example:" << endl
|
||||||
|
<< defaultDetectorType << " " << defaultDescriptorType << " " << defaultMatcherType << " "
|
||||||
|
<< defaultQueryImageName << " " << defaultFileWithTrainImages << " " << defaultDirToSaveResImages << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
string detectorType = defaultDetectorType;
|
||||||
|
string descriptorType = defaultDescriptorType;
|
||||||
|
string matcherType = defaultMatcherType;
|
||||||
|
string queryImageName = defaultQueryImageName;
|
||||||
|
string fileWithTrainImages = defaultFileWithTrainImages;
|
||||||
|
string dirToSaveResImages = defaultDirToSaveResImages;
|
||||||
|
|
||||||
|
if( argc != 7 && argc != 1 )
|
||||||
|
{
|
||||||
|
printPrompt( argv[0] );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( argc != 1 )
|
||||||
|
{
|
||||||
|
detectorType = argv[1]; descriptorType = argv[2]; matcherType = argv[3];
|
||||||
|
queryImageName = argv[4]; fileWithTrainImages = argv[5];
|
||||||
|
dirToSaveResImages = argv[6];
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr<FeatureDetector> featureDetector;
|
||||||
|
Ptr<DescriptorExtractor> descriptorExtractor;
|
||||||
|
Ptr<DescriptorMatcher> descriptorMatcher;
|
||||||
|
if( !createDetectorDescriptorMatcher( detectorType, descriptorType, matcherType, featureDetector, descriptorExtractor, descriptorMatcher ) )
|
||||||
|
{
|
||||||
|
printPrompt( argv[0] );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat queryImage;
|
||||||
|
vector<Mat> trainImages;
|
||||||
|
vector<string> trainImagesNames;
|
||||||
|
if( !readImages( queryImageName, fileWithTrainImages, queryImage, trainImages, trainImagesNames ) )
|
||||||
|
{
|
||||||
|
printPrompt( argv[0] );
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<KeyPoint> queryKeypoints;
|
||||||
|
vector<vector<KeyPoint> > trainKeypoints;
|
||||||
|
detectKeypoints( queryImage, queryKeypoints, trainImages, trainKeypoints, featureDetector );
|
||||||
|
|
||||||
|
Mat queryDescriptors;
|
||||||
|
vector<Mat> trainDescriptors;
|
||||||
|
computeDescriptors( queryImage, queryKeypoints, queryDescriptors,
|
||||||
|
trainImages, trainKeypoints, trainDescriptors,
|
||||||
|
descriptorExtractor );
|
||||||
|
|
||||||
|
vector<DMatch> matches;
|
||||||
|
matchDescriptors( queryDescriptors, trainDescriptors, matches, descriptorMatcher );
|
||||||
|
|
||||||
|
saveResultImages( queryImage, queryKeypoints, trainImages, trainKeypoints,
|
||||||
|
matches, trainImagesNames, dirToSaveResImages );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
BIN
samples/cpp/matching_to_many_images/query.png
Executable file
BIN
samples/cpp/matching_to_many_images/query.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 119 KiB |
BIN
samples/cpp/matching_to_many_images/train/1.png
Executable file
BIN
samples/cpp/matching_to_many_images/train/1.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 116 KiB |
BIN
samples/cpp/matching_to_many_images/train/2.png
Executable file
BIN
samples/cpp/matching_to_many_images/train/2.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 112 KiB |
BIN
samples/cpp/matching_to_many_images/train/3.png
Executable file
BIN
samples/cpp/matching_to_many_images/train/3.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 118 KiB |
3
samples/cpp/matching_to_many_images/train/trainImages.txt
Executable file
3
samples/cpp/matching_to_many_images/train/trainImages.txt
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
1.png
|
||||||
|
2.png
|
||||||
|
3.png
|
@ -60,7 +60,7 @@ public:
|
|||||||
CvTest( testName, "cv::FeatureDetector::detect"), fdetector(_fdetector) {}
|
CvTest( testName, "cv::FeatureDetector::detect"), fdetector(_fdetector) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void run( int start_from )
|
virtual void run( int /*start_from*/ )
|
||||||
{
|
{
|
||||||
const float maxPtDif = 1.f;
|
const float maxPtDif = 1.f;
|
||||||
const float maxSizeDif = 1.f;
|
const float maxSizeDif = 1.f;
|
||||||
@ -112,7 +112,7 @@ protected:
|
|||||||
for( size_t c = 0; c < calcKeypoints.size(); c++ )
|
for( size_t c = 0; c < calcKeypoints.size(); c++ )
|
||||||
{
|
{
|
||||||
progress = update_progress( progress, v*calcKeypoints.size() + c, progressCount, 0 );
|
progress = update_progress( progress, v*calcKeypoints.size() + c, progressCount, 0 );
|
||||||
float curDist = norm( calcKeypoints[c].pt - validKeypoints[v].pt );
|
float curDist = (float)norm( calcKeypoints[c].pt - validKeypoints[v].pt );
|
||||||
if( curDist < minDist )
|
if( curDist < minDist )
|
||||||
{
|
{
|
||||||
minDist = curDist;
|
minDist = curDist;
|
||||||
@ -434,7 +434,7 @@ int CV_DescriptorMatcherTest::testMatch( const Mat& query, const Mat& train )
|
|||||||
for( size_t i = 0; i < matches.size(); i++ )
|
for( size_t i = 0; i < matches.size(); i++ )
|
||||||
{
|
{
|
||||||
DMatch match = matches[i];
|
DMatch match = matches[i];
|
||||||
int shift = dmatcher->supportMask() ? 1 : 0;
|
int shift = dmatcher->isMaskSupported() ? 1 : 0;
|
||||||
{
|
{
|
||||||
if( i < queryDescCount/2 )
|
if( i < queryDescCount/2 )
|
||||||
{
|
{
|
||||||
@ -533,7 +533,7 @@ int CV_DescriptorMatcherTest::testKnnMatch( const Mat& query, const Mat& train )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
int badCount = 0;
|
int badCount = 0;
|
||||||
int shift = dmatcher->supportMask() ? 1 : 0;
|
int shift = dmatcher->isMaskSupported() ? 1 : 0;
|
||||||
for( size_t i = 0; i < matches.size(); i++ )
|
for( size_t i = 0; i < matches.size(); i++ )
|
||||||
{
|
{
|
||||||
if( (int)matches[i].size() != knn )
|
if( (int)matches[i].size() != knn )
|
||||||
@ -641,8 +641,8 @@ int CV_DescriptorMatcherTest::testRadiusMatch( const Mat& query, const Mat& trai
|
|||||||
res = curRes != CvTS::OK ? curRes : res;
|
res = curRes != CvTS::OK ? curRes : res;
|
||||||
|
|
||||||
int badCount = 0;
|
int badCount = 0;
|
||||||
int shift = dmatcher->supportMask() ? 1 : 0;
|
int shift = dmatcher->isMaskSupported() ? 1 : 0;
|
||||||
int needMatchCount = dmatcher->supportMask() ? n-1 : n;
|
int needMatchCount = dmatcher->isMaskSupported() ? n-1 : n;
|
||||||
for( size_t i = 0; i < matches.size(); i++ )
|
for( size_t i = 0; i < matches.size(); i++ )
|
||||||
{
|
{
|
||||||
if( (int)matches[i].size() != needMatchCount )
|
if( (int)matches[i].size() != needMatchCount )
|
||||||
@ -741,6 +741,6 @@ CV_CalonderDescriptorExtractorTest<float> floatCalonderTest( "descriptor-calonde
|
|||||||
* Matchers
|
* Matchers
|
||||||
*/
|
*/
|
||||||
CV_DescriptorMatcherTest bruteForceMatcherTest( "descriptor-matcher-brute-force",
|
CV_DescriptorMatcherTest bruteForceMatcherTest( "descriptor-matcher-brute-force",
|
||||||
new BruteForceMatcher<L2<float> >, 0.01 );
|
new BruteForceMatcher<L2<float> >, 0.01f );
|
||||||
CV_DescriptorMatcherTest flannBasedMatcherTest( "descriptor-matcher-flann-based",
|
CV_DescriptorMatcherTest flannBasedMatcherTest( "descriptor-matcher-flann-based",
|
||||||
new FlannBasedMatcher, 0.04 );
|
new FlannBasedMatcher, 0.04f );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user