a LOT of obsolete stuff has been moved to the legacy module.
This commit is contained in:
264
modules/legacy/test/test_nearestneighbors.cpp
Normal file
264
modules/legacy/test/test_nearestneighbors.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
using namespace cv;
|
||||
using namespace cv::flann;
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
class NearestNeighborTest : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
NearestNeighborTest() {}
|
||||
protected:
|
||||
static const int minValue = 0;
|
||||
static const int maxValue = 1;
|
||||
static const int dims = 30;
|
||||
static const int featuresCount = 2000;
|
||||
static const int K = 1; // * should also test 2nd nn etc.?
|
||||
|
||||
|
||||
virtual void run( int start_from );
|
||||
virtual void createModel( const Mat& data ) = 0;
|
||||
virtual int findNeighbors( Mat& points, Mat& neighbors ) = 0;
|
||||
virtual int checkGetPoins( const Mat& data );
|
||||
virtual int checkFindBoxed();
|
||||
virtual int checkFind( const Mat& data );
|
||||
virtual void releaseModel() = 0;
|
||||
};
|
||||
|
||||
int NearestNeighborTest::checkGetPoins( const Mat& )
|
||||
{
|
||||
return cvtest::TS::OK;
|
||||
}
|
||||
|
||||
int NearestNeighborTest::checkFindBoxed()
|
||||
{
|
||||
return cvtest::TS::OK;
|
||||
}
|
||||
|
||||
int NearestNeighborTest::checkFind( const Mat& data )
|
||||
{
|
||||
int code = cvtest::TS::OK;
|
||||
int pointsCount = 1000;
|
||||
float noise = 0.2f;
|
||||
|
||||
RNG rng;
|
||||
Mat points( pointsCount, dims, CV_32FC1 );
|
||||
Mat results( pointsCount, K, CV_32SC1 );
|
||||
|
||||
std::vector<int> fmap( pointsCount );
|
||||
for( int pi = 0; pi < pointsCount; pi++ )
|
||||
{
|
||||
int fi = rng.next() % featuresCount;
|
||||
fmap[pi] = fi;
|
||||
for( int d = 0; d < dims; d++ )
|
||||
points.at<float>(pi, d) = data.at<float>(fi, d) + rng.uniform(0.0f, 1.0f) * noise;
|
||||
}
|
||||
|
||||
code = findNeighbors( points, results );
|
||||
|
||||
if( code == cvtest::TS::OK )
|
||||
{
|
||||
int correctMatches = 0;
|
||||
for( int pi = 0; pi < pointsCount; pi++ )
|
||||
{
|
||||
if( fmap[pi] == results.at<int>(pi, 0) )
|
||||
correctMatches++;
|
||||
}
|
||||
|
||||
double correctPerc = correctMatches / (double)pointsCount;
|
||||
if (correctPerc < .75)
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "correct_perc = %d\n", correctPerc );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
}
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
void NearestNeighborTest::run( int /*start_from*/ ) {
|
||||
int code = cvtest::TS::OK, tempCode;
|
||||
Mat desc( featuresCount, dims, CV_32FC1 );
|
||||
randu( desc, Scalar(minValue), Scalar(maxValue) );
|
||||
|
||||
createModel( desc );
|
||||
|
||||
tempCode = checkGetPoins( desc );
|
||||
if( tempCode != cvtest::TS::OK )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "bad accuracy of GetPoints \n" );
|
||||
code = tempCode;
|
||||
}
|
||||
|
||||
tempCode = checkFindBoxed();
|
||||
if( tempCode != cvtest::TS::OK )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "bad accuracy of FindBoxed \n" );
|
||||
code = tempCode;
|
||||
}
|
||||
|
||||
tempCode = checkFind( desc );
|
||||
if( tempCode != cvtest::TS::OK )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "bad accuracy of Find \n" );
|
||||
code = tempCode;
|
||||
}
|
||||
|
||||
releaseModel();
|
||||
|
||||
ts->set_failed_test_info( code );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
class CV_LSHTest : public NearestNeighborTest
|
||||
{
|
||||
public:
|
||||
CV_LSHTest() {}
|
||||
protected:
|
||||
virtual void createModel( const Mat& data );
|
||||
virtual int findNeighbors( Mat& points, Mat& neighbors );
|
||||
virtual void releaseModel();
|
||||
struct CvLSH* lsh;
|
||||
CvMat desc;
|
||||
};
|
||||
|
||||
void CV_LSHTest::createModel( const Mat& data )
|
||||
{
|
||||
desc = data;
|
||||
lsh = cvCreateMemoryLSH( data.cols, data.rows, 70, 20, CV_32FC1 );
|
||||
cvLSHAdd( lsh, &desc );
|
||||
}
|
||||
|
||||
int CV_LSHTest::findNeighbors( Mat& points, Mat& neighbors )
|
||||
{
|
||||
const int emax = 20;
|
||||
Mat dist( points.rows, neighbors.cols, CV_64FC1);
|
||||
CvMat _dist = dist, _points = points, _neighbors = neighbors;
|
||||
cvLSHQuery( lsh, &_points, &_neighbors, &_dist, neighbors.cols, emax );
|
||||
return cvtest::TS::OK;
|
||||
}
|
||||
|
||||
void CV_LSHTest::releaseModel()
|
||||
{
|
||||
cvReleaseLSH( &lsh );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
class CV_FeatureTreeTest_C : public NearestNeighborTest
|
||||
{
|
||||
public:
|
||||
CV_FeatureTreeTest_C() {}
|
||||
protected:
|
||||
virtual int findNeighbors( Mat& points, Mat& neighbors );
|
||||
virtual void releaseModel();
|
||||
CvFeatureTree* tr;
|
||||
CvMat desc;
|
||||
};
|
||||
|
||||
int CV_FeatureTreeTest_C::findNeighbors( Mat& points, Mat& neighbors )
|
||||
{
|
||||
const int emax = 20;
|
||||
Mat dist( points.rows, neighbors.cols, CV_64FC1);
|
||||
CvMat _dist = dist, _points = points, _neighbors = neighbors;
|
||||
cvFindFeatures( tr, &_points, &_neighbors, &_dist, neighbors.cols, emax );
|
||||
return cvtest::TS::OK;
|
||||
}
|
||||
|
||||
void CV_FeatureTreeTest_C::releaseModel()
|
||||
{
|
||||
cvReleaseFeatureTree( tr );
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
class CV_SpillTreeTest_C : public CV_FeatureTreeTest_C
|
||||
{
|
||||
public:
|
||||
CV_SpillTreeTest_C() {}
|
||||
protected:
|
||||
virtual void createModel( const Mat& data );
|
||||
};
|
||||
|
||||
void CV_SpillTreeTest_C::createModel( const Mat& data )
|
||||
{
|
||||
desc = data;
|
||||
tr = cvCreateSpillTree( &desc );
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
class CV_KDTreeTest_C : public CV_FeatureTreeTest_C
|
||||
{
|
||||
public:
|
||||
CV_KDTreeTest_C() {}
|
||||
protected:
|
||||
virtual void createModel( const Mat& data );
|
||||
virtual int checkFindBoxed();
|
||||
};
|
||||
|
||||
void CV_KDTreeTest_C::createModel( const Mat& data )
|
||||
{
|
||||
desc = data;
|
||||
tr = cvCreateKDTree( &desc );
|
||||
}
|
||||
|
||||
int CV_KDTreeTest_C::checkFindBoxed()
|
||||
{
|
||||
Mat min(1, dims, CV_32FC1 ), max(1, dims, CV_32FC1 ), indices( 1, 1, CV_32SC1 );
|
||||
float l = minValue, r = maxValue;
|
||||
min.setTo(Scalar(l)), max.setTo(Scalar(r));
|
||||
CvMat _min = min, _max = max, _indices = indices;
|
||||
// TODO check indices
|
||||
if( cvFindFeaturesBoxed( tr, &_min, &_max, &_indices ) != featuresCount )
|
||||
return cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
return cvtest::TS::OK;
|
||||
}
|
||||
|
||||
|
||||
TEST(Features2d_LSH, regression) { CV_LSHTest test; test.safe_run(); }
|
||||
TEST(Features2d_SpillTree, regression) { CV_SpillTreeTest_C test; test.safe_run(); }
|
||||
TEST(Features2d_KDTree_C, regression) { CV_KDTreeTest_C test; test.safe_run(); }
|
||||
356
modules/legacy/test/test_optflow.cpp
Normal file
356
modules/legacy/test/test_optflow.cpp
Normal file
@@ -0,0 +1,356 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of the copyright holders may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
#include "opencv2/video/tracking.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
class CV_OptFlowTest : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
CV_OptFlowTest();
|
||||
~CV_OptFlowTest();
|
||||
protected:
|
||||
void run(int);
|
||||
|
||||
bool runDense(const Point& shift = Point(3, 0));
|
||||
bool runSparse();
|
||||
};
|
||||
|
||||
CV_OptFlowTest::CV_OptFlowTest() {}
|
||||
CV_OptFlowTest::~CV_OptFlowTest() {}
|
||||
|
||||
|
||||
Mat copnvert2flow(const Mat& velx, const Mat& vely)
|
||||
{
|
||||
Mat flow(velx.size(), CV_32FC2);
|
||||
for(int y = 0 ; y < flow.rows; ++y)
|
||||
for(int x = 0 ; x < flow.cols; ++x)
|
||||
flow.at<Point2f>(y, x) = Point2f(velx.at<float>(y, x), vely.at<float>(y, x));
|
||||
return flow;
|
||||
}
|
||||
|
||||
void calcOpticalFlowLK( const Mat& prev, const Mat& curr, Size winSize, Mat& flow )
|
||||
{
|
||||
Mat velx(prev.size(), CV_32F), vely(prev.size(), CV_32F);
|
||||
CvMat cvvelx = velx; CvMat cvvely = vely;
|
||||
CvMat cvprev = prev; CvMat cvcurr = curr;
|
||||
cvCalcOpticalFlowLK( &cvprev, &cvcurr, winSize, &cvvelx, &cvvely );
|
||||
flow = copnvert2flow(velx, vely);
|
||||
}
|
||||
|
||||
void calcOpticalFlowBM( const Mat& prev, const Mat& curr, Size bSize, Size shiftSize, Size maxRange, int usePrevious, Mat& flow )
|
||||
{
|
||||
Size sz((curr.cols - bSize.width)/shiftSize.width, (curr.rows - bSize.height)/shiftSize.height);
|
||||
Mat velx(sz, CV_32F), vely(sz, CV_32F);
|
||||
|
||||
CvMat cvvelx = velx; CvMat cvvely = vely;
|
||||
CvMat cvprev = prev; CvMat cvcurr = curr;
|
||||
cvCalcOpticalFlowBM( &cvprev, &cvcurr, bSize, shiftSize, maxRange, usePrevious, &cvvelx, &cvvely);
|
||||
flow = copnvert2flow(velx, vely);
|
||||
}
|
||||
|
||||
void calcOpticalFlowHS( const Mat& prev, const Mat& curr, int usePrevious, double lambda, TermCriteria criteria, Mat& flow)
|
||||
{
|
||||
Mat velx(prev.size(), CV_32F), vely(prev.size(), CV_32F);
|
||||
CvMat cvvelx = velx; CvMat cvvely = vely;
|
||||
CvMat cvprev = prev; CvMat cvcurr = curr;
|
||||
cvCalcOpticalFlowHS( &cvprev, &cvcurr, usePrevious, &cvvelx, &cvvely, lambda, criteria );
|
||||
flow = copnvert2flow(velx, vely);
|
||||
}
|
||||
|
||||
void calcAffineFlowPyrLK( const Mat& prev, const Mat& curr,
|
||||
const vector<Point2f>& prev_features, vector<Point2f>& curr_features,
|
||||
vector<uchar>& status, vector<float>& track_error, vector<float>& matrices,
|
||||
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,30, 0.01),
|
||||
Size win_size = Size(15, 15), int level = 3, int flags = 0)
|
||||
{
|
||||
CvMat cvprev = prev;
|
||||
CvMat cvcurr = curr;
|
||||
|
||||
size_t count = prev_features.size();
|
||||
curr_features.resize(count);
|
||||
status.resize(count);
|
||||
track_error.resize(count);
|
||||
matrices.resize(count * 6);
|
||||
|
||||
cvCalcAffineFlowPyrLK( &cvprev, &cvcurr, 0, 0,
|
||||
(const CvPoint2D32f*)&prev_features[0], (CvPoint2D32f*)&curr_features[0], &matrices[0],
|
||||
(int)count, win_size, level, (char*)&status[0], &track_error[0], criteria, flags );
|
||||
}
|
||||
|
||||
double showFlowAndCalcError(const string& name, const Mat& gray, const Mat& flow,
|
||||
const Rect& where, const Point& d,
|
||||
bool showImages = false, bool writeError = false)
|
||||
{
|
||||
const int mult = 16;
|
||||
|
||||
if (showImages)
|
||||
{
|
||||
Mat tmp, cflow;
|
||||
resize(gray, tmp, gray.size() * mult, 0, 0, INTER_NEAREST);
|
||||
cvtColor(tmp, cflow, CV_GRAY2BGR);
|
||||
|
||||
const float m2 = 0.3f;
|
||||
const float minVel = 0.1f;
|
||||
|
||||
for(int y = 0; y < flow.rows; ++y)
|
||||
for(int x = 0; x < flow.cols; ++x)
|
||||
{
|
||||
Point2f f = flow.at<Point2f>(y, x);
|
||||
|
||||
if (f.x * f.x + f.y * f.y > minVel * minVel)
|
||||
{
|
||||
Point p1 = Point(x, y) * mult;
|
||||
Point p2 = Point(cvRound((x + f.x*m2) * mult), cvRound((y + f.y*m2) * mult));
|
||||
|
||||
line(cflow, p1, p2, CV_RGB(0, 255, 0));
|
||||
circle(cflow, Point(x, y) * mult, 2, CV_RGB(255, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
rectangle(cflow, (where.tl() + d) * mult, (where.br() + d - Point(1,1)) * mult, CV_RGB(0, 0, 255));
|
||||
namedWindow(name, 1); imshow(name, cflow);
|
||||
}
|
||||
|
||||
double angle = atan2((float)d.y, (float)d.x);
|
||||
double error = 0;
|
||||
|
||||
bool all = true;
|
||||
Mat inner = flow(where);
|
||||
for(int y = 0; y < inner.rows; ++y)
|
||||
for(int x = 0; x < inner.cols; ++x)
|
||||
{
|
||||
const Point2f f = inner.at<Point2f>(y, x);
|
||||
|
||||
if (f.x == 0 && f.y == 0)
|
||||
continue;
|
||||
|
||||
all = false;
|
||||
|
||||
double a = atan2(f.y, f.x);
|
||||
error += fabs(angle - a);
|
||||
}
|
||||
double res = all ? numeric_limits<double>::max() : error / (inner.cols * inner.rows);
|
||||
|
||||
if (writeError)
|
||||
cout << "Error " + name << " = " << res << endl;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Mat generateImage(const Size& sz, bool doBlur = true)
|
||||
{
|
||||
RNG rng;
|
||||
Mat mat(sz, CV_8U);
|
||||
mat = Scalar(0);
|
||||
for(int y = 0; y < mat.rows; ++y)
|
||||
for(int x = 0; x < mat.cols; ++x)
|
||||
mat.at<uchar>(y, x) = (uchar)rng;
|
||||
if (doBlur)
|
||||
blur(mat, mat, Size(3, 3));
|
||||
return mat;
|
||||
}
|
||||
|
||||
Mat generateSample(const Size& sz)
|
||||
{
|
||||
Mat smpl(sz, CV_8U);
|
||||
smpl = Scalar(0);
|
||||
Point sc(smpl.cols/2, smpl.rows/2);
|
||||
rectangle(smpl, Point(0,0), sc - Point(1,1), Scalar(255), CV_FILLED);
|
||||
rectangle(smpl, sc, Point(smpl.cols, smpl.rows), Scalar(255), CV_FILLED);
|
||||
return smpl;
|
||||
}
|
||||
|
||||
bool CV_OptFlowTest::runDense(const Point& d)
|
||||
{
|
||||
Size matSize(40, 40);
|
||||
Size movSize(8, 8);
|
||||
|
||||
Mat smpl = generateSample(movSize);
|
||||
Mat prev = generateImage(matSize);
|
||||
Mat curr = prev.clone();
|
||||
|
||||
Rect rect(Point(prev.cols/2, prev.rows/2) - Point(movSize.width/2, movSize.height/2), movSize);
|
||||
|
||||
Mat flowLK, flowBM, flowHS, flowFB, flowFB_G, flowBM_received, m1;
|
||||
|
||||
m1 = prev(rect); smpl.copyTo(m1);
|
||||
m1 = curr(Rect(rect.tl() + d, rect.br() + d)); smpl.copyTo(m1);
|
||||
|
||||
calcOpticalFlowLK( prev, curr, Size(15, 15), flowLK);
|
||||
calcOpticalFlowBM( prev, curr, Size(15, 15), Size(1, 1), Size(15, 15), 0, flowBM_received);
|
||||
calcOpticalFlowHS( prev, curr, 0, 5, TermCriteria(TermCriteria::MAX_ITER, 400, 0), flowHS);
|
||||
calcOpticalFlowFarneback( prev, curr, flowFB, 0.5, 3, std::max(d.x, d.y) + 10, 100, 6, 2, 0);
|
||||
calcOpticalFlowFarneback( prev, curr, flowFB_G, 0.5, 3, std::max(d.x, d.y) + 10, 100, 6, 2, OPTFLOW_FARNEBACK_GAUSSIAN);
|
||||
|
||||
flowBM.create(prev.size(), CV_32FC2);
|
||||
flowBM = Scalar(0);
|
||||
Point origin((flowBM.cols - flowBM_received.cols)/2, (flowBM.rows - flowBM_received.rows)/2);
|
||||
Mat wcp = flowBM(Rect(origin, flowBM_received.size()));
|
||||
flowBM_received.copyTo(wcp);
|
||||
|
||||
double errorLK = showFlowAndCalcError("LK", prev, flowLK, rect, d);
|
||||
double errorBM = showFlowAndCalcError("BM", prev, flowBM, rect, d);
|
||||
double errorFB = showFlowAndCalcError("FB", prev, flowFB, rect, d);
|
||||
double errorFBG = showFlowAndCalcError("FBG", prev, flowFB_G, rect, d);
|
||||
double errorHS = showFlowAndCalcError("HS", prev, flowHS, rect, d); (void)errorHS;
|
||||
//waitKey();
|
||||
|
||||
const double thres = 0.2;
|
||||
if (errorLK > thres || errorBM > thres || errorFB > thres || errorFBG > thres /*|| errorHS > thres */)
|
||||
{
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CV_OptFlowTest::runSparse()
|
||||
{
|
||||
Mat prev = imread(string(ts->get_data_path()) + "optflow/rock_1.bmp", 0);
|
||||
Mat next = imread(string(ts->get_data_path()) + "optflow/rock_2.bmp", 0);
|
||||
|
||||
if (prev.empty() || next.empty())
|
||||
{
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
|
||||
return false;
|
||||
}
|
||||
|
||||
Mat cprev, cnext;
|
||||
cvtColor(prev, cprev, CV_GRAY2BGR);
|
||||
cvtColor(next, cnext, CV_GRAY2BGR);
|
||||
|
||||
vector<Point2f> prev_pts;
|
||||
vector<Point2f> next_ptsOpt;
|
||||
vector<Point2f> next_ptsAff;
|
||||
vector<uchar> status_Opt;
|
||||
vector<uchar> status_Aff;
|
||||
vector<float> error;
|
||||
vector<float> matrices;
|
||||
|
||||
Size netSize(10, 10);
|
||||
Point2f center = Point(prev.cols/2, prev.rows/2);
|
||||
|
||||
for(int i = 0 ; i < netSize.width; ++i)
|
||||
for(int j = 0 ; j < netSize.width; ++j)
|
||||
{
|
||||
Point2f p(i * float(prev.cols)/netSize.width, j * float(prev.rows)/netSize.height);
|
||||
prev_pts.push_back((p - center) * 0.5f + center);
|
||||
}
|
||||
|
||||
calcOpticalFlowPyrLK( prev, next, prev_pts, next_ptsOpt, status_Opt, error );
|
||||
calcAffineFlowPyrLK ( prev, next, prev_pts, next_ptsAff, status_Aff, error, matrices);
|
||||
|
||||
const double expected_shift = 25;
|
||||
const double thres = 1;
|
||||
for(size_t i = 0; i < prev_pts.size(); ++i)
|
||||
{
|
||||
circle(cprev, prev_pts[i], 2, CV_RGB(255, 0, 0));
|
||||
|
||||
if (status_Opt[i])
|
||||
{
|
||||
circle(cnext, next_ptsOpt[i], 2, CV_RGB(0, 0, 255));
|
||||
Point2f shift = prev_pts[i] - next_ptsOpt[i];
|
||||
|
||||
double n = sqrt(shift.ddot(shift));
|
||||
if (fabs(n - expected_shift) > thres)
|
||||
{
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (status_Aff[i])
|
||||
{
|
||||
circle(cnext, next_ptsAff[i], 4, CV_RGB(0, 255, 0));
|
||||
Point2f shift = prev_pts[i] - next_ptsAff[i];
|
||||
|
||||
double n = sqrt(shift.ddot(shift));
|
||||
if (fabs(n - expected_shift) > thres)
|
||||
{
|
||||
ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*namedWindow("P"); imshow("P", cprev);
|
||||
namedWindow("N"); imshow("N", cnext);
|
||||
waitKey();*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CV_OptFlowTest::run( int /* start_from */)
|
||||
{
|
||||
|
||||
if (!runDense(Point(3, 0)))
|
||||
return;
|
||||
|
||||
if (!runDense(Point(0, 3)))
|
||||
return;
|
||||
|
||||
//if (!runDense(Point(3, 3))) return; //probably LK works incorrectly in this case.
|
||||
|
||||
if (!runSparse())
|
||||
return;
|
||||
|
||||
ts->set_failed_test_info(cvtest::TS::OK);
|
||||
}
|
||||
|
||||
|
||||
TEST(Video_OpticalFlow, accuracy) { CV_OptFlowTest test; test.safe_run(); }
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "opencv2/imgproc/imgproc_c.h"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
#include "opencv2/highgui/highgui_c.h"
|
||||
#include "opencv2/legacy/legacy.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#endif
|
||||
|
||||
204
modules/legacy/test/test_pyrsegmentation.cpp
Normal file
204
modules/legacy/test/test_pyrsegmentation.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
class CV_PyrSegmentationTest : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
CV_PyrSegmentationTest();
|
||||
protected:
|
||||
void run(int);
|
||||
};
|
||||
|
||||
#define SCAN 0
|
||||
|
||||
CV_PyrSegmentationTest::CV_PyrSegmentationTest()
|
||||
{
|
||||
}
|
||||
|
||||
void CV_PyrSegmentationTest::run( int /*start_from*/ )
|
||||
{
|
||||
Mat _image_f, _image, _image_s;
|
||||
const int level = 5;
|
||||
const double range = 15;
|
||||
|
||||
int code = cvtest::TS::OK;
|
||||
|
||||
CvPoint _cp[] ={{33,33}, {43,33}, {43,43}, {33,43}};
|
||||
CvPoint _cp2[] ={{50,50}, {70,50}, {70,70}, {50,70}};
|
||||
CvPoint* cp = _cp;
|
||||
CvPoint* cp2 = _cp2;
|
||||
CvConnectedComp *dst_comp[3];
|
||||
CvRect rect[3] = {{50,50,21,21}, {0,0,128,128}, {33,33,11,11}};
|
||||
double a[3] = {441.0, 15822.0, 121.0};
|
||||
|
||||
/* ippiPoint cp3[] ={130,130, 150,130, 150,150, 130,150}; */
|
||||
/* CvPoint cp[] ={0,0, 5,5, 5,0, 10,5, 10,0, 15,5, 15,0}; */
|
||||
int nPoints = 4;
|
||||
int block_size = 1000;
|
||||
|
||||
CvMemStorage *storage; /* storage for connected component writing */
|
||||
CvSeq *comp;
|
||||
|
||||
RNG& rng = ts->get_rng();
|
||||
int i, j, iter;
|
||||
|
||||
IplImage *image, *image_f, *image_s;
|
||||
CvSize size = {128, 128};
|
||||
const int threshold1 = 50, threshold2 = 50;
|
||||
|
||||
rect[1].width = size.width;
|
||||
rect[1].height = size.height;
|
||||
a[1] = size.width*size.height - a[0] - a[2];
|
||||
|
||||
OPENCV_CALL( storage = cvCreateMemStorage( block_size ) );
|
||||
|
||||
for( iter = 0; iter < 2; iter++ )
|
||||
{
|
||||
int channels = iter == 0 ? 1 : 3;
|
||||
int mask[] = {0,0,0};
|
||||
|
||||
image = cvCreateImage(size, 8, channels );
|
||||
image_s = cvCloneImage( image );
|
||||
image_f = cvCloneImage( image );
|
||||
|
||||
if( channels == 1 )
|
||||
{
|
||||
int color1 = 30, color2 = 110, color3 = 190;
|
||||
|
||||
cvSet( image, cvScalarAll(color1));
|
||||
cvFillPoly( image, &cp, &nPoints, 1, cvScalar(color2));
|
||||
cvFillPoly( image, &cp2, &nPoints, 1, cvScalar(color3));
|
||||
}
|
||||
else
|
||||
{
|
||||
CvScalar color1 = CV_RGB(30,30,30), color2 = CV_RGB(255,0,0), color3 = CV_RGB(0,255,0);
|
||||
|
||||
assert( channels == 3 );
|
||||
cvSet( image, color1 );
|
||||
cvFillPoly( image, &cp, &nPoints, 1, color2);
|
||||
cvFillPoly( image, &cp2, &nPoints, 1, color3);
|
||||
}
|
||||
|
||||
_image_f = cvarrToMat(image_f);
|
||||
cvtest::randUni( rng, _image_f, cvScalarAll(0), cvScalarAll(range*2) );
|
||||
cvAddWeighted( image, 1, image_f, 1, -range, image_f );
|
||||
|
||||
cvPyrSegmentation( image_f, image_s,
|
||||
storage, &comp,
|
||||
level, threshold1, threshold2 );
|
||||
|
||||
if(comp->total != 3)
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG,
|
||||
"The segmentation function returned %d (not 3) components\n", comp->total );
|
||||
code = cvtest::TS::FAIL_INVALID_OUTPUT;
|
||||
goto _exit_;
|
||||
}
|
||||
/* read the connected components */
|
||||
dst_comp[0] = (CvConnectedComp*)CV_GET_SEQ_ELEM( CvConnectedComp, comp, 0 );
|
||||
dst_comp[1] = (CvConnectedComp*)CV_GET_SEQ_ELEM( CvConnectedComp, comp, 1 );
|
||||
dst_comp[2] = (CvConnectedComp*)CV_GET_SEQ_ELEM( CvConnectedComp, comp, 2 );
|
||||
|
||||
/*{
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
CvRect r = dst_comp[i]->rect;
|
||||
cvRectangle( image_s, cvPoint(r.x,r.y), cvPoint(r.x+r.width,r.y+r.height),
|
||||
CV_RGB(255,255,255), 3, 8, 0 );
|
||||
}
|
||||
|
||||
cvNamedWindow( "test", 1 );
|
||||
cvShowImage( "test", image_s );
|
||||
cvWaitKey(0);
|
||||
}*/
|
||||
|
||||
_image = cvarrToMat(image);
|
||||
_image_s = cvarrToMat(image_s);
|
||||
code = cvtest::cmpEps2( ts, _image, _image_s, 10, false, "the output image" );
|
||||
if( code < 0 )
|
||||
goto _exit_;
|
||||
|
||||
for( i = 0; i < 3; i++)
|
||||
{
|
||||
for( j = 0; j < 3; j++ )
|
||||
{
|
||||
if( !mask[j] && dst_comp[i]->area == a[j] &&
|
||||
dst_comp[i]->rect.x == rect[j].x &&
|
||||
dst_comp[i]->rect.y == rect[j].y &&
|
||||
dst_comp[i]->rect.width == rect[j].width &&
|
||||
dst_comp[i]->rect.height == rect[j].height )
|
||||
{
|
||||
mask[j] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( j == 3 )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "The component #%d is incorrect\n", i );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
goto _exit_;
|
||||
}
|
||||
}
|
||||
|
||||
cvReleaseImage(&image_f);
|
||||
cvReleaseImage(&image);
|
||||
cvReleaseImage(&image_s);
|
||||
}
|
||||
|
||||
_exit_:
|
||||
|
||||
cvReleaseMemStorage( &storage );
|
||||
cvReleaseImage(&image_f);
|
||||
cvReleaseImage(&image);
|
||||
cvReleaseImage(&image_s);
|
||||
|
||||
if( code < 0 )
|
||||
ts->set_failed_test_info( code );
|
||||
}
|
||||
|
||||
TEST(Imgproc_PyrSegmentation, regression) { CV_PyrSegmentationTest test; test.safe_run(); }
|
||||
|
||||
/* End of file. */
|
||||
722
modules/legacy/test/test_stereomatching.cpp
Normal file
722
modules/legacy/test/test_stereomatching.cpp
Normal file
@@ -0,0 +1,722 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
/*
|
||||
This is a regression test for stereo matching algorithms. This test gets some quality metrics
|
||||
discribed in "A Taxonomy and Evaluation of Dense Two-Frame Stereo Correspondence Algorithms".
|
||||
Daniel Scharstein, Richard Szeliski
|
||||
*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
#include <limits>
|
||||
#include <cstdio>
|
||||
|
||||
using namespace std;
|
||||
using namespace cv;
|
||||
|
||||
const float EVAL_BAD_THRESH = 1.f;
|
||||
const int EVAL_TEXTURELESS_WIDTH = 3;
|
||||
const float EVAL_TEXTURELESS_THRESH = 4.f;
|
||||
const float EVAL_DISP_THRESH = 1.f;
|
||||
const float EVAL_DISP_GAP = 2.f;
|
||||
const int EVAL_DISCONT_WIDTH = 9;
|
||||
const int EVAL_IGNORE_BORDER = 10;
|
||||
|
||||
const int ERROR_KINDS_COUNT = 6;
|
||||
|
||||
//============================== quality measuring functions =================================================
|
||||
|
||||
/*
|
||||
Calculate textureless regions of image (regions where the squared horizontal intensity gradient averaged over
|
||||
a square window of size=evalTexturelessWidth is below a threshold=evalTexturelessThresh) and textured regions.
|
||||
*/
|
||||
void computeTextureBasedMasks( const Mat& _img, Mat* texturelessMask, Mat* texturedMask,
|
||||
int texturelessWidth = EVAL_TEXTURELESS_WIDTH, float texturelessThresh = EVAL_TEXTURELESS_THRESH )
|
||||
{
|
||||
if( !texturelessMask && !texturedMask )
|
||||
return;
|
||||
if( _img.empty() )
|
||||
CV_Error( CV_StsBadArg, "img is empty" );
|
||||
|
||||
Mat img = _img;
|
||||
if( _img.channels() > 1)
|
||||
{
|
||||
Mat tmp; cvtColor( _img, tmp, CV_BGR2GRAY ); img = tmp;
|
||||
}
|
||||
Mat dxI; Sobel( img, dxI, CV_32FC1, 1, 0, 3 );
|
||||
Mat dxI2; pow( dxI / 8.f/*normalize*/, 2, dxI2 );
|
||||
Mat avgDxI2; boxFilter( dxI2, avgDxI2, CV_32FC1, Size(texturelessWidth,texturelessWidth) );
|
||||
|
||||
if( texturelessMask )
|
||||
*texturelessMask = avgDxI2 < texturelessThresh;
|
||||
if( texturedMask )
|
||||
*texturedMask = avgDxI2 >= texturelessThresh;
|
||||
}
|
||||
|
||||
void checkTypeAndSizeOfDisp( const Mat& dispMap, const Size* sz )
|
||||
{
|
||||
if( dispMap.empty() )
|
||||
CV_Error( CV_StsBadArg, "dispMap is empty" );
|
||||
if( dispMap.type() != CV_32FC1 )
|
||||
CV_Error( CV_StsBadArg, "dispMap must have CV_32FC1 type" );
|
||||
if( sz && (dispMap.rows != sz->height || dispMap.cols != sz->width) )
|
||||
CV_Error( CV_StsBadArg, "dispMap has incorrect size" );
|
||||
}
|
||||
|
||||
void checkTypeAndSizeOfMask( const Mat& mask, Size sz )
|
||||
{
|
||||
if( mask.empty() )
|
||||
CV_Error( CV_StsBadArg, "mask is empty" );
|
||||
if( mask.type() != CV_8UC1 )
|
||||
CV_Error( CV_StsBadArg, "mask must have CV_8UC1 type" );
|
||||
if( mask.rows != sz.height || mask.cols != sz.width )
|
||||
CV_Error( CV_StsBadArg, "mask has incorrect size" );
|
||||
}
|
||||
|
||||
void checkDispMapsAndUnknDispMasks( const Mat& leftDispMap, const Mat& rightDispMap,
|
||||
const Mat& leftUnknDispMask, const Mat& rightUnknDispMask )
|
||||
{
|
||||
// check type and size of disparity maps
|
||||
checkTypeAndSizeOfDisp( leftDispMap, 0 );
|
||||
if( !rightDispMap.empty() )
|
||||
{
|
||||
Size sz = leftDispMap.size();
|
||||
checkTypeAndSizeOfDisp( rightDispMap, &sz );
|
||||
}
|
||||
|
||||
// check size and type of unknown disparity maps
|
||||
if( !leftUnknDispMask.empty() )
|
||||
checkTypeAndSizeOfMask( leftUnknDispMask, leftDispMap.size() );
|
||||
if( !rightUnknDispMask.empty() )
|
||||
checkTypeAndSizeOfMask( rightUnknDispMask, rightDispMap.size() );
|
||||
|
||||
// check values of disparity maps (known disparity values musy be positive)
|
||||
double leftMinVal = 0, rightMinVal = 0;
|
||||
if( leftUnknDispMask.empty() )
|
||||
minMaxLoc( leftDispMap, &leftMinVal );
|
||||
else
|
||||
minMaxLoc( leftDispMap, &leftMinVal, 0, 0, 0, ~leftUnknDispMask );
|
||||
if( !rightDispMap.empty() )
|
||||
{
|
||||
if( rightUnknDispMask.empty() )
|
||||
minMaxLoc( rightDispMap, &rightMinVal );
|
||||
else
|
||||
minMaxLoc( rightDispMap, &rightMinVal, 0, 0, 0, ~rightUnknDispMask );
|
||||
}
|
||||
if( leftMinVal < 0 || rightMinVal < 0)
|
||||
CV_Error( CV_StsBadArg, "known disparity values must be positive" );
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate occluded regions of reference image (left image) (regions that are occluded in the matching image (right image),
|
||||
i.e., where the forward-mapped disparity lands at a location with a larger (nearer) disparity) and non occluded regions.
|
||||
*/
|
||||
void computeOcclusionBasedMasks( const Mat& leftDisp, const Mat& _rightDisp,
|
||||
Mat* occludedMask, Mat* nonOccludedMask,
|
||||
const Mat& leftUnknDispMask = Mat(), const Mat& rightUnknDispMask = Mat(),
|
||||
float dispThresh = EVAL_DISP_THRESH )
|
||||
{
|
||||
if( !occludedMask && !nonOccludedMask )
|
||||
return;
|
||||
checkDispMapsAndUnknDispMasks( leftDisp, _rightDisp, leftUnknDispMask, rightUnknDispMask );
|
||||
|
||||
Mat rightDisp;
|
||||
if( _rightDisp.empty() )
|
||||
{
|
||||
if( !rightUnknDispMask.empty() )
|
||||
CV_Error( CV_StsBadArg, "rightUnknDispMask must be empty if _rightDisp is empty" );
|
||||
rightDisp.create(leftDisp.size(), CV_32FC1);
|
||||
rightDisp.setTo(Scalar::all(0) );
|
||||
for( int leftY = 0; leftY < leftDisp.rows; leftY++ )
|
||||
{
|
||||
for( int leftX = 0; leftX < leftDisp.cols; leftX++ )
|
||||
{
|
||||
if( !leftUnknDispMask.empty() && leftUnknDispMask.at<uchar>(leftY,leftX) )
|
||||
continue;
|
||||
float leftDispVal = leftDisp.at<float>(leftY, leftX);
|
||||
int rightX = leftX - cvRound(leftDispVal), rightY = leftY;
|
||||
if( rightX >= 0)
|
||||
rightDisp.at<float>(rightY,rightX) = max(rightDisp.at<float>(rightY,rightX), leftDispVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
_rightDisp.copyTo(rightDisp);
|
||||
|
||||
if( occludedMask )
|
||||
{
|
||||
occludedMask->create(leftDisp.size(), CV_8UC1);
|
||||
occludedMask->setTo(Scalar::all(0) );
|
||||
}
|
||||
if( nonOccludedMask )
|
||||
{
|
||||
nonOccludedMask->create(leftDisp.size(), CV_8UC1);
|
||||
nonOccludedMask->setTo(Scalar::all(0) );
|
||||
}
|
||||
for( int leftY = 0; leftY < leftDisp.rows; leftY++ )
|
||||
{
|
||||
for( int leftX = 0; leftX < leftDisp.cols; leftX++ )
|
||||
{
|
||||
if( !leftUnknDispMask.empty() && leftUnknDispMask.at<uchar>(leftY,leftX) )
|
||||
continue;
|
||||
float leftDispVal = leftDisp.at<float>(leftY, leftX);
|
||||
int rightX = leftX - cvRound(leftDispVal), rightY = leftY;
|
||||
if( rightX < 0 && occludedMask )
|
||||
occludedMask->at<uchar>(leftY, leftX) = 255;
|
||||
else
|
||||
{
|
||||
if( !rightUnknDispMask.empty() && rightUnknDispMask.at<uchar>(rightY,rightX) )
|
||||
continue;
|
||||
float rightDispVal = rightDisp.at<float>(rightY, rightX);
|
||||
if( rightDispVal > leftDispVal + dispThresh )
|
||||
{
|
||||
if( occludedMask )
|
||||
occludedMask->at<uchar>(leftY, leftX) = 255;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( nonOccludedMask )
|
||||
nonOccludedMask->at<uchar>(leftY, leftX) = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate depth discontinuty regions: pixels whose neiboring disparities differ by more than
|
||||
dispGap, dilated by window of width discontWidth.
|
||||
*/
|
||||
void computeDepthDiscontMask( const Mat& disp, Mat& depthDiscontMask, const Mat& unknDispMask = Mat(),
|
||||
float dispGap = EVAL_DISP_GAP, int discontWidth = EVAL_DISCONT_WIDTH )
|
||||
{
|
||||
if( disp.empty() )
|
||||
CV_Error( CV_StsBadArg, "disp is empty" );
|
||||
if( disp.type() != CV_32FC1 )
|
||||
CV_Error( CV_StsBadArg, "disp must have CV_32FC1 type" );
|
||||
if( !unknDispMask.empty() )
|
||||
checkTypeAndSizeOfMask( unknDispMask, disp.size() );
|
||||
|
||||
Mat curDisp; disp.copyTo( curDisp );
|
||||
if( !unknDispMask.empty() )
|
||||
curDisp.setTo( Scalar(numeric_limits<float>::min()), unknDispMask );
|
||||
Mat maxNeighbDisp; dilate( curDisp, maxNeighbDisp, Mat(3, 3, CV_8UC1, Scalar(1)) );
|
||||
if( !unknDispMask.empty() )
|
||||
curDisp.setTo( Scalar(numeric_limits<float>::max()), unknDispMask );
|
||||
Mat minNeighbDisp; erode( curDisp, minNeighbDisp, Mat(3, 3, CV_8UC1, Scalar(1)) );
|
||||
depthDiscontMask = max( (Mat)(maxNeighbDisp-disp), (Mat)(disp-minNeighbDisp) ) > dispGap;
|
||||
if( !unknDispMask.empty() )
|
||||
depthDiscontMask &= ~unknDispMask;
|
||||
dilate( depthDiscontMask, depthDiscontMask, Mat(discontWidth, discontWidth, CV_8UC1, Scalar(1)) );
|
||||
}
|
||||
|
||||
/*
|
||||
Get evaluation masks excluding a border.
|
||||
*/
|
||||
Mat getBorderedMask( Size maskSize, int border = EVAL_IGNORE_BORDER )
|
||||
{
|
||||
CV_Assert( border >= 0 );
|
||||
Mat mask(maskSize, CV_8UC1, Scalar(0));
|
||||
int w = maskSize.width - 2*border, h = maskSize.height - 2*border;
|
||||
if( w < 0 || h < 0 )
|
||||
mask.setTo(Scalar(0));
|
||||
else
|
||||
mask( Rect(Point(border,border),Size(w,h)) ).setTo(Scalar(255));
|
||||
return mask;
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate root-mean-squared error between the computed disparity map (computedDisp) and ground truth map (groundTruthDisp).
|
||||
*/
|
||||
float dispRMS( const Mat& computedDisp, const Mat& groundTruthDisp, const Mat& mask )
|
||||
{
|
||||
checkTypeAndSizeOfDisp( groundTruthDisp, 0 );
|
||||
Size sz = groundTruthDisp.size();
|
||||
checkTypeAndSizeOfDisp( computedDisp, &sz );
|
||||
|
||||
int pointsCount = sz.height*sz.width;
|
||||
if( !mask.empty() )
|
||||
{
|
||||
checkTypeAndSizeOfMask( mask, sz );
|
||||
pointsCount = countNonZero(mask);
|
||||
}
|
||||
return 1.f/sqrt((float)pointsCount) * (float)norm(computedDisp, groundTruthDisp, NORM_L2, mask);
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate fraction of bad matching pixels.
|
||||
*/
|
||||
float badMatchPxlsFraction( const Mat& computedDisp, const Mat& groundTruthDisp, const Mat& mask,
|
||||
float _badThresh = EVAL_BAD_THRESH )
|
||||
{
|
||||
int badThresh = cvRound(_badThresh);
|
||||
checkTypeAndSizeOfDisp( groundTruthDisp, 0 );
|
||||
Size sz = groundTruthDisp.size();
|
||||
checkTypeAndSizeOfDisp( computedDisp, &sz );
|
||||
|
||||
Mat badPxlsMap;
|
||||
absdiff( computedDisp, groundTruthDisp, badPxlsMap );
|
||||
badPxlsMap = badPxlsMap > badThresh;
|
||||
int pointsCount = sz.height*sz.width;
|
||||
if( !mask.empty() )
|
||||
{
|
||||
checkTypeAndSizeOfMask( mask, sz );
|
||||
badPxlsMap = badPxlsMap & mask;
|
||||
pointsCount = countNonZero(mask);
|
||||
}
|
||||
return 1.f/pointsCount * countNonZero(badPxlsMap);
|
||||
}
|
||||
|
||||
//===================== regression test for stereo matching algorithms ==============================
|
||||
|
||||
const string ALGORITHMS_DIR = "stereomatching/algorithms/";
|
||||
const string DATASETS_DIR = "stereomatching/datasets/";
|
||||
const string DATASETS_FILE = "datasets.xml";
|
||||
|
||||
const string RUN_PARAMS_FILE = "_params.xml";
|
||||
const string RESULT_FILE = "_res.xml";
|
||||
|
||||
const string LEFT_IMG_NAME = "im2.png";
|
||||
const string RIGHT_IMG_NAME = "im6.png";
|
||||
const string TRUE_LEFT_DISP_NAME = "disp2.png";
|
||||
const string TRUE_RIGHT_DISP_NAME = "disp6.png";
|
||||
|
||||
string ERROR_PREFIXES[] = { "borderedAll",
|
||||
"borderedNoOccl",
|
||||
"borderedOccl",
|
||||
"borderedTextured",
|
||||
"borderedTextureless",
|
||||
"borderedDepthDiscont" }; // size of ERROR_KINDS_COUNT
|
||||
|
||||
|
||||
const string RMS_STR = "RMS";
|
||||
const string BAD_PXLS_FRACTION_STR = "BadPxlsFraction";
|
||||
|
||||
class QualityEvalParams
|
||||
{
|
||||
public:
|
||||
QualityEvalParams() { setDefaults(); }
|
||||
QualityEvalParams( int _ignoreBorder )
|
||||
{
|
||||
setDefaults();
|
||||
ignoreBorder = _ignoreBorder;
|
||||
}
|
||||
void setDefaults()
|
||||
{
|
||||
badThresh = EVAL_BAD_THRESH;
|
||||
texturelessWidth = EVAL_TEXTURELESS_WIDTH;
|
||||
texturelessThresh = EVAL_TEXTURELESS_THRESH;
|
||||
dispThresh = EVAL_DISP_THRESH;
|
||||
dispGap = EVAL_DISP_GAP;
|
||||
discontWidth = EVAL_DISCONT_WIDTH;
|
||||
ignoreBorder = EVAL_IGNORE_BORDER;
|
||||
}
|
||||
float badThresh;
|
||||
int texturelessWidth;
|
||||
float texturelessThresh;
|
||||
float dispThresh;
|
||||
float dispGap;
|
||||
int discontWidth;
|
||||
int ignoreBorder;
|
||||
};
|
||||
|
||||
class CV_StereoMatchingTest : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
CV_StereoMatchingTest()
|
||||
{ rmsEps.resize( ERROR_KINDS_COUNT, 0.01f ); fracEps.resize( ERROR_KINDS_COUNT, 1.e-6f ); }
|
||||
protected:
|
||||
// assumed that left image is a reference image
|
||||
virtual int runStereoMatchingAlgorithm( const Mat& leftImg, const Mat& rightImg,
|
||||
Mat& leftDisp, Mat& rightDisp, int caseIdx ) = 0; // return ignored border width
|
||||
|
||||
int readDatasetsParams( FileStorage& fs );
|
||||
virtual int readRunParams( FileStorage& fs );
|
||||
void writeErrors( const string& errName, const vector<float>& errors, FileStorage* fs = 0 );
|
||||
void readErrors( FileNode& fn, const string& errName, vector<float>& errors );
|
||||
int compareErrors( const vector<float>& calcErrors, const vector<float>& validErrors,
|
||||
const vector<float>& eps, const string& errName );
|
||||
int processStereoMatchingResults( FileStorage& fs, int caseIdx, bool isWrite,
|
||||
const Mat& leftImg, const Mat& rightImg,
|
||||
const Mat& trueLeftDisp, const Mat& trueRightDisp,
|
||||
const Mat& leftDisp, const Mat& rightDisp,
|
||||
const QualityEvalParams& qualityEvalParams );
|
||||
void run( int );
|
||||
|
||||
vector<float> rmsEps;
|
||||
vector<float> fracEps;
|
||||
|
||||
struct DatasetParams
|
||||
{
|
||||
int dispScaleFactor;
|
||||
int dispUnknVal;
|
||||
};
|
||||
map<string, DatasetParams> datasetsParams;
|
||||
|
||||
vector<string> caseNames;
|
||||
vector<string> caseDatasets;
|
||||
};
|
||||
|
||||
void CV_StereoMatchingTest::run(int)
|
||||
{
|
||||
string dataPath = ts->get_data_path();
|
||||
string algorithmName = name;
|
||||
assert( !algorithmName.empty() );
|
||||
if( dataPath.empty() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "dataPath is empty" );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ARG_CHECK );
|
||||
return;
|
||||
}
|
||||
|
||||
FileStorage datasetsFS( dataPath + DATASETS_DIR + DATASETS_FILE, FileStorage::READ );
|
||||
int code = readDatasetsParams( datasetsFS );
|
||||
if( code != cvtest::TS::OK )
|
||||
{
|
||||
ts->set_failed_test_info( code );
|
||||
return;
|
||||
}
|
||||
FileStorage runParamsFS( dataPath + ALGORITHMS_DIR + algorithmName + RUN_PARAMS_FILE, FileStorage::READ );
|
||||
code = readRunParams( runParamsFS );
|
||||
if( code != cvtest::TS::OK )
|
||||
{
|
||||
ts->set_failed_test_info( code );
|
||||
return;
|
||||
}
|
||||
|
||||
string fullResultFilename = dataPath + ALGORITHMS_DIR + algorithmName + RESULT_FILE;
|
||||
FileStorage resFS( fullResultFilename, FileStorage::READ );
|
||||
bool isWrite = true; // write or compare results
|
||||
if( resFS.isOpened() )
|
||||
isWrite = false;
|
||||
else
|
||||
{
|
||||
resFS.open( fullResultFilename, FileStorage::WRITE );
|
||||
if( !resFS.isOpened() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "file %s can not be read or written\n", fullResultFilename.c_str() );
|
||||
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ARG_CHECK );
|
||||
return;
|
||||
}
|
||||
resFS << "stereo_matching" << "{";
|
||||
}
|
||||
|
||||
int progress = 0, caseCount = (int)caseNames.size();
|
||||
for( int ci = 0; ci < caseCount; ci++)
|
||||
{
|
||||
progress = update_progress( progress, ci, caseCount, 0 );
|
||||
printf("progress: %d%%\n", progress);
|
||||
fflush(stdout);
|
||||
string datasetName = caseDatasets[ci];
|
||||
string datasetFullDirName = dataPath + DATASETS_DIR + datasetName + "/";
|
||||
Mat leftImg = imread(datasetFullDirName + LEFT_IMG_NAME);
|
||||
Mat rightImg = imread(datasetFullDirName + RIGHT_IMG_NAME);
|
||||
Mat trueLeftDisp = imread(datasetFullDirName + TRUE_LEFT_DISP_NAME, 0);
|
||||
Mat trueRightDisp = imread(datasetFullDirName + TRUE_RIGHT_DISP_NAME, 0);
|
||||
|
||||
if( leftImg.empty() || rightImg.empty() || trueLeftDisp.empty() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "images or left ground-truth disparities of dataset %s can not be read", datasetName.c_str() );
|
||||
code = cvtest::TS::FAIL_INVALID_TEST_DATA;
|
||||
continue;
|
||||
}
|
||||
int dispScaleFactor = datasetsParams[datasetName].dispScaleFactor;
|
||||
Mat tmp; trueLeftDisp.convertTo( tmp, CV_32FC1, 1.f/dispScaleFactor ); trueLeftDisp = tmp; tmp.release();
|
||||
if( !trueRightDisp.empty() )
|
||||
trueRightDisp.convertTo( tmp, CV_32FC1, 1.f/dispScaleFactor ); trueRightDisp = tmp; tmp.release();
|
||||
|
||||
Mat leftDisp, rightDisp;
|
||||
int ignBorder = max(runStereoMatchingAlgorithm(leftImg, rightImg, leftDisp, rightDisp, ci), EVAL_IGNORE_BORDER);
|
||||
leftDisp.convertTo( tmp, CV_32FC1 ); leftDisp = tmp; tmp.release();
|
||||
rightDisp.convertTo( tmp, CV_32FC1 ); rightDisp = tmp; tmp.release();
|
||||
|
||||
int tempCode = processStereoMatchingResults( resFS, ci, isWrite,
|
||||
leftImg, rightImg, trueLeftDisp, trueRightDisp, leftDisp, rightDisp, QualityEvalParams(ignBorder));
|
||||
code = tempCode==cvtest::TS::OK ? code : tempCode;
|
||||
}
|
||||
|
||||
if( isWrite )
|
||||
resFS << "}"; // "stereo_matching"
|
||||
|
||||
ts->set_failed_test_info( code );
|
||||
}
|
||||
|
||||
void calcErrors( const Mat& leftImg, const Mat& /*rightImg*/,
|
||||
const Mat& trueLeftDisp, const Mat& trueRightDisp,
|
||||
const Mat& trueLeftUnknDispMask, const Mat& trueRightUnknDispMask,
|
||||
const Mat& calcLeftDisp, const Mat& /*calcRightDisp*/,
|
||||
vector<float>& rms, vector<float>& badPxlsFractions,
|
||||
const QualityEvalParams& qualityEvalParams )
|
||||
{
|
||||
Mat texturelessMask, texturedMask;
|
||||
computeTextureBasedMasks( leftImg, &texturelessMask, &texturedMask,
|
||||
qualityEvalParams.texturelessWidth, qualityEvalParams.texturelessThresh );
|
||||
Mat occludedMask, nonOccludedMask;
|
||||
computeOcclusionBasedMasks( trueLeftDisp, trueRightDisp, &occludedMask, &nonOccludedMask,
|
||||
trueLeftUnknDispMask, trueRightUnknDispMask, qualityEvalParams.dispThresh);
|
||||
Mat depthDiscontMask;
|
||||
computeDepthDiscontMask( trueLeftDisp, depthDiscontMask, trueLeftUnknDispMask,
|
||||
qualityEvalParams.dispGap, qualityEvalParams.discontWidth);
|
||||
|
||||
Mat borderedKnownMask = getBorderedMask( leftImg.size(), qualityEvalParams.ignoreBorder ) & ~trueLeftUnknDispMask;
|
||||
|
||||
nonOccludedMask &= borderedKnownMask;
|
||||
occludedMask &= borderedKnownMask;
|
||||
texturedMask &= nonOccludedMask; // & borderedKnownMask
|
||||
texturelessMask &= nonOccludedMask; // & borderedKnownMask
|
||||
depthDiscontMask &= nonOccludedMask; // & borderedKnownMask
|
||||
|
||||
rms.resize(ERROR_KINDS_COUNT);
|
||||
rms[0] = dispRMS( calcLeftDisp, trueLeftDisp, borderedKnownMask );
|
||||
rms[1] = dispRMS( calcLeftDisp, trueLeftDisp, nonOccludedMask );
|
||||
rms[2] = dispRMS( calcLeftDisp, trueLeftDisp, occludedMask );
|
||||
rms[3] = dispRMS( calcLeftDisp, trueLeftDisp, texturedMask );
|
||||
rms[4] = dispRMS( calcLeftDisp, trueLeftDisp, texturelessMask );
|
||||
rms[5] = dispRMS( calcLeftDisp, trueLeftDisp, depthDiscontMask );
|
||||
|
||||
badPxlsFractions.resize(ERROR_KINDS_COUNT);
|
||||
badPxlsFractions[0] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, borderedKnownMask, qualityEvalParams.badThresh );
|
||||
badPxlsFractions[1] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, nonOccludedMask, qualityEvalParams.badThresh );
|
||||
badPxlsFractions[2] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, occludedMask, qualityEvalParams.badThresh );
|
||||
badPxlsFractions[3] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, texturedMask, qualityEvalParams.badThresh );
|
||||
badPxlsFractions[4] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, texturelessMask, qualityEvalParams.badThresh );
|
||||
badPxlsFractions[5] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, depthDiscontMask, qualityEvalParams.badThresh );
|
||||
}
|
||||
|
||||
int CV_StereoMatchingTest::processStereoMatchingResults( FileStorage& fs, int caseIdx, bool isWrite,
|
||||
const Mat& leftImg, const Mat& rightImg,
|
||||
const Mat& trueLeftDisp, const Mat& trueRightDisp,
|
||||
const Mat& leftDisp, const Mat& rightDisp,
|
||||
const QualityEvalParams& qualityEvalParams )
|
||||
{
|
||||
// rightDisp is not used in current test virsion
|
||||
int code = cvtest::TS::OK;
|
||||
assert( fs.isOpened() );
|
||||
assert( trueLeftDisp.type() == CV_32FC1 && trueRightDisp.type() == CV_32FC1 );
|
||||
assert( leftDisp.type() == CV_32FC1 && rightDisp.type() == CV_32FC1 );
|
||||
|
||||
// get masks for unknown ground truth disparity values
|
||||
Mat leftUnknMask, rightUnknMask;
|
||||
DatasetParams params = datasetsParams[caseDatasets[caseIdx]];
|
||||
absdiff( trueLeftDisp, Scalar(params.dispUnknVal), leftUnknMask );
|
||||
leftUnknMask = leftUnknMask < numeric_limits<float>::epsilon();
|
||||
assert(leftUnknMask.type() == CV_8UC1);
|
||||
if( !trueRightDisp.empty() )
|
||||
{
|
||||
absdiff( trueRightDisp, Scalar(params.dispUnknVal), rightUnknMask );
|
||||
rightUnknMask = rightUnknMask < numeric_limits<float>::epsilon();
|
||||
assert(leftUnknMask.type() == CV_8UC1);
|
||||
}
|
||||
|
||||
// calculate errors
|
||||
vector<float> rmss, badPxlsFractions;
|
||||
calcErrors( leftImg, rightImg, trueLeftDisp, trueRightDisp, leftUnknMask, rightUnknMask,
|
||||
leftDisp, rightDisp, rmss, badPxlsFractions, qualityEvalParams );
|
||||
|
||||
if( isWrite )
|
||||
{
|
||||
fs << caseNames[caseIdx] << "{";
|
||||
cvWriteComment( fs.fs, RMS_STR.c_str(), 0 );
|
||||
writeErrors( RMS_STR, rmss, &fs );
|
||||
cvWriteComment( fs.fs, BAD_PXLS_FRACTION_STR.c_str(), 0 );
|
||||
writeErrors( BAD_PXLS_FRACTION_STR, badPxlsFractions, &fs );
|
||||
fs << "}"; // datasetName
|
||||
}
|
||||
else // compare
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "\nquality of case named %s\n", caseNames[caseIdx].c_str() );
|
||||
ts->printf( cvtest::TS::LOG, "%s\n", RMS_STR.c_str() );
|
||||
writeErrors( RMS_STR, rmss );
|
||||
ts->printf( cvtest::TS::LOG, "%s\n", BAD_PXLS_FRACTION_STR.c_str() );
|
||||
writeErrors( BAD_PXLS_FRACTION_STR, badPxlsFractions );
|
||||
|
||||
FileNode fn = fs.getFirstTopLevelNode()[caseNames[caseIdx]];
|
||||
vector<float> validRmss, validBadPxlsFractions;
|
||||
|
||||
readErrors( fn, RMS_STR, validRmss );
|
||||
readErrors( fn, BAD_PXLS_FRACTION_STR, validBadPxlsFractions );
|
||||
int tempCode = compareErrors( rmss, validRmss, rmsEps, RMS_STR );
|
||||
code = tempCode==cvtest::TS::OK ? code : tempCode;
|
||||
tempCode = compareErrors( badPxlsFractions, validBadPxlsFractions, fracEps, BAD_PXLS_FRACTION_STR );
|
||||
code = tempCode==cvtest::TS::OK ? code : tempCode;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
int CV_StereoMatchingTest::readDatasetsParams( FileStorage& fs )
|
||||
{
|
||||
if( !fs.isOpened() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "datasetsParams can not be read " );
|
||||
return cvtest::TS::FAIL_INVALID_TEST_DATA;
|
||||
}
|
||||
datasetsParams.clear();
|
||||
FileNode fn = fs.getFirstTopLevelNode();
|
||||
assert(fn.isSeq());
|
||||
for( int i = 0; i < (int)fn.size(); i+=3 )
|
||||
{
|
||||
string name = fn[i];
|
||||
DatasetParams params;
|
||||
string sf = fn[i+1]; params.dispScaleFactor = atoi(sf.c_str());
|
||||
string uv = fn[i+2]; params.dispUnknVal = atoi(uv.c_str());
|
||||
datasetsParams[name] = params;
|
||||
}
|
||||
return cvtest::TS::OK;
|
||||
}
|
||||
|
||||
int CV_StereoMatchingTest::readRunParams( FileStorage& fs )
|
||||
{
|
||||
if( !fs.isOpened() )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "runParams can not be read " );
|
||||
return cvtest::TS::FAIL_INVALID_TEST_DATA;
|
||||
}
|
||||
caseNames.clear();;
|
||||
caseDatasets.clear();
|
||||
return cvtest::TS::OK;
|
||||
}
|
||||
|
||||
void CV_StereoMatchingTest::writeErrors( const string& errName, const vector<float>& errors, FileStorage* fs )
|
||||
{
|
||||
assert( (int)errors.size() == ERROR_KINDS_COUNT );
|
||||
vector<float>::const_iterator it = errors.begin();
|
||||
if( fs )
|
||||
for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
|
||||
*fs << ERROR_PREFIXES[i] + errName << *it;
|
||||
else
|
||||
for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
|
||||
ts->printf( cvtest::TS::LOG, "%s = %f\n", string(ERROR_PREFIXES[i]+errName).c_str(), *it );
|
||||
}
|
||||
|
||||
void CV_StereoMatchingTest::readErrors( FileNode& fn, const string& errName, vector<float>& errors )
|
||||
{
|
||||
errors.resize( ERROR_KINDS_COUNT );
|
||||
vector<float>::iterator it = errors.begin();
|
||||
for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
|
||||
fn[ERROR_PREFIXES[i]+errName] >> *it;
|
||||
}
|
||||
|
||||
int CV_StereoMatchingTest::compareErrors( const vector<float>& calcErrors, const vector<float>& validErrors,
|
||||
const vector<float>& eps, const string& errName )
|
||||
{
|
||||
assert( (int)calcErrors.size() == ERROR_KINDS_COUNT );
|
||||
assert( (int)validErrors.size() == ERROR_KINDS_COUNT );
|
||||
assert( (int)eps.size() == ERROR_KINDS_COUNT );
|
||||
vector<float>::const_iterator calcIt = calcErrors.begin(),
|
||||
validIt = validErrors.begin(),
|
||||
epsIt = eps.begin();
|
||||
bool ok = true;
|
||||
for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++calcIt, ++validIt, ++epsIt )
|
||||
if( *calcIt - *validIt > *epsIt )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "bad accuracy of %s (valid=%f; calc=%f)\n", string(ERROR_PREFIXES[i]+errName).c_str(), *validIt, *calcIt );
|
||||
ok = false;
|
||||
}
|
||||
return ok ? cvtest::TS::OK : cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
}
|
||||
|
||||
//----------------------------------- StereoGC test -----------------------------------------------------
|
||||
|
||||
class CV_StereoGCTest : public CV_StereoMatchingTest
|
||||
{
|
||||
public:
|
||||
CV_StereoGCTest()
|
||||
{
|
||||
name = "stereogc";
|
||||
fill(rmsEps.begin(), rmsEps.end(), 3.f);
|
||||
fracEps[0] = 0.05f; // all
|
||||
fracEps[1] = 0.05f; // noOccl
|
||||
fracEps[2] = 0.25f; // occl
|
||||
fracEps[3] = 0.05f; // textured
|
||||
fracEps[4] = 0.10f; // textureless
|
||||
fracEps[5] = 0.10f; // borderedDepthDiscont
|
||||
}
|
||||
protected:
|
||||
struct RunParams
|
||||
{
|
||||
int ndisp;
|
||||
int iterCount;
|
||||
};
|
||||
vector<RunParams> caseRunParams;
|
||||
|
||||
virtual int readRunParams( FileStorage& fs )
|
||||
{
|
||||
int code = CV_StereoMatchingTest::readRunParams(fs);
|
||||
FileNode fn = fs.getFirstTopLevelNode();
|
||||
assert(fn.isSeq());
|
||||
for( int i = 0; i < (int)fn.size(); i+=4 )
|
||||
{
|
||||
string caseName = fn[i], datasetName = fn[i+1];
|
||||
RunParams params;
|
||||
string ndisp = fn[i+2]; params.ndisp = atoi(ndisp.c_str());
|
||||
string iterCount = fn[i+3]; params.iterCount = atoi(iterCount.c_str());
|
||||
caseNames.push_back( caseName );
|
||||
caseDatasets.push_back( datasetName );
|
||||
caseRunParams.push_back( params );
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
virtual int runStereoMatchingAlgorithm( const Mat& _leftImg, const Mat& _rightImg,
|
||||
Mat& leftDisp, Mat& rightDisp, int caseIdx )
|
||||
{
|
||||
RunParams params = caseRunParams[caseIdx];
|
||||
assert( _leftImg.type() == CV_8UC3 && _rightImg.type() == CV_8UC3 );
|
||||
Mat leftImg, rightImg, tmp;
|
||||
cvtColor( _leftImg, leftImg, CV_BGR2GRAY );
|
||||
cvtColor( _rightImg, rightImg, CV_BGR2GRAY );
|
||||
|
||||
leftDisp.create( leftImg.size(), CV_16SC1 );
|
||||
rightDisp.create( rightImg.size(), CV_16SC1 );
|
||||
|
||||
CvMat _limg = leftImg, _rimg = rightImg, _ldisp = leftDisp, _rdisp = rightDisp;
|
||||
CvStereoGCState *state = cvCreateStereoGCState( params.ndisp, params.iterCount );
|
||||
cvFindStereoCorrespondenceGC( &_limg, &_rimg, &_ldisp, &_rdisp, state );
|
||||
cvReleaseStereoGCState( &state );
|
||||
|
||||
leftDisp = - leftDisp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
TEST(Calib3d_StereoGC, regression) { CV_StereoGCTest test; test.safe_run(); }
|
||||
341
modules/legacy/test/test_subdivisions.cpp
Normal file
341
modules/legacy/test/test_subdivisions.cpp
Normal file
@@ -0,0 +1,341 @@
|
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// Intel License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000, Intel Corporation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// * The name of Intel Corporation may not be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// This software is provided by the copyright holders and contributors "as is" and
|
||||
// any express or implied warranties, including, but not limited to, the implied
|
||||
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
||||
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
||||
// indirect, incidental, special, exemplary, or consequential damages
|
||||
// (including, but not limited to, procurement of substitute goods or services;
|
||||
// loss of use, data, or profits; or business interruption) however caused
|
||||
// and on any theory of liability, whether in contract, strict liability,
|
||||
// or tort (including negligence or otherwise) arising in any way out of
|
||||
// the use of this software, even if advised of the possibility of such damage.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "test_precomp.hpp"
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
class CV_SubdivTest : public cvtest::BaseTest
|
||||
{
|
||||
public:
|
||||
CV_SubdivTest();
|
||||
~CV_SubdivTest();
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
int read_params( CvFileStorage* fs );
|
||||
int prepare_test_case( int test_case_idx );
|
||||
int validate_test_results( int test_case_idx );
|
||||
void run_func();
|
||||
|
||||
int min_log_img_size, max_log_img_size;
|
||||
CvSize img_size;
|
||||
int min_log_point_count;
|
||||
int max_log_point_count;
|
||||
int point_count;
|
||||
CvSubdiv2D* subdiv;
|
||||
CvMemStorage* storage;
|
||||
};
|
||||
|
||||
|
||||
CV_SubdivTest::CV_SubdivTest()
|
||||
{
|
||||
test_case_count = 100;
|
||||
min_log_point_count = 1;
|
||||
max_log_point_count = 10;
|
||||
min_log_img_size = 1;
|
||||
max_log_img_size = 10;
|
||||
|
||||
storage = 0;
|
||||
}
|
||||
|
||||
|
||||
CV_SubdivTest::~CV_SubdivTest()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
|
||||
void CV_SubdivTest::clear()
|
||||
{
|
||||
cvtest::BaseTest::clear();
|
||||
cvReleaseMemStorage( &storage );
|
||||
}
|
||||
|
||||
|
||||
int CV_SubdivTest::read_params( CvFileStorage* fs )
|
||||
{
|
||||
int code = cvtest::BaseTest::read_params( fs );
|
||||
int t;
|
||||
|
||||
if( code < 0 )
|
||||
return code;
|
||||
|
||||
test_case_count = cvReadInt( find_param( fs, "test_case_count" ), test_case_count );
|
||||
min_log_point_count = cvReadInt( find_param( fs, "min_log_point_count" ), min_log_point_count );
|
||||
max_log_point_count = cvReadInt( find_param( fs, "max_log_point_count" ), max_log_point_count );
|
||||
min_log_img_size = cvReadInt( find_param( fs, "min_log_img_size" ), min_log_img_size );
|
||||
max_log_img_size = cvReadInt( find_param( fs, "max_log_img_size" ), max_log_img_size );
|
||||
|
||||
min_log_point_count = cvtest::clipInt( min_log_point_count, 1, 10 );
|
||||
max_log_point_count = cvtest::clipInt( max_log_point_count, 1, 10 );
|
||||
if( min_log_point_count > max_log_point_count )
|
||||
CV_SWAP( min_log_point_count, max_log_point_count, t );
|
||||
|
||||
min_log_img_size = cvtest::clipInt( min_log_img_size, 1, 10 );
|
||||
max_log_img_size = cvtest::clipInt( max_log_img_size, 1, 10 );
|
||||
if( min_log_img_size > max_log_img_size )
|
||||
CV_SWAP( min_log_img_size, max_log_img_size, t );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int CV_SubdivTest::prepare_test_case( int test_case_idx )
|
||||
{
|
||||
RNG& rng = ts->get_rng();
|
||||
int code = cvtest::BaseTest::prepare_test_case( test_case_idx );
|
||||
if( code < 0 )
|
||||
return code;
|
||||
|
||||
clear();
|
||||
|
||||
point_count = cvRound(exp((cvtest::randReal(rng)*
|
||||
(max_log_point_count - min_log_point_count) + min_log_point_count)*CV_LOG2));
|
||||
img_size.width = cvRound(exp((cvtest::randReal(rng)*
|
||||
(max_log_img_size - min_log_img_size) + min_log_img_size)*CV_LOG2));
|
||||
img_size.height = cvRound(exp((cvtest::randReal(rng)*
|
||||
(max_log_img_size - min_log_img_size) + min_log_img_size)*CV_LOG2));
|
||||
|
||||
storage = cvCreateMemStorage( 1 << 10 );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void CV_SubdivTest::run_func()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static inline double sqdist( CvPoint2D32f pt1, CvPoint2D32f pt2 )
|
||||
{
|
||||
double dx = pt1.x - pt2.x;
|
||||
double dy = pt1.y - pt2.y;
|
||||
|
||||
return dx*dx + dy*dy;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
subdiv2DCheck( CvSubdiv2D* subdiv )
|
||||
{
|
||||
int i, j, total = subdiv->edges->total;
|
||||
CV_Assert( subdiv != 0 );
|
||||
|
||||
for( i = 0; i < total; i++ )
|
||||
{
|
||||
CvQuadEdge2D* edge = (CvQuadEdge2D*)cvGetSetElem(subdiv->edges,i);
|
||||
|
||||
if( edge && CV_IS_SET_ELEM( edge ))
|
||||
{
|
||||
for( j = 0; j < 4; j++ )
|
||||
{
|
||||
CvSubdiv2DEdge e = (CvSubdiv2DEdge)edge + j;
|
||||
CvSubdiv2DEdge o_next = cvSubdiv2DNextEdge(e);
|
||||
CvSubdiv2DEdge o_prev = cvSubdiv2DGetEdge(e, CV_PREV_AROUND_ORG );
|
||||
CvSubdiv2DEdge d_prev = cvSubdiv2DGetEdge(e, CV_PREV_AROUND_DST );
|
||||
CvSubdiv2DEdge d_next = cvSubdiv2DGetEdge(e, CV_NEXT_AROUND_DST );
|
||||
|
||||
// check points
|
||||
if( cvSubdiv2DEdgeOrg(e) != cvSubdiv2DEdgeOrg(o_next))
|
||||
return 0;
|
||||
if( cvSubdiv2DEdgeOrg(e) != cvSubdiv2DEdgeOrg(o_prev))
|
||||
return 0;
|
||||
if( cvSubdiv2DEdgeDst(e) != cvSubdiv2DEdgeDst(d_next))
|
||||
return 0;
|
||||
if( cvSubdiv2DEdgeDst(e) != cvSubdiv2DEdgeDst(d_prev))
|
||||
return 0;
|
||||
if( j % 2 == 0 )
|
||||
{
|
||||
if( cvSubdiv2DEdgeDst(o_next) != cvSubdiv2DEdgeOrg(d_prev))
|
||||
return 0;
|
||||
if( cvSubdiv2DEdgeDst(o_prev) != cvSubdiv2DEdgeOrg(d_next))
|
||||
return 0;
|
||||
if( cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(
|
||||
e,CV_NEXT_AROUND_LEFT),CV_NEXT_AROUND_LEFT),CV_NEXT_AROUND_LEFT) != e )
|
||||
return 0;
|
||||
if( cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(
|
||||
e,CV_NEXT_AROUND_RIGHT),CV_NEXT_AROUND_RIGHT),CV_NEXT_AROUND_RIGHT) != e)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// the whole testing is done here, run_func() is not utilized in this test
|
||||
int CV_SubdivTest::validate_test_results( int /*test_case_idx*/ )
|
||||
{
|
||||
int code = cvtest::TS::OK;
|
||||
RNG& rng = ts->get_rng();
|
||||
int j, k, real_count = point_count;
|
||||
double xrange = img_size.width*(1 - FLT_EPSILON);
|
||||
double yrange = img_size.height*(1 - FLT_EPSILON);
|
||||
|
||||
subdiv = cvCreateSubdivDelaunay2D(
|
||||
cvRect( 0, 0, img_size.width, img_size.height ), storage );
|
||||
|
||||
CvSeq* seq = cvCreateSeq( 0, sizeof(*seq), sizeof(CvPoint2D32f), storage );
|
||||
CvSeqWriter writer;
|
||||
cvStartAppendToSeq( seq, &writer );
|
||||
|
||||
// insert random points
|
||||
for( j = 0; j < point_count; j++ )
|
||||
{
|
||||
CvPoint2D32f pt;
|
||||
CvSubdiv2DPoint* point;
|
||||
|
||||
pt.x = (float)(cvtest::randReal(rng)*xrange);
|
||||
pt.y = (float)(cvtest::randReal(rng)*yrange);
|
||||
|
||||
CvSubdiv2DPointLocation loc =
|
||||
cvSubdiv2DLocate( subdiv, pt, 0, &point );
|
||||
|
||||
if( loc == CV_PTLOC_VERTEX )
|
||||
{
|
||||
int index = cvSeqElemIdx( (CvSeq*)subdiv, point );
|
||||
CvPoint2D32f* pt1;
|
||||
cvFlushSeqWriter( &writer );
|
||||
pt1 = (CvPoint2D32f*)cvGetSeqElem( seq, index - 3 );
|
||||
|
||||
if( !pt1 ||
|
||||
fabs(pt1->x - pt.x) > FLT_EPSILON ||
|
||||
fabs(pt1->y - pt.y) > FLT_EPSILON )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "The point #%d: (%.1f,%.1f) is said to coinside with a subdivision vertex, "
|
||||
"however it could be found in a sequence of inserted points\n", j, pt.x, pt.y );
|
||||
code = cvtest::TS::FAIL_INVALID_OUTPUT;
|
||||
goto _exit_;
|
||||
}
|
||||
real_count--;
|
||||
}
|
||||
|
||||
point = cvSubdivDelaunay2DInsert( subdiv, pt );
|
||||
if( point->pt.x != pt.x || point->pt.y != pt.y )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "The point #%d: (%.1f,%.1f) has been incorrectly added\n", j, pt.x, pt.y );
|
||||
code = cvtest::TS::FAIL_INVALID_OUTPUT;
|
||||
goto _exit_;
|
||||
}
|
||||
|
||||
if( (j + 1) % 10 == 0 || j == point_count - 1 )
|
||||
{
|
||||
if( !subdiv2DCheck( subdiv ))
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "Subdivision consistency check failed after inserting the point #%d\n", j );
|
||||
code = cvtest::TS::FAIL_INVALID_OUTPUT;
|
||||
goto _exit_;
|
||||
}
|
||||
}
|
||||
|
||||
if( loc != CV_PTLOC_VERTEX )
|
||||
{
|
||||
CV_WRITE_SEQ_ELEM( pt, writer );
|
||||
}
|
||||
}
|
||||
|
||||
if( code < 0 )
|
||||
goto _exit_;
|
||||
|
||||
cvCalcSubdivVoronoi2D( subdiv );
|
||||
seq = cvEndWriteSeq( &writer );
|
||||
|
||||
if( !subdiv2DCheck( subdiv ))
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "The subdivision failed consistency check after building the Voronoi tesselation\n" );
|
||||
code = cvtest::TS::FAIL_INVALID_OUTPUT;
|
||||
goto _exit_;
|
||||
}
|
||||
|
||||
for( j = 0; j < MAX((point_count - 5)/10 + 5, 10); j++ )
|
||||
{
|
||||
CvPoint2D32f pt;
|
||||
double minDistance;
|
||||
|
||||
pt.x = (float)(cvtest::randReal(rng)*xrange);
|
||||
pt.y = (float)(cvtest::randReal(rng)*yrange);
|
||||
|
||||
CvSubdiv2DPoint* point = cvFindNearestPoint2D( subdiv, pt );
|
||||
CvSeqReader reader;
|
||||
|
||||
if( !point )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "There is no nearest point (?!) for the point (%.1f, %.1f) in the subdivision\n",
|
||||
pt.x, pt.y );
|
||||
code = cvtest::TS::FAIL_INVALID_OUTPUT;
|
||||
goto _exit_;
|
||||
}
|
||||
|
||||
cvStartReadSeq( seq, &reader );
|
||||
minDistance = sqdist( pt, point->pt );
|
||||
|
||||
for( k = 0; k < seq->total; k++ )
|
||||
{
|
||||
CvPoint2D32f ptt;
|
||||
CV_READ_SEQ_ELEM( ptt, reader );
|
||||
|
||||
double distance = sqdist( pt, ptt );
|
||||
if( minDistance > distance && sqdist(ptt, point->pt) > FLT_EPSILON*1000 )
|
||||
{
|
||||
ts->printf( cvtest::TS::LOG, "The triangulation vertex (%.3f,%.3f) was said to be nearest to (%.3f,%.3f),\n"
|
||||
"whereas another vertex (%.3f,%.3f) is closer\n",
|
||||
point->pt.x, point->pt.y, pt.x, pt.y, ptt.x, ptt.y );
|
||||
code = cvtest::TS::FAIL_BAD_ACCURACY;
|
||||
goto _exit_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_exit_:
|
||||
if( code < 0 )
|
||||
ts->set_failed_test_info( code );
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
TEST(Imgproc_Subdiv, correctness) { CV_SubdivTest test; test.safe_run(); }
|
||||
|
||||
/* End of file. */
|
||||
|
||||
Reference in New Issue
Block a user