refactored features2d and sample on matching to many images

This commit is contained in:
Maria Dimashova 2010-11-22 18:27:08 +00:00
parent cf0d9da643
commit e406dfee44
13 changed files with 1619 additions and 1025 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
}

View File

@ -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

View File

@ -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 *
\****************************************************************************************/

View File

@ -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;
}

View File

@ -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
*/

View File

@ -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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

View File

@ -0,0 +1,3 @@
1.png
2.png
3.png

View File

@ -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 );