lot's of changes; nonfree & photo modules added; SIFT & SURF -> nonfree module; Inpainting -> photo; refactored features2d (ORB is still failing tests), optimized brute-force matcher and made it non-template.
This commit is contained in:
@@ -77,7 +77,7 @@ template<typename _KeyTp, typename _ValueTp> struct sorted_vector
|
||||
b = c;
|
||||
}
|
||||
|
||||
if( vec[a].first == key )
|
||||
if( a < vec.size() && vec[a].first == key )
|
||||
{
|
||||
value = vec[a].second;
|
||||
return true;
|
||||
@@ -176,6 +176,66 @@ string Algorithm::name() const
|
||||
{
|
||||
return info()->name();
|
||||
}
|
||||
|
||||
void Algorithm::set(const string& name, int value)
|
||||
{
|
||||
info()->set(this, name.c_str(), ParamType<int>::type, &value);
|
||||
}
|
||||
|
||||
void Algorithm::set(const string& name, double value)
|
||||
{
|
||||
info()->set(this, name.c_str(), ParamType<double>::type, &value);
|
||||
}
|
||||
|
||||
void Algorithm::set(const string& name, bool value)
|
||||
{
|
||||
info()->set(this, name.c_str(), ParamType<bool>::type, &value);
|
||||
}
|
||||
|
||||
void Algorithm::set(const string& name, const string& value)
|
||||
{
|
||||
info()->set(this, name.c_str(), ParamType<string>::type, &value);
|
||||
}
|
||||
|
||||
void Algorithm::set(const string& name, const Mat& value)
|
||||
{
|
||||
info()->set(this, name.c_str(), ParamType<Mat>::type, &value);
|
||||
}
|
||||
|
||||
void Algorithm::set(const string& name, const Ptr<Algorithm>& value)
|
||||
{
|
||||
info()->set(this, name.c_str(), ParamType<Algorithm>::type, &value);
|
||||
}
|
||||
|
||||
void Algorithm::set(const char* name, int value)
|
||||
{
|
||||
info()->set(this, name, ParamType<int>::type, &value);
|
||||
}
|
||||
|
||||
void Algorithm::set(const char* name, double value)
|
||||
{
|
||||
info()->set(this, name, ParamType<double>::type, &value);
|
||||
}
|
||||
|
||||
void Algorithm::set(const char* name, bool value)
|
||||
{
|
||||
info()->set(this, name, ParamType<bool>::type, &value);
|
||||
}
|
||||
|
||||
void Algorithm::set(const char* name, const string& value)
|
||||
{
|
||||
info()->set(this, name, ParamType<string>::type, &value);
|
||||
}
|
||||
|
||||
void Algorithm::set(const char* name, const Mat& value)
|
||||
{
|
||||
info()->set(this, name, ParamType<Mat>::type, &value);
|
||||
}
|
||||
|
||||
void Algorithm::set(const char* name, const Ptr<Algorithm>& value)
|
||||
{
|
||||
info()->set(this, name, ParamType<Algorithm>::type, &value);
|
||||
}
|
||||
|
||||
string Algorithm::paramHelp(const string& name) const
|
||||
{
|
||||
@@ -261,25 +321,25 @@ void AlgorithmInfo::read(Algorithm* algo, const FileNode& fn) const
|
||||
if( n.empty() )
|
||||
continue;
|
||||
if( p.type == Param::INT )
|
||||
algo->set<int>(pname, (int)n);
|
||||
algo->set(pname, (int)n);
|
||||
else if( p.type == Param::BOOLEAN )
|
||||
algo->set<bool>(pname, (int)n != 0);
|
||||
algo->set(pname, (int)n != 0);
|
||||
else if( p.type == Param::REAL )
|
||||
algo->set<double>(pname, (double)n);
|
||||
algo->set(pname, (double)n);
|
||||
else if( p.type == Param::STRING )
|
||||
algo->set<string>(pname, (string)n);
|
||||
algo->set(pname, (string)n);
|
||||
else if( p.type == Param::MAT )
|
||||
{
|
||||
Mat m;
|
||||
cv::read(fn, m);
|
||||
algo->set<Mat>(pname, m);
|
||||
algo->set(pname, m);
|
||||
}
|
||||
else if( p.type == Param::ALGORITHM )
|
||||
{
|
||||
Ptr<Algorithm> nestedAlgo = Algorithm::_create((string)n["name"]);
|
||||
CV_Assert( !nestedAlgo.empty() );
|
||||
nestedAlgo->read(n);
|
||||
algo->set<Algorithm>(pname, nestedAlgo);
|
||||
algo->set(pname, nestedAlgo);
|
||||
}
|
||||
else
|
||||
CV_Error( CV_StsUnsupportedFormat, "unknown/unsupported parameter type");
|
||||
@@ -505,6 +565,16 @@ void AlgorithmInfo::addParam(const Algorithm* algo, const char* name,
|
||||
(Algorithm::Getter)getter, (Algorithm::Setter)setter, help);
|
||||
}
|
||||
|
||||
void AlgorithmInfo::addParam(const Algorithm* algo, const char* name,
|
||||
const bool& value, bool readOnly,
|
||||
int (Algorithm::*getter)(),
|
||||
void (Algorithm::*setter)(int),
|
||||
const string& help)
|
||||
{
|
||||
addParam_(algo, name, ParamType<bool>::type, &value, readOnly,
|
||||
(Algorithm::Getter)getter, (Algorithm::Setter)setter, help);
|
||||
}
|
||||
|
||||
void AlgorithmInfo::addParam(const Algorithm* algo, const char* name,
|
||||
const double& value, bool readOnly,
|
||||
double (Algorithm::*getter)(),
|
||||
|
@@ -113,11 +113,13 @@ namespace
|
||||
|
||||
const CvOpenGlFuncTab* g_glFuncTab = 0;
|
||||
|
||||
#ifdef HAVE_CUDA
|
||||
const CvOpenGlFuncTab* glFuncTab()
|
||||
{
|
||||
static EmptyGlFuncTab empty;
|
||||
return g_glFuncTab ? g_glFuncTab : ∅
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CvOpenGlFuncTab::~CvOpenGlFuncTab()
|
||||
|
@@ -41,6 +41,7 @@
|
||||
//M*/
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include <climits>
|
||||
|
||||
namespace cv
|
||||
{
|
||||
@@ -1425,6 +1426,339 @@ double cv::norm( InputArray _src1, InputArray _src2, int normType, InputArray _m
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////// batch distance ///////////////////////////////////////
|
||||
|
||||
namespace cv
|
||||
{
|
||||
|
||||
template<typename _Tp, typename _Rt>
|
||||
void batchDistL1_(const _Tp* src1, const _Tp* src2, size_t step2,
|
||||
int nvecs, int len, _Rt* dist, const uchar* mask)
|
||||
{
|
||||
step2 /= sizeof(src2[0]);
|
||||
if( !mask )
|
||||
{
|
||||
for( int i = 0; i < nvecs; i++ )
|
||||
dist[i] = normL1<_Tp, _Rt>(src1, src2 + step2*i, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
_Rt val0 = std::numeric_limits<_Rt>::max();
|
||||
for( int i = 0; i < nvecs; i++ )
|
||||
dist[i] = mask[i] ? normL1<_Tp, _Rt>(src1, src2 + step2*i, len) : val0;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _Tp, typename _Rt>
|
||||
void batchDistL2Sqr_(const _Tp* src1, const _Tp* src2, size_t step2,
|
||||
int nvecs, int len, _Rt* dist, const uchar* mask)
|
||||
{
|
||||
step2 /= sizeof(src2[0]);
|
||||
if( !mask )
|
||||
{
|
||||
for( int i = 0; i < nvecs; i++ )
|
||||
dist[i] = normL2Sqr<_Tp, _Rt>(src1, src2 + step2*i, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
_Rt val0 = std::numeric_limits<_Rt>::max();
|
||||
for( int i = 0; i < nvecs; i++ )
|
||||
dist[i] = mask[i] ? normL2Sqr<_Tp, _Rt>(src1, src2 + step2*i, len) : val0;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _Tp, typename _Rt>
|
||||
void batchDistL2_(const _Tp* src1, const _Tp* src2, size_t step2,
|
||||
int nvecs, int len, _Rt* dist, const uchar* mask)
|
||||
{
|
||||
step2 /= sizeof(src2[0]);
|
||||
if( !mask )
|
||||
{
|
||||
for( int i = 0; i < nvecs; i++ )
|
||||
dist[i] = std::sqrt(normL2Sqr<_Tp, _Rt>(src1, src2 + step2*i, len));
|
||||
}
|
||||
else
|
||||
{
|
||||
_Rt val0 = std::numeric_limits<_Rt>::max();
|
||||
for( int i = 0; i < nvecs; i++ )
|
||||
dist[i] = mask[i] ? std::sqrt(normL2Sqr<_Tp, _Rt>(src1, src2 + step2*i, len)) : val0;
|
||||
}
|
||||
}
|
||||
|
||||
static void batchDistHamming(const uchar* src1, const uchar* src2, size_t step2,
|
||||
int nvecs, int len, int* dist, const uchar* mask)
|
||||
{
|
||||
step2 /= sizeof(src2[0]);
|
||||
if( !mask )
|
||||
{
|
||||
for( int i = 0; i < nvecs; i++ )
|
||||
dist[i] = normHamming(src1, src2 + step2*i, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
int val0 = INT_MAX;
|
||||
for( int i = 0; i < nvecs; i++ )
|
||||
dist[i] = mask[i] ? normHamming(src1, src2 + step2*i, len) : val0;
|
||||
}
|
||||
}
|
||||
|
||||
static void batchDistHamming2(const uchar* src1, const uchar* src2, size_t step2,
|
||||
int nvecs, int len, int* dist, const uchar* mask)
|
||||
{
|
||||
step2 /= sizeof(src2[0]);
|
||||
if( !mask )
|
||||
{
|
||||
for( int i = 0; i < nvecs; i++ )
|
||||
dist[i] = normHamming(src1, src2 + step2*i, len, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
int val0 = INT_MAX;
|
||||
for( int i = 0; i < nvecs; i++ )
|
||||
dist[i] = mask[i] ? normHamming(src1, src2 + step2*i, len, 2) : val0;
|
||||
}
|
||||
}
|
||||
|
||||
static void batchDistL1_8u32s(const uchar* src1, const uchar* src2, size_t step2,
|
||||
int nvecs, int len, int* dist, const uchar* mask)
|
||||
{
|
||||
batchDistL1_<uchar, int>(src1, src2, step2, nvecs, len, dist, mask);
|
||||
}
|
||||
|
||||
static void batchDistL1_8u32f(const uchar* src1, const uchar* src2, size_t step2,
|
||||
int nvecs, int len, float* dist, const uchar* mask)
|
||||
{
|
||||
batchDistL1_<uchar, float>(src1, src2, step2, nvecs, len, dist, mask);
|
||||
}
|
||||
|
||||
static void batchDistL2Sqr_8u32s(const uchar* src1, const uchar* src2, size_t step2,
|
||||
int nvecs, int len, int* dist, const uchar* mask)
|
||||
{
|
||||
batchDistL2Sqr_<uchar, int>(src1, src2, step2, nvecs, len, dist, mask);
|
||||
}
|
||||
|
||||
static void batchDistL2Sqr_8u32f(const uchar* src1, const uchar* src2, size_t step2,
|
||||
int nvecs, int len, float* dist, const uchar* mask)
|
||||
{
|
||||
batchDistL2Sqr_<uchar, float>(src1, src2, step2, nvecs, len, dist, mask);
|
||||
}
|
||||
|
||||
static void batchDistL2_8u32f(const uchar* src1, const uchar* src2, size_t step2,
|
||||
int nvecs, int len, float* dist, const uchar* mask)
|
||||
{
|
||||
batchDistL2_<uchar, float>(src1, src2, step2, nvecs, len, dist, mask);
|
||||
}
|
||||
|
||||
static void batchDistL1_32f(const float* src1, const float* src2, size_t step2,
|
||||
int nvecs, int len, float* dist, const uchar* mask)
|
||||
{
|
||||
batchDistL1_<float, float>(src1, src2, step2, nvecs, len, dist, mask);
|
||||
}
|
||||
|
||||
static void batchDistL2Sqr_32f(const float* src1, const float* src2, size_t step2,
|
||||
int nvecs, int len, float* dist, const uchar* mask)
|
||||
{
|
||||
batchDistL2Sqr_<float, float>(src1, src2, step2, nvecs, len, dist, mask);
|
||||
}
|
||||
|
||||
static void batchDistL2_32f(const float* src1, const float* src2, size_t step2,
|
||||
int nvecs, int len, float* dist, const uchar* mask)
|
||||
{
|
||||
batchDistL2_<float, float>(src1, src2, step2, nvecs, len, dist, mask);
|
||||
}
|
||||
|
||||
typedef void (*BatchDistFunc)(const uchar* src1, const uchar* src2, size_t step2,
|
||||
int nvecs, int len, uchar* dist, const uchar* mask);
|
||||
|
||||
|
||||
struct BatchDistInvoker
|
||||
{
|
||||
BatchDistInvoker( const Mat& _src1, const Mat& _src2,
|
||||
Mat& _dist, Mat& _nidx, int _K,
|
||||
const Mat& _mask, int _update,
|
||||
BatchDistFunc _func)
|
||||
{
|
||||
src1 = &_src1;
|
||||
src2 = &_src2;
|
||||
dist = &_dist;
|
||||
nidx = &_nidx;
|
||||
K = _K;
|
||||
mask = &_mask;
|
||||
update = _update;
|
||||
func = _func;
|
||||
}
|
||||
|
||||
void operator()(const BlockedRange& range) const
|
||||
{
|
||||
AutoBuffer<int> buf(src2->rows);
|
||||
int* bufptr = buf;
|
||||
Cv32suf val0;
|
||||
if( dist->type() == CV_32S )
|
||||
val0.i = INT_MAX;
|
||||
else
|
||||
val0.f = FLT_MAX;
|
||||
|
||||
for( int i = range.begin(); i < range.end(); i++ )
|
||||
{
|
||||
func(src1->ptr(i), src2->ptr(), src2->step, src2->rows, src2->cols,
|
||||
K > 0 ? (uchar*)bufptr : dist->ptr(i), mask->data ? mask->ptr(i) : 0);
|
||||
|
||||
if( K > 0 )
|
||||
{
|
||||
int* nidxptr = nidx->ptr<int>(i);
|
||||
// since positive float's can be compared just like int's,
|
||||
// we handle both CV_32S and CV_32F cases with a single branch
|
||||
int* distptr = (int*)dist->ptr(i);
|
||||
|
||||
int k, k0, k0_, j;
|
||||
for( k0 = 0; k0 < K; k0++ )
|
||||
if( nidxptr[k0] < 0 )
|
||||
break;
|
||||
k0_ = std::max(k0, 1);
|
||||
|
||||
for( j = 0; j < src2->rows; j++ )
|
||||
{
|
||||
int d = bufptr[j];
|
||||
if( d < distptr[k0_-1] )
|
||||
{
|
||||
for( k = std::min(k0-1, K-2); k >= 0 && distptr[k] > d; k-- )
|
||||
{
|
||||
nidxptr[k+1] = nidxptr[k];
|
||||
distptr[k+1] = distptr[k];
|
||||
}
|
||||
nidxptr[k+1] = j + update;
|
||||
distptr[k+1] = d;
|
||||
k0_ = k0 = std::min(k0 + 1, K);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Mat *src1;
|
||||
const Mat *src2;
|
||||
Mat *dist;
|
||||
Mat *nidx;
|
||||
const Mat *mask;
|
||||
int K;
|
||||
int update;
|
||||
BatchDistFunc func;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void cv::batchDistance( InputArray _src1, InputArray _src2,
|
||||
OutputArray _dist, int dtype, OutputArray _nidx,
|
||||
int normType, int K, InputArray _mask,
|
||||
int update, bool crosscheck )
|
||||
{
|
||||
Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat();
|
||||
int type = src1.type();
|
||||
CV_Assert( type == src2.type() && src1.cols == src2.cols &&
|
||||
(type == CV_32F || type == CV_8U));
|
||||
CV_Assert( _nidx.needed() == (K > 0) );
|
||||
|
||||
if( dtype == -1 )
|
||||
{
|
||||
dtype = normType == NORM_HAMMING || normType == NORM_HAMMING2 ? CV_32S : CV_32F;
|
||||
}
|
||||
CV_Assert( (type == CV_8U && dtype == CV_32S) || dtype == CV_32F);
|
||||
|
||||
K = std::min(K, src2.rows);
|
||||
|
||||
_dist.create(src1.rows, (K > 0 ? K : src2.rows), dtype);
|
||||
Mat dist = _dist.getMat(), nidx;
|
||||
if( _nidx.needed() )
|
||||
{
|
||||
_nidx.create(dist.size(), CV_32S);
|
||||
nidx = _nidx.getMat();
|
||||
}
|
||||
|
||||
if( update == 0 && K > 0 )
|
||||
{
|
||||
dist = Scalar::all(dtype == CV_32S ? (double)INT_MAX : (double)FLT_MAX);
|
||||
nidx = Scalar::all(-1);
|
||||
}
|
||||
|
||||
if( crosscheck )
|
||||
{
|
||||
CV_Assert( K == 1 && update == 0 && mask.empty() );
|
||||
Mat tdist, tidx;
|
||||
batchDistance(src2, src1, tdist, dtype, tidx, normType, K, mask, 0, false);
|
||||
|
||||
// if an idx-th element from src1 appeared to be the nearest to i-th element of src2,
|
||||
// we update the minimum mutual distance between idx-th element of src1 and the whole src2 set.
|
||||
// As a result, if nidx[idx] = i*, it means that idx-th element of src1 is the nearest
|
||||
// to i*-th element of src2 and i*-th element of src2 is the closest to idx-th element of src1.
|
||||
// If nidx[idx] = -1, it means that there is no such ideal couple for it in src2.
|
||||
// This O(N) procedure is called cross-check and it helps to eliminate some false matches.
|
||||
if( dtype == CV_32S )
|
||||
{
|
||||
for( int i = 0; i < tdist.rows; i++ )
|
||||
{
|
||||
int idx = tidx.at<int>(i);
|
||||
int d = tdist.at<int>(i), d0 = dist.at<int>(idx);
|
||||
if( d < d0 )
|
||||
{
|
||||
dist.at<int>(idx) = d0;
|
||||
nidx.at<int>(idx) = i + update;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( int i = 0; i < tdist.rows; i++ )
|
||||
{
|
||||
int idx = tidx.at<int>(i);
|
||||
float d = tdist.at<float>(i), d0 = dist.at<float>(idx);
|
||||
if( d < d0 )
|
||||
{
|
||||
dist.at<float>(idx) = d0;
|
||||
nidx.at<int>(idx) = i + update;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BatchDistFunc func = 0;
|
||||
if( type == CV_8U )
|
||||
{
|
||||
if( normType == NORM_L1 && dtype == CV_32S )
|
||||
func = (BatchDistFunc)batchDistL1_8u32s;
|
||||
else if( normType == NORM_L1 && dtype == CV_32F )
|
||||
func = (BatchDistFunc)batchDistL1_8u32f;
|
||||
else if( normType == NORM_L2SQR && dtype == CV_32S )
|
||||
func = (BatchDistFunc)batchDistL2Sqr_8u32s;
|
||||
else if( normType == NORM_L2SQR && dtype == CV_32F )
|
||||
func = (BatchDistFunc)batchDistL2Sqr_8u32f;
|
||||
else if( normType == NORM_L2 && dtype == CV_32F )
|
||||
func = (BatchDistFunc)batchDistL2_8u32f;
|
||||
else if( normType == NORM_HAMMING && dtype == CV_32S )
|
||||
func = (BatchDistFunc)batchDistHamming;
|
||||
else if( normType == NORM_HAMMING2 && dtype == CV_32S )
|
||||
func = (BatchDistFunc)batchDistHamming2;
|
||||
}
|
||||
else if( type == CV_32F && dtype == CV_32F )
|
||||
{
|
||||
if( normType == NORM_L1 )
|
||||
func = (BatchDistFunc)batchDistL1_32f;
|
||||
else if( normType == NORM_L2SQR )
|
||||
func = (BatchDistFunc)batchDistL2Sqr_32f;
|
||||
else if( normType == NORM_L2 )
|
||||
func = (BatchDistFunc)batchDistL2_32f;
|
||||
}
|
||||
|
||||
if( func == 0 )
|
||||
CV_Error_(CV_StsUnsupportedFormat,
|
||||
("The combination of type=%d, dtype=%d and normType=%d is not supported",
|
||||
type, dtype, normType));
|
||||
|
||||
parallel_for(BlockedRange(0, src1.rows),
|
||||
BatchDistInvoker(src1, src2, dist, nidx, K, mask, update, func));
|
||||
}
|
||||
|
||||
|
||||
CV_IMPL CvScalar cvSum( const CvArr* srcarr )
|
||||
{
|
||||
cv::Scalar sum = cv::sum(cv::cvarrToMat(srcarr, false, true, 1));
|
||||
|
Reference in New Issue
Block a user