1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
43 This is a regression test for stereo matching algorithms. This test gets some quality metrics
44 discribed in "A Taxonomy and Evaluation of Dense Two-Frame Stereo Correspondence Algorithms".
45 Daniel Scharstein, Richard Szeliski
54 const float EVAL_BAD_THRESH = 1.f;
55 const int EVAL_TEXTURELESS_WIDTH = 9;
56 const float EVAL_TEXTURELESS_THRESH = 2.f;
57 const float EVAL_DISP_THRESH = 1.f;
58 const float EVAL_DISP_GAP = 2.f;
59 const int EVAL_DISCONT_WIDTH = 9;
60 const int EVAL_IGNORE_BORDER = 10;
62 const int ERROR_KINDS_COUNT = 6;
64 //============================== quality measuring functions =================================================
67 Calculate textureless regions of image (regions where the squared horizontal intensity gradient averaged over
68 a square window of size=evalTexturelessWidth is below a threshold=evalTexturelessThresh) and textured regions.
70 void computeTextureBasedMasks( const Mat& img, Mat* texturelessMask, Mat* texturedMask,
71 int texturelessWidth = EVAL_TEXTURELESS_WIDTH, float texturelessThresh = EVAL_TEXTURELESS_THRESH )
73 if( !texturelessMask && !texturedMask )
76 CV_Error( CV_StsBadArg, "img is empty" );
78 Mat dxI; Sobel( img, dxI, CV_32F, 1, 0, 3 );
79 Mat dxI2; pow( dxI / 8.f/*normalize*/, 2, dxI2 );
80 if( dxI2.channels() > 1)
82 Mat tmp; cvtColor( dxI2, tmp, CV_BGR2GRAY ); dxI2 = tmp;
84 Mat avgDxI2; boxFilter( dxI2, avgDxI2, CV_32FC1, Size(texturelessWidth,texturelessWidth) );
87 *texturelessMask = avgDxI2 < texturelessThresh;
89 *texturedMask = avgDxI2 >= texturelessThresh;
92 void checkSizeAndTypeOfDispMaps( const Mat& dispMap1, const Mat& dispMap2 )
94 if( dispMap1.empty() || dispMap2.empty() )
95 CV_Error( CV_StsBadArg, "dispMap1 or dispMap2 is empty" );
96 if( dispMap1.cols != dispMap2.cols || dispMap1.rows != dispMap2.rows )
97 CV_Error( CV_StsBadArg, "dispMap1 and dispMap2 must have the same size" );
98 if( dispMap1.type() != CV_32FC1 && dispMap2.type() != CV_32FC1 )
99 CV_Error( CV_StsBadArg, "dispMap1 and dispMap2 must have CV_32FC1 type" );
102 void checkSizeAndTypeOfMask( const Mat& mask, Size sz )
105 CV_Error( CV_StsBadArg, "mask is empty" );
106 if( mask.type() != CV_8UC1 )
107 CV_Error( CV_StsBadArg, "mask must have CV_8UC1 type" );
108 if( mask.rows != sz.height || mask.cols != sz.width )
109 CV_Error( CV_StsBadArg, "mask has incorrect size" );
112 void checkDispMapsAndUnknDispMasks( const Mat& dispMap1, const Mat& dispMap2,
113 const Mat& unknDispMask1, const Mat& unknDispMask2 )
115 checkSizeAndTypeOfDispMaps( dispMap1, dispMap2 );
117 if( !unknDispMask1.empty() )
118 checkSizeAndTypeOfMask( unknDispMask1, dispMap1.size() );
119 if( !unknDispMask2.empty() )
120 checkSizeAndTypeOfMask( unknDispMask2, dispMap1.size() );
122 double minVal1, minVal2;
123 if( unknDispMask1.empty() )
124 minMaxLoc( dispMap1, &minVal1 );
126 minMaxLoc( dispMap1, &minVal1, 0, 0, 0, ~unknDispMask1 );
127 if( unknDispMask2.empty() )
128 minMaxLoc( dispMap2, &minVal2 );
130 minMaxLoc( dispMap2, &minVal2, 0, 0, 0, ~unknDispMask2 );
131 if( minVal1 < 0 || minVal2 < 0)
132 CV_Error( CV_StsBadArg, "known disparity values must be positive" );
136 Calculate occluded regions of reference image (left image) (regions that are occluded in the matching image (right image),
137 i.e., where the forward-mapped disparity lands at a location with a larger (nearer) disparity) and non occluded regions.
139 void computeOcclusionBasedMasks( const Mat& leftDisp, const Mat& rightDisp,
140 Mat* occludedMask, Mat* nonOccludedMask,
141 const Mat& leftUnknDispMask = Mat(), const Mat& rightUnknDispMask = Mat(),
142 float dispThresh = EVAL_DISP_THRESH )
144 const float dispDiff = 1.f;
145 if( !occludedMask && !nonOccludedMask )
147 checkDispMapsAndUnknDispMasks( leftDisp, rightDisp, leftUnknDispMask, rightUnknDispMask );
151 occludedMask->create( leftDisp.size(), CV_8UC1 );
152 occludedMask->setTo(Scalar::all(0) );
154 if( nonOccludedMask )
156 nonOccludedMask->create( leftDisp.size(), CV_8UC1 );
157 occludedMask->setTo(Scalar::all(0) );
159 for( int leftY = 0; leftY < leftDisp.rows; leftY++ )
161 for( int leftX = 0; leftX < leftDisp.cols; leftX++ )
163 if( !leftUnknDispMask.empty() && leftUnknDispMask.at<uchar>(leftY,leftX) )
165 float leftDispVal = leftDisp.at<float>(leftY, leftX);
166 int rightX = leftX - (int)leftDispVal, rightY = leftY;
167 if( occludedMask && rightX < 0 )
168 occludedMask->at<uchar>(leftY, leftX) = 255;
171 if( !rightUnknDispMask.empty() && rightUnknDispMask.at<uchar>(rightY,rightX) )
173 float rightDispVal = rightDisp.at<float>(rightY, rightX);
174 if( rightDispVal > leftDispVal + dispDiff )
177 occludedMask->at<uchar>(leftY, leftX) = 255;
181 if( nonOccludedMask )
182 nonOccludedMask->at<uchar>(leftY, leftX) = 255;
190 Calculate depth discontinuty regions: pixels whose neiboring disparities differ by more than
191 dispGap, dilated by window of width discontWidth.
193 void computeDepthDiscontMask( const Mat& disp, Mat& depthDiscontMask, const Mat& unknDispMask = Mat(),
194 float dispGap = EVAL_DISP_GAP, int discontWidth = EVAL_DISCONT_WIDTH )
197 CV_Error( CV_StsBadArg, "disp is empty" );
198 if( disp.type() != CV_32FC1 )
199 CV_Error( CV_StsBadArg, "disp must have CV_32FC1 type" );
200 if( !unknDispMask.empty() )
201 checkSizeAndTypeOfMask( unknDispMask, disp.size() );
203 Mat curDisp; disp.copyTo( curDisp );
204 if( !unknDispMask.empty() )
205 curDisp.setTo( Scalar(numeric_limits<float>::min()), unknDispMask );
206 Mat maxNeighbDisp; dilate( curDisp, maxNeighbDisp, Mat(3, 3, CV_8UC1, Scalar(1)) );
207 if( !unknDispMask.empty() )
208 curDisp.setTo( Scalar(numeric_limits<float>::max()), unknDispMask );
209 Mat minNeighbDisp; erode( curDisp, minNeighbDisp, Mat(3, 3, CV_8UC1, Scalar(1)) );
210 depthDiscontMask = max( (Mat)(maxNeighbDisp-disp), (Mat)(disp-minNeighbDisp) ) > dispGap;
211 if( !unknDispMask.empty() )
212 depthDiscontMask &= ~unknDispMask;
213 dilate( depthDiscontMask, depthDiscontMask, Mat(discontWidth, discontWidth, CV_8UC1, Scalar(1)) );
217 Get evaluation masks excluding a border.
219 Mat getBorderedMask( Size maskSize, int border = EVAL_IGNORE_BORDER )
221 CV_Assert( border >= 0 );
222 Mat mask(maskSize, CV_8UC1, Scalar(0));
223 int w = maskSize.width - 2*border, h = maskSize.height - 2*border;
225 mask.setTo(Scalar(0));
227 mask( Rect(Point(border,border),Size(w,h)) ).setTo(Scalar(255));
232 Calculate root-mean-squared error between the computed disparity map (computedDisp) and ground truth map (groundTruthDisp).
234 float dispRMS( const Mat& computedDisp, const Mat& groundTruthDisp, const Mat& mask )
236 checkSizeAndTypeOfDispMaps( computedDisp, groundTruthDisp );
237 int pointsCount = computedDisp.cols*computedDisp.rows;
240 checkSizeAndTypeOfMask( mask, computedDisp.size() );
241 pointsCount = countNonZero(mask);
243 return 1.f/sqrt((float)pointsCount) * norm(computedDisp, groundTruthDisp, NORM_L2, mask);
247 Calculate percentage of bad matching pixels.
249 float badMatchPxlsPercentage( const Mat& computedDisp, const Mat& groundTruthDisp, const Mat& mask,
250 int badThresh = EVAL_BAD_THRESH )
252 checkSizeAndTypeOfDispMaps( computedDisp, groundTruthDisp );
254 absdiff( computedDisp, groundTruthDisp, badPxlsMap );
255 badPxlsMap = badPxlsMap > badThresh;
256 int pointsCount = computedDisp.cols*computedDisp.rows;
259 checkSizeAndTypeOfMask( mask, computedDisp.size() );
260 badPxlsMap = badPxlsMap & mask;
261 pointsCount = countNonZero(mask);
263 return 1.f/pointsCount * countNonZero(badPxlsMap);
266 //===================== regression test for stereo matching algorithms ==============================
268 const string ALGORITHMS_DIR = "stereomatching/algorithms/";
269 const string DATASETS_DIR = "stereomatching/datasets/";
270 const string DATASETS_FILE = "datasets.xml";
272 const string RUN_PARAMS_FILE = "_params.xml";
273 const string RESULT_FILE = "_res.xml";
275 const string LEFT_IMG_NAME = "im2.png";
276 const string RIGHT_IMG_NAME = "im6.png";
277 const string TRUE_LEFT_DISP_NAME = "disp2.png";
278 const string TRUE_RIGHT_DISP_NAME = "disp6.png";
280 string ERROR_PREFIXES[] = { "borderedAll",
284 "borderedTextureless",
285 "borderedDepthDiscont" }; // size of ERROR_KINDS_COUNT
288 const string RMS_STR = "RMS";
289 const string BAD_PXLS_PERCENTAGE_STR = "BadPxlsPercentage";
291 class CV_StereoMatchingTest : public CvTest
294 CV_StereoMatchingTest( const char* testName ) :
295 CvTest( testName, "stereo-matching" ) {}
297 // assumed that left image is a reference image
298 virtual void runStereoMatchingAlgorithm( const Mat& leftImg, const Mat& rigthImg,
299 Mat& leftDisp, Mat& rightDisp, FileStorage& paramsFS, const string& datasetName ) = 0;
301 int readDatasetsInfo();
302 void readDatasetRunParams( FileStorage& fs, const string datasetName ) {}
303 void writeErrors( const string& errName, const vector<float>& errors, FileStorage* fs = 0 );
304 void readErrors( FileNode& fn, const string& errName, vector<float>& errors );
305 int compareErrors( const vector<float>& calcErrors, const vector<float>& validErrors,
306 const vector<float>& eps, const string& errName );
307 int processStereoMatchingResults( FileStorage& fs, int datasetIdx, bool isWrite,
308 const Mat& leftImg, const Mat& rightImg,
309 const Mat& trueLeftDisp, const Mat& trueRightDisp,
310 const Mat& leftDisp, const Mat& rightDisp );
313 vector<string> datasetsNames;
314 vector<int> dispScaleFactors;
315 vector<int> dispUnknownVal;
318 void CV_StereoMatchingTest::run(int)
320 string dataPath = ts->get_data_path();
321 string algoritmName = name;
322 assert( !algoritmName.empty() );
323 if( dataPath.empty() )
325 ts->printf( CvTS::LOG, "dataPath is empty" );
326 ts->set_failed_test_info( CvTS::FAIL_BAD_ARG_CHECK );
330 int code = readDatasetsInfo();
331 if( code != CvTS::OK )
333 ts->set_failed_test_info( code );
337 string fullResultFilename = dataPath + ALGORITHMS_DIR + algoritmName + RESULT_FILE;
338 bool isWrite = true; // write or compare results
339 FileStorage runParamsFS( dataPath + ALGORITHMS_DIR + algoritmName + RUN_PARAMS_FILE, FileStorage::READ );
340 FileStorage resFS( fullResultFilename, FileStorage::READ );
341 if( resFS.isOpened() )
345 resFS.open( fullResultFilename, FileStorage::WRITE );
346 if( !resFS.isOpened() )
348 ts->printf( CvTS::LOG, "file named %s can not be read or written\n", fullResultFilename.c_str() );
349 ts->set_failed_test_info( CvTS::FAIL_BAD_ARG_CHECK );
352 resFS << "stereo_matching" << "{";
355 for( int dsi = 0; dsi < (int)datasetsNames.size(); dsi++)
357 string datasetFullDirName = dataPath + DATASETS_DIR + datasetsNames[dsi] + "/";
358 Mat leftImg = imread(datasetFullDirName + LEFT_IMG_NAME);
359 Mat rightImg = imread(datasetFullDirName + RIGHT_IMG_NAME);
360 Mat trueLeftDisp = imread(datasetFullDirName + TRUE_LEFT_DISP_NAME, 0);
361 Mat trueRightDisp = imread(datasetFullDirName + TRUE_RIGHT_DISP_NAME, 0);
363 if( leftImg.empty() || rightImg.empty() || trueLeftDisp.empty() || trueRightDisp.empty() )
365 ts->printf( CvTS::LOG, "images or ground-truth disparities of dataset %s can not be read", datasetsNames[dsi].c_str() );
366 code = CvTS::FAIL_INVALID_TEST_DATA;
370 int scaleFactor = dispScaleFactors[dsi];
371 trueLeftDisp.convertTo( tmp, CV_32FC1, 1.f/scaleFactor ); trueLeftDisp = tmp; tmp.release();
372 trueRightDisp.convertTo( tmp, CV_32FC1, 1.f/scaleFactor ); trueRightDisp = tmp; tmp.release();
374 Mat leftDisp, rightDisp;
375 runStereoMatchingAlgorithm( leftImg, rightImg, leftDisp, rightDisp, runParamsFS, datasetsNames[dsi] );
376 leftDisp.convertTo( tmp, CV_32FC1 ); leftDisp = tmp; tmp.release();
377 rightDisp.convertTo( tmp, CV_32FC1 ); rightDisp = tmp; tmp.release();
379 int tempCode = processStereoMatchingResults( resFS, dsi, isWrite,
380 leftImg, rightImg, trueLeftDisp, trueRightDisp, leftDisp, rightDisp);
382 code = tempCode==CvTS::OK ? code : tempCode;
386 resFS << "}"; // "stereo_matching"
388 ts->set_failed_test_info( code );
391 void calcErrors( const Mat& leftImg, const Mat& rightImg,
392 const Mat& trueLeftDisp, const Mat& trueRightDisp,
393 const Mat& trueLeftUnknDispMask, const Mat& trueRightUnknDispMask,
394 const Mat& calcLeftDisp, const Mat& calcRightDisp,
395 vector<float>& rms, vector<float>& badPxlsPercentages )
397 Mat texturelessMask, texturedMask;
398 computeTextureBasedMasks( leftImg, &texturelessMask, &texturedMask );
399 Mat occludedMask, nonOccludedMask;
400 computeOcclusionBasedMasks( trueLeftDisp, trueRightDisp, &occludedMask, &nonOccludedMask,
401 trueLeftUnknDispMask, trueRightUnknDispMask);
402 Mat depthDiscontMask;
403 computeDepthDiscontMask( trueLeftDisp, depthDiscontMask, trueLeftUnknDispMask);
405 Mat borderedKnownMask = getBorderedMask( leftImg.size() ) & ~trueLeftUnknDispMask;
407 nonOccludedMask &= borderedKnownMask;
408 occludedMask &= borderedKnownMask;
409 texturedMask &= nonOccludedMask; // & borderedKnownMask
410 texturelessMask &= nonOccludedMask; // & borderedKnownMask
411 depthDiscontMask &= nonOccludedMask; // & borderedKnownMask
413 rms.resize(ERROR_KINDS_COUNT);
414 rms[0] = dispRMS( calcLeftDisp, trueLeftDisp, borderedKnownMask );
415 rms[1] = dispRMS( calcLeftDisp, trueLeftDisp, nonOccludedMask );
416 rms[2] = dispRMS( calcLeftDisp, trueLeftDisp, occludedMask );
417 rms[3] = dispRMS( calcLeftDisp, trueLeftDisp, texturedMask );
418 rms[4] = dispRMS( calcLeftDisp, trueLeftDisp, texturelessMask );
419 rms[5] = dispRMS( calcLeftDisp, trueLeftDisp, depthDiscontMask );
421 badPxlsPercentages.resize(ERROR_KINDS_COUNT);
422 badPxlsPercentages[0] = badMatchPxlsPercentage( calcLeftDisp, trueLeftDisp, borderedKnownMask );
423 badPxlsPercentages[1] = badMatchPxlsPercentage( calcLeftDisp, trueLeftDisp, nonOccludedMask );
424 badPxlsPercentages[2] = badMatchPxlsPercentage( calcLeftDisp, trueLeftDisp, occludedMask );
425 badPxlsPercentages[3] = badMatchPxlsPercentage( calcLeftDisp, trueLeftDisp, texturedMask );
426 badPxlsPercentages[4] = badMatchPxlsPercentage( calcLeftDisp, trueLeftDisp, texturelessMask );
427 badPxlsPercentages[5] = badMatchPxlsPercentage( calcLeftDisp, trueLeftDisp, depthDiscontMask );
430 int CV_StereoMatchingTest::processStereoMatchingResults( FileStorage& fs, int datasetIdx, bool isWrite,
431 const Mat& leftImg, const Mat& rightImg,
432 const Mat& trueLeftDisp, const Mat& trueRightDisp,
433 const Mat& leftDisp, const Mat& rightDisp )
435 // rightDisp is not used in current test virsion
437 assert( fs.isOpened() );
438 assert( trueLeftDisp.type() == CV_32FC1 && trueRightDisp.type() == CV_32FC1 );
439 assert( leftDisp.type() == CV_32FC1 && rightDisp.type() == CV_32FC1 );
442 Mat leftUnknMask, rightUnknMask;
443 absdiff( trueLeftDisp, Scalar(dispUnknownVal[datasetIdx]), leftUnknMask );
444 leftUnknMask = leftUnknMask < numeric_limits<float>::epsilon();
445 absdiff( trueRightDisp, Scalar(dispUnknownVal[datasetIdx]), rightUnknMask );
446 rightUnknMask = rightUnknMask < numeric_limits<float>::epsilon();
447 vector<float> rmss, badPxlsPercentages;
448 calcErrors( leftImg, rightImg, trueLeftDisp, trueRightDisp, leftUnknMask, rightUnknMask,
449 leftDisp, rightDisp, rmss, badPxlsPercentages );
451 const string& datasetName = datasetsNames[datasetIdx];
454 fs << datasetName << "{";
455 cvWriteComment( fs.fs, RMS_STR.c_str(), 0 );
456 writeErrors( RMS_STR, rmss, &fs );
457 cvWriteComment( fs.fs, BAD_PXLS_PERCENTAGE_STR.c_str(), 0 );
458 writeErrors( BAD_PXLS_PERCENTAGE_STR, badPxlsPercentages, &fs );
459 fs << "}"; // datasetName
463 ts->printf( CvTS::LOG, "\nerrors on dataset %s\n", datasetName.c_str() );
464 ts->printf( CvTS::LOG, "%s\n", RMS_STR.c_str() );
465 writeErrors( RMS_STR, rmss );
466 ts->printf( CvTS::LOG, "%s\n", BAD_PXLS_PERCENTAGE_STR.c_str() );
467 writeErrors( BAD_PXLS_PERCENTAGE_STR, badPxlsPercentages );
469 FileNode fn = fs.getFirstTopLevelNode()[datasetName];
470 vector<float> validRmss, validBadPxlsPercentages;
472 readErrors( fn, RMS_STR, validRmss );
473 readErrors( fn, BAD_PXLS_PERCENTAGE_STR, validBadPxlsPercentages );
474 int tempCode = compareErrors( rmss, validRmss,
475 vector<float>(ERROR_KINDS_COUNT, 0.01f), RMS_STR );
476 code = tempCode==CvTS::OK ? code : tempCode;
477 tempCode = compareErrors( badPxlsPercentages, validBadPxlsPercentages,
478 vector<float>(ERROR_KINDS_COUNT, 0.01f), BAD_PXLS_PERCENTAGE_STR );
479 code = tempCode==CvTS::OK ? code : tempCode;
484 int CV_StereoMatchingTest::readDatasetsInfo()
486 string datasetsFilename = string(ts->get_data_path()) + DATASETS_DIR + DATASETS_FILE;
488 FileStorage fs( datasetsFilename, FileStorage::READ );
491 ts->printf( CvTS::LOG, "%s can not be read\n", datasetsFilename.c_str() );
492 return CvTS::FAIL_INVALID_TEST_DATA;
494 FileNode fn = fs.getFirstTopLevelNode()["names_scale_unknown"];
496 datasetsNames.clear();
497 dispScaleFactors.clear();
498 dispUnknownVal.clear();
499 for( int i = 0; i < (int)fn.size(); i+=3 )
501 string name = fn[i]; datasetsNames.push_back(name);
502 string scale = fn[i+1]; dispScaleFactors.push_back(atoi(scale.c_str()));
503 string unkn = fn[i+2]; dispUnknownVal.push_back(atoi(unkn.c_str()));
509 void CV_StereoMatchingTest::writeErrors( const string& errName, const vector<float>& errors, FileStorage* fs )
511 assert( (int)errors.size() == ERROR_KINDS_COUNT );
512 vector<float>::const_iterator it = errors.begin();
514 for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
515 *fs << ERROR_PREFIXES[i] + errName << *it;
517 for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
518 ts->printf( CvTS::LOG, "%s = %f\n", string(ERROR_PREFIXES[i]+errName).c_str(), *it );
521 void CV_StereoMatchingTest::readErrors( FileNode& fn, const string& errName, vector<float>& errors )
523 errors.resize( ERROR_KINDS_COUNT );
524 vector<float>::iterator it = errors.begin();
525 for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
526 fn[ERROR_PREFIXES[i]+errName] >> *it;
529 int CV_StereoMatchingTest::compareErrors( const vector<float>& calcErrors, const vector<float>& validErrors,
530 const vector<float>& eps, const string& errName )
532 assert( (int)calcErrors.size() == ERROR_KINDS_COUNT );
533 assert( (int)validErrors.size() == ERROR_KINDS_COUNT );
534 assert( (int)eps.size() == ERROR_KINDS_COUNT );
535 vector<float>::const_iterator calcIt = calcErrors.begin(),
536 validIt = validErrors.begin(),
538 for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++calcIt, ++validIt, ++epsIt )
539 if( fabs(*calcIt - *validIt) > *epsIt )
541 ts->printf( CvTS::LOG, "bad accuracy of %s\n", string(ERROR_PREFIXES[i]+errName).c_str());
542 return CvTS::FAIL_BAD_ACCURACY;
547 //----------------------------------- StereoBM test -----------------------------------------------------
549 class CV_StereoBMTest : public CV_StereoMatchingTest
553 CV_StereoMatchingTest( "stereobm" ) {}
555 virtual void runStereoMatchingAlgorithm( const Mat& leftImg, const Mat& rigthImg,
556 Mat& leftDisp, Mat& rightDisp, FileStorage& paramsFS, const string& datasetName );
559 void CV_StereoBMTest::runStereoMatchingAlgorithm( const Mat& _leftImg, const Mat& _rigthImg,
560 Mat& leftDisp, Mat& rightDisp, FileStorage& paramsFS, const string& datasetName )
564 if( paramsFS.isOpened() && !datasetName.empty())
566 FileNodeIterator fni = paramsFS.getFirstTopLevelNode()[datasetName].begin();
567 fni >> ndisp >> winSize;
570 assert( _leftImg.type() == CV_8UC3 && _rigthImg.type() == CV_8UC3 );
571 Mat leftImg; cvtColor( _leftImg, leftImg, CV_BGR2GRAY );
572 Mat rigthImg; cvtColor( _rigthImg, rigthImg, CV_BGR2GRAY );
574 StereoBM bm( StereoBM::BASIC_PRESET, ndisp*16 );
575 bm( leftImg, rigthImg, leftDisp, CV_32F );
578 CV_StereoBMTest stereoBM;