/*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; template class ShapeBaseTest : public cvtest::BaseTest { public: typedef Point_ PointType; ShapeBaseTest(int _NSN, int _NP, float _CURRENT_MAX_ACCUR) : NSN(_NSN), NP(_NP), CURRENT_MAX_ACCUR(_CURRENT_MAX_ACCUR) { // generate file list vector shapeNames; shapeNames.push_back("apple"); //ok shapeNames.push_back("children"); // ok shapeNames.push_back("device7"); // ok shapeNames.push_back("Heart"); // ok shapeNames.push_back("teddy"); // ok for (vector::const_iterator i = shapeNames.begin(); i != shapeNames.end(); ++i) { for (int j = 0; j < NSN; ++j) { stringstream filename; filename << cvtest::TS::ptr()->get_data_path() << "shape/mpeg_test/" << *i << "-" << j + 1 << ".png"; filenames.push_back(filename.str()); } } // distance matrix const int totalCount = (int)filenames.size(); distanceMat = Mat::zeros(totalCount, totalCount, CV_32F); } protected: void run(int) { mpegTest(); displayMPEGResults(); } vector convertContourType(const Mat& currentQuery) const { if (currentQuery.empty()) { return vector(); } vector > _contoursQuery; findContours(currentQuery, _contoursQuery, RETR_LIST, CHAIN_APPROX_NONE); vector contoursQuery; for (size_t border=0; border<_contoursQuery.size(); border++) { for (size_t p=0; p<_contoursQuery[border].size(); p++) { contoursQuery.push_back(PointType((T)_contoursQuery[border][p].x, (T)_contoursQuery[border][p].y)); } } // In case actual number of points is less than n for (int add=(int)contoursQuery.size()-1; add cont; for (int i=0; i contoursQuery1, contoursQuery2, contoursQuery3, contoursTesting; // reading query and computing its properties for (vector::const_iterator a = filenames.begin(); a != filenames.end(); ++a) { // read current image int aIndex = (int)(a - filenames.begin()); Mat currentQuery = imread(*a, IMREAD_GRAYSCALE); Mat flippedHQuery, flippedVQuery; flip(currentQuery, flippedHQuery, 0); flip(currentQuery, flippedVQuery, 1); // compute border of the query and its flipped versions contoursQuery1=convertContourType(currentQuery); contoursQuery2=convertContourType(flippedHQuery); contoursQuery3=convertContourType(flippedVQuery); // compare with all the rest of the images: testing for (vector::const_iterator b = filenames.begin(); b != filenames.end(); ++b) { int bIndex = (int)(b - filenames.begin()); float distance = 0; // skip self-comparisson if (a != b) { // read testing image Mat currentTest = imread(*b, IMREAD_GRAYSCALE); // compute border of the testing contoursTesting=convertContourType(currentTest); // compute shape distance distance = cmp(contoursQuery1, contoursQuery2, contoursQuery3, contoursTesting); } distanceMat.at(aIndex, bIndex) = distance; } } } void displayMPEGResults() { const int FIRST_MANY=2*NSN; int corrects=0; int divi=0; for (int row=0; row(row,col) > distanceMat.at(row,i)) { nsmall++; } } if (nsmall<=FIRST_MANY) { corrects++; } } } float porc = 100*float(corrects)/(NSN*distanceMat.rows); std::cout << "Test result: " << porc << "%" << std::endl; if (porc >= CURRENT_MAX_ACCUR) ts->set_failed_test_info(cvtest::TS::OK); else ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); } protected: int NSN; int NP; float CURRENT_MAX_ACCUR; vector filenames; Mat distanceMat; compute cmp; }; //------------------------------------------------------------------------ // Test Shape_SCD.regression //------------------------------------------------------------------------ class computeShapeDistance_Chi { Ptr mysc; public: computeShapeDistance_Chi() { const int angularBins=12; const int radialBins=4; const float minRad=0.2f; const float maxRad=2; mysc = createShapeContextDistanceExtractor(angularBins, radialBins, minRad, maxRad); mysc->setIterations(1); mysc->setCostExtractor(createChiHistogramCostExtractor(30,0.15f)); mysc->setTransformAlgorithm( createThinPlateSplineShapeTransformer() ); } float operator()(vector & query1, vector & query2, vector & query3, vector & testq) { return std::min(mysc->computeDistance(query1, testq), std::min(mysc->computeDistance(query2, testq), mysc->computeDistance(query3, testq))); } }; TEST(Shape_SCD, regression) { const int NSN_val=5;//10;//20; //number of shapes per class const int NP_val=120; //number of points simplifying the contour const float CURRENT_MAX_ACCUR_val=95; //99% and 100% reached in several tests, 95 is fixed as minimum boundary ShapeBaseTest test(NSN_val, NP_val, CURRENT_MAX_ACCUR_val); test.safe_run(); } //------------------------------------------------------------------------ // Test ShapeEMD_SCD.regression //------------------------------------------------------------------------ class computeShapeDistance_EMD { Ptr mysc; public: computeShapeDistance_EMD() { const int angularBins=12; const int radialBins=4; const float minRad=0.2f; const float maxRad=2; mysc = createShapeContextDistanceExtractor(angularBins, radialBins, minRad, maxRad); mysc->setIterations(1); mysc->setCostExtractor( createEMDL1HistogramCostExtractor() ); mysc->setTransformAlgorithm( createThinPlateSplineShapeTransformer() ); } float operator()(vector & query1, vector & query2, vector & query3, vector & testq) { return std::min(mysc->computeDistance(query1, testq), std::min(mysc->computeDistance(query2, testq), mysc->computeDistance(query3, testq))); } }; TEST(ShapeEMD_SCD, regression) { const int NSN_val=5;//10;//20; //number of shapes per class const int NP_val=100; //number of points simplifying the contour const float CURRENT_MAX_ACCUR_val=95; //98% and 99% reached in several tests, 95 is fixed as minimum boundary ShapeBaseTest test(NSN_val, NP_val, CURRENT_MAX_ACCUR_val); test.safe_run(); } //------------------------------------------------------------------------ // Test Hauss.regression //------------------------------------------------------------------------ class computeShapeDistance_Haussdorf { Ptr haus; public: computeShapeDistance_Haussdorf() { haus = createHausdorffDistanceExtractor(); } float operator()(vector &query1, vector &query2, vector &query3, vector &testq) { return std::min(haus->computeDistance(query1,testq), std::min(haus->computeDistance(query2,testq), haus->computeDistance(query3,testq))); } }; TEST(Hauss, regression) { const int NSN_val=5;//10;//20; //number of shapes per class const int NP_val = 180; //number of points simplifying the contour const float CURRENT_MAX_ACCUR_val=85; //90% and 91% reached in several tests, 85 is fixed as minimum boundary ShapeBaseTest test(NSN_val, NP_val, CURRENT_MAX_ACCUR_val); test.safe_run(); } TEST(computeDistance, regression_4976) { Mat a = imread(cvtest::findDataFile("shape/samples/1.png"), 0); Mat b = imread(cvtest::findDataFile("shape/samples/2.png"), 0); vector > ca,cb; findContours(a, ca, cv::RETR_CCOMP, cv::CHAIN_APPROX_TC89_KCOS); findContours(b, cb, cv::RETR_CCOMP, cv::CHAIN_APPROX_TC89_KCOS); Ptr hd = createHausdorffDistanceExtractor(); Ptr sd = createShapeContextDistanceExtractor(); double d1 = hd->computeDistance(ca[0],cb[0]); double d2 = sd->computeDistance(ca[0],cb[0]); EXPECT_NEAR(d1, 26.4196891785, 1e-3) << "HausdorffDistanceExtractor"; EXPECT_NEAR(d2, 0.25804194808, 1e-3) << "ShapeContextDistanceExtractor"; }