1 /*M/////////////////////////////////////////////////////////////////////////////////////// 2 // 3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 4 // 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. 8 // 9 // 10 // Intel License Agreement 11 // For Open Source Computer Vision Library 12 // 13 // Copyright (C) 2000, Intel Corporation, all rights reserved. 14 // Third party copyrights are property of their respective owners. 15 // 16 // Redistribution and use in source and binary forms, with or without modification, 17 // are permitted provided that the following conditions are met: 18 // 19 // * Redistribution's of source code must retain the above copyright notice, 20 // this list of conditions and the following disclaimer. 21 // 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. 25 // 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. 28 // 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. 39 // 40 //M*/ 41 42 #include "test_precomp.hpp" 43 44 using namespace cv; 45 using namespace std; 46 47 template <typename T, typename compute> 48 class ShapeBaseTest : public cvtest::BaseTest 49 { 50 public: 51 typedef Point_<T> PointType; 52 ShapeBaseTest(int _NSN, int _NP, float _CURRENT_MAX_ACCUR) 53 : NSN(_NSN), NP(_NP), CURRENT_MAX_ACCUR(_CURRENT_MAX_ACCUR) 54 { 55 // generate file list 56 vector<string> shapeNames; 57 shapeNames.push_back("apple"); //ok 58 shapeNames.push_back("children"); // ok 59 shapeNames.push_back("device7"); // ok 60 shapeNames.push_back("Heart"); // ok 61 shapeNames.push_back("teddy"); // ok 62 for (vector<string>::const_iterator i = shapeNames.begin(); i != shapeNames.end(); ++i) 63 { 64 for (int j = 0; j < NSN; ++j) 65 { 66 stringstream filename; 67 filename << cvtest::TS::ptr()->get_data_path() 68 << "shape/mpeg_test/" << *i << "-" << j + 1 << ".png"; 69 filenames.push_back(filename.str()); 70 } 71 } 72 // distance matrix 73 const int totalCount = (int)filenames.size(); 74 distanceMat = Mat::zeros(totalCount, totalCount, CV_32F); 75 } 76 77 protected: 78 void run(int) 79 { 80 mpegTest(); 81 displayMPEGResults(); 82 } 83 84 vector<PointType> convertContourType(const Mat& currentQuery) const 85 { 86 vector<vector<Point> > _contoursQuery; 87 findContours(currentQuery, _contoursQuery, RETR_LIST, CHAIN_APPROX_NONE); 88 89 vector <PointType> contoursQuery; 90 for (size_t border=0; border<_contoursQuery.size(); border++) 91 { 92 for (size_t p=0; p<_contoursQuery[border].size(); p++) 93 { 94 contoursQuery.push_back(PointType((T)_contoursQuery[border][p].x, 95 (T)_contoursQuery[border][p].y)); 96 } 97 } 98 99 // In case actual number of points is less than n 100 for (int add=(int)contoursQuery.size()-1; add<NP; add++) 101 { 102 contoursQuery.push_back(contoursQuery[contoursQuery.size()-add+1]); //adding dummy values 103 } 104 105 // Uniformly sampling 106 random_shuffle(contoursQuery.begin(), contoursQuery.end()); 107 int nStart=NP; 108 vector<PointType> cont; 109 for (int i=0; i<nStart; i++) 110 { 111 cont.push_back(contoursQuery[i]); 112 } 113 return cont; 114 } 115 116 void mpegTest() 117 { 118 // query contours (normal v flipped, h flipped) and testing contour 119 vector<PointType> contoursQuery1, contoursQuery2, contoursQuery3, contoursTesting; 120 // reading query and computing its properties 121 for (vector<string>::const_iterator a = filenames.begin(); a != filenames.end(); ++a) 122 { 123 // read current image 124 int aIndex = (int)(a - filenames.begin()); 125 Mat currentQuery = imread(*a, IMREAD_GRAYSCALE); 126 Mat flippedHQuery, flippedVQuery; 127 flip(currentQuery, flippedHQuery, 0); 128 flip(currentQuery, flippedVQuery, 1); 129 // compute border of the query and its flipped versions 130 contoursQuery1=convertContourType(currentQuery); 131 contoursQuery2=convertContourType(flippedHQuery); 132 contoursQuery3=convertContourType(flippedVQuery); 133 // compare with all the rest of the images: testing 134 for (vector<string>::const_iterator b = filenames.begin(); b != filenames.end(); ++b) 135 { 136 int bIndex = (int)(b - filenames.begin()); 137 float distance = 0; 138 // skip self-comparisson 139 if (a != b) 140 { 141 // read testing image 142 Mat currentTest = imread(*b, IMREAD_GRAYSCALE); 143 // compute border of the testing 144 contoursTesting=convertContourType(currentTest); 145 // compute shape distance 146 distance = cmp(contoursQuery1, contoursQuery2, 147 contoursQuery3, contoursTesting); 148 } 149 distanceMat.at<float>(aIndex, bIndex) = distance; 150 } 151 } 152 } 153 154 void displayMPEGResults() 155 { 156 const int FIRST_MANY=2*NSN; 157 158 int corrects=0; 159 int divi=0; 160 for (int row=0; row<distanceMat.rows; row++) 161 { 162 if (row%NSN==0) //another group 163 { 164 divi+=NSN; 165 } 166 for (int col=divi-NSN; col<divi; col++) 167 { 168 int nsmall=0; 169 for (int i=0; i<distanceMat.cols; i++) 170 { 171 if (distanceMat.at<float>(row,col) > distanceMat.at<float>(row,i)) 172 { 173 nsmall++; 174 } 175 } 176 if (nsmall<=FIRST_MANY) 177 { 178 corrects++; 179 } 180 } 181 } 182 float porc = 100*float(corrects)/(NSN*distanceMat.rows); 183 std::cout << "Test result: " << porc << "%" << std::endl; 184 if (porc >= CURRENT_MAX_ACCUR) 185 ts->set_failed_test_info(cvtest::TS::OK); 186 else 187 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); 188 } 189 190 protected: 191 int NSN; 192 int NP; 193 float CURRENT_MAX_ACCUR; 194 vector<string> filenames; 195 Mat distanceMat; 196 compute cmp; 197 }; 198 199 //------------------------------------------------------------------------ 200 // Test Shape_SCD.regression 201 //------------------------------------------------------------------------ 202 203 class computeShapeDistance_Chi 204 { 205 Ptr <ShapeContextDistanceExtractor> mysc; 206 public: 207 computeShapeDistance_Chi() 208 { 209 const int angularBins=12; 210 const int radialBins=4; 211 const float minRad=0.2f; 212 const float maxRad=2; 213 mysc = createShapeContextDistanceExtractor(angularBins, radialBins, minRad, maxRad); 214 mysc->setIterations(1); 215 mysc->setCostExtractor(createChiHistogramCostExtractor(30,0.15f)); 216 mysc->setTransformAlgorithm( createThinPlateSplineShapeTransformer() ); 217 } 218 float operator()(vector <Point2f>& query1, vector <Point2f>& query2, 219 vector <Point2f>& query3, vector <Point2f>& testq) 220 { 221 return std::min(mysc->computeDistance(query1, testq), 222 std::min(mysc->computeDistance(query2, testq), 223 mysc->computeDistance(query3, testq))); 224 } 225 }; 226 227 TEST(Shape_SCD, regression) 228 { 229 const int NSN_val=5;//10;//20; //number of shapes per class 230 const int NP_val=120; //number of points simplifying the contour 231 const float CURRENT_MAX_ACCUR_val=95; //99% and 100% reached in several tests, 95 is fixed as minimum boundary 232 ShapeBaseTest<float, computeShapeDistance_Chi> test(NSN_val, NP_val, CURRENT_MAX_ACCUR_val); 233 test.safe_run(); 234 } 235 236 //------------------------------------------------------------------------ 237 // Test ShapeEMD_SCD.regression 238 //------------------------------------------------------------------------ 239 240 class computeShapeDistance_EMD 241 { 242 Ptr <ShapeContextDistanceExtractor> mysc; 243 public: 244 computeShapeDistance_EMD() 245 { 246 const int angularBins=12; 247 const int radialBins=4; 248 const float minRad=0.2f; 249 const float maxRad=2; 250 mysc = createShapeContextDistanceExtractor(angularBins, radialBins, minRad, maxRad); 251 mysc->setIterations(1); 252 mysc->setCostExtractor( createEMDL1HistogramCostExtractor() ); 253 mysc->setTransformAlgorithm( createThinPlateSplineShapeTransformer() ); 254 } 255 float operator()(vector <Point2f>& query1, vector <Point2f>& query2, 256 vector <Point2f>& query3, vector <Point2f>& testq) 257 { 258 return std::min(mysc->computeDistance(query1, testq), 259 std::min(mysc->computeDistance(query2, testq), 260 mysc->computeDistance(query3, testq))); 261 } 262 }; 263 264 TEST(ShapeEMD_SCD, regression) 265 { 266 const int NSN_val=5;//10;//20; //number of shapes per class 267 const int NP_val=100; //number of points simplifying the contour 268 const float CURRENT_MAX_ACCUR_val=95; //98% and 99% reached in several tests, 95 is fixed as minimum boundary 269 ShapeBaseTest<float, computeShapeDistance_EMD> test(NSN_val, NP_val, CURRENT_MAX_ACCUR_val); 270 test.safe_run(); 271 } 272 273 //------------------------------------------------------------------------ 274 // Test Hauss.regression 275 //------------------------------------------------------------------------ 276 277 class computeShapeDistance_Haussdorf 278 { 279 Ptr <HausdorffDistanceExtractor> haus; 280 public: 281 computeShapeDistance_Haussdorf() 282 { 283 haus = createHausdorffDistanceExtractor(); 284 } 285 float operator()(vector<Point> &query1, vector<Point> &query2, 286 vector<Point> &query3, vector<Point> &testq) 287 { 288 return std::min(haus->computeDistance(query1,testq), 289 std::min(haus->computeDistance(query2,testq), 290 haus->computeDistance(query3,testq))); 291 } 292 }; 293 294 TEST(Hauss, regression) 295 { 296 const int NSN_val=5;//10;//20; //number of shapes per class 297 const int NP_val = 180; //number of points simplifying the contour 298 const float CURRENT_MAX_ACCUR_val=85; //90% and 91% reached in several tests, 85 is fixed as minimum boundary 299 ShapeBaseTest<int, computeShapeDistance_Haussdorf> test(NSN_val, NP_val, CURRENT_MAX_ACCUR_val); 300 test.safe_run(); 301 } 302