Home | History | Annotate | Download | only in test
      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