test_shape.cpp 12 KB

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