OpenCV におけるキーポイントディスクリプタの Matcher は,同一の問題を解く異なるアルゴリズム間を容易にスイッチできる共通のインタフェースによってラップされています. このセクションでは,多次元空間の vector として表現できるディスクリプタ同士の,マッチング方法について述べます. “vector” ディスクリプタ Matcher を実装するすべてのオブジェクトは, DescriptorMatcher() インタフェースから派生します.
2つのキーポイントディスクリプタ同士をマッチングします:クエリディスクリプタインデックス, 訓練ディスクリプタインデックス,訓練画像インデックス,ディスクリプタ同士の距離.
struct DMatch
{
DMatch() : queryIdx(-1), trainIdx(-1), imgIdx(-1),
distance(std::numeric_limits<float>::max()) {}
DMatch( int _queryIdx, int _trainIdx, float _distance ) :
queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(-1),
distance(_distance) {}
DMatch( int _queryIdx, int _trainIdx, int _imgIdx, float _distance ) :
queryIdx(_queryIdx), trainIdx(_trainIdx), imgIdx(_imgIdx),
distance(_distance) {}
int queryIdx; // クエリディスクリプタインデックス
int trainIdx; // 訓練ディスクリプタインデックス
int imgIdx; // 訓練画像インデックス
float distance;
// 小さいほど良い
bool operator<( const DMatch &m ) const;
};
キーポイントディスクリプタ同士のマッチングのための抽象基底クラス. マッチング方法は,1つの画像のディスクリプタに対するマッチングと,画像集合のディスクリプタに対するマッチングの2種類に分けられます
class DescriptorMatcher
{
public:
virtual ~DescriptorMatcher();
virtual void add( const vector<Mat>& descriptors );
const vector<Mat>& getTrainDescriptors() const;
virtual void clear();
bool empty() const;
virtual bool isMaskSupported() const = 0;
virtual void train();
/*
* 画像ペアから得たディスクリプタ同士のマッチメソッド一覧.
*/
void match( const Mat& queryDescriptors, const Mat& trainDescriptors,
vector<DMatch>& matches, const Mat& mask=Mat() ) const;
void knnMatch( const Mat& queryDescriptors, const Mat& trainDescriptors,
vector<vector<DMatch> >& matches, int k,
const Mat& mask=Mat(), bool compactResult=false ) const;
void radiusMatch( const Mat& queryDescriptors, const Mat& trainDescriptors,
vector<vector<DMatch> >& matches, float maxDistance,
const Mat& mask=Mat(), bool compactResult=false ) const;
/*
* 画像集合から得たディスクリプタ同士のマッチメソッド一覧.
*/
void match( const Mat& queryDescriptors, vector<DMatch>& matches,
const vector<Mat>& masks=vector<Mat>() );
void knnMatch( const Mat& queryDescriptors, vector<vector<DMatch> >& matches,
int k, const vector<Mat>& masks=vector<Mat>(),
bool compactResult=false );
void radiusMatch( const Mat& queryDescriptors, vector<vector<DMatch> >& matches,
float maxDistance, const vector<Mat>& masks=vector<Mat>(),
bool compactResult=false );
virtual void read( const FileNode& );
virtual void write( FileStorage& ) const;
virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const = 0;
static Ptr<DescriptorMatcher> create( const string& descriptorMatcherType );
protected:
vector<Mat> trainDescCollection;
...
};
コレクション trainDescCollectionが空ではない場合,新しいディスクリプタは,存在する訓練ディスクリプタに追加されます.
param descriptors: 追加されるディスクリプタ.各 decriptors[i] は, 同一の(1 つの)訓練画像から得られたディスクリプタの集合です.
コレクション内に訓練ディスクリプタが存在しない場合に true を返します.
ディスクリプタ Matcher がマスキング可能なマッチングをサポートする場合に true を返します.
訓練ディスクリプタ Matcher(例えば,訓練 flann インデックス).
すべてのマッチングメソッドにおいて,マッチングの前に train() メソッドが毎回実行されます. このメソッドが存在しないディスクリプタ Matcher(例えば BruteForceMatcher)もありますが, その他の Matcher では内部構造を実際に学習します(例えば FlannBasedMatcher は flann::Index を学習します).
クエリ集合の各ディスクリプタに最もマッチするものを,訓練ディスクリプタから見つけます.
クエリディスクリプタはすべて,同じクエリ画像から検出されたキーポイントに対するディスクリプタです. このメソッドの第1のバージョンでは,引数で訓練ディスクリプタを与えます.これらは同じ訓練画像から検出されたキーポイントに対してのディスクリプタになります. 第2のバージョンでは,addメソッドによってセットされた訓練ディスクリプタコレクションが利用されます. オプションとして,どのディスクリプタをマッチさせるかを記述するマスク(または,マスクの集合)が利用できます.mask.at<uchar>(i,j)が0ではない場合にのみ, queryDescriptors[i]は trainDescriptors[j]とマッチされます.
パラメタ: |
|
---|
DescriptorMatcher::match()
クエリ集合の各ディスクリプタに対して,最も良い上位 k 個のマッチを訓練ディスクリプタから見つけます.
見つかった k 個(無理な場合は,それより少ない個数)のマッチは,その距離の昇順で返されます. クエリおよび訓練ディスクリプタに関する詳細は, を参照してください.
パラメタ: |
|
---|
DescriptorMatcher::match()
各クエリディスクリプタに対して,与えられた閾値よりも小さい距離にあるベストマッチを見つけます.
見つかったマッチは,その距離の昇順で返されます.クエリおよび訓練ディスクリプタに関する詳細は,を参照してください.
パラメタ: |
|
---|
Matcher を複製します.
パラメタ: |
|
---|
ブルートフォースディスクリプタ Matcher.この Matcher は, 1番目の集合の各ディスクリプタに対して,それに最も近いディスクリプタを見つけるために2番目の集合を全探索します. このディスクリプタ Matcher は,ディスクリプタ集合同士のマスキング可能なマッチングをサポートします.
template<class Distance>
class BruteForceMatcher : public DescriptorMatcher
{
public:
BruteForceMatcher( Distance d = Distance() );
virtual ~BruteForceMatcher();
virtual bool isMaskSupported() const;
virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const;
protected:
...
}
効率化のため,BruteForceMatcher は,距離基準によってテンプレート化されています. 浮動小数点型ディスクリプタに対しては, L2<float> が選択されます. サポートされる距離のクラスは,次のようになります:
template<typename T>
struct Accumulator
{
typedef T Type;
};
template<> struct Accumulator<unsigned char> { typedef unsigned int Type; };
template<> struct Accumulator<unsigned short> { typedef unsigned int Type; };
template<> struct Accumulator<char> { typedef int Type; };
template<> struct Accumulator<short> { typedef int Type; };
/*
* ユークリッド2乗距離ファンクタ
*/
template<class T>
struct L2
{
typedef T ValueType;
typedef typename Accumulator<T>::Type ResultType;
ResultType operator()( const T* a, const T* b, int size ) const;
};
/*
* マンハッタン距離(city block distance)ファンクタ
*/
template<class T>
struct CV_EXPORTS L1
{
typedef T ValueType;
typedef typename Accumulator<T>::Type ResultType;
ResultType operator()( const T* a, const T* b, int size ) const;
...
};
/*
* ハミング距離(city block distance)ファンクタ
*/
struct HammingLUT
{
typedef unsigned char ValueType;
typedef int ResultType;
ResultType operator()( const unsigned char* a, const unsigned char* b,
int size ) const;
...
};
struct Hamming
{
typedef unsigned char ValueType;
typedef int ResultType;
ResultType operator()( const unsigned char* a, const unsigned char* b,
int size ) const;
...
};
Flann ベースのディスクリプタ Matcher.この Matcher は,訓練ディスクリプタコレクションの flann::Index() を学習して, ベストマッチを見つけるために,その最近傍探索メソッドを呼び出します. したがって,巨大な訓練コレクションとマッチングする場合は,この Matcher は,ブルートフォース Matcher よりも高速になります. flann::Index() が,マスキング可能なディスクリプタ集合同士のマッチングをサポートしないので, FlannBasedMatcher も,それをサポートしません.
class FlannBasedMatcher : public DescriptorMatcher
{
public:
FlannBasedMatcher(
const Ptr<flann::IndexParams>& indexParams=new flann::KDTreeIndexParams(),
const Ptr<flann::SearchParams>& searchParams=new flann::SearchParams() );
virtual void add( const vector<Mat>& descriptors );
virtual void clear();
virtual void train();
virtual bool isMaskSupported() const;
virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const;
protected:
...
};