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 /*static int
     48 cvTsPointConvexPolygon( CvPoint2D32f pt, CvPoint2D32f* v, int n )
     49 {
     50     CvPoint2D32f v0 = v[n-1];
     51     int i, sign = 0;
     52 
     53     for( i = 0; i < n; i++ )
     54     {
     55         CvPoint2D32f v1 = v[i];
     56         float dx = pt.x - v0.x, dy = pt.y - v0.y;
     57         float dx1 = v1.x - v0.x, dy1 = v1.y - v0.y;
     58         double t = (double)dx*dy1 - (double)dx1*dy;
     59         if( fabs(t) > DBL_EPSILON )
     60         {
     61             if( t*sign < 0 )
     62                 break;
     63             if( sign == 0 )
     64                 sign = t < 0 ? -1 : 1;
     65         }
     66         else if( fabs(dx) + fabs(dy) < DBL_EPSILON )
     67             return i+1;
     68         v0 = v1;
     69     }
     70 
     71     return i < n ? -1 : 0;
     72 }*/
     73 
     74 CV_INLINE double
     75 cvTsDist( CvPoint2D32f a, CvPoint2D32f b )
     76 {
     77     double dx = a.x - b.x;
     78     double dy = a.y - b.y;
     79     return sqrt(dx*dx + dy*dy);
     80 }
     81 
     82 CV_INLINE double
     83 cvTsPtLineDist( CvPoint2D32f pt, CvPoint2D32f a, CvPoint2D32f b )
     84 {
     85     double d0 = cvTsDist( pt, a ), d1;
     86     double dd = cvTsDist( a, b );
     87     if( dd < FLT_EPSILON )
     88         return d0;
     89     d1 = cvTsDist( pt, b );
     90     dd = fabs((double)(pt.x - a.x)*(b.y - a.y) - (double)(pt.y - a.y)*(b.x - a.x))/dd;
     91     d0 = MIN( d0, d1 );
     92     return MIN( d0, dd );
     93 }
     94 
     95 static double
     96 cvTsPointPolygonTest( CvPoint2D32f pt, const CvPoint2D32f* vv, int n, int* _idx=0, int* _on_edge=0 )
     97 {
     98     int i;
     99     CvPoint2D32f v = vv[n-1], v0;
    100     double min_dist_num = FLT_MAX, min_dist_denom = 1;
    101     int min_dist_idx = -1, min_on_edge = 0;
    102     int counter = 0;
    103     double result;
    104 
    105     for( i = 0; i < n; i++ )
    106     {
    107         double dx, dy, dx1, dy1, dx2, dy2, dist_num, dist_denom = 1;
    108         int on_edge = 0, idx = i;
    109 
    110         v0 = v; v = vv[i];
    111         dx = v.x - v0.x; dy = v.y - v0.y;
    112         dx1 = pt.x - v0.x; dy1 = pt.y - v0.y;
    113         dx2 = pt.x - v.x; dy2 = pt.y - v.y;
    114 
    115         if( dx2*dx + dy2*dy >= 0 )
    116             dist_num = dx2*dx2 + dy2*dy2;
    117         else if( dx1*dx + dy1*dy <= 0 )
    118         {
    119             dist_num = dx1*dx1 + dy1*dy1;
    120             idx = i - 1;
    121             if( idx < 0 ) idx = n-1;
    122         }
    123         else
    124         {
    125             dist_num = (dy1*dx - dx1*dy);
    126             dist_num *= dist_num;
    127             dist_denom = dx*dx + dy*dy;
    128             on_edge = 1;
    129         }
    130 
    131         if( dist_num*min_dist_denom < min_dist_num*dist_denom )
    132         {
    133             min_dist_num = dist_num;
    134             min_dist_denom = dist_denom;
    135             min_dist_idx = idx;
    136             min_on_edge = on_edge;
    137             if( min_dist_num == 0 )
    138                 break;
    139         }
    140 
    141         if( (v0.y <= pt.y && v.y <= pt.y) ||
    142             (v0.y > pt.y && v.y > pt.y) ||
    143             (v0.x < pt.x && v.x < pt.x) )
    144             continue;
    145 
    146         dist_num = dy1*dx - dx1*dy;
    147         if( dy < 0 )
    148             dist_num = -dist_num;
    149         counter += dist_num > 0;
    150     }
    151 
    152     result = sqrt(min_dist_num/min_dist_denom);
    153     if( counter % 2 == 0 )
    154         result = -result;
    155 
    156     if( _idx )
    157         *_idx = min_dist_idx;
    158     if( _on_edge )
    159         *_on_edge = min_on_edge;
    160 
    161     return result;
    162 }
    163 
    164 static cv::Point2f
    165 cvTsMiddlePoint(const cv::Point2f &a, const cv::Point2f &b)
    166 {
    167     return cv::Point2f((a.x + b.x) / 2, (a.y + b.y) / 2);
    168 }
    169 
    170 static bool
    171 cvTsIsPointOnLineSegment(const cv::Point2f &x, const cv::Point2f &a, const cv::Point2f &b)
    172 {
    173     double d1 = cvTsDist(CvPoint2D32f(x.x, x.y), CvPoint2D32f(a.x, a.y));
    174     double d2 = cvTsDist(CvPoint2D32f(x.x, x.y), CvPoint2D32f(b.x, b.y));
    175     double d3 = cvTsDist(CvPoint2D32f(a.x, a.y), CvPoint2D32f(b.x, b.y));
    176 
    177     return (abs(d1 + d2 - d3) <= (1E-5));
    178 }
    179 
    180 
    181 /****************************************************************************************\
    182 *                              Base class for shape descriptor tests                     *
    183 \****************************************************************************************/
    184 
    185 class CV_BaseShapeDescrTest : public cvtest::BaseTest
    186 {
    187 public:
    188     CV_BaseShapeDescrTest();
    189     virtual ~CV_BaseShapeDescrTest();
    190     void clear();
    191 
    192 protected:
    193     int read_params( CvFileStorage* fs );
    194     void run_func(void);
    195     int prepare_test_case( int test_case_idx );
    196     int validate_test_results( int test_case_idx );
    197     virtual void generate_point_set( void* points );
    198     virtual void extract_points();
    199 
    200     int min_log_size;
    201     int max_log_size;
    202     int dims;
    203     bool enable_flt_points;
    204 
    205     CvMemStorage* storage;
    206     CvSeq* points1;
    207     CvMat* points2;
    208     void* points;
    209     void* result;
    210     double low_high_range;
    211     CvScalar low, high;
    212 
    213     bool test_cpp;
    214 };
    215 
    216 
    217 CV_BaseShapeDescrTest::CV_BaseShapeDescrTest()
    218 {
    219     points1 = 0;
    220     points2 = 0;
    221     points = 0;
    222     storage = 0;
    223     test_case_count = 500;
    224     min_log_size = 0;
    225     max_log_size = 10;
    226     low = high = cvScalarAll(0);
    227     low_high_range = 50;
    228     dims = 2;
    229     enable_flt_points = true;
    230 
    231     test_cpp = false;
    232 }
    233 
    234 
    235 CV_BaseShapeDescrTest::~CV_BaseShapeDescrTest()
    236 {
    237     clear();
    238 }
    239 
    240 
    241 void CV_BaseShapeDescrTest::clear()
    242 {
    243     cvtest::BaseTest::clear();
    244     cvReleaseMemStorage( &storage );
    245     cvReleaseMat( &points2 );
    246     points1 = 0;
    247     points = 0;
    248 }
    249 
    250 
    251 int CV_BaseShapeDescrTest::read_params( CvFileStorage* fs )
    252 {
    253     int code = cvtest::BaseTest::read_params( fs );
    254     if( code < 0 )
    255         return code;
    256 
    257     test_case_count = cvReadInt( find_param( fs, "struct_count" ), test_case_count );
    258     min_log_size = cvReadInt( find_param( fs, "min_log_size" ), min_log_size );
    259     max_log_size = cvReadInt( find_param( fs, "max_log_size" ), max_log_size );
    260 
    261     min_log_size = cvtest::clipInt( min_log_size, 0, 8 );
    262     max_log_size = cvtest::clipInt( max_log_size, 0, 10 );
    263     if( min_log_size > max_log_size )
    264     {
    265         int t;
    266         CV_SWAP( min_log_size, max_log_size, t );
    267     }
    268 
    269     return 0;
    270 }
    271 
    272 
    273 void CV_BaseShapeDescrTest::generate_point_set( void* pointsSet )
    274 {
    275     RNG& rng = ts->get_rng();
    276     int i, k, n, total, point_type;
    277     CvSeqReader reader;
    278     uchar* data = 0;
    279     double a[4], b[4];
    280 
    281     for( k = 0; k < 4; k++ )
    282     {
    283         a[k] = high.val[k] - low.val[k];
    284         b[k] = low.val[k];
    285     }
    286     memset( &reader, 0, sizeof(reader) );
    287 
    288     if( CV_IS_SEQ(pointsSet) )
    289     {
    290         CvSeq* ptseq = (CvSeq*)pointsSet;
    291         total = ptseq->total;
    292         point_type = CV_SEQ_ELTYPE(ptseq);
    293         cvStartReadSeq( ptseq, &reader );
    294     }
    295     else
    296     {
    297         CvMat* ptm = (CvMat*)pointsSet;
    298         assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) );
    299         total = ptm->rows + ptm->cols - 1;
    300         point_type = CV_MAT_TYPE(ptm->type);
    301         data = ptm->data.ptr;
    302     }
    303 
    304     n = CV_MAT_CN(point_type);
    305     point_type = CV_MAT_DEPTH(point_type);
    306 
    307     assert( (point_type == CV_32S || point_type == CV_32F) && n <= 4 );
    308 
    309     for( i = 0; i < total; i++ )
    310     {
    311         int* pi;
    312         float* pf;
    313         if( reader.ptr )
    314         {
    315             pi = (int*)reader.ptr;
    316             pf = (float*)reader.ptr;
    317             CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
    318         }
    319         else
    320         {
    321             pi = (int*)data + i*n;
    322             pf = (float*)data + i*n;
    323         }
    324         if( point_type == CV_32S )
    325             for( k = 0; k < n; k++ )
    326                 pi[k] = cvRound(cvtest::randReal(rng)*a[k] + b[k]);
    327         else
    328             for( k = 0; k < n; k++ )
    329                 pf[k] = (float)(cvtest::randReal(rng)*a[k] + b[k]);
    330     }
    331 }
    332 
    333 
    334 int CV_BaseShapeDescrTest::prepare_test_case( int test_case_idx )
    335 {
    336     int size;
    337     int use_storage = 0;
    338     int point_type;
    339     int i;
    340     RNG& rng = ts->get_rng();
    341 
    342     cvtest::BaseTest::prepare_test_case( test_case_idx );
    343 
    344     clear();
    345     size = cvRound( exp((cvtest::randReal(rng) * (max_log_size - min_log_size) + min_log_size)*CV_LOG2) );
    346     use_storage = cvtest::randInt(rng) % 2;
    347     point_type = CV_MAKETYPE(cvtest::randInt(rng) %
    348         (enable_flt_points ? 2 : 1) ? CV_32F : CV_32S, dims);
    349 
    350     if( use_storage )
    351     {
    352         storage = cvCreateMemStorage( (cvtest::randInt(rng)%10 + 1)*1024 );
    353         points1 = cvCreateSeq( point_type, sizeof(CvSeq), CV_ELEM_SIZE(point_type), storage );
    354         cvSeqPushMulti( points1, 0, size );
    355         points = points1;
    356     }
    357     else
    358     {
    359         int rows = 1, cols = size;
    360         if( cvtest::randInt(rng) % 2 )
    361             rows = size, cols = 1;
    362 
    363         points2 = cvCreateMat( rows, cols, point_type );
    364         points = points2;
    365     }
    366 
    367     for( i = 0; i < 4; i++ )
    368     {
    369         low.val[i] = (cvtest::randReal(rng)-0.5)*low_high_range*2;
    370         high.val[i] = (cvtest::randReal(rng)-0.5)*low_high_range*2;
    371         if( low.val[i] > high.val[i] )
    372         {
    373             double t;
    374             CV_SWAP( low.val[i], high.val[i], t );
    375         }
    376         if( high.val[i] < low.val[i] + 1 )
    377             high.val[i] += 1;
    378     }
    379 
    380     generate_point_set( points );
    381 
    382     test_cpp = (cvtest::randInt(rng) & 16) == 0;
    383     return 1;
    384 }
    385 
    386 
    387 void CV_BaseShapeDescrTest::extract_points()
    388 {
    389     if( points1 )
    390     {
    391         points2 = cvCreateMat( 1, points1->total, CV_SEQ_ELTYPE(points1) );
    392         cvCvtSeqToArray( points1, points2->data.ptr );
    393     }
    394 
    395     if( CV_MAT_DEPTH(points2->type) != CV_32F && enable_flt_points )
    396     {
    397         CvMat tmp = cvMat( points2->rows, points2->cols,
    398             (points2->type & ~CV_MAT_DEPTH_MASK) | CV_32F, points2->data.ptr );
    399         cvConvert( points2, &tmp );
    400     }
    401 }
    402 
    403 
    404 void CV_BaseShapeDescrTest::run_func(void)
    405 {
    406 }
    407 
    408 
    409 int CV_BaseShapeDescrTest::validate_test_results( int /*test_case_idx*/ )
    410 {
    411     extract_points();
    412     return 0;
    413 }
    414 
    415 
    416 /****************************************************************************************\
    417 *                                     Convex Hull Test                                   *
    418 \****************************************************************************************/
    419 
    420 class CV_ConvHullTest : public CV_BaseShapeDescrTest
    421 {
    422 public:
    423     CV_ConvHullTest();
    424     virtual ~CV_ConvHullTest();
    425     void clear();
    426 
    427 protected:
    428     void run_func(void);
    429     int prepare_test_case( int test_case_idx );
    430     int validate_test_results( int test_case_idx );
    431 
    432     CvSeq* hull1;
    433     CvMat* hull2;
    434     void* hull_storage;
    435     int orientation;
    436     int return_points;
    437 };
    438 
    439 
    440 CV_ConvHullTest::CV_ConvHullTest()
    441 {
    442     hull1 = 0;
    443     hull2 = 0;
    444     hull_storage = 0;
    445     orientation = return_points = 0;
    446 }
    447 
    448 
    449 CV_ConvHullTest::~CV_ConvHullTest()
    450 {
    451     clear();
    452 }
    453 
    454 
    455 void CV_ConvHullTest::clear()
    456 {
    457     CV_BaseShapeDescrTest::clear();
    458     cvReleaseMat( &hull2 );
    459     hull1 = 0;
    460     hull_storage = 0;
    461 }
    462 
    463 
    464 int CV_ConvHullTest::prepare_test_case( int test_case_idx )
    465 {
    466     int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx );
    467     int use_storage_for_hull = 0;
    468     RNG& rng = ts->get_rng();
    469 
    470     if( code <= 0 )
    471         return code;
    472 
    473     orientation = cvtest::randInt(rng) % 2 ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE;
    474     return_points = cvtest::randInt(rng) % 2;
    475 
    476     use_storage_for_hull = (cvtest::randInt(rng) % 2) && !test_cpp;
    477     if( use_storage_for_hull )
    478     {
    479         if( !storage )
    480             storage = cvCreateMemStorage( (cvtest::randInt(rng)%10 + 1)*1024 );
    481         hull_storage = storage;
    482     }
    483     else
    484     {
    485         int rows, cols;
    486         int sz = points1 ? points1->total : points2->cols + points2->rows - 1;
    487         int point_type = points1 ? CV_SEQ_ELTYPE(points1) : CV_MAT_TYPE(points2->type);
    488 
    489         if( cvtest::randInt(rng) % 2 )
    490             rows = sz, cols = 1;
    491         else
    492             rows = 1, cols = sz;
    493 
    494         hull2 = cvCreateMat( rows, cols, return_points ? point_type : CV_32SC1 );
    495         hull_storage = hull2;
    496     }
    497 
    498     return code;
    499 }
    500 
    501 
    502 void CV_ConvHullTest::run_func()
    503 {
    504     if(!test_cpp)
    505         hull1 = cvConvexHull2( points, hull_storage, orientation, return_points );
    506     else
    507     {
    508         cv::Mat _points = cv::cvarrToMat(points);
    509         bool clockwise = orientation == CV_CLOCKWISE;
    510         size_t n = 0;
    511         if( !return_points )
    512         {
    513             std::vector<int> _hull;
    514             cv::convexHull(_points, _hull, clockwise);
    515             n = _hull.size();
    516             memcpy(hull2->data.ptr, &_hull[0], n*sizeof(_hull[0]));
    517         }
    518         else if(_points.type() == CV_32SC2)
    519         {
    520             std::vector<cv::Point> _hull;
    521             cv::convexHull(_points, _hull, clockwise);
    522             n = _hull.size();
    523             memcpy(hull2->data.ptr, &_hull[0], n*sizeof(_hull[0]));
    524         }
    525         else if(_points.type() == CV_32FC2)
    526         {
    527             std::vector<cv::Point2f> _hull;
    528             cv::convexHull(_points, _hull, clockwise);
    529             n = _hull.size();
    530             memcpy(hull2->data.ptr, &_hull[0], n*sizeof(_hull[0]));
    531         }
    532         if(hull2->rows > hull2->cols)
    533             hull2->rows = (int)n;
    534         else
    535             hull2->cols = (int)n;
    536     }
    537 }
    538 
    539 
    540 int CV_ConvHullTest::validate_test_results( int test_case_idx )
    541 {
    542     int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
    543     CvMat* hull = 0;
    544     CvMat* mask = 0;
    545     int i, point_count, hull_count;
    546     CvPoint2D32f *p, *h;
    547     CvSeq header, hheader, *ptseq, *hseq;
    548     CvSeqBlock block, hblock;
    549 
    550     if( points1 )
    551         ptseq = points1;
    552     else
    553         ptseq = cvMakeSeqHeaderForArray( CV_MAT_TYPE(points2->type),
    554             sizeof(CvSeq), CV_ELEM_SIZE(points2->type), points2->data.ptr,
    555             points2->rows + points2->cols - 1, &header, &block );
    556     point_count = ptseq->total;
    557     p = (CvPoint2D32f*)(points2->data.ptr);
    558 
    559     if( hull1 )
    560         hseq = hull1;
    561     else
    562         hseq = cvMakeSeqHeaderForArray( CV_MAT_TYPE(hull2->type),
    563             sizeof(CvSeq), CV_ELEM_SIZE(hull2->type), hull2->data.ptr,
    564             hull2->rows + hull2->cols - 1, &hheader, &hblock );
    565     hull_count = hseq->total;
    566     hull = cvCreateMat( 1, hull_count, CV_32FC2 );
    567     mask = cvCreateMat( 1, hull_count, CV_8UC1 );
    568     cvZero( mask );
    569     Mat _mask = cvarrToMat(mask);
    570 
    571     h = (CvPoint2D32f*)(hull->data.ptr);
    572 
    573     // extract convex hull points
    574     if( return_points )
    575     {
    576         cvCvtSeqToArray( hseq, hull->data.ptr );
    577         if( CV_SEQ_ELTYPE(hseq) != CV_32FC2 )
    578         {
    579             CvMat tmp = cvMat( hull->rows, hull->cols, CV_32SC2, hull->data.ptr );
    580             cvConvert( &tmp, hull );
    581         }
    582     }
    583     else
    584     {
    585         CvSeqReader reader;
    586         cvStartReadSeq( hseq, &reader );
    587 
    588         for( i = 0; i < hull_count; i++ )
    589         {
    590             schar* ptr = reader.ptr;
    591             int idx;
    592             CV_NEXT_SEQ_ELEM( hseq->elem_size, reader );
    593 
    594             if( hull1 )
    595                 idx = cvSeqElemIdx( ptseq, *(uchar**)ptr );
    596             else
    597                 idx = *(int*)ptr;
    598 
    599             if( idx < 0 || idx >= point_count )
    600             {
    601                 ts->printf( cvtest::TS::LOG, "Invalid convex hull point #%d\n", i );
    602                 code = cvtest::TS::FAIL_INVALID_OUTPUT;
    603                 goto _exit_;
    604             }
    605             h[i] = p[idx];
    606         }
    607     }
    608 
    609     // check that the convex hull is a convex polygon
    610     if( hull_count >= 3 )
    611     {
    612         CvPoint2D32f pt0 = h[hull_count-1];
    613         for( i = 0; i < hull_count; i++ )
    614         {
    615             int j = i+1;
    616             CvPoint2D32f pt1 = h[i], pt2 = h[j < hull_count ? j : 0];
    617             float dx0 = pt1.x - pt0.x, dy0 = pt1.y - pt0.y;
    618             float dx1 = pt2.x - pt1.x, dy1 = pt2.y - pt1.y;
    619             double t = (double)dx0*dy1 - (double)dx1*dy0;
    620             if( (t < 0) ^ (orientation != CV_COUNTER_CLOCKWISE) )
    621             {
    622                 ts->printf( cvtest::TS::LOG, "The convex hull is not convex or has a wrong orientation (vtx %d)\n", i );
    623                 code = cvtest::TS::FAIL_INVALID_OUTPUT;
    624                 goto _exit_;
    625             }
    626             pt0 = pt1;
    627         }
    628     }
    629 
    630     // check that all the points are inside the hull or on the hull edge
    631     // and at least hull_point points are at the hull vertices
    632     for( i = 0; i < point_count; i++ )
    633     {
    634         int idx = 0, on_edge = 0;
    635         double pptresult = cvTsPointPolygonTest( p[i], h, hull_count, &idx, &on_edge );
    636 
    637         if( pptresult < 0 )
    638         {
    639             ts->printf( cvtest::TS::LOG, "The point #%d is outside of the convex hull\n", i );
    640             code = cvtest::TS::FAIL_BAD_ACCURACY;
    641             goto _exit_;
    642         }
    643 
    644         if( pptresult < FLT_EPSILON && !on_edge )
    645             mask->data.ptr[idx] = (uchar)1;
    646     }
    647 
    648     if( cvtest::norm( _mask, Mat::zeros(_mask.dims, _mask.size, _mask.type()), NORM_L1 ) != hull_count )
    649     {
    650         ts->printf( cvtest::TS::LOG, "Not every convex hull vertex coincides with some input point\n" );
    651         code = cvtest::TS::FAIL_BAD_ACCURACY;
    652         goto _exit_;
    653     }
    654 
    655 _exit_:
    656 
    657     cvReleaseMat( &hull );
    658     cvReleaseMat( &mask );
    659     if( code < 0 )
    660         ts->set_failed_test_info( code );
    661     return code;
    662 }
    663 
    664 
    665 /****************************************************************************************\
    666 *                                     MinAreaRect Test                                   *
    667 \****************************************************************************************/
    668 
    669 class CV_MinAreaRectTest : public CV_BaseShapeDescrTest
    670 {
    671 public:
    672     CV_MinAreaRectTest();
    673 
    674 protected:
    675     void run_func(void);
    676     int validate_test_results( int test_case_idx );
    677 
    678     CvBox2D box;
    679     CvPoint2D32f box_pt[4];
    680 };
    681 
    682 
    683 CV_MinAreaRectTest::CV_MinAreaRectTest()
    684 {
    685 }
    686 
    687 
    688 void CV_MinAreaRectTest::run_func()
    689 {
    690     if(!test_cpp)
    691     {
    692         box = cvMinAreaRect2( points, storage );
    693         cvBoxPoints( box, box_pt );
    694     }
    695     else
    696     {
    697         cv::RotatedRect r = cv::minAreaRect(cv::cvarrToMat(points));
    698         box = (CvBox2D)r;
    699         r.points((cv::Point2f*)box_pt);
    700     }
    701 }
    702 
    703 
    704 int CV_MinAreaRectTest::validate_test_results( int test_case_idx )
    705 {
    706     double eps = 1e-1;
    707     int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
    708     int i, j, point_count = points2->rows + points2->cols - 1;
    709     CvPoint2D32f *p = (CvPoint2D32f*)(points2->data.ptr);
    710     int mask[] = {0,0,0,0};
    711 
    712     // check that the bounding box is a rotated rectangle:
    713     //  1. diagonals should be equal
    714     //  2. they must intersect in their middle points
    715     {
    716         double d0 = cvTsDist( box_pt[0], box_pt[2] );
    717         double d1 = cvTsDist( box_pt[1], box_pt[3] );
    718 
    719         double x0 = (box_pt[0].x + box_pt[2].x)*0.5;
    720         double y0 = (box_pt[0].y + box_pt[2].y)*0.5;
    721         double x1 = (box_pt[1].x + box_pt[3].x)*0.5;
    722         double y1 = (box_pt[1].y + box_pt[3].y)*0.5;
    723 
    724         if( fabs(d0 - d1) + fabs(x0 - x1) + fabs(y0 - y1) > eps*MAX(d0,d1) )
    725         {
    726             ts->printf( cvtest::TS::LOG, "The bounding box is not a rectangle\n" );
    727             code = cvtest::TS::FAIL_INVALID_OUTPUT;
    728             goto _exit_;
    729         }
    730     }
    731 
    732 #if 0
    733     {
    734     int n = 4;
    735     double a = 8, c = 8, b = 100, d = 150;
    736     CvPoint bp[4], *bpp = bp;
    737     cvNamedWindow( "test", 1 );
    738     IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 );
    739     cvZero(img);
    740     for( i = 0; i < point_count; i++ )
    741         cvCircle(img,cvPoint(cvRound(p[i].x*a+b),cvRound(p[i].y*c+d)), 3, CV_RGB(0,255,0), -1 );
    742     for( i = 0; i < n; i++ )
    743         bp[i] = cvPoint(cvRound(box_pt[i].x*a+b),cvRound(box_pt[i].y*c+d));
    744     cvPolyLine( img, &bpp, &n, 1, 1, CV_RGB(255,255,0), 1, CV_AA, 0 );
    745     cvShowImage( "test", img );
    746     cvWaitKey();
    747     cvReleaseImage(&img);
    748     }
    749 #endif
    750 
    751     // check that the box includes all the points
    752     // and there is at least one point at (or very close to) every box side
    753     for( i = 0; i < point_count; i++ )
    754     {
    755         int idx = 0, on_edge = 0;
    756         double pptresult = cvTsPointPolygonTest( p[i], box_pt, 4, &idx, &on_edge );
    757         if( pptresult < -eps )
    758         {
    759             ts->printf( cvtest::TS::LOG, "The point #%d is outside of the box\n", i );
    760             code = cvtest::TS::FAIL_BAD_ACCURACY;
    761             goto _exit_;
    762         }
    763 
    764         if( pptresult < eps )
    765         {
    766             for( j = 0; j < 4; j++ )
    767             {
    768                 double d = cvTsPtLineDist( p[i], box_pt[(j-1)&3], box_pt[j] );
    769                 if( d < eps )
    770                     mask[j] = (uchar)1;
    771             }
    772         }
    773     }
    774 
    775     if( mask[0] + mask[1] + mask[2] + mask[3] != 4 )
    776     {
    777         ts->printf( cvtest::TS::LOG, "Not every box side has a point nearby\n" );
    778         code = cvtest::TS::FAIL_BAD_ACCURACY;
    779         goto _exit_;
    780     }
    781 
    782 _exit_:
    783 
    784     if( code < 0 )
    785         ts->set_failed_test_info( code );
    786     return code;
    787 }
    788 
    789 
    790 /****************************************************************************************\
    791 *                                   MinEnclosingTriangle Test                            *
    792 \****************************************************************************************/
    793 
    794 class CV_MinTriangleTest : public CV_BaseShapeDescrTest
    795 {
    796 public:
    797     CV_MinTriangleTest();
    798 
    799 protected:
    800     void run_func(void);
    801     int validate_test_results( int test_case_idx );
    802     std::vector<cv::Point2f> getTriangleMiddlePoints();
    803 
    804     std::vector<cv::Point2f> convexPolygon;
    805     std::vector<cv::Point2f> triangle;
    806 };
    807 
    808 
    809 CV_MinTriangleTest::CV_MinTriangleTest()
    810 {
    811 }
    812 
    813 std::vector<cv::Point2f> CV_MinTriangleTest::getTriangleMiddlePoints()
    814 {
    815     std::vector<cv::Point2f> triangleMiddlePoints;
    816 
    817     for (int i = 0; i < 3; i++) {
    818         triangleMiddlePoints.push_back(cvTsMiddlePoint(triangle[i], triangle[(i + 1) % 3]));
    819     }
    820 
    821     return triangleMiddlePoints;
    822 }
    823 
    824 
    825 void CV_MinTriangleTest::run_func()
    826 {
    827     std::vector<cv::Point2f> pointsAsVector;
    828 
    829     cv::cvarrToMat(points).convertTo(pointsAsVector, CV_32F);
    830 
    831     cv::minEnclosingTriangle(pointsAsVector, triangle);
    832     cv::convexHull(pointsAsVector, convexPolygon, true, true);
    833 }
    834 
    835 
    836 int CV_MinTriangleTest::validate_test_results( int test_case_idx )
    837 {
    838     bool errorEnclosed = false, errorMiddlePoints = false, errorFlush = true;
    839     double eps = 1e-4;
    840     int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
    841 
    842 #if 0
    843     {
    844     int n = 3;
    845     double a = 8, c = 8, b = 100, d = 150;
    846     CvPoint bp[4], *bpp = bp;
    847     cvNamedWindow( "test", 1 );
    848     IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 );
    849     cvZero(img);
    850     for( i = 0; i < point_count; i++ )
    851         cvCircle(img,cvPoint(cvRound(p[i].x*a+b),cvRound(p[i].y*c+d)), 3, CV_RGB(0,255,0), -1 );
    852     for( i = 0; i < n; i++ )
    853         bp[i] = cvPoint(cvRound(triangle[i].x*a+b),cvRound(triangle[i].y*c+d));
    854     cvPolyLine( img, &bpp, &n, 1, 1, CV_RGB(255,255,0), 1, CV_AA, 0 );
    855     cvShowImage( "test", img );
    856     cvWaitKey();
    857     cvReleaseImage(&img);
    858     }
    859 #endif
    860 
    861     int polygonVertices = (int) convexPolygon.size();
    862 
    863     if (polygonVertices > 2) {
    864         // Check if all points are enclosed by the triangle
    865         for (int i = 0; (i < polygonVertices) && (!errorEnclosed); i++)
    866         {
    867             if (cv::pointPolygonTest(triangle, cv::Point2f(convexPolygon[i].x, convexPolygon[i].y), true) < (-eps))
    868                 errorEnclosed = true;
    869         }
    870 
    871         // Check if triangle edges middle points touch the polygon
    872         std::vector<cv::Point2f> middlePoints = getTriangleMiddlePoints();
    873 
    874         for (int i = 0; (i < 3) && (!errorMiddlePoints); i++)
    875         {
    876             bool isTouching = false;
    877 
    878             for (int j = 0; (j < polygonVertices) && (!isTouching); j++)
    879             {
    880                 if (cvTsIsPointOnLineSegment(middlePoints[i], convexPolygon[j],
    881                                              convexPolygon[(j + 1) % polygonVertices]))
    882                     isTouching = true;
    883             }
    884 
    885             errorMiddlePoints = (isTouching) ? false : true;
    886         }
    887 
    888         // Check if at least one of the edges is flush
    889         for (int i = 0; (i < 3) && (errorFlush); i++)
    890         {
    891             for (int j = 0; (j < polygonVertices) && (errorFlush); j++)
    892             {
    893                 if ((cvTsIsPointOnLineSegment(convexPolygon[j], triangle[i],
    894                                               triangle[(i + 1) % 3])) &&
    895                     (cvTsIsPointOnLineSegment(convexPolygon[(j + 1) % polygonVertices], triangle[i],
    896                                               triangle[(i + 1) % 3])))
    897                     errorFlush = false;
    898             }
    899         }
    900 
    901         // Report any found errors
    902         if (errorEnclosed)
    903         {
    904             ts->printf( cvtest::TS::LOG,
    905             "All points should be enclosed by the triangle.\n" );
    906             code = cvtest::TS::FAIL_BAD_ACCURACY;
    907         }
    908         else if (errorMiddlePoints)
    909         {
    910             ts->printf( cvtest::TS::LOG,
    911             "All triangle edges middle points should touch the convex hull of the points.\n" );
    912             code = cvtest::TS::FAIL_INVALID_OUTPUT;
    913         }
    914         else if (errorFlush)
    915         {
    916             ts->printf( cvtest::TS::LOG,
    917             "At least one edge of the enclosing triangle should be flush with one edge of the polygon.\n" );
    918             code = cvtest::TS::FAIL_INVALID_OUTPUT;
    919         }
    920     }
    921 
    922     if ( code < 0 )
    923         ts->set_failed_test_info( code );
    924 
    925     return code;
    926 }
    927 
    928 
    929 /****************************************************************************************\
    930 *                                     MinEnclosingCircle Test                            *
    931 \****************************************************************************************/
    932 
    933 class CV_MinCircleTest : public CV_BaseShapeDescrTest
    934 {
    935 public:
    936     CV_MinCircleTest();
    937 
    938 protected:
    939     void run_func(void);
    940     int validate_test_results( int test_case_idx );
    941 
    942     CvPoint2D32f center;
    943     float radius;
    944 };
    945 
    946 
    947 CV_MinCircleTest::CV_MinCircleTest()
    948 {
    949 }
    950 
    951 
    952 void CV_MinCircleTest::run_func()
    953 {
    954     if(!test_cpp)
    955         cvMinEnclosingCircle( points, &center, &radius );
    956     else
    957     {
    958         cv::Point2f tmpcenter;
    959         cv::minEnclosingCircle(cv::cvarrToMat(points), tmpcenter, radius);
    960         center = tmpcenter;
    961     }
    962 }
    963 
    964 
    965 int CV_MinCircleTest::validate_test_results( int test_case_idx )
    966 {
    967     double eps = 1.03;
    968     int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
    969     int i, j = 0, point_count = points2->rows + points2->cols - 1;
    970     CvPoint2D32f *p = (CvPoint2D32f*)(points2->data.ptr);
    971     CvPoint2D32f v[3];
    972 
    973 #if 0
    974     {
    975     double a = 2, b = 200, d = 400;
    976     cvNamedWindow( "test", 1 );
    977     IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 );
    978     cvZero(img);
    979     for( i = 0; i < point_count; i++ )
    980         cvCircle(img,cvPoint(cvRound(p[i].x*a+b),cvRound(p[i].y*a+d)), 3, CV_RGB(0,255,0), -1 );
    981     cvCircle( img, cvPoint(cvRound(center.x*a+b),cvRound(center.y*a+d)),
    982               cvRound(radius*a), CV_RGB(255,255,0), 1 );
    983     cvShowImage( "test", img );
    984     cvWaitKey();
    985     cvReleaseImage(&img);
    986     }
    987 #endif
    988 
    989     // check that the circle contains all the points inside and
    990     // remember at most 3 points that are close to the boundary
    991     for( i = 0; i < point_count; i++ )
    992     {
    993         double d = cvTsDist( p[i], center );
    994         if( d > radius )
    995         {
    996             ts->printf( cvtest::TS::LOG, "The point #%d is outside of the circle\n", i );
    997             code = cvtest::TS::FAIL_BAD_ACCURACY;
    998             goto _exit_;
    999         }
   1000 
   1001         if( radius - d < eps*radius && j < 3 )
   1002             v[j++] = p[i];
   1003     }
   1004 
   1005     if( point_count >= 2 && (j < 2 || (j == 2 && cvTsDist(v[0],v[1]) < (radius-1)*2/eps)) )
   1006     {
   1007         ts->printf( cvtest::TS::LOG,
   1008             "There should be at at least 3 points near the circle boundary or 2 points on the diameter\n" );
   1009         code = cvtest::TS::FAIL_BAD_ACCURACY;
   1010         goto _exit_;
   1011     }
   1012 
   1013 _exit_:
   1014 
   1015     if( code < 0 )
   1016         ts->set_failed_test_info( code );
   1017     return code;
   1018 }
   1019 
   1020 
   1021 /****************************************************************************************\
   1022 *                                   Perimeter Test                                     *
   1023 \****************************************************************************************/
   1024 
   1025 class CV_PerimeterTest : public CV_BaseShapeDescrTest
   1026 {
   1027 public:
   1028     CV_PerimeterTest();
   1029 
   1030 protected:
   1031     int prepare_test_case( int test_case_idx );
   1032     void run_func(void);
   1033     int validate_test_results( int test_case_idx );
   1034     CvSlice slice;
   1035     int is_closed;
   1036     double result;
   1037 };
   1038 
   1039 
   1040 CV_PerimeterTest::CV_PerimeterTest()
   1041 {
   1042 }
   1043 
   1044 
   1045 int CV_PerimeterTest::prepare_test_case( int test_case_idx )
   1046 {
   1047     int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx );
   1048     RNG& rng = ts->get_rng();
   1049     int total;
   1050 
   1051     if( code < 0 )
   1052         return code;
   1053 
   1054     is_closed = cvtest::randInt(rng) % 2;
   1055 
   1056     if( points1 )
   1057     {
   1058         points1->flags |= CV_SEQ_KIND_CURVE;
   1059         if( is_closed )
   1060             points1->flags |= CV_SEQ_FLAG_CLOSED;
   1061         total = points1->total;
   1062     }
   1063     else
   1064         total = points2->cols + points2->rows - 1;
   1065 
   1066     if( (cvtest::randInt(rng) % 3) && !test_cpp )
   1067     {
   1068         slice.start_index = cvtest::randInt(rng) % total;
   1069         slice.end_index = cvtest::randInt(rng) % total;
   1070     }
   1071     else
   1072         slice = CV_WHOLE_SEQ;
   1073 
   1074     return 1;
   1075 }
   1076 
   1077 
   1078 void CV_PerimeterTest::run_func()
   1079 {
   1080     if(!test_cpp)
   1081         result = cvArcLength( points, slice, points1 ? -1 : is_closed );
   1082     else
   1083         result = cv::arcLength(cv::cvarrToMat(points),
   1084             !points1 ? is_closed != 0 : (points1->flags & CV_SEQ_FLAG_CLOSED) != 0);
   1085 }
   1086 
   1087 
   1088 int CV_PerimeterTest::validate_test_results( int test_case_idx )
   1089 {
   1090     int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
   1091     int i, len = slice.end_index - slice.start_index, total = points2->cols + points2->rows - 1;
   1092     double result0 = 0;
   1093     CvPoint2D32f prev_pt, pt, *ptr;
   1094 
   1095     if( len < 0 )
   1096         len += total;
   1097 
   1098     len = MIN( len, total );
   1099     //len -= !is_closed && len == total;
   1100 
   1101     ptr = (CvPoint2D32f*)points2->data.fl;
   1102     prev_pt = ptr[(is_closed ? slice.start_index+len-1 : slice.start_index) % total];
   1103 
   1104     for( i = 0; i < len + (len < total && (!is_closed || len==1)); i++ )
   1105     {
   1106         pt = ptr[(i + slice.start_index) % total];
   1107         double dx = pt.x - prev_pt.x, dy = pt.y - prev_pt.y;
   1108         result0 += sqrt(dx*dx + dy*dy);
   1109         prev_pt = pt;
   1110     }
   1111 
   1112     if( cvIsNaN(result) || cvIsInf(result) )
   1113     {
   1114         ts->printf( cvtest::TS::LOG, "cvArcLength() returned invalid value (%g)\n", result );
   1115         code = cvtest::TS::FAIL_INVALID_OUTPUT;
   1116     }
   1117     else if( fabs(result - result0) > FLT_EPSILON*100*result0 )
   1118     {
   1119         ts->printf( cvtest::TS::LOG, "The function returned %g, while the correct result is %g\n", result, result0 );
   1120         code = cvtest::TS::FAIL_BAD_ACCURACY;
   1121     }
   1122 
   1123     if( code < 0 )
   1124         ts->set_failed_test_info( code );
   1125     return code;
   1126 }
   1127 
   1128 
   1129 /****************************************************************************************\
   1130 *                                   FitEllipse Test                                      *
   1131 \****************************************************************************************/
   1132 
   1133 class CV_FitEllipseTest : public CV_BaseShapeDescrTest
   1134 {
   1135 public:
   1136     CV_FitEllipseTest();
   1137 
   1138 protected:
   1139     int prepare_test_case( int test_case_idx );
   1140     void generate_point_set( void* points );
   1141     void run_func(void);
   1142     int validate_test_results( int test_case_idx );
   1143     CvBox2D box0, box;
   1144     double min_ellipse_size, max_noise;
   1145 };
   1146 
   1147 
   1148 CV_FitEllipseTest::CV_FitEllipseTest()
   1149 {
   1150     min_log_size = 5; // for robust ellipse fitting a dozen of points is needed at least
   1151     max_log_size = 10;
   1152     min_ellipse_size = 10;
   1153     max_noise = 0.05;
   1154 }
   1155 
   1156 
   1157 void CV_FitEllipseTest::generate_point_set( void* pointsSet )
   1158 {
   1159     RNG& rng = ts->get_rng();
   1160     int i, total, point_type;
   1161     CvSeqReader reader;
   1162     uchar* data = 0;
   1163     double a, b;
   1164 
   1165     box0.center.x = (float)((low.val[0] + high.val[0])*0.5);
   1166     box0.center.y = (float)((low.val[1] + high.val[1])*0.5);
   1167     box0.size.width = (float)(MAX(high.val[0] - low.val[0], min_ellipse_size)*2);
   1168     box0.size.height = (float)(MAX(high.val[1] - low.val[1], min_ellipse_size)*2);
   1169     box0.angle = (float)(cvtest::randReal(rng)*180);
   1170     a = cos(box0.angle*CV_PI/180.);
   1171     b = sin(box0.angle*CV_PI/180.);
   1172 
   1173     if( box0.size.width > box0.size.height )
   1174     {
   1175         float t;
   1176         CV_SWAP( box0.size.width, box0.size.height, t );
   1177     }
   1178     memset( &reader, 0, sizeof(reader) );
   1179 
   1180     if( CV_IS_SEQ(pointsSet) )
   1181     {
   1182         CvSeq* ptseq = (CvSeq*)pointsSet;
   1183         total = ptseq->total;
   1184         point_type = CV_SEQ_ELTYPE(ptseq);
   1185         cvStartReadSeq( ptseq, &reader );
   1186     }
   1187     else
   1188     {
   1189         CvMat* ptm = (CvMat*)pointsSet;
   1190         assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) );
   1191         total = ptm->rows + ptm->cols - 1;
   1192         point_type = CV_MAT_TYPE(ptm->type);
   1193         data = ptm->data.ptr;
   1194     }
   1195 
   1196     assert( point_type == CV_32SC2 || point_type == CV_32FC2 );
   1197 
   1198     for( i = 0; i < total; i++ )
   1199     {
   1200         CvPoint* pp;
   1201         CvPoint2D32f p;
   1202         double angle = cvtest::randReal(rng)*CV_PI*2;
   1203         double x = box0.size.height*0.5*(cos(angle) + (cvtest::randReal(rng)-0.5)*2*max_noise);
   1204         double y = box0.size.width*0.5*(sin(angle) + (cvtest::randReal(rng)-0.5)*2*max_noise);
   1205         p.x = (float)(box0.center.x + a*x + b*y);
   1206         p.y = (float)(box0.center.y - b*x + a*y);
   1207 
   1208         if( reader.ptr )
   1209         {
   1210             pp = (CvPoint*)reader.ptr;
   1211             CV_NEXT_SEQ_ELEM( sizeof(*pp), reader );
   1212         }
   1213         else
   1214             pp = ((CvPoint*)data) + i;
   1215         if( point_type == CV_32SC2 )
   1216         {
   1217             pp->x = cvRound(p.x);
   1218             pp->y = cvRound(p.y);
   1219         }
   1220         else
   1221             *(CvPoint2D32f*)pp = p;
   1222     }
   1223 }
   1224 
   1225 
   1226 int CV_FitEllipseTest::prepare_test_case( int test_case_idx )
   1227 {
   1228     min_log_size = MAX(min_log_size,4);
   1229     max_log_size = MAX(min_log_size,max_log_size);
   1230     return CV_BaseShapeDescrTest::prepare_test_case( test_case_idx );
   1231 }
   1232 
   1233 
   1234 void CV_FitEllipseTest::run_func()
   1235 {
   1236     if(!test_cpp)
   1237         box = cvFitEllipse2( points );
   1238     else
   1239         box = (CvBox2D)cv::fitEllipse(cv::cvarrToMat(points));
   1240 }
   1241 
   1242 int CV_FitEllipseTest::validate_test_results( int test_case_idx )
   1243 {
   1244     int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
   1245     double diff_angle;
   1246 
   1247     if( cvIsNaN(box.center.x) || cvIsInf(box.center.x) ||
   1248         cvIsNaN(box.center.y) || cvIsInf(box.center.y) ||
   1249         cvIsNaN(box.size.width) || cvIsInf(box.size.width) ||
   1250         cvIsNaN(box.size.height) || cvIsInf(box.size.height) ||
   1251         cvIsNaN(box.angle) || cvIsInf(box.angle) )
   1252     {
   1253         ts->printf( cvtest::TS::LOG, "Some of the computed ellipse parameters are invalid (x=%g,y=%g,w=%g,h=%g,angle=%g)\n",
   1254             box.center.x, box.center.y, box.size.width, box.size.height, box.angle );
   1255         code = cvtest::TS::FAIL_INVALID_OUTPUT;
   1256         goto _exit_;
   1257     }
   1258 
   1259     box.angle = (float)(90-box.angle);
   1260     if( box.angle < 0 )
   1261         box.angle += 360;
   1262     if( box.angle > 360 )
   1263         box.angle -= 360;
   1264 
   1265     if( fabs(box.center.x - box0.center.x) > 3 ||
   1266         fabs(box.center.y - box0.center.y) > 3 ||
   1267         fabs(box.size.width - box0.size.width) > 0.1*fabs(box0.size.width) ||
   1268         fabs(box.size.height - box0.size.height) > 0.1*fabs(box0.size.height) )
   1269     {
   1270         ts->printf( cvtest::TS::LOG, "The computed ellipse center and/or size are incorrect:\n\t"
   1271             "(x=%.1f,y=%.1f,w=%.1f,h=%.1f), while it should be (x=%.1f,y=%.1f,w=%.1f,h=%.1f)\n",
   1272             box.center.x, box.center.y, box.size.width, box.size.height,
   1273             box0.center.x, box0.center.y, box0.size.width, box0.size.height );
   1274         code = cvtest::TS::FAIL_BAD_ACCURACY;
   1275         goto _exit_;
   1276     }
   1277 
   1278     diff_angle = fabs(box0.angle - box.angle);
   1279     diff_angle = MIN( diff_angle, fabs(diff_angle - 360));
   1280     diff_angle = MIN( diff_angle, fabs(diff_angle - 180));
   1281 
   1282     if( box0.size.height >= 1.3*box0.size.width && diff_angle > 30 )
   1283     {
   1284         ts->printf( cvtest::TS::LOG, "Incorrect ellipse angle (=%1.f, should be %1.f)\n",
   1285             box.angle, box0.angle );
   1286         code = cvtest::TS::FAIL_BAD_ACCURACY;
   1287         goto _exit_;
   1288     }
   1289 
   1290 _exit_:
   1291 
   1292 #if 0
   1293     if( code < 0 )
   1294     {
   1295     cvNamedWindow( "test", 0 );
   1296     IplImage* img = cvCreateImage( cvSize(cvRound(low_high_range*4),
   1297         cvRound(low_high_range*4)), 8, 3 );
   1298     cvZero( img );
   1299 
   1300     box.center.x += (float)low_high_range*2;
   1301     box.center.y += (float)low_high_range*2;
   1302     cvEllipseBox( img, box, CV_RGB(255,0,0), 3, 8 );
   1303 
   1304     for( int i = 0; i < points2->rows + points2->cols - 1; i++ )
   1305     {
   1306         CvPoint pt;
   1307         pt.x = cvRound(points2->data.fl[i*2] + low_high_range*2);
   1308         pt.y = cvRound(points2->data.fl[i*2+1] + low_high_range*2);
   1309         cvCircle( img, pt, 1, CV_RGB(255,255,255), -1, 8 );
   1310     }
   1311 
   1312     cvShowImage( "test", img );
   1313     cvReleaseImage( &img );
   1314     cvWaitKey(0);
   1315     }
   1316 #endif
   1317 
   1318     if( code < 0 )
   1319     {
   1320         ts->set_failed_test_info( code );
   1321     }
   1322     return code;
   1323 }
   1324 
   1325 
   1326 class CV_FitEllipseSmallTest : public cvtest::BaseTest
   1327 {
   1328 public:
   1329     CV_FitEllipseSmallTest() {}
   1330     ~CV_FitEllipseSmallTest() {}
   1331 protected:
   1332     void run(int)
   1333     {
   1334         Size sz(50, 50);
   1335         vector<vector<Point> > c;
   1336         c.push_back(vector<Point>());
   1337         int scale = 1;
   1338         Point ofs = Point(0,0);//sz.width/2, sz.height/2) - Point(4,4)*scale;
   1339         c[0].push_back(Point(2, 0)*scale+ofs);
   1340         c[0].push_back(Point(0, 2)*scale+ofs);
   1341         c[0].push_back(Point(0, 6)*scale+ofs);
   1342         c[0].push_back(Point(2, 8)*scale+ofs);
   1343         c[0].push_back(Point(6, 8)*scale+ofs);
   1344         c[0].push_back(Point(8, 6)*scale+ofs);
   1345         c[0].push_back(Point(8, 2)*scale+ofs);
   1346         c[0].push_back(Point(6, 0)*scale+ofs);
   1347 
   1348         RotatedRect e = fitEllipse(c[0]);
   1349         CV_Assert( fabs(e.center.x - 4) <= 1. &&
   1350                    fabs(e.center.y - 4) <= 1. &&
   1351                    fabs(e.size.width - 9) <= 1. &&
   1352                    fabs(e.size.height - 9) <= 1. );
   1353     }
   1354 };
   1355 
   1356 
   1357 // Regression test for incorrect fitEllipse result reported in Bug #3989
   1358 // Check edge cases for rotation angles of ellipse ([-180, 90, 0, 90, 180] degrees)
   1359 class CV_FitEllipseParallelTest : public CV_FitEllipseTest
   1360 {
   1361 public:
   1362     CV_FitEllipseParallelTest();
   1363     ~CV_FitEllipseParallelTest();
   1364 protected:
   1365     void generate_point_set( void* points );
   1366     void run_func(void);
   1367     Mat pointsMat;
   1368 };
   1369 
   1370 CV_FitEllipseParallelTest::CV_FitEllipseParallelTest()
   1371 {
   1372     min_ellipse_size = 5;
   1373 }
   1374 
   1375 void CV_FitEllipseParallelTest::generate_point_set( void* )
   1376 {
   1377     RNG& rng = ts->get_rng();
   1378     int height = (int)(MAX(high.val[0] - low.val[0], min_ellipse_size));
   1379     int width = (int)(MAX(high.val[1] - low.val[1], min_ellipse_size));
   1380     const int angle = ( (cvtest::randInt(rng) % 5) - 2 ) * 90;
   1381     const int dim = max(height, width);
   1382     const Point center = Point(dim*2, dim*2);
   1383 
   1384     if( width > height )
   1385     {
   1386         int t;
   1387         CV_SWAP( width, height, t );
   1388     }
   1389 
   1390     Mat image = Mat::zeros(dim*4, dim*4, CV_8UC1);
   1391     ellipse(image, center, Size(height, width), angle,
   1392             0, 360, Scalar(255, 0, 0), 1, 8);
   1393 
   1394     box0.center.x = (float)center.x;
   1395     box0.center.y = (float)center.y;
   1396     box0.size.width = (float)width*2;
   1397     box0.size.height = (float)height*2;
   1398     box0.angle = (float)angle;
   1399 
   1400     vector<vector<Point> > contours;
   1401     findContours(image, contours,  RETR_EXTERNAL,  CHAIN_APPROX_NONE);
   1402     Mat(contours[0]).convertTo(pointsMat, CV_32F);
   1403 }
   1404 
   1405 void CV_FitEllipseParallelTest::run_func()
   1406 {
   1407     box = (CvBox2D)cv::fitEllipse(pointsMat);
   1408 }
   1409 
   1410 CV_FitEllipseParallelTest::~CV_FitEllipseParallelTest(){
   1411     pointsMat.release();
   1412 }
   1413 
   1414 /****************************************************************************************\
   1415 *                                   FitLine Test                                         *
   1416 \****************************************************************************************/
   1417 
   1418 class CV_FitLineTest : public CV_BaseShapeDescrTest
   1419 {
   1420 public:
   1421     CV_FitLineTest();
   1422 
   1423 protected:
   1424     int prepare_test_case( int test_case_idx );
   1425     void generate_point_set( void* points );
   1426     void run_func(void);
   1427     int validate_test_results( int test_case_idx );
   1428     double max_noise;
   1429     float line[6], line0[6];
   1430     int dist_type;
   1431     double reps, aeps;
   1432 };
   1433 
   1434 
   1435 CV_FitLineTest::CV_FitLineTest()
   1436 {
   1437     min_log_size = 5; // for robust line fitting a dozen of points is needed at least
   1438     max_log_size = 10;
   1439     max_noise = 0.05;
   1440 }
   1441 
   1442 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
   1443 # pragma GCC diagnostic push
   1444 # pragma GCC diagnostic ignored "-Warray-bounds"
   1445 #endif
   1446 
   1447 void CV_FitLineTest::generate_point_set( void* pointsSet )
   1448 {
   1449     RNG& rng = ts->get_rng();
   1450     int i, k, n, total, point_type;
   1451     CvSeqReader reader;
   1452     uchar* data = 0;
   1453     double s = 0;
   1454 
   1455     n = dims;
   1456     for( k = 0; k < n; k++ )
   1457     {
   1458         line0[k+n] = (float)((low.val[k] + high.val[k])*0.5);
   1459         line0[k] = (float)(high.val[k] - low.val[k]);
   1460         if( cvtest::randInt(rng) % 2 )
   1461             line0[k] = -line0[k];
   1462         s += (double)line0[k]*line0[k];
   1463     }
   1464 
   1465     s = 1./sqrt(s);
   1466     for( k = 0; k < n; k++ )
   1467         line0[k] = (float)(line0[k]*s);
   1468 
   1469     memset( &reader, 0, sizeof(reader) );
   1470 
   1471     if( CV_IS_SEQ(pointsSet) )
   1472     {
   1473         CvSeq* ptseq = (CvSeq*)pointsSet;
   1474         total = ptseq->total;
   1475         point_type = CV_MAT_DEPTH(CV_SEQ_ELTYPE(ptseq));
   1476         cvStartReadSeq( ptseq, &reader );
   1477     }
   1478     else
   1479     {
   1480         CvMat* ptm = (CvMat*)pointsSet;
   1481         assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) );
   1482         total = ptm->rows + ptm->cols - 1;
   1483         point_type = CV_MAT_DEPTH(CV_MAT_TYPE(ptm->type));
   1484         data = ptm->data.ptr;
   1485     }
   1486 
   1487     for( i = 0; i < total; i++ )
   1488     {
   1489         int* pi;
   1490         float* pf;
   1491         float p[4], t;
   1492         if( reader.ptr )
   1493         {
   1494             pi = (int*)reader.ptr;
   1495             pf = (float*)reader.ptr;
   1496             CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
   1497         }
   1498         else
   1499         {
   1500             pi = (int*)data + i*n;
   1501             pf = (float*)data + i*n;
   1502         }
   1503 
   1504         t = (float)((cvtest::randReal(rng)-0.5)*low_high_range*2);
   1505 
   1506         for( k = 0; k < n; k++ )
   1507         {
   1508             p[k] = (float)((cvtest::randReal(rng)-0.5)*max_noise*2 + t*line0[k] + line0[k+n]);
   1509 
   1510             if( point_type == CV_32S )
   1511                 pi[k] = cvRound(p[k]);
   1512             else
   1513                 pf[k] = p[k];
   1514         }
   1515     }
   1516 }
   1517 
   1518 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
   1519 # pragma GCC diagnostic pop
   1520 #endif
   1521 
   1522 int CV_FitLineTest::prepare_test_case( int test_case_idx )
   1523 {
   1524     RNG& rng = ts->get_rng();
   1525     dims = cvtest::randInt(rng) % 2 + 2;
   1526     min_log_size = MAX(min_log_size,5);
   1527     max_log_size = MAX(min_log_size,max_log_size);
   1528     int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx );
   1529     dist_type = cvtest::randInt(rng) % 6 + 1;
   1530     dist_type += dist_type == CV_DIST_C;
   1531     reps = 0.1; aeps = 0.01;
   1532     return code;
   1533 }
   1534 
   1535 
   1536 void CV_FitLineTest::run_func()
   1537 {
   1538     if(!test_cpp)
   1539         cvFitLine( points, dist_type, 0, reps, aeps, line );
   1540     else if(dims == 2)
   1541         cv::fitLine(cv::cvarrToMat(points), (cv::Vec4f&)line[0], dist_type, 0, reps, aeps);
   1542     else
   1543         cv::fitLine(cv::cvarrToMat(points), (cv::Vec6f&)line[0], dist_type, 0, reps, aeps);
   1544 }
   1545 
   1546 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
   1547 # pragma GCC diagnostic push
   1548 # pragma GCC diagnostic ignored "-Warray-bounds"
   1549 #endif
   1550 
   1551 int CV_FitLineTest::validate_test_results( int test_case_idx )
   1552 {
   1553     int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
   1554     int k, max_k = 0;
   1555     double vec_diff = 0, t;
   1556 
   1557     for( k = 0; k < dims*2; k++ )
   1558     {
   1559         if( cvIsNaN(line[k]) || cvIsInf(line[k]) )
   1560         {
   1561             ts->printf( cvtest::TS::LOG, "Some of the computed line parameters are invalid (line[%d]=%g)\n",
   1562                 k, line[k] );
   1563             code = cvtest::TS::FAIL_INVALID_OUTPUT;
   1564             goto _exit_;
   1565         }
   1566     }
   1567 
   1568     if( fabs(line0[1]) > fabs(line0[0]) )
   1569         max_k = 1;
   1570     if( fabs(line0[dims-1]) > fabs(line0[max_k]) )
   1571         max_k = dims-1;
   1572     if( line0[max_k] < 0 )
   1573         for( k = 0; k < dims; k++ )
   1574             line0[k] = -line0[k];
   1575     if( line[max_k] < 0 )
   1576         for( k = 0; k < dims; k++ )
   1577             line[k] = -line[k];
   1578 
   1579     for( k = 0; k < dims; k++ )
   1580     {
   1581         double dt = line[k] - line0[k];
   1582         vec_diff += dt*dt;
   1583     }
   1584 
   1585     if( sqrt(vec_diff) > 0.05 )
   1586     {
   1587         if( dims == 2 )
   1588             ts->printf( cvtest::TS::LOG,
   1589                 "The computed line vector (%.2f,%.2f) is different from the actual (%.2f,%.2f)\n",
   1590                 line[0], line[1], line0[0], line0[1] );
   1591         else
   1592             ts->printf( cvtest::TS::LOG,
   1593                 "The computed line vector (%.2f,%.2f,%.2f) is different from the actual (%.2f,%.2f,%.2f)\n",
   1594                 line[0], line[1], line[2], line0[0], line0[1], line0[2] );
   1595         code = cvtest::TS::FAIL_BAD_ACCURACY;
   1596         goto _exit_;
   1597     }
   1598 
   1599     t = (line[max_k+dims] - line0[max_k+dims])/line0[max_k];
   1600     for( k = 0; k < dims; k++ )
   1601     {
   1602         double p = line0[k+dims] + t*line0[k] - line[k+dims];
   1603         vec_diff += p*p;
   1604     }
   1605 
   1606     if( sqrt(vec_diff) > 1*MAX(fabs(t),1) )
   1607     {
   1608         if( dims == 2 )
   1609             ts->printf( cvtest::TS::LOG,
   1610                 "The computed line point (%.2f,%.2f) is too far from the actual line\n",
   1611                 line[2]+line0[2], line[3]+line0[3] );
   1612         else
   1613             ts->printf( cvtest::TS::LOG,
   1614                 "The computed line point (%.2f,%.2f,%.2f) is too far from the actual line\n",
   1615                 line[3]+line0[3], line[4]+line0[4], line[5]+line0[5] );
   1616         code = cvtest::TS::FAIL_BAD_ACCURACY;
   1617         goto _exit_;
   1618     }
   1619 
   1620 _exit_:
   1621 
   1622     if( code < 0 )
   1623     {
   1624         ts->set_failed_test_info( code );
   1625     }
   1626     return code;
   1627 }
   1628 
   1629 #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
   1630 # pragma GCC diagnostic pop
   1631 #endif
   1632 
   1633 /****************************************************************************************\
   1634 *                                   ContourMoments Test                                  *
   1635 \****************************************************************************************/
   1636 
   1637 
   1638 static void
   1639 cvTsGenerateTousledBlob( CvPoint2D32f center, CvSize2D32f axes,
   1640     double max_r_scale, double angle, CvArr* points, RNG& rng )
   1641 {
   1642     int i, total, point_type;
   1643     uchar* data = 0;
   1644     CvSeqReader reader;
   1645     memset( &reader, 0, sizeof(reader) );
   1646 
   1647     if( CV_IS_SEQ(points) )
   1648     {
   1649         CvSeq* ptseq = (CvSeq*)points;
   1650         total = ptseq->total;
   1651         point_type = CV_SEQ_ELTYPE(ptseq);
   1652         cvStartReadSeq( ptseq, &reader );
   1653     }
   1654     else
   1655     {
   1656         CvMat* ptm = (CvMat*)points;
   1657         assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) );
   1658         total = ptm->rows + ptm->cols - 1;
   1659         point_type = CV_MAT_TYPE(ptm->type);
   1660         data = ptm->data.ptr;
   1661     }
   1662 
   1663     assert( point_type == CV_32SC2 || point_type == CV_32FC2 );
   1664 
   1665     for( i = 0; i < total; i++ )
   1666     {
   1667         CvPoint* pp;
   1668         CvPoint2D32f p;
   1669 
   1670         double phi0 = 2*CV_PI*i/total;
   1671         double phi = CV_PI*angle/180.;
   1672         double t = cvtest::randReal(rng)*max_r_scale + (1 - max_r_scale);
   1673         double ta = axes.height*t;
   1674         double tb = axes.width*t;
   1675         double c0 = cos(phi0)*ta, s0 = sin(phi0)*tb;
   1676         double c = cos(phi), s = sin(phi);
   1677         p.x = (float)(c0*c - s0*s + center.x);
   1678         p.y = (float)(c0*s + s0*c + center.y);
   1679 
   1680         if( reader.ptr )
   1681         {
   1682             pp = (CvPoint*)reader.ptr;
   1683             CV_NEXT_SEQ_ELEM( sizeof(*pp), reader );
   1684         }
   1685         else
   1686             pp = ((CvPoint*)data) + i;
   1687 
   1688         if( point_type == CV_32SC2 )
   1689         {
   1690             pp->x = cvRound(p.x);
   1691             pp->y = cvRound(p.y);
   1692         }
   1693         else
   1694             *(CvPoint2D32f*)pp = p;
   1695     }
   1696 }
   1697 
   1698 
   1699 class CV_ContourMomentsTest : public CV_BaseShapeDescrTest
   1700 {
   1701 public:
   1702     CV_ContourMomentsTest();
   1703 
   1704 protected:
   1705     int prepare_test_case( int test_case_idx );
   1706     void generate_point_set( void* points );
   1707     void run_func(void);
   1708     int validate_test_results( int test_case_idx );
   1709     CvMoments moments0, moments;
   1710     double area0, area;
   1711     CvSize2D32f axes;
   1712     CvPoint2D32f center;
   1713     int max_max_r_scale;
   1714     double max_r_scale, angle;
   1715     CvSize img_size;
   1716 };
   1717 
   1718 
   1719 CV_ContourMomentsTest::CV_ContourMomentsTest()
   1720 {
   1721     min_log_size = 3;
   1722     max_log_size = 8;
   1723     max_max_r_scale = 15;
   1724     low_high_range = 200;
   1725     enable_flt_points = false;
   1726 }
   1727 
   1728 
   1729 void CV_ContourMomentsTest::generate_point_set( void* pointsSet )
   1730 {
   1731     RNG& rng = ts->get_rng();
   1732     float max_sz;
   1733 
   1734     axes.width = (float)((cvtest::randReal(rng)*0.9 + 0.1)*low_high_range);
   1735     axes.height = (float)((cvtest::randReal(rng)*0.9 + 0.1)*low_high_range);
   1736     max_sz = MAX(axes.width, axes.height);
   1737 
   1738     img_size.width = img_size.height = cvRound(low_high_range*2.2);
   1739 
   1740     center.x = (float)(img_size.width*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.width - max_sz*2)*0.8);
   1741     center.y = (float)(img_size.height*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.height - max_sz*2)*0.8);
   1742 
   1743     assert( 0 < center.x - max_sz && center.x + max_sz < img_size.width &&
   1744         0 < center.y - max_sz && center.y + max_sz < img_size.height );
   1745 
   1746     max_r_scale = cvtest::randReal(rng)*max_max_r_scale*0.01;
   1747     angle = cvtest::randReal(rng)*360;
   1748 
   1749     cvTsGenerateTousledBlob( center, axes, max_r_scale, angle, pointsSet, rng );
   1750 
   1751     if( points1 )
   1752         points1->flags = CV_SEQ_MAGIC_VAL + CV_SEQ_POLYGON;
   1753 }
   1754 
   1755 
   1756 int CV_ContourMomentsTest::prepare_test_case( int test_case_idx )
   1757 {
   1758     min_log_size = MAX(min_log_size,3);
   1759     max_log_size = MIN(max_log_size,8);
   1760     max_log_size = MAX(min_log_size,max_log_size);
   1761     int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx );
   1762     return code;
   1763 }
   1764 
   1765 
   1766 void CV_ContourMomentsTest::run_func()
   1767 {
   1768     if(!test_cpp)
   1769     {
   1770         cvMoments( points, &moments );
   1771         area = cvContourArea( points );
   1772     }
   1773     else
   1774     {
   1775         moments = (CvMoments)cv::moments(cv::cvarrToMat(points));
   1776         area = cv::contourArea(cv::cvarrToMat(points));
   1777     }
   1778 }
   1779 
   1780 
   1781 int CV_ContourMomentsTest::validate_test_results( int test_case_idx )
   1782 {
   1783     int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
   1784     int i, n = (int)(sizeof(moments)/sizeof(moments.inv_sqrt_m00));
   1785     CvMat* img = cvCreateMat( img_size.height, img_size.width, CV_8UC1 );
   1786     CvPoint* pt = (CvPoint*)points2->data.i;
   1787     int count = points2->cols + points2->rows - 1;
   1788     double max_v0 = 0;
   1789 
   1790     cvZero(img);
   1791     cvFillPoly( img, &pt, &count, 1, cvScalarAll(1));
   1792     cvMoments( img, &moments0 );
   1793 
   1794     for( i = 0; i < n; i++ )
   1795     {
   1796         double t = fabs((&moments0.m00)[i]);
   1797         max_v0 = MAX(max_v0, t);
   1798     }
   1799 
   1800     for( i = 0; i <= n; i++ )
   1801     {
   1802         double v = i < n ? (&moments.m00)[i] : area;
   1803         double v0 = i < n ? (&moments0.m00)[i] : moments0.m00;
   1804 
   1805         if( cvIsNaN(v) || cvIsInf(v) )
   1806         {
   1807             ts->printf( cvtest::TS::LOG,
   1808                 "The contour %s is invalid (=%g)\n", i < n ? "moment" : "area", v );
   1809             code = cvtest::TS::FAIL_INVALID_OUTPUT;
   1810             break;
   1811         }
   1812 
   1813         if( fabs(v - v0) > 0.1*max_v0 )
   1814         {
   1815             ts->printf( cvtest::TS::LOG,
   1816                 "The computed contour %s is %g, while it should be %g\n",
   1817                 i < n ? "moment" : "area", v, v0 );
   1818             code = cvtest::TS::FAIL_BAD_ACCURACY;
   1819             break;
   1820         }
   1821     }
   1822 
   1823     if( code < 0 )
   1824     {
   1825 #if 0
   1826         cvCmpS( img, 0, img, CV_CMP_GT );
   1827         cvNamedWindow( "test", 1 );
   1828         cvShowImage( "test", img );
   1829         cvWaitKey();
   1830 #endif
   1831         ts->set_failed_test_info( code );
   1832     }
   1833 
   1834     cvReleaseMat( &img );
   1835     return code;
   1836 }
   1837 
   1838 
   1839 ////////////////////////////////////// Perimeter/Area/Slice test ///////////////////////////////////
   1840 
   1841 class CV_PerimeterAreaSliceTest : public cvtest::BaseTest
   1842 {
   1843 public:
   1844     CV_PerimeterAreaSliceTest();
   1845     ~CV_PerimeterAreaSliceTest();
   1846 protected:
   1847     void run(int);
   1848 };
   1849 
   1850 CV_PerimeterAreaSliceTest::CV_PerimeterAreaSliceTest()
   1851 {
   1852 }
   1853 CV_PerimeterAreaSliceTest::~CV_PerimeterAreaSliceTest() {}
   1854 
   1855 void CV_PerimeterAreaSliceTest::run( int )
   1856 {
   1857     Ptr<CvMemStorage> storage(cvCreateMemStorage());
   1858     RNG& rng = theRNG();
   1859     const double min_r = 90, max_r = 120;
   1860 
   1861     for( int i = 0; i < 100; i++ )
   1862     {
   1863         ts->update_context( this, i, true );
   1864         int n = rng.uniform(3, 30);
   1865         cvClearMemStorage(storage);
   1866         CvSeq* contour = cvCreateSeq(CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(CvPoint), storage);
   1867         double dphi = CV_PI*2/n;
   1868         CvPoint center;
   1869         center.x = rng.uniform(cvCeil(max_r), cvFloor(640-max_r));
   1870         center.y = rng.uniform(cvCeil(max_r), cvFloor(480-max_r));
   1871 
   1872         for( int j = 0; j < n; j++ )
   1873         {
   1874             CvPoint pt;
   1875             double r = rng.uniform(min_r, max_r);
   1876             double phi = j*dphi;
   1877             pt.x = cvRound(center.x + r*cos(phi));
   1878             pt.y = cvRound(center.y - r*sin(phi));
   1879             cvSeqPush(contour, &pt);
   1880         }
   1881 
   1882         CvSlice slice;
   1883         for(;;)
   1884         {
   1885             slice.start_index = rng.uniform(-n/2, 3*n/2);
   1886             slice.end_index = rng.uniform(-n/2, 3*n/2);
   1887             int len = cvSliceLength(slice, contour);
   1888             if( len > 2 )
   1889                 break;
   1890         }
   1891         CvSeq *cslice = cvSeqSlice(contour, slice);
   1892         /*printf( "%d. (%d, %d) of %d, length = %d, length1 = %d\n",
   1893                i, slice.start_index, slice.end_index,
   1894                contour->total, cvSliceLength(slice, contour), cslice->total );
   1895 
   1896         double area0 = cvContourArea(cslice);
   1897         double area1 = cvContourArea(contour, slice);
   1898         if( area0 != area1 )
   1899         {
   1900             ts->printf(cvtest::TS::LOG,
   1901                        "The contour area slice is computed differently (%g vs %g)\n", area0, area1 );
   1902             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
   1903             return;
   1904         }*/
   1905 
   1906         double len0 = cvArcLength(cslice, CV_WHOLE_SEQ, 1);
   1907         double len1 = cvArcLength(contour, slice, 1);
   1908         if( len0 != len1 )
   1909         {
   1910             ts->printf(cvtest::TS::LOG,
   1911                        "The contour arc length is computed differently (%g vs %g)\n", len0, len1 );
   1912             ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
   1913             return;
   1914         }
   1915     }
   1916     ts->set_failed_test_info(cvtest::TS::OK);
   1917 }
   1918 
   1919 
   1920 TEST(Imgproc_ConvexHull, accuracy) { CV_ConvHullTest test; test.safe_run(); }
   1921 TEST(Imgproc_MinAreaRect, accuracy) { CV_MinAreaRectTest test; test.safe_run(); }
   1922 TEST(Imgproc_MinTriangle, accuracy) { CV_MinTriangleTest test; test.safe_run(); }
   1923 TEST(Imgproc_MinCircle, accuracy) { CV_MinCircleTest test; test.safe_run(); }
   1924 TEST(Imgproc_ContourPerimeter, accuracy) { CV_PerimeterTest test; test.safe_run(); }
   1925 TEST(Imgproc_FitEllipse, accuracy) { CV_FitEllipseTest test; test.safe_run(); }
   1926 TEST(Imgproc_FitEllipse, parallel) { CV_FitEllipseParallelTest test; test.safe_run(); }
   1927 TEST(Imgproc_FitLine, accuracy) { CV_FitLineTest test; test.safe_run(); }
   1928 TEST(Imgproc_ContourMoments, accuracy) { CV_ContourMomentsTest test; test.safe_run(); }
   1929 TEST(Imgproc_ContourPerimeterSlice, accuracy) { CV_PerimeterAreaSliceTest test; test.safe_run(); }
   1930 TEST(Imgproc_FitEllipse, small) { CV_FitEllipseSmallTest test; test.safe_run(); }
   1931 
   1932 /* End of file. */
   1933