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
|
||||
{
|
||||
|
||||
BOWTrainer::BOWTrainer()
|
||||
{}
|
||||
|
||||
BOWTrainer::~BOWTrainer()
|
||||
{}
|
||||
|
||||
void BOWTrainer::add( const Mat& _descriptors )
|
||||
{
|
||||
CV_Assert( !_descriptors.empty() );
|
||||
@ -63,6 +69,16 @@ void BOWTrainer::add( const Mat& _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()
|
||||
{
|
||||
descriptors.clear();
|
||||
@ -91,6 +107,9 @@ Mat BOWKMeansTrainer::cluster() const
|
||||
return cluster( mergedDescriptors );
|
||||
}
|
||||
|
||||
BOWKMeansTrainer::~BOWKMeansTrainer()
|
||||
{}
|
||||
|
||||
Mat BOWKMeansTrainer::cluster( const Mat& descriptors ) const
|
||||
{
|
||||
Mat labels, vocabulary;
|
||||
@ -104,6 +123,9 @@ BOWImgDescriptorExtractor::BOWImgDescriptorExtractor( const Ptr<DescriptorExtrac
|
||||
dextractor(_dextractor), dmatcher(_dmatcher)
|
||||
{}
|
||||
|
||||
BOWImgDescriptorExtractor::~BOWImgDescriptorExtractor()
|
||||
{}
|
||||
|
||||
void BOWImgDescriptorExtractor::setVocabulary( const Mat& _vocabulary )
|
||||
{
|
||||
dmatcher->clear();
|
||||
@ -111,6 +133,11 @@ void BOWImgDescriptorExtractor::setVocabulary( const Mat& _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,
|
||||
vector<vector<int> >* pointIdxsOfClusters, Mat* _descriptors )
|
||||
{
|
||||
@ -153,4 +180,14 @@ void BOWImgDescriptorExtractor::compute( const Mat& image, vector<KeyPoint>& key
|
||||
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 <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
|
||||
{
|
||||
|
||||
BriefDescriptorExtractor::BriefDescriptorExtractor(int bytes) :
|
||||
bytes_(bytes), test_fn_(NULL)
|
||||
bytes_(bytes), test_fn_(NULL)
|
||||
{
|
||||
switch (bytes)
|
||||
{
|
||||
case 16:
|
||||
test_fn_ = pixelTests16;
|
||||
break;
|
||||
case 32:
|
||||
test_fn_ = pixelTests32;
|
||||
break;
|
||||
case 64:
|
||||
test_fn_ = pixelTests64;
|
||||
break;
|
||||
default:
|
||||
CV_Error(CV_StsBadArg, "bytes must be 16, 32, or 64");
|
||||
}
|
||||
switch (bytes)
|
||||
{
|
||||
case 16:
|
||||
test_fn_ = pixelTests16;
|
||||
break;
|
||||
case 32:
|
||||
test_fn_ = pixelTests32;
|
||||
break;
|
||||
case 64:
|
||||
test_fn_ = pixelTests64;
|
||||
break;
|
||||
default:
|
||||
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)
|
||||
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);
|
||||
return bytes_;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
uchar* desc = descriptors.ptr(i);
|
||||
const KeyPoint& pt = keypoints[i];
|
||||
|
||||
#include "generated_16.i"
|
||||
}
|
||||
return CV_8UC1;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
uchar* desc = descriptors.ptr(i);
|
||||
const KeyPoint& pt = keypoints[i];
|
||||
// Construct integral image for fast smoothing (box filter)
|
||||
Mat sum;
|
||||
|
||||
#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)
|
||||
{
|
||||
for (int i = 0; i < (int)keypoints.size(); ++i)
|
||||
{
|
||||
uchar* desc = descriptors.ptr(i);
|
||||
const KeyPoint& pt = keypoints[i];
|
||||
integral(image, sum, CV_32S);
|
||||
|
||||
#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>
|
||||
struct ByteBits
|
||||
{
|
||||
/**
|
||||
* number of bits in the byte given by the template constant
|
||||
*/
|
||||
enum
|
||||
{
|
||||
COUNT = ((b >> 0) & 1) +
|
||||
((b >> 1) & 1) +
|
||||
((b >> 2) & 1) +
|
||||
((b >> 3) & 1) +
|
||||
((b >> 4) & 1) +
|
||||
((b >> 5) & 1) +
|
||||
((b >> 6) & 1) +
|
||||
((b >> 7) & 1)
|
||||
};
|
||||
/**
|
||||
* number of bits in the byte given by the template constant
|
||||
*/
|
||||
enum
|
||||
{
|
||||
COUNT = ((b >> 0) & 1) +
|
||||
((b >> 1) & 1) +
|
||||
((b >> 2) & 1) +
|
||||
((b >> 3) & 1) +
|
||||
((b >> 4) & 1) +
|
||||
((b >> 5) & 1) +
|
||||
((b >> 6) & 1) +
|
||||
((b >> 7) & 1)
|
||||
};
|
||||
};
|
||||
unsigned char HammingLUT::byteBitsLookUp(unsigned char b){
|
||||
static const unsigned char table[256] =
|
||||
{
|
||||
ByteBits<0>::COUNT,
|
||||
ByteBits<1>::COUNT,
|
||||
ByteBits<2>::COUNT,
|
||||
ByteBits<3>::COUNT,
|
||||
ByteBits<4>::COUNT,
|
||||
ByteBits<5>::COUNT,
|
||||
ByteBits<6>::COUNT,
|
||||
ByteBits<7>::COUNT,
|
||||
ByteBits<8>::COUNT,
|
||||
ByteBits<9>::COUNT,
|
||||
ByteBits<10>::COUNT,
|
||||
ByteBits<11>::COUNT,
|
||||
ByteBits<12>::COUNT,
|
||||
ByteBits<13>::COUNT,
|
||||
ByteBits<14>::COUNT,
|
||||
ByteBits<15>::COUNT,
|
||||
ByteBits<16>::COUNT,
|
||||
ByteBits<17>::COUNT,
|
||||
ByteBits<18>::COUNT,
|
||||
ByteBits<19>::COUNT,
|
||||
ByteBits<20>::COUNT,
|
||||
ByteBits<21>::COUNT,
|
||||
ByteBits<22>::COUNT,
|
||||
ByteBits<23>::COUNT,
|
||||
ByteBits<24>::COUNT,
|
||||
ByteBits<25>::COUNT,
|
||||
ByteBits<26>::COUNT,
|
||||
ByteBits<27>::COUNT,
|
||||
ByteBits<28>::COUNT,
|
||||
ByteBits<29>::COUNT,
|
||||
ByteBits<30>::COUNT,
|
||||
ByteBits<31>::COUNT,
|
||||
ByteBits<32>::COUNT,
|
||||
ByteBits<33>::COUNT,
|
||||
ByteBits<34>::COUNT,
|
||||
ByteBits<35>::COUNT,
|
||||
ByteBits<36>::COUNT,
|
||||
ByteBits<37>::COUNT,
|
||||
ByteBits<38>::COUNT,
|
||||
ByteBits<39>::COUNT,
|
||||
ByteBits<40>::COUNT,
|
||||
ByteBits<41>::COUNT,
|
||||
ByteBits<42>::COUNT,
|
||||
ByteBits<43>::COUNT,
|
||||
ByteBits<44>::COUNT,
|
||||
ByteBits<45>::COUNT,
|
||||
ByteBits<46>::COUNT,
|
||||
ByteBits<47>::COUNT,
|
||||
ByteBits<48>::COUNT,
|
||||
ByteBits<49>::COUNT,
|
||||
ByteBits<50>::COUNT,
|
||||
ByteBits<51>::COUNT,
|
||||
ByteBits<52>::COUNT,
|
||||
ByteBits<53>::COUNT,
|
||||
ByteBits<54>::COUNT,
|
||||
ByteBits<55>::COUNT,
|
||||
ByteBits<56>::COUNT,
|
||||
ByteBits<57>::COUNT,
|
||||
ByteBits<58>::COUNT,
|
||||
ByteBits<59>::COUNT,
|
||||
ByteBits<60>::COUNT,
|
||||
ByteBits<61>::COUNT,
|
||||
ByteBits<62>::COUNT,
|
||||
ByteBits<63>::COUNT,
|
||||
ByteBits<64>::COUNT,
|
||||
ByteBits<65>::COUNT,
|
||||
ByteBits<66>::COUNT,
|
||||
ByteBits<67>::COUNT,
|
||||
ByteBits<68>::COUNT,
|
||||
ByteBits<69>::COUNT,
|
||||
ByteBits<70>::COUNT,
|
||||
ByteBits<71>::COUNT,
|
||||
ByteBits<72>::COUNT,
|
||||
ByteBits<73>::COUNT,
|
||||
ByteBits<74>::COUNT,
|
||||
ByteBits<75>::COUNT,
|
||||
ByteBits<76>::COUNT,
|
||||
ByteBits<77>::COUNT,
|
||||
ByteBits<78>::COUNT,
|
||||
ByteBits<79>::COUNT,
|
||||
ByteBits<80>::COUNT,
|
||||
ByteBits<81>::COUNT,
|
||||
ByteBits<82>::COUNT,
|
||||
ByteBits<83>::COUNT,
|
||||
ByteBits<84>::COUNT,
|
||||
ByteBits<85>::COUNT,
|
||||
ByteBits<86>::COUNT,
|
||||
ByteBits<87>::COUNT,
|
||||
ByteBits<88>::COUNT,
|
||||
ByteBits<89>::COUNT,
|
||||
ByteBits<90>::COUNT,
|
||||
ByteBits<91>::COUNT,
|
||||
ByteBits<92>::COUNT,
|
||||
ByteBits<93>::COUNT,
|
||||
ByteBits<94>::COUNT,
|
||||
ByteBits<95>::COUNT,
|
||||
ByteBits<96>::COUNT,
|
||||
ByteBits<97>::COUNT,
|
||||
ByteBits<98>::COUNT,
|
||||
ByteBits<99>::COUNT,
|
||||
ByteBits<100>::COUNT,
|
||||
ByteBits<101>::COUNT,
|
||||
ByteBits<102>::COUNT,
|
||||
ByteBits<103>::COUNT,
|
||||
ByteBits<104>::COUNT,
|
||||
ByteBits<105>::COUNT,
|
||||
ByteBits<106>::COUNT,
|
||||
ByteBits<107>::COUNT,
|
||||
ByteBits<108>::COUNT,
|
||||
ByteBits<109>::COUNT,
|
||||
ByteBits<110>::COUNT,
|
||||
ByteBits<111>::COUNT,
|
||||
ByteBits<112>::COUNT,
|
||||
ByteBits<113>::COUNT,
|
||||
ByteBits<114>::COUNT,
|
||||
ByteBits<115>::COUNT,
|
||||
ByteBits<116>::COUNT,
|
||||
ByteBits<117>::COUNT,
|
||||
ByteBits<118>::COUNT,
|
||||
ByteBits<119>::COUNT,
|
||||
ByteBits<120>::COUNT,
|
||||
ByteBits<121>::COUNT,
|
||||
ByteBits<122>::COUNT,
|
||||
ByteBits<123>::COUNT,
|
||||
ByteBits<124>::COUNT,
|
||||
ByteBits<125>::COUNT,
|
||||
ByteBits<126>::COUNT,
|
||||
ByteBits<127>::COUNT,
|
||||
ByteBits<128>::COUNT,
|
||||
ByteBits<129>::COUNT,
|
||||
ByteBits<130>::COUNT,
|
||||
ByteBits<131>::COUNT,
|
||||
ByteBits<132>::COUNT,
|
||||
ByteBits<133>::COUNT,
|
||||
ByteBits<134>::COUNT,
|
||||
ByteBits<135>::COUNT,
|
||||
ByteBits<136>::COUNT,
|
||||
ByteBits<137>::COUNT,
|
||||
ByteBits<138>::COUNT,
|
||||
ByteBits<139>::COUNT,
|
||||
ByteBits<140>::COUNT,
|
||||
ByteBits<141>::COUNT,
|
||||
ByteBits<142>::COUNT,
|
||||
ByteBits<143>::COUNT,
|
||||
ByteBits<144>::COUNT,
|
||||
ByteBits<145>::COUNT,
|
||||
ByteBits<146>::COUNT,
|
||||
ByteBits<147>::COUNT,
|
||||
ByteBits<148>::COUNT,
|
||||
ByteBits<149>::COUNT,
|
||||
ByteBits<150>::COUNT,
|
||||
ByteBits<151>::COUNT,
|
||||
ByteBits<152>::COUNT,
|
||||
ByteBits<153>::COUNT,
|
||||
ByteBits<154>::COUNT,
|
||||
ByteBits<155>::COUNT,
|
||||
ByteBits<156>::COUNT,
|
||||
ByteBits<157>::COUNT,
|
||||
ByteBits<158>::COUNT,
|
||||
ByteBits<159>::COUNT,
|
||||
ByteBits<160>::COUNT,
|
||||
ByteBits<161>::COUNT,
|
||||
ByteBits<162>::COUNT,
|
||||
ByteBits<163>::COUNT,
|
||||
ByteBits<164>::COUNT,
|
||||
ByteBits<165>::COUNT,
|
||||
ByteBits<166>::COUNT,
|
||||
ByteBits<167>::COUNT,
|
||||
ByteBits<168>::COUNT,
|
||||
ByteBits<169>::COUNT,
|
||||
ByteBits<170>::COUNT,
|
||||
ByteBits<171>::COUNT,
|
||||
ByteBits<172>::COUNT,
|
||||
ByteBits<173>::COUNT,
|
||||
ByteBits<174>::COUNT,
|
||||
ByteBits<175>::COUNT,
|
||||
ByteBits<176>::COUNT,
|
||||
ByteBits<177>::COUNT,
|
||||
ByteBits<178>::COUNT,
|
||||
ByteBits<179>::COUNT,
|
||||
ByteBits<180>::COUNT,
|
||||
ByteBits<181>::COUNT,
|
||||
ByteBits<182>::COUNT,
|
||||
ByteBits<183>::COUNT,
|
||||
ByteBits<184>::COUNT,
|
||||
ByteBits<185>::COUNT,
|
||||
ByteBits<186>::COUNT,
|
||||
ByteBits<187>::COUNT,
|
||||
ByteBits<188>::COUNT,
|
||||
ByteBits<189>::COUNT,
|
||||
ByteBits<190>::COUNT,
|
||||
ByteBits<191>::COUNT,
|
||||
ByteBits<192>::COUNT,
|
||||
ByteBits<193>::COUNT,
|
||||
ByteBits<194>::COUNT,
|
||||
ByteBits<195>::COUNT,
|
||||
ByteBits<196>::COUNT,
|
||||
ByteBits<197>::COUNT,
|
||||
ByteBits<198>::COUNT,
|
||||
ByteBits<199>::COUNT,
|
||||
ByteBits<200>::COUNT,
|
||||
ByteBits<201>::COUNT,
|
||||
ByteBits<202>::COUNT,
|
||||
ByteBits<203>::COUNT,
|
||||
ByteBits<204>::COUNT,
|
||||
ByteBits<205>::COUNT,
|
||||
ByteBits<206>::COUNT,
|
||||
ByteBits<207>::COUNT,
|
||||
ByteBits<208>::COUNT,
|
||||
ByteBits<209>::COUNT,
|
||||
ByteBits<210>::COUNT,
|
||||
ByteBits<211>::COUNT,
|
||||
ByteBits<212>::COUNT,
|
||||
ByteBits<213>::COUNT,
|
||||
ByteBits<214>::COUNT,
|
||||
ByteBits<215>::COUNT,
|
||||
ByteBits<216>::COUNT,
|
||||
ByteBits<217>::COUNT,
|
||||
ByteBits<218>::COUNT,
|
||||
ByteBits<219>::COUNT,
|
||||
ByteBits<220>::COUNT,
|
||||
ByteBits<221>::COUNT,
|
||||
ByteBits<222>::COUNT,
|
||||
ByteBits<223>::COUNT,
|
||||
ByteBits<224>::COUNT,
|
||||
ByteBits<225>::COUNT,
|
||||
ByteBits<226>::COUNT,
|
||||
ByteBits<227>::COUNT,
|
||||
ByteBits<228>::COUNT,
|
||||
ByteBits<229>::COUNT,
|
||||
ByteBits<230>::COUNT,
|
||||
ByteBits<231>::COUNT,
|
||||
ByteBits<232>::COUNT,
|
||||
ByteBits<233>::COUNT,
|
||||
ByteBits<234>::COUNT,
|
||||
ByteBits<235>::COUNT,
|
||||
ByteBits<236>::COUNT,
|
||||
ByteBits<237>::COUNT,
|
||||
ByteBits<238>::COUNT,
|
||||
ByteBits<239>::COUNT,
|
||||
ByteBits<240>::COUNT,
|
||||
ByteBits<241>::COUNT,
|
||||
ByteBits<242>::COUNT,
|
||||
ByteBits<243>::COUNT,
|
||||
ByteBits<244>::COUNT,
|
||||
ByteBits<245>::COUNT,
|
||||
ByteBits<246>::COUNT,
|
||||
ByteBits<247>::COUNT,
|
||||
ByteBits<248>::COUNT,
|
||||
ByteBits<249>::COUNT,
|
||||
ByteBits<250>::COUNT,
|
||||
ByteBits<251>::COUNT,
|
||||
ByteBits<252>::COUNT,
|
||||
ByteBits<253>::COUNT,
|
||||
ByteBits<254>::COUNT,
|
||||
ByteBits<255>::COUNT
|
||||
};
|
||||
return table[b];
|
||||
|
||||
unsigned char HammingLUT::byteBitsLookUp(unsigned char b)
|
||||
{
|
||||
static const unsigned char table[256] =
|
||||
{
|
||||
ByteBits<0>::COUNT,
|
||||
ByteBits<1>::COUNT,
|
||||
ByteBits<2>::COUNT,
|
||||
ByteBits<3>::COUNT,
|
||||
ByteBits<4>::COUNT,
|
||||
ByteBits<5>::COUNT,
|
||||
ByteBits<6>::COUNT,
|
||||
ByteBits<7>::COUNT,
|
||||
ByteBits<8>::COUNT,
|
||||
ByteBits<9>::COUNT,
|
||||
ByteBits<10>::COUNT,
|
||||
ByteBits<11>::COUNT,
|
||||
ByteBits<12>::COUNT,
|
||||
ByteBits<13>::COUNT,
|
||||
ByteBits<14>::COUNT,
|
||||
ByteBits<15>::COUNT,
|
||||
ByteBits<16>::COUNT,
|
||||
ByteBits<17>::COUNT,
|
||||
ByteBits<18>::COUNT,
|
||||
ByteBits<19>::COUNT,
|
||||
ByteBits<20>::COUNT,
|
||||
ByteBits<21>::COUNT,
|
||||
ByteBits<22>::COUNT,
|
||||
ByteBits<23>::COUNT,
|
||||
ByteBits<24>::COUNT,
|
||||
ByteBits<25>::COUNT,
|
||||
ByteBits<26>::COUNT,
|
||||
ByteBits<27>::COUNT,
|
||||
ByteBits<28>::COUNT,
|
||||
ByteBits<29>::COUNT,
|
||||
ByteBits<30>::COUNT,
|
||||
ByteBits<31>::COUNT,
|
||||
ByteBits<32>::COUNT,
|
||||
ByteBits<33>::COUNT,
|
||||
ByteBits<34>::COUNT,
|
||||
ByteBits<35>::COUNT,
|
||||
ByteBits<36>::COUNT,
|
||||
ByteBits<37>::COUNT,
|
||||
ByteBits<38>::COUNT,
|
||||
ByteBits<39>::COUNT,
|
||||
ByteBits<40>::COUNT,
|
||||
ByteBits<41>::COUNT,
|
||||
ByteBits<42>::COUNT,
|
||||
ByteBits<43>::COUNT,
|
||||
ByteBits<44>::COUNT,
|
||||
ByteBits<45>::COUNT,
|
||||
ByteBits<46>::COUNT,
|
||||
ByteBits<47>::COUNT,
|
||||
ByteBits<48>::COUNT,
|
||||
ByteBits<49>::COUNT,
|
||||
ByteBits<50>::COUNT,
|
||||
ByteBits<51>::COUNT,
|
||||
ByteBits<52>::COUNT,
|
||||
ByteBits<53>::COUNT,
|
||||
ByteBits<54>::COUNT,
|
||||
ByteBits<55>::COUNT,
|
||||
ByteBits<56>::COUNT,
|
||||
ByteBits<57>::COUNT,
|
||||
ByteBits<58>::COUNT,
|
||||
ByteBits<59>::COUNT,
|
||||
ByteBits<60>::COUNT,
|
||||
ByteBits<61>::COUNT,
|
||||
ByteBits<62>::COUNT,
|
||||
ByteBits<63>::COUNT,
|
||||
ByteBits<64>::COUNT,
|
||||
ByteBits<65>::COUNT,
|
||||
ByteBits<66>::COUNT,
|
||||
ByteBits<67>::COUNT,
|
||||
ByteBits<68>::COUNT,
|
||||
ByteBits<69>::COUNT,
|
||||
ByteBits<70>::COUNT,
|
||||
ByteBits<71>::COUNT,
|
||||
ByteBits<72>::COUNT,
|
||||
ByteBits<73>::COUNT,
|
||||
ByteBits<74>::COUNT,
|
||||
ByteBits<75>::COUNT,
|
||||
ByteBits<76>::COUNT,
|
||||
ByteBits<77>::COUNT,
|
||||
ByteBits<78>::COUNT,
|
||||
ByteBits<79>::COUNT,
|
||||
ByteBits<80>::COUNT,
|
||||
ByteBits<81>::COUNT,
|
||||
ByteBits<82>::COUNT,
|
||||
ByteBits<83>::COUNT,
|
||||
ByteBits<84>::COUNT,
|
||||
ByteBits<85>::COUNT,
|
||||
ByteBits<86>::COUNT,
|
||||
ByteBits<87>::COUNT,
|
||||
ByteBits<88>::COUNT,
|
||||
ByteBits<89>::COUNT,
|
||||
ByteBits<90>::COUNT,
|
||||
ByteBits<91>::COUNT,
|
||||
ByteBits<92>::COUNT,
|
||||
ByteBits<93>::COUNT,
|
||||
ByteBits<94>::COUNT,
|
||||
ByteBits<95>::COUNT,
|
||||
ByteBits<96>::COUNT,
|
||||
ByteBits<97>::COUNT,
|
||||
ByteBits<98>::COUNT,
|
||||
ByteBits<99>::COUNT,
|
||||
ByteBits<100>::COUNT,
|
||||
ByteBits<101>::COUNT,
|
||||
ByteBits<102>::COUNT,
|
||||
ByteBits<103>::COUNT,
|
||||
ByteBits<104>::COUNT,
|
||||
ByteBits<105>::COUNT,
|
||||
ByteBits<106>::COUNT,
|
||||
ByteBits<107>::COUNT,
|
||||
ByteBits<108>::COUNT,
|
||||
ByteBits<109>::COUNT,
|
||||
ByteBits<110>::COUNT,
|
||||
ByteBits<111>::COUNT,
|
||||
ByteBits<112>::COUNT,
|
||||
ByteBits<113>::COUNT,
|
||||
ByteBits<114>::COUNT,
|
||||
ByteBits<115>::COUNT,
|
||||
ByteBits<116>::COUNT,
|
||||
ByteBits<117>::COUNT,
|
||||
ByteBits<118>::COUNT,
|
||||
ByteBits<119>::COUNT,
|
||||
ByteBits<120>::COUNT,
|
||||
ByteBits<121>::COUNT,
|
||||
ByteBits<122>::COUNT,
|
||||
ByteBits<123>::COUNT,
|
||||
ByteBits<124>::COUNT,
|
||||
ByteBits<125>::COUNT,
|
||||
ByteBits<126>::COUNT,
|
||||
ByteBits<127>::COUNT,
|
||||
ByteBits<128>::COUNT,
|
||||
ByteBits<129>::COUNT,
|
||||
ByteBits<130>::COUNT,
|
||||
ByteBits<131>::COUNT,
|
||||
ByteBits<132>::COUNT,
|
||||
ByteBits<133>::COUNT,
|
||||
ByteBits<134>::COUNT,
|
||||
ByteBits<135>::COUNT,
|
||||
ByteBits<136>::COUNT,
|
||||
ByteBits<137>::COUNT,
|
||||
ByteBits<138>::COUNT,
|
||||
ByteBits<139>::COUNT,
|
||||
ByteBits<140>::COUNT,
|
||||
ByteBits<141>::COUNT,
|
||||
ByteBits<142>::COUNT,
|
||||
ByteBits<143>::COUNT,
|
||||
ByteBits<144>::COUNT,
|
||||
ByteBits<145>::COUNT,
|
||||
ByteBits<146>::COUNT,
|
||||
ByteBits<147>::COUNT,
|
||||
ByteBits<148>::COUNT,
|
||||
ByteBits<149>::COUNT,
|
||||
ByteBits<150>::COUNT,
|
||||
ByteBits<151>::COUNT,
|
||||
ByteBits<152>::COUNT,
|
||||
ByteBits<153>::COUNT,
|
||||
ByteBits<154>::COUNT,
|
||||
ByteBits<155>::COUNT,
|
||||
ByteBits<156>::COUNT,
|
||||
ByteBits<157>::COUNT,
|
||||
ByteBits<158>::COUNT,
|
||||
ByteBits<159>::COUNT,
|
||||
ByteBits<160>::COUNT,
|
||||
ByteBits<161>::COUNT,
|
||||
ByteBits<162>::COUNT,
|
||||
ByteBits<163>::COUNT,
|
||||
ByteBits<164>::COUNT,
|
||||
ByteBits<165>::COUNT,
|
||||
ByteBits<166>::COUNT,
|
||||
ByteBits<167>::COUNT,
|
||||
ByteBits<168>::COUNT,
|
||||
ByteBits<169>::COUNT,
|
||||
ByteBits<170>::COUNT,
|
||||
ByteBits<171>::COUNT,
|
||||
ByteBits<172>::COUNT,
|
||||
ByteBits<173>::COUNT,
|
||||
ByteBits<174>::COUNT,
|
||||
ByteBits<175>::COUNT,
|
||||
ByteBits<176>::COUNT,
|
||||
ByteBits<177>::COUNT,
|
||||
ByteBits<178>::COUNT,
|
||||
ByteBits<179>::COUNT,
|
||||
ByteBits<180>::COUNT,
|
||||
ByteBits<181>::COUNT,
|
||||
ByteBits<182>::COUNT,
|
||||
ByteBits<183>::COUNT,
|
||||
ByteBits<184>::COUNT,
|
||||
ByteBits<185>::COUNT,
|
||||
ByteBits<186>::COUNT,
|
||||
ByteBits<187>::COUNT,
|
||||
ByteBits<188>::COUNT,
|
||||
ByteBits<189>::COUNT,
|
||||
ByteBits<190>::COUNT,
|
||||
ByteBits<191>::COUNT,
|
||||
ByteBits<192>::COUNT,
|
||||
ByteBits<193>::COUNT,
|
||||
ByteBits<194>::COUNT,
|
||||
ByteBits<195>::COUNT,
|
||||
ByteBits<196>::COUNT,
|
||||
ByteBits<197>::COUNT,
|
||||
ByteBits<198>::COUNT,
|
||||
ByteBits<199>::COUNT,
|
||||
ByteBits<200>::COUNT,
|
||||
ByteBits<201>::COUNT,
|
||||
ByteBits<202>::COUNT,
|
||||
ByteBits<203>::COUNT,
|
||||
ByteBits<204>::COUNT,
|
||||
ByteBits<205>::COUNT,
|
||||
ByteBits<206>::COUNT,
|
||||
ByteBits<207>::COUNT,
|
||||
ByteBits<208>::COUNT,
|
||||
ByteBits<209>::COUNT,
|
||||
ByteBits<210>::COUNT,
|
||||
ByteBits<211>::COUNT,
|
||||
ByteBits<212>::COUNT,
|
||||
ByteBits<213>::COUNT,
|
||||
ByteBits<214>::COUNT,
|
||||
ByteBits<215>::COUNT,
|
||||
ByteBits<216>::COUNT,
|
||||
ByteBits<217>::COUNT,
|
||||
ByteBits<218>::COUNT,
|
||||
ByteBits<219>::COUNT,
|
||||
ByteBits<220>::COUNT,
|
||||
ByteBits<221>::COUNT,
|
||||
ByteBits<222>::COUNT,
|
||||
ByteBits<223>::COUNT,
|
||||
ByteBits<224>::COUNT,
|
||||
ByteBits<225>::COUNT,
|
||||
ByteBits<226>::COUNT,
|
||||
ByteBits<227>::COUNT,
|
||||
ByteBits<228>::COUNT,
|
||||
ByteBits<229>::COUNT,
|
||||
ByteBits<230>::COUNT,
|
||||
ByteBits<231>::COUNT,
|
||||
ByteBits<232>::COUNT,
|
||||
ByteBits<233>::COUNT,
|
||||
ByteBits<234>::COUNT,
|
||||
ByteBits<235>::COUNT,
|
||||
ByteBits<236>::COUNT,
|
||||
ByteBits<237>::COUNT,
|
||||
ByteBits<238>::COUNT,
|
||||
ByteBits<239>::COUNT,
|
||||
ByteBits<240>::COUNT,
|
||||
ByteBits<241>::COUNT,
|
||||
ByteBits<242>::COUNT,
|
||||
ByteBits<243>::COUNT,
|
||||
ByteBits<244>::COUNT,
|
||||
ByteBits<245>::COUNT,
|
||||
ByteBits<246>::COUNT,
|
||||
ByteBits<247>::COUNT,
|
||||
ByteBits<248>::COUNT,
|
||||
ByteBits<249>::COUNT,
|
||||
ByteBits<250>::COUNT,
|
||||
ByteBits<251>::COUNT,
|
||||
ByteBits<252>::COUNT,
|
||||
ByteBits<253>::COUNT,
|
||||
ByteBits<254>::COUNT,
|
||||
ByteBits<255>::COUNT
|
||||
};
|
||||
|
||||
return table[b];
|
||||
}
|
||||
|
||||
} // namespace cv
|
||||
|
@ -67,6 +67,21 @@ struct RoiPredicate
|
||||
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
|
||||
{
|
||||
descCollection.resize( imageCollection.size() );
|
||||
@ -74,27 +89,42 @@ void DescriptorExtractor::compute( const vector<Mat>& imageCollection, vector<ve
|
||||
compute( imageCollection[i], pointCollection[i], descCollection[i] );
|
||||
}
|
||||
|
||||
void DescriptorExtractor::read( const FileNode& )
|
||||
{}
|
||||
|
||||
void DescriptorExtractor::write( FileStorage& ) const
|
||||
{}
|
||||
|
||||
void DescriptorExtractor::removeBorderKeypoints( vector<KeyPoint>& keypoints,
|
||||
Size imageSize, int borderPixels )
|
||||
Size imageSize, int borderSize )
|
||||
{
|
||||
keypoints.erase( remove_if(keypoints.begin(), keypoints.end(),
|
||||
RoiPredicate((float)borderPixels, (float)borderPixels,
|
||||
(float)(imageSize.width - borderPixels),
|
||||
(float)(imageSize.height - borderPixels))),
|
||||
keypoints.end());
|
||||
if( borderSize > 0)
|
||||
{
|
||||
keypoints.erase( remove_if(keypoints.begin(), keypoints.end(),
|
||||
RoiPredicate((float)borderSize, (float)borderSize,
|
||||
(float)(imageSize.width - borderSize),
|
||||
(float)(imageSize.height - borderSize))),
|
||||
keypoints.end() );
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************************\
|
||||
* 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,
|
||||
int nOctaves, int nOctaveLayers, int firstOctave, int angleMode )
|
||||
: sift( magnification, isNormalize, recalculateAngles, nOctaves, nOctaveLayers, firstOctave, angleMode )
|
||||
{}
|
||||
|
||||
void SiftDescriptorExtractor::compute( const Mat& image,
|
||||
vector<KeyPoint>& keypoints,
|
||||
Mat& descriptors) const
|
||||
void SiftDescriptorExtractor::computeImpl( const Mat& image,
|
||||
vector<KeyPoint>& keypoints,
|
||||
Mat& descriptors) const
|
||||
{
|
||||
bool useProvidedKeypoints = true;
|
||||
Mat grayImage = image;
|
||||
@ -131,6 +161,16 @@ void SiftDescriptorExtractor::write (FileStorage &fs) const
|
||||
fs << "angleMode" << commParams.angleMode;
|
||||
}
|
||||
|
||||
int SiftDescriptorExtractor::descriptorSize() const
|
||||
{
|
||||
return sift.descriptorSize();
|
||||
}
|
||||
|
||||
int SiftDescriptorExtractor::descriptorType() const
|
||||
{
|
||||
return CV_32FC1;
|
||||
}
|
||||
|
||||
/****************************************************************************************\
|
||||
* SurfDescriptorExtractor *
|
||||
\****************************************************************************************/
|
||||
@ -139,9 +179,9 @@ SurfDescriptorExtractor::SurfDescriptorExtractor( int nOctaves,
|
||||
: surf( 0.0, nOctaves, nOctaveLayers, extended )
|
||||
{}
|
||||
|
||||
void SurfDescriptorExtractor::compute( const Mat& image,
|
||||
vector<KeyPoint>& keypoints,
|
||||
Mat& descriptors) const
|
||||
void SurfDescriptorExtractor::computeImpl( const Mat& image,
|
||||
vector<KeyPoint>& keypoints,
|
||||
Mat& descriptors) const
|
||||
{
|
||||
// Compute descriptors for given keypoints
|
||||
vector<float> _descriptors;
|
||||
@ -175,11 +215,21 @@ void SurfDescriptorExtractor::write( FileStorage &fs ) const
|
||||
fs << "extended" << surf.extended;
|
||||
}
|
||||
|
||||
int SurfDescriptorExtractor::descriptorSize() const
|
||||
{
|
||||
return surf.descriptorSize();
|
||||
}
|
||||
|
||||
int SurfDescriptorExtractor::descriptorType() const
|
||||
{
|
||||
return CV_32FC1;
|
||||
}
|
||||
|
||||
/****************************************************************************************\
|
||||
* OpponentColorDescriptorExtractor *
|
||||
\****************************************************************************************/
|
||||
OpponentColorDescriptorExtractor::OpponentColorDescriptorExtractor( const Ptr<DescriptorExtractor>& _dextractor ) :
|
||||
dextractor(_dextractor)
|
||||
OpponentColorDescriptorExtractor::OpponentColorDescriptorExtractor( const Ptr<DescriptorExtractor>& _descriptorExtractor ) :
|
||||
descriptorExtractor(_descriptorExtractor)
|
||||
{}
|
||||
|
||||
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;
|
||||
convertBGRImageToOpponentColorSpace( bgrImage, opponentChannels );
|
||||
|
||||
// Compute descriptors three times, once for each Opponent channel
|
||||
// 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 );
|
||||
for( int i = 0; i < 3/*channel count*/; i++ )
|
||||
{
|
||||
CV_Assert( opponentChannels[i].type() == CV_8UC1 );
|
||||
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 )
|
||||
{
|
||||
dextractor->read( fn );
|
||||
descriptorExtractor->read(fn);
|
||||
}
|
||||
|
||||
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 *
|
||||
\****************************************************************************************/
|
||||
|
@ -61,6 +61,21 @@ struct MaskPredicate
|
||||
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
|
||||
{
|
||||
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());
|
||||
};
|
||||
|
||||
void FeatureDetector::read( const FileNode& )
|
||||
{}
|
||||
|
||||
void FeatureDetector::write( FileStorage& ) const
|
||||
{}
|
||||
|
||||
/*
|
||||
* FastFeatureDetector
|
||||
*/
|
||||
@ -95,7 +116,7 @@ void FastFeatureDetector::write (FileStorage& fs) const
|
||||
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;
|
||||
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( int _maxCorners, double _qualityLevel, \
|
||||
double _minDistance, int _blockSize,
|
||||
bool _useHarrisDetector, double _k )
|
||||
: maxCorners(_maxCorners), qualityLevel(_qualityLevel), minDistance(_minDistance),
|
||||
blockSize(_blockSize), useHarrisDetector(_useHarrisDetector), k(_k)
|
||||
GoodFeaturesToTrackDetector::Params::Params( int _maxCorners, double _qualityLevel, double _minDistance,
|
||||
int _blockSize, bool _useHarrisDetector, double _k ) :
|
||||
maxCorners(_maxCorners), qualityLevel(_qualityLevel), minDistance(_minDistance),
|
||||
blockSize(_blockSize), useHarrisDetector(_useHarrisDetector), k(_k)
|
||||
{}
|
||||
|
||||
void GoodFeaturesToTrackDetector::read (const FileNode& fn)
|
||||
void GoodFeaturesToTrackDetector::Params::read (const FileNode& fn)
|
||||
{
|
||||
maxCorners = fn["maxCorners"];
|
||||
qualityLevel = fn["qualityLevel"];
|
||||
@ -123,7 +143,7 @@ void GoodFeaturesToTrackDetector::read (const FileNode& fn)
|
||||
k = fn["k"];
|
||||
}
|
||||
|
||||
void GoodFeaturesToTrackDetector::write (FileStorage& fs) const
|
||||
void GoodFeaturesToTrackDetector::Params::write (FileStorage& fs) const
|
||||
{
|
||||
fs << "maxCorners" << maxCorners;
|
||||
fs << "qualityLevel" << qualityLevel;
|
||||
@ -133,20 +153,40 @@ void GoodFeaturesToTrackDetector::write (FileStorage& fs) const
|
||||
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;
|
||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||
|
||||
vector<Point2f> corners;
|
||||
goodFeaturesToTrack( grayImage, corners, maxCorners, qualityLevel, minDistance, mask,
|
||||
blockSize, useHarrisDetector, k );
|
||||
goodFeaturesToTrack( grayImage, corners, params.maxCorners, params.qualityLevel, params.minDistance, mask,
|
||||
params.blockSize, params.useHarrisDetector, params.k );
|
||||
keypoints.resize(corners.size());
|
||||
vector<Point2f>::const_iterator corner_it = corners.begin();
|
||||
vector<KeyPoint>::iterator keypoint_it = keypoints.begin();
|
||||
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;
|
||||
|
||||
mser(image, msers, mask);
|
||||
|
||||
keypoints.clear();
|
||||
vector<vector<Point> >::const_iterator contour_it = msers.begin();
|
||||
for( ; contour_it != msers.end(); ++contour_it )
|
||||
{
|
||||
@ -220,6 +259,12 @@ void MserFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints,
|
||||
/*
|
||||
* StarFeatureDetector
|
||||
*/
|
||||
|
||||
StarFeatureDetector::StarFeatureDetector( const CvStarDetectorParams& params )
|
||||
: star( params.maxSize, params.responseThreshold, params.lineThresholdProjected,
|
||||
params.lineThresholdBinarized, params.suppressNonmaxSize)
|
||||
{}
|
||||
|
||||
StarFeatureDetector::StarFeatureDetector(int maxSize, int responseThreshold,
|
||||
int lineThresholdProjected,
|
||||
int lineThresholdBinarized,
|
||||
@ -251,7 +296,7 @@ void StarFeatureDetector::write (FileStorage& fs) const
|
||||
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;
|
||||
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(double threshold, double edgeThreshold,
|
||||
int nOctaves, int nOctaveLayers, int firstOctave, int angleMode) :
|
||||
SiftFeatureDetector::SiftFeatureDetector( const SIFT::DetectorParams &detectorParams,
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
void SiftFeatureDetector::read (const FileNode& fn)
|
||||
void SiftFeatureDetector::read( const FileNode& fn )
|
||||
{
|
||||
double threshold = fn["threshold"];
|
||||
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;
|
||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||
@ -329,7 +381,7 @@ void SurfFeatureDetector::write (FileStorage& fs) const
|
||||
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;
|
||||
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
||||
@ -340,14 +392,24 @@ void SurfFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints,
|
||||
/*
|
||||
* DenseFeatureDetector
|
||||
*/
|
||||
void DenseFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
||||
{
|
||||
keypoints.clear();
|
||||
DenseFeatureDetector::Params::Params( float _initFeatureScale, int _featureScaleLevels,
|
||||
float _featureScaleMul, int _initXyStep,
|
||||
int _initImgBound, bool _varyXyStepWithScale,
|
||||
bool _varyImgBoundWithScale ) :
|
||||
initFeatureScale(_initFeatureScale), featureScaleLevels(_featureScaleLevels),
|
||||
featureScaleMul(_featureScaleMul), initXyStep(_initXyStep), initImgBound(_initImgBound),
|
||||
varyXyStepWithScale(_varyXyStepWithScale), varyImgBoundWithScale(_varyImgBoundWithScale)
|
||||
{}
|
||||
|
||||
float curScale = initFeatureScale;
|
||||
int curStep = initXyStep;
|
||||
int curBound = initImgBound;
|
||||
for( int curLevel = 0; curLevel < featureScaleLevels; curLevel++ )
|
||||
DenseFeatureDetector::DenseFeatureDetector(const DenseFeatureDetector::Params &_params) : params(_params)
|
||||
{}
|
||||
|
||||
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 )
|
||||
{
|
||||
@ -357,9 +419,9 @@ void DenseFeatureDetector::detect( const Mat& image, vector<KeyPoint>& keypoints
|
||||
}
|
||||
}
|
||||
|
||||
curScale = curScale * featureScaleMul;
|
||||
if( varyXyStepWithScale ) curStep = static_cast<int>( curStep * featureScaleMul + 0.5f );
|
||||
if( varyImgBoundWithScale ) curBound = static_cast<int>( curBound * featureScaleMul + 0.5f );
|
||||
curScale = curScale * params.featureScaleMul;
|
||||
if( params.varyXyStepWithScale ) curStep = static_cast<int>( curStep * params.featureScaleMul + 0.5f );
|
||||
if( params.varyImgBoundWithScale ) curBound = static_cast<int>( curBound * params.featureScaleMul + 0.5f );
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
int maxPerCell = maxTotalKeypoints / (gridRows * gridCols);
|
||||
@ -430,7 +491,7 @@ PyramidAdaptedFeatureDetector::PyramidAdaptedFeatureDetector( const Ptr<FeatureD
|
||||
: 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;
|
||||
for( int l = 0, multiplier = 1; l <= levels; ++l, multiplier *= 2 )
|
||||
@ -463,12 +524,11 @@ Ptr<FeatureDetector> createFeatureDetector( const string& detectorType )
|
||||
FeatureDetector* fd = 0;
|
||||
if( !detectorType.compare( "FAST" ) )
|
||||
{
|
||||
fd = new FastFeatureDetector( 10/*threshold*/, true/*nonmax_suppression*/ );
|
||||
fd = new FastFeatureDetector();
|
||||
}
|
||||
else if( !detectorType.compare( "STAR" ) )
|
||||
{
|
||||
fd = new StarFeatureDetector( 16/*max_size*/, 5/*response_threshold*/, 10/*line_threshold_projected*/,
|
||||
8/*line_threshold_binarized*/, 5/*suppress_nonmax_size*/ );
|
||||
fd = new StarFeatureDetector();
|
||||
}
|
||||
else if( !detectorType.compare( "SIFT" ) )
|
||||
{
|
||||
@ -477,23 +537,21 @@ Ptr<FeatureDetector> createFeatureDetector( const string& detectorType )
|
||||
}
|
||||
else if( !detectorType.compare( "SURF" ) )
|
||||
{
|
||||
fd = new SurfFeatureDetector( 400./*hessian_threshold*/, 3 /*octaves*/, 4/*octave_layers*/ );
|
||||
fd = new SurfFeatureDetector();
|
||||
}
|
||||
else if( !detectorType.compare( "MSER" ) )
|
||||
{
|
||||
fd = new MserFeatureDetector( 5/*delta*/, 60/*min_area*/, 14400/*_max_area*/, 0.25f/*max_variation*/,
|
||||
0.2/*min_diversity*/, 200/*max_evolution*/, 1.01/*area_threshold*/, 0.003/*min_margin*/,
|
||||
5/*edge_blur_size*/ );
|
||||
fd = new MserFeatureDetector();
|
||||
}
|
||||
else if( !detectorType.compare( "GFTT" ) )
|
||||
{
|
||||
fd = new GoodFeaturesToTrackDetector( 1000/*maxCorners*/, 0.01/*qualityLevel*/, 1./*minDistance*/,
|
||||
3/*int _blockSize*/, false/*useHarrisDetector*/, 0.04/*k*/ );
|
||||
fd = new GoodFeaturesToTrackDetector();
|
||||
}
|
||||
else if( !detectorType.compare( "HARRIS" ) )
|
||||
{
|
||||
fd = new GoodFeaturesToTrackDetector( 1000/*maxCorners*/, 0.01/*qualityLevel*/, 1./*minDistance*/,
|
||||
3/*int _blockSize*/, true/*useHarrisDetector*/, 0.04/*k*/ );
|
||||
GoodFeaturesToTrackDetector::Params params;
|
||||
params.useHarrisDetector = true;
|
||||
fd = new GoodFeaturesToTrackDetector(params);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
@ -71,11 +71,23 @@ Mat windowedMatchingMask( const vector<KeyPoint>& keypoints1, const vector<KeyPo
|
||||
/****************************************************************************************\
|
||||
* 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();
|
||||
|
||||
size_t imageCount = descCollection.size();
|
||||
size_t imageCount = descriptors.size();
|
||||
CV_Assert( imageCount > 0 );
|
||||
|
||||
startIdxs.resize( imageCount );
|
||||
@ -86,35 +98,35 @@ void DescriptorMatcher::DescriptorCollection::set( const vector<Mat>& descCollec
|
||||
for( size_t i = 1; i < imageCount; i++ )
|
||||
{
|
||||
int s = 0;
|
||||
if( !descCollection[i-1].empty() )
|
||||
if( !descriptors[i-1].empty() )
|
||||
{
|
||||
dim = descCollection[i-1].cols;
|
||||
type = descCollection[i-1].type();
|
||||
s = descCollection[i-1].rows;
|
||||
dim = descriptors[i-1].cols;
|
||||
type = descriptors[i-1].type();
|
||||
s = descriptors[i-1].rows;
|
||||
}
|
||||
startIdxs[i] = startIdxs[i-1] + s;
|
||||
}
|
||||
if( imageCount == 1 )
|
||||
{
|
||||
if( descCollection[0].empty() ) return;
|
||||
if( descriptors[0].empty() ) return;
|
||||
|
||||
dim = descCollection[0].cols;
|
||||
type = descCollection[0].type();
|
||||
dim = descriptors[0].cols;
|
||||
type = descriptors[0].type();
|
||||
}
|
||||
assert( dim > 0 );
|
||||
|
||||
int count = startIdxs[imageCount-1] + descCollection[imageCount-1].rows;
|
||||
int count = startIdxs[imageCount-1] + descriptors[imageCount-1].rows;
|
||||
|
||||
if( count > 0 )
|
||||
{
|
||||
dmatrix.create( count, dim, type );
|
||||
mergedDescriptors.create( count, dim, type );
|
||||
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 );
|
||||
Mat m = dmatrix.rowRange( startIdxs[i], startIdxs[i] + descCollection[i].rows );
|
||||
descCollection[i].copyTo(m);
|
||||
CV_Assert( descriptors[i].cols == dim && descriptors[i].type() == type );
|
||||
Mat m = mergedDescriptors.rowRange( startIdxs[i], startIdxs[i] + descriptors[i].rows );
|
||||
descriptors[i].copyTo(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -123,7 +135,7 @@ void DescriptorMatcher::DescriptorCollection::set( const vector<Mat>& descCollec
|
||||
void DescriptorMatcher::DescriptorCollection::clear()
|
||||
{
|
||||
startIdxs.clear();
|
||||
dmatrix.release();
|
||||
mergedDescriptors.release();
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
const Mat& DescriptorMatcher::DescriptorCollection::getDescriptors() const
|
||||
{
|
||||
return mergedDescriptors;
|
||||
}
|
||||
|
||||
const Mat DescriptorMatcher::DescriptorCollection::getDescriptor( int globalDescIdx ) const
|
||||
{
|
||||
CV_Assert( globalDescIdx < size() );
|
||||
return dmatrix.row( globalDescIdx );
|
||||
return mergedDescriptors.row( globalDescIdx );
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
int DescriptorMatcher::DescriptorCollection::size() const
|
||||
{
|
||||
return mergedDescriptors.rows;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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()
|
||||
@ -182,67 +212,134 @@ void DescriptorMatcher::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();
|
||||
tempMatcher->add( vector<Mat>(1, trainDescs) );
|
||||
tempMatcher->match( queryDescs, matches, vector<Mat>(1, mask) );
|
||||
return trainDescCollection.size() == 0;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
Ptr<DescriptorMatcher> tempMatcher = cloneWithoutData();
|
||||
tempMatcher->add( vector<Mat>(1, trainDescs) );
|
||||
tempMatcher->knnMatch( queryDescs, matches, knn, vector<Mat>(1, mask), compactResult );
|
||||
Ptr<DescriptorMatcher> tempMatcher = clone(true);
|
||||
tempMatcher->add( vector<Mat>(1, trainDescriptors) );
|
||||
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
|
||||
{
|
||||
Ptr<DescriptorMatcher> tempMatcher = cloneWithoutData();
|
||||
tempMatcher->add( vector<Mat>(1, trainDescs) );
|
||||
tempMatcher->radiusMatch( queryDescs, matches, maxDistance, vector<Mat>(1, mask), compactResult );
|
||||
Ptr<DescriptorMatcher> tempMatcher = clone(true);
|
||||
tempMatcher->add( vector<Mat>(1, trainDescriptors) );
|
||||
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;
|
||||
knnMatch( queryDescs, knnMatches, 1, masks, true /*compactResult*/ );
|
||||
knnMatch( queryDescriptors, knnMatches, 1, masks, true /*compactResult*/ );
|
||||
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 )
|
||||
{
|
||||
matches.empty();
|
||||
if( empty() || queryDescriptors.empty() )
|
||||
return;
|
||||
|
||||
CV_Assert( knn > 0 );
|
||||
|
||||
checkMasks( masks, queryDescriptors.rows );
|
||||
|
||||
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 )
|
||||
{
|
||||
matches.empty();
|
||||
if( empty() || queryDescriptors.empty() )
|
||||
return;
|
||||
|
||||
CV_Assert( maxDistance > std::numeric_limits<float>::epsilon() );
|
||||
|
||||
checkMasks( masks, queryDescriptors.rows );
|
||||
|
||||
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<>
|
||||
void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescs, vector<vector<DMatch> >& matches, int knn,
|
||||
const vector<Mat>& masks, bool compactResult )
|
||||
void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescriptors, vector<vector<DMatch> >& matches, int knn,
|
||||
const vector<Mat>& masks, bool compactResult )
|
||||
{
|
||||
#ifndef HAVE_EIGEN2
|
||||
bfKnnMatchImpl( *this, queryDescs, matches, knn, masks, compactResult );
|
||||
commonKnnMatchImpl( *this, queryDescriptors, matches, knn, masks, compactResult );
|
||||
#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() );
|
||||
|
||||
matches.reserve(queryDescs.rows);
|
||||
matches.reserve(queryDescriptors.rows);
|
||||
size_t imgCount = trainDescCollection.size();
|
||||
|
||||
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_trainNorms2(trainDescCollection.size());
|
||||
cv2eigen( queryDescs.t(), e_query_t);
|
||||
cv2eigen( queryDescriptors.t(), e_query_t);
|
||||
for( size_t i = 0; i < trainDescCollection.size(); 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
|
||||
|
||||
for( int qIdx = 0; qIdx < queryDescs.rows; qIdx++ )
|
||||
for( int qIdx = 0; qIdx < queryDescriptors.rows; 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++ )
|
||||
{
|
||||
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 ) );
|
||||
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_trainNorms2[iIdx];
|
||||
@ -315,22 +412,22 @@ void BruteForceMatcher<L2<float> >::knnMatchImpl( const Mat& queryDescs, vector<
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
#ifndef HAVE_EIGEN2
|
||||
bfRadiusMatchImpl( *this, queryDescs, matches, maxDistance, masks, compactResult );
|
||||
commonRadiusMatchImpl( *this, queryDescriptors, matches, maxDistance, masks, compactResult );
|
||||
#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() );
|
||||
|
||||
matches.reserve(queryDescs.rows);
|
||||
matches.reserve(queryDescriptors.rows);
|
||||
size_t imgCount = trainDescCollection.size();
|
||||
|
||||
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_trainNorms2(trainDescCollection.size());
|
||||
cv2eigen( queryDescs.t(), e_query_t);
|
||||
cv2eigen( queryDescriptors.t(), e_query_t);
|
||||
for( size_t i = 0; i < trainDescCollection.size(); 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
|
||||
|
||||
for( int qIdx = 0; qIdx < queryDescs.rows; qIdx++ )
|
||||
for( int qIdx = 0; qIdx < queryDescriptors.rows; 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++ )
|
||||
{
|
||||
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 ) );
|
||||
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_trainNorms2[iIdx];
|
||||
@ -393,12 +490,12 @@ FlannBasedMatcher::FlannBasedMatcher( const Ptr<flann::IndexParams>& _indexParam
|
||||
CV_Assert( !_searchParams.empty() );
|
||||
}
|
||||
|
||||
void FlannBasedMatcher::add( const vector<Mat>& descCollection )
|
||||
void FlannBasedMatcher::add( const vector<Mat>& descriptors )
|
||||
{
|
||||
DescriptorMatcher::add( descCollection );
|
||||
for( size_t i = 0; i < descCollection.size(); i++ )
|
||||
DescriptorMatcher::add( descriptors );
|
||||
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,
|
||||
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*/ )
|
||||
{
|
||||
Mat indices( queryDescs.rows, knn, CV_32SC1 );
|
||||
Mat dists( queryDescs.rows, knn, CV_32FC1);
|
||||
flannIndex->knnSearch( queryDescs, indices, dists, knn, *searchParams );
|
||||
Mat indices( queryDescriptors.rows, knn, CV_32SC1 );
|
||||
Mat dists( queryDescriptors.rows, knn, CV_32FC1);
|
||||
flannIndex->knnSearch( queryDescriptors, indices, dists, knn, *searchParams );
|
||||
|
||||
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 int count = mergedDescriptors.size(); // TODO do count as param?
|
||||
Mat indices( queryDescs.rows, count, CV_32SC1, Scalar::all(-1) );
|
||||
Mat dists( queryDescs.rows, count, CV_32FC1, Scalar::all(-1) );
|
||||
for( int qIdx = 0; qIdx < queryDescs.rows; qIdx++ )
|
||||
Mat indices( queryDescriptors.rows, count, CV_32SC1, Scalar::all(-1) );
|
||||
Mat dists( queryDescriptors.rows, count, CV_32FC1, Scalar::all(-1) );
|
||||
for( int qIdx = 0; qIdx < queryDescriptors.rows; qIdx++ )
|
||||
{
|
||||
Mat queryDescsRow = queryDescs.row(qIdx);
|
||||
Mat queryDescriptorsRow = queryDescriptors.row(qIdx);
|
||||
Mat indicesRow = indices.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 );
|
||||
@ -507,6 +625,22 @@ Ptr<DescriptorMatcher> createDescriptorMatcher( const string& descriptorMatcherT
|
||||
/*
|
||||
* 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,
|
||||
const vector<vector<KeyPoint> >& _points )
|
||||
{
|
||||
@ -514,9 +648,9 @@ void GenericDescriptorMatcher::KeyPointCollection::add( const vector<Mat>& _imag
|
||||
CV_Assert( _images.size() == _points.size() );
|
||||
|
||||
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++ )
|
||||
size += _points[i].size();
|
||||
pointCount += _points[i].size();
|
||||
|
||||
size_t prevSize = startIndices.size(), addSize = _images.size();
|
||||
startIndices.resize( prevSize + addSize );
|
||||
@ -524,37 +658,58 @@ void GenericDescriptorMatcher::KeyPointCollection::add( const vector<Mat>& _imag
|
||||
if( prevSize == 0 )
|
||||
startIndices[prevSize] = 0; //first
|
||||
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++ )
|
||||
{
|
||||
startIndices[i] = startIndices[i - 1] + points[i - 1].size();
|
||||
startIndices[i] = startIndices[i - 1] + keypoints[i - 1].size();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
CV_Assert( imgIdx < (int)images.size() );
|
||||
CV_Assert( localPointIdx < (int)points[imgIdx].size() );
|
||||
return points[imgIdx][localPointIdx];
|
||||
CV_Assert( localPointIdx < (int)keypoints[imgIdx].size() );
|
||||
return keypoints[imgIdx][localPointIdx];
|
||||
}
|
||||
|
||||
const KeyPoint& GenericDescriptorMatcher::KeyPointCollection::getKeyPoint( int globalPointIdx ) const
|
||||
{
|
||||
int 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
|
||||
{
|
||||
imgIdx = -1;
|
||||
CV_Assert( globalPointIdx < (int)pointCount() );
|
||||
CV_Assert( globalPointIdx < (int)keypointCount() );
|
||||
for( size_t i = 1; i < startIndices.size(); i++ )
|
||||
{
|
||||
if( globalPointIdx < startIndices[i] )
|
||||
@ -567,20 +722,50 @@ void GenericDescriptorMatcher::KeyPointCollection::getLocalIdx( int globalPointI
|
||||
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()
|
||||
{}
|
||||
|
||||
void GenericDescriptorMatcher::add( const vector<Mat>& imgCollection,
|
||||
vector<vector<KeyPoint> >& 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()
|
||||
{
|
||||
trainPointCollection.clear();
|
||||
}
|
||||
|
||||
void GenericDescriptorMatcher::train()
|
||||
{}
|
||||
|
||||
void GenericDescriptorMatcher::classify( const Mat& queryImage, vector<KeyPoint>& queryPoints,
|
||||
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,
|
||||
vector<DMatch>& matches, const Mat& mask ) const
|
||||
{
|
||||
Ptr<GenericDescriptorMatcher> tempMatcher = createEmptyMatcherCopy();
|
||||
Ptr<GenericDescriptorMatcher> tempMatcher = clone( true );
|
||||
vector<vector<KeyPoint> > vecTrainPoints(1, trainPoints);
|
||||
tempMatcher->add( vector<Mat>(1, trainImg), vecTrainPoints );
|
||||
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,
|
||||
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);
|
||||
tempMatcher->add( vector<Mat>(1, trainImg), vecTrainPoints );
|
||||
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,
|
||||
const Mat& mask, bool compactResult ) const
|
||||
{
|
||||
Ptr<GenericDescriptorMatcher> tempMatcher = createEmptyMatcherCopy();
|
||||
Ptr<GenericDescriptorMatcher> tempMatcher = clone( true );
|
||||
vector<vector<KeyPoint> > vecTrainPoints(1, trainPoints);
|
||||
tempMatcher->add( vector<Mat>(1, trainImg), vecTrainPoints );
|
||||
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 );
|
||||
}
|
||||
|
||||
void GenericDescriptorMatcher::read( const FileNode& )
|
||||
{}
|
||||
|
||||
void GenericDescriptorMatcher::write( FileStorage& ) const
|
||||
{}
|
||||
|
||||
/****************************************************************************************\
|
||||
* 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)
|
||||
{
|
||||
initialize(_params);
|
||||
@ -691,13 +892,13 @@ void OneWayDescriptorMatcher::clear()
|
||||
|
||||
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,
|
||||
params.trainPath, params.trainImagesList, params.minScale, params.maxScale, params.stepScale );
|
||||
|
||||
base->Allocate( trainPointCollection.pointCount() );
|
||||
prevTrainCount = trainPointCollection.pointCount();
|
||||
base->Allocate( trainPointCollection.keypointCount() );
|
||||
prevTrainCount = trainPointCollection.keypointCount();
|
||||
|
||||
const vector<vector<KeyPoint> >& points = trainPointCollection.getKeypoints();
|
||||
int count = 0;
|
||||
@ -714,6 +915,11 @@ void OneWayDescriptorMatcher::train()
|
||||
}
|
||||
}
|
||||
|
||||
bool OneWayDescriptorMatcher::isMaskSupported()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void OneWayDescriptorMatcher::knnMatchImpl( const Mat& queryImg, vector<KeyPoint>& queryPoints,
|
||||
vector<vector<DMatch> >& matches, int knn,
|
||||
const vector<Mat>& /*masks*/, bool /*compactResult*/ )
|
||||
@ -763,6 +969,23 @@ void OneWayDescriptorMatcher::write( FileStorage& fs ) const
|
||||
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 *
|
||||
\****************************************************************************************/
|
||||
@ -805,7 +1028,7 @@ void FernDescriptorMatcher::clear()
|
||||
|
||||
void FernDescriptorMatcher::train()
|
||||
{
|
||||
if( classifier.empty() || prevTrainCount < (int)trainPointCollection.pointCount() )
|
||||
if( classifier.empty() || prevTrainCount < (int)trainPointCollection.keypointCount() )
|
||||
{
|
||||
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,
|
||||
float& bestProb, int& bestMatchIdx, vector<float>& signature )
|
||||
{
|
||||
@ -921,16 +1149,42 @@ void FernDescriptorMatcher::write( FileStorage& fs ) const
|
||||
// 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,
|
||||
vector<vector<KeyPoint> >& pointCollection )
|
||||
{
|
||||
vector<Mat> descCollection;
|
||||
extractor->compute( imgCollection, pointCollection, descCollection );
|
||||
vector<Mat> descriptors;
|
||||
extractor->compute( imgCollection, pointCollection, descriptors );
|
||||
|
||||
matcher->add( descCollection );
|
||||
matcher->add( descriptors );
|
||||
|
||||
trainPointCollection.add( imgCollection, pointCollection );
|
||||
}
|
||||
@ -947,28 +1201,33 @@ void VectorDescriptorMatcher::train()
|
||||
matcher->train();
|
||||
}
|
||||
|
||||
bool VectorDescriptorMatcher::isMaskSupported()
|
||||
{
|
||||
return matcher->isMaskSupported();
|
||||
}
|
||||
|
||||
void VectorDescriptorMatcher::knnMatchImpl( const Mat& queryImg, vector<KeyPoint>& queryPoints,
|
||||
vector<vector<DMatch> >& matches, int knn,
|
||||
const vector<Mat>& masks, bool compactResult )
|
||||
{
|
||||
Mat queryDescs;
|
||||
extractor->compute( queryImg, queryPoints, queryDescs );
|
||||
matcher->knnMatch( queryDescs, matches, knn, masks, compactResult );
|
||||
Mat queryDescriptors;
|
||||
extractor->compute( queryImg, queryPoints, queryDescriptors );
|
||||
matcher->knnMatch( queryDescriptors, matches, knn, masks, compactResult );
|
||||
}
|
||||
|
||||
void VectorDescriptorMatcher::radiusMatchImpl( const Mat& queryImg, vector<KeyPoint>& queryPoints,
|
||||
vector<vector<DMatch> >& matches, float maxDistance,
|
||||
const vector<Mat>& masks, bool compactResult )
|
||||
{
|
||||
Mat queryDescs;
|
||||
extractor->compute( queryImg, queryPoints, queryDescs );
|
||||
matcher->radiusMatch( queryDescs, matches, maxDistance, masks, compactResult );
|
||||
Mat queryDescriptors;
|
||||
extractor->compute( queryImg, queryPoints, queryDescriptors );
|
||||
matcher->radiusMatch( queryDescriptors, matches, maxDistance, masks, compactResult );
|
||||
}
|
||||
|
||||
void VectorDescriptorMatcher::read( const FileNode& fn )
|
||||
{
|
||||
GenericDescriptorMatcher::read(fn);
|
||||
extractor->read (fn);
|
||||
extractor->read(fn);
|
||||
}
|
||||
|
||||
void VectorDescriptorMatcher::write (FileStorage& fs) const
|
||||
@ -977,6 +1236,12 @@ void VectorDescriptorMatcher::write (FileStorage& fs) const
|
||||
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
|
||||
*/
|
||||
|
@ -7,103 +7,22 @@
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
void maskMatchesByTrainImgIdx( const vector<DMatch>& matches, int trainImgIdx, vector<char>& mask );
|
||||
void readTrainFilenames( const string& filename, string& dirName, vector<string>& trainFilenames );
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Mat queryImg;
|
||||
vector<KeyPoint> queryPoints;
|
||||
Mat queryDescs;
|
||||
|
||||
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;
|
||||
}
|
||||
/*
|
||||
* 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
|
||||
* 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).
|
||||
* Match is drawn as line between corresponding points. Count of all matches is equel to count of
|
||||
* query keypoints, so we have the same count of lines in all set of result images (but not for each result
|
||||
* (train) image).
|
||||
*/
|
||||
|
||||
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 )
|
||||
{
|
||||
@ -136,3 +55,180 @@ void readTrainFilenames( const string& filename, string& dirName, vector<string>
|
||||
}
|
||||
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) {}
|
||||
|
||||
protected:
|
||||
virtual void run( int start_from )
|
||||
virtual void run( int /*start_from*/ )
|
||||
{
|
||||
const float maxPtDif = 1.f;
|
||||
const float maxSizeDif = 1.f;
|
||||
@ -112,7 +112,7 @@ protected:
|
||||
for( size_t c = 0; c < calcKeypoints.size(); c++ )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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++ )
|
||||
{
|
||||
DMatch match = matches[i];
|
||||
int shift = dmatcher->supportMask() ? 1 : 0;
|
||||
int shift = dmatcher->isMaskSupported() ? 1 : 0;
|
||||
{
|
||||
if( i < queryDescCount/2 )
|
||||
{
|
||||
@ -533,7 +533,7 @@ int CV_DescriptorMatcherTest::testKnnMatch( const Mat& query, const Mat& train )
|
||||
else
|
||||
{
|
||||
int badCount = 0;
|
||||
int shift = dmatcher->supportMask() ? 1 : 0;
|
||||
int shift = dmatcher->isMaskSupported() ? 1 : 0;
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
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;
|
||||
|
||||
int badCount = 0;
|
||||
int shift = dmatcher->supportMask() ? 1 : 0;
|
||||
int needMatchCount = dmatcher->supportMask() ? n-1 : n;
|
||||
int shift = dmatcher->isMaskSupported() ? 1 : 0;
|
||||
int needMatchCount = dmatcher->isMaskSupported() ? n-1 : n;
|
||||
for( size_t i = 0; i < matches.size(); i++ )
|
||||
{
|
||||
if( (int)matches[i].size() != needMatchCount )
|
||||
@ -741,6 +741,6 @@ CV_CalonderDescriptorExtractorTest<float> floatCalonderTest( "descriptor-calonde
|
||||
* Matchers
|
||||
*/
|
||||
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",
|
||||
new FlannBasedMatcher, 0.04 );
|
||||
new FlannBasedMatcher, 0.04f );
|
||||
|
Loading…
Reference in New Issue
Block a user