Home | History | Annotate | Download | only in src
      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 "_cv.h"
     42 
     43 /* calculates length of a curve (e.g. contour perimeter) */
     44 CV_IMPL  double
     45 cvArcLength( const void *array, CvSlice slice, int is_closed )
     46 {
     47     double perimeter = 0;
     48 
     49     CV_FUNCNAME( "cvArcLength" );
     50 
     51     __BEGIN__;
     52 
     53     int i, j = 0, count;
     54     const int N = 16;
     55     float buf[N];
     56     CvMat buffer = cvMat( 1, N, CV_32F, buf );
     57     CvSeqReader reader;
     58     CvContour contour_header;
     59     CvSeq* contour = 0;
     60     CvSeqBlock block;
     61 
     62     if( CV_IS_SEQ( array ))
     63     {
     64         contour = (CvSeq*)array;
     65         if( !CV_IS_SEQ_POLYLINE( contour ))
     66             CV_ERROR( CV_StsBadArg, "Unsupported sequence type" );
     67         if( is_closed < 0 )
     68             is_closed = CV_IS_SEQ_CLOSED( contour );
     69     }
     70     else
     71     {
     72         is_closed = is_closed > 0;
     73         CV_CALL( contour = cvPointSeqFromMat(
     74             CV_SEQ_KIND_CURVE | (is_closed ? CV_SEQ_FLAG_CLOSED : 0),
     75             array, &contour_header, &block ));
     76     }
     77 
     78     if( contour->total > 1 )
     79     {
     80         int is_float = CV_SEQ_ELTYPE( contour ) == CV_32FC2;
     81 
     82         cvStartReadSeq( contour, &reader, 0 );
     83         cvSetSeqReaderPos( &reader, slice.start_index );
     84         count = cvSliceLength( slice, contour );
     85 
     86         count -= !is_closed && count == contour->total;
     87 
     88         /* scroll the reader by 1 point */
     89         reader.prev_elem = reader.ptr;
     90         CV_NEXT_SEQ_ELEM( sizeof(CvPoint), reader );
     91 
     92         for( i = 0; i < count; i++ )
     93         {
     94             float dx, dy;
     95 
     96             if( !is_float )
     97             {
     98                 CvPoint* pt = (CvPoint*)reader.ptr;
     99                 CvPoint* prev_pt = (CvPoint*)reader.prev_elem;
    100 
    101                 dx = (float)pt->x - (float)prev_pt->x;
    102                 dy = (float)pt->y - (float)prev_pt->y;
    103             }
    104             else
    105             {
    106                 CvPoint2D32f* pt = (CvPoint2D32f*)reader.ptr;
    107                 CvPoint2D32f* prev_pt = (CvPoint2D32f*)reader.prev_elem;
    108 
    109                 dx = pt->x - prev_pt->x;
    110                 dy = pt->y - prev_pt->y;
    111             }
    112 
    113             reader.prev_elem = reader.ptr;
    114             CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
    115 
    116             buffer.data.fl[j] = dx * dx + dy * dy;
    117             if( ++j == N || i == count - 1 )
    118             {
    119                 buffer.cols = j;
    120                 cvPow( &buffer, &buffer, 0.5 );
    121                 for( ; j > 0; j-- )
    122                     perimeter += buffer.data.fl[j-1];
    123             }
    124         }
    125     }
    126 
    127     __END__;
    128 
    129     return perimeter;
    130 }
    131 
    132 
    133 static CvStatus
    134 icvFindCircle( CvPoint2D32f pt0, CvPoint2D32f pt1,
    135                CvPoint2D32f pt2, CvPoint2D32f * center, float *radius )
    136 {
    137     double x1 = (pt0.x + pt1.x) * 0.5;
    138     double dy1 = pt0.x - pt1.x;
    139     double x2 = (pt1.x + pt2.x) * 0.5;
    140     double dy2 = pt1.x - pt2.x;
    141     double y1 = (pt0.y + pt1.y) * 0.5;
    142     double dx1 = pt1.y - pt0.y;
    143     double y2 = (pt1.y + pt2.y) * 0.5;
    144     double dx2 = pt2.y - pt1.y;
    145     double t = 0;
    146 
    147     CvStatus result = CV_OK;
    148 
    149     if( icvIntersectLines( x1, dx1, y1, dy1, x2, dx2, y2, dy2, &t ) >= 0 )
    150     {
    151         center->x = (float) (x2 + dx2 * t);
    152         center->y = (float) (y2 + dy2 * t);
    153         *radius = (float) icvDistanceL2_32f( *center, pt0 );
    154     }
    155     else
    156     {
    157         center->x = center->y = 0.f;
    158         radius = 0;
    159         result = CV_NOTDEFINED_ERR;
    160     }
    161 
    162     return result;
    163 }
    164 
    165 
    166 CV_INLINE double icvIsPtInCircle( CvPoint2D32f pt, CvPoint2D32f center, float radius )
    167 {
    168     double dx = pt.x - center.x;
    169     double dy = pt.y - center.y;
    170     return (double)radius*radius - dx*dx - dy*dy;
    171 }
    172 
    173 
    174 static int
    175 icvFindEnslosingCicle4pts_32f( CvPoint2D32f * pts, CvPoint2D32f * _center, float *_radius )
    176 {
    177     int shuffles[4][4] = { {0, 1, 2, 3}, {0, 1, 3, 2}, {2, 3, 0, 1}, {2, 3, 1, 0} };
    178 
    179     int idxs[4] = { 0, 1, 2, 3 };
    180     int i, j, k = 1, mi = 0;
    181     float max_dist = 0;
    182     CvPoint2D32f center;
    183     CvPoint2D32f min_center;
    184     float radius, min_radius = FLT_MAX;
    185     CvPoint2D32f res_pts[4];
    186 
    187     center = min_center = pts[0];
    188     radius = 1.f;
    189 
    190     for( i = 0; i < 4; i++ )
    191         for( j = i + 1; j < 4; j++ )
    192         {
    193             float dist = icvDistanceL2_32f( pts[i], pts[j] );
    194 
    195             if( max_dist < dist )
    196             {
    197                 max_dist = dist;
    198                 idxs[0] = i;
    199                 idxs[1] = j;
    200             }
    201         }
    202 
    203     if( max_dist == 0 )
    204         goto function_exit;
    205 
    206     k = 2;
    207     for( i = 0; i < 4; i++ )
    208     {
    209         for( j = 0; j < k; j++ )
    210             if( i == idxs[j] )
    211                 break;
    212         if( j == k )
    213             idxs[k++] = i;
    214     }
    215 
    216     center = cvPoint2D32f( (pts[idxs[0]].x + pts[idxs[1]].x)*0.5f,
    217                            (pts[idxs[0]].y + pts[idxs[1]].y)*0.5f );
    218     radius = (float)(icvDistanceL2_32f( pts[idxs[0]], center )*1.03);
    219     if( radius < 1.f )
    220         radius = 1.f;
    221 
    222     if( icvIsPtInCircle( pts[idxs[2]], center, radius ) >= 0 &&
    223         icvIsPtInCircle( pts[idxs[3]], center, radius ) >= 0 )
    224     {
    225         k = 2; //rand()%2+2;
    226     }
    227     else
    228     {
    229         mi = -1;
    230         for( i = 0; i < 4; i++ )
    231         {
    232             if( icvFindCircle( pts[shuffles[i][0]], pts[shuffles[i][1]],
    233                                pts[shuffles[i][2]], &center, &radius ) >= 0 )
    234             {
    235                 radius *= 1.03f;
    236                 if( radius < 2.f )
    237                     radius = 2.f;
    238 
    239                 if( icvIsPtInCircle( pts[shuffles[i][3]], center, radius ) >= 0 &&
    240                     min_radius > radius )
    241                 {
    242                     min_radius = radius;
    243                     min_center = center;
    244                     mi = i;
    245                 }
    246             }
    247         }
    248         assert( mi >= 0 );
    249         if( mi < 0 )
    250             mi = 0;
    251         k = 3;
    252         center = min_center;
    253         radius = min_radius;
    254         for( i = 0; i < 4; i++ )
    255             idxs[i] = shuffles[mi][i];
    256     }
    257 
    258   function_exit:
    259 
    260     *_center = center;
    261     *_radius = radius;
    262 
    263     /* reorder output points */
    264     for( i = 0; i < 4; i++ )
    265         res_pts[i] = pts[idxs[i]];
    266 
    267     for( i = 0; i < 4; i++ )
    268     {
    269         pts[i] = res_pts[i];
    270         assert( icvIsPtInCircle( pts[i], center, radius ) >= 0 );
    271     }
    272 
    273     return k;
    274 }
    275 
    276 
    277 CV_IMPL int
    278 cvMinEnclosingCircle( const void* array, CvPoint2D32f * _center, float *_radius )
    279 {
    280     const int max_iters = 100;
    281     const float eps = FLT_EPSILON*2;
    282     CvPoint2D32f center = { 0, 0 };
    283     float radius = 0;
    284     int result = 0;
    285 
    286     if( _center )
    287         _center->x = _center->y = 0.f;
    288     if( _radius )
    289         *_radius = 0;
    290 
    291     CV_FUNCNAME( "cvMinEnclosingCircle" );
    292 
    293     __BEGIN__;
    294 
    295     CvSeqReader reader;
    296     int i, k, count;
    297     CvPoint2D32f pts[8];
    298     CvContour contour_header;
    299     CvSeqBlock block;
    300     CvSeq* sequence = 0;
    301     int is_float;
    302 
    303     if( !_center || !_radius )
    304         CV_ERROR( CV_StsNullPtr, "Null center or radius pointers" );
    305 
    306     if( CV_IS_SEQ(array) )
    307     {
    308         sequence = (CvSeq*)array;
    309         if( !CV_IS_SEQ_POINT_SET( sequence ))
    310             CV_ERROR( CV_StsBadArg, "The passed sequence is not a valid contour" );
    311     }
    312     else
    313     {
    314         CV_CALL( sequence = cvPointSeqFromMat(
    315             CV_SEQ_KIND_GENERIC, array, &contour_header, &block ));
    316     }
    317 
    318     if( sequence->total <= 0 )
    319         CV_ERROR_FROM_STATUS( CV_BADSIZE_ERR );
    320 
    321     CV_CALL( cvStartReadSeq( sequence, &reader, 0 ));
    322 
    323     count = sequence->total;
    324     is_float = CV_SEQ_ELTYPE(sequence) == CV_32FC2;
    325 
    326     if( !is_float )
    327     {
    328         CvPoint *pt_left, *pt_right, *pt_top, *pt_bottom;
    329         CvPoint pt;
    330         pt_left = pt_right = pt_top = pt_bottom = (CvPoint *)(reader.ptr);
    331         CV_READ_SEQ_ELEM( pt, reader );
    332 
    333         for( i = 1; i < count; i++ )
    334         {
    335             CvPoint* pt_ptr = (CvPoint*)reader.ptr;
    336             CV_READ_SEQ_ELEM( pt, reader );
    337 
    338             if( pt.x < pt_left->x )
    339                 pt_left = pt_ptr;
    340             if( pt.x > pt_right->x )
    341                 pt_right = pt_ptr;
    342             if( pt.y < pt_top->y )
    343                 pt_top = pt_ptr;
    344             if( pt.y > pt_bottom->y )
    345                 pt_bottom = pt_ptr;
    346         }
    347 
    348         pts[0] = cvPointTo32f( *pt_left );
    349         pts[1] = cvPointTo32f( *pt_right );
    350         pts[2] = cvPointTo32f( *pt_top );
    351         pts[3] = cvPointTo32f( *pt_bottom );
    352     }
    353     else
    354     {
    355         CvPoint2D32f *pt_left, *pt_right, *pt_top, *pt_bottom;
    356         CvPoint2D32f pt;
    357         pt_left = pt_right = pt_top = pt_bottom = (CvPoint2D32f *) (reader.ptr);
    358         CV_READ_SEQ_ELEM( pt, reader );
    359 
    360         for( i = 1; i < count; i++ )
    361         {
    362             CvPoint2D32f* pt_ptr = (CvPoint2D32f*)reader.ptr;
    363             CV_READ_SEQ_ELEM( pt, reader );
    364 
    365             if( pt.x < pt_left->x )
    366                 pt_left = pt_ptr;
    367             if( pt.x > pt_right->x )
    368                 pt_right = pt_ptr;
    369             if( pt.y < pt_top->y )
    370                 pt_top = pt_ptr;
    371             if( pt.y > pt_bottom->y )
    372                 pt_bottom = pt_ptr;
    373         }
    374 
    375         pts[0] = *pt_left;
    376         pts[1] = *pt_right;
    377         pts[2] = *pt_top;
    378         pts[3] = *pt_bottom;
    379     }
    380 
    381     for( k = 0; k < max_iters; k++ )
    382     {
    383         double min_delta = 0, delta;
    384         CvPoint2D32f ptfl;
    385 
    386         icvFindEnslosingCicle4pts_32f( pts, &center, &radius );
    387         cvStartReadSeq( sequence, &reader, 0 );
    388 
    389         for( i = 0; i < count; i++ )
    390         {
    391             if( !is_float )
    392             {
    393                 ptfl.x = (float)((CvPoint*)reader.ptr)->x;
    394                 ptfl.y = (float)((CvPoint*)reader.ptr)->y;
    395             }
    396             else
    397             {
    398                 ptfl = *(CvPoint2D32f*)reader.ptr;
    399             }
    400             CV_NEXT_SEQ_ELEM( sequence->elem_size, reader );
    401 
    402             delta = icvIsPtInCircle( ptfl, center, radius );
    403             if( delta < min_delta )
    404             {
    405                 min_delta = delta;
    406                 pts[3] = ptfl;
    407             }
    408         }
    409         result = min_delta >= 0;
    410         if( result )
    411             break;
    412     }
    413 
    414     if( !result )
    415     {
    416         cvStartReadSeq( sequence, &reader, 0 );
    417         radius = 0.f;
    418 
    419         for( i = 0; i < count; i++ )
    420         {
    421             CvPoint2D32f ptfl;
    422             float t, dx, dy;
    423 
    424             if( !is_float )
    425             {
    426                 ptfl.x = (float)((CvPoint*)reader.ptr)->x;
    427                 ptfl.y = (float)((CvPoint*)reader.ptr)->y;
    428             }
    429             else
    430             {
    431                 ptfl = *(CvPoint2D32f*)reader.ptr;
    432             }
    433 
    434             CV_NEXT_SEQ_ELEM( sequence->elem_size, reader );
    435             dx = center.x - ptfl.x;
    436             dy = center.y - ptfl.y;
    437             t = dx*dx + dy*dy;
    438             radius = MAX(radius,t);
    439         }
    440 
    441         radius = (float)(sqrt(radius)*(1 + eps));
    442         result = 1;
    443     }
    444 
    445     __END__;
    446 
    447     *_center = center;
    448     *_radius = radius;
    449 
    450     return result;
    451 }
    452 
    453 
    454 /* area of a whole sequence */
    455 static CvStatus
    456 icvContourArea( const CvSeq* contour, double *area )
    457 {
    458     if( contour->total )
    459     {
    460         CvSeqReader reader;
    461         int lpt = contour->total;
    462         double a00 = 0, xi_1, yi_1;
    463         int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2;
    464 
    465         cvStartReadSeq( contour, &reader, 0 );
    466 
    467         if( !is_float )
    468         {
    469             xi_1 = ((CvPoint*)(reader.ptr))->x;
    470             yi_1 = ((CvPoint*)(reader.ptr))->y;
    471         }
    472         else
    473         {
    474             xi_1 = ((CvPoint2D32f*)(reader.ptr))->x;
    475             yi_1 = ((CvPoint2D32f*)(reader.ptr))->y;
    476         }
    477         CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
    478 
    479         while( lpt-- > 0 )
    480         {
    481             double dxy, xi, yi;
    482 
    483             if( !is_float )
    484             {
    485                 xi = ((CvPoint*)(reader.ptr))->x;
    486                 yi = ((CvPoint*)(reader.ptr))->y;
    487             }
    488             else
    489             {
    490                 xi = ((CvPoint2D32f*)(reader.ptr))->x;
    491                 yi = ((CvPoint2D32f*)(reader.ptr))->y;
    492             }
    493             CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
    494 
    495             dxy = xi_1 * yi - xi * yi_1;
    496             a00 += dxy;
    497             xi_1 = xi;
    498             yi_1 = yi;
    499         }
    500 
    501         *area = a00 * 0.5;
    502     }
    503     else
    504         *area = 0;
    505 
    506     return CV_OK;
    507 }
    508 
    509 
    510 /****************************************************************************************\
    511 
    512  copy data from one buffer to other buffer
    513 
    514 \****************************************************************************************/
    515 
    516 static CvStatus
    517 icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max )
    518 {
    519     int bb;
    520 
    521     if( (*buf1 == NULL && *buf2 == NULL) || *buf3 == NULL )
    522         return CV_NULLPTR_ERR;
    523 
    524     bb = *b_max;
    525     if( *buf2 == NULL )
    526     {
    527         *b_max = 2 * (*b_max);
    528         *buf2 = (double *)cvAlloc( (*b_max) * sizeof( double ));
    529 
    530         if( *buf2 == NULL )
    531             return CV_OUTOFMEM_ERR;
    532 
    533         memcpy( *buf2, *buf3, bb * sizeof( double ));
    534 
    535         *buf3 = *buf2;
    536         cvFree( buf1 );
    537         *buf1 = NULL;
    538     }
    539     else
    540     {
    541         *b_max = 2 * (*b_max);
    542         *buf1 = (double *) cvAlloc( (*b_max) * sizeof( double ));
    543 
    544         if( *buf1 == NULL )
    545             return CV_OUTOFMEM_ERR;
    546 
    547         memcpy( *buf1, *buf3, bb * sizeof( double ));
    548 
    549         *buf3 = *buf1;
    550         cvFree( buf2 );
    551         *buf2 = NULL;
    552     }
    553     return CV_OK;
    554 }
    555 
    556 
    557 /* area of a contour sector */
    558 static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area )
    559 {
    560     CvPoint pt;                 /*  pointer to points   */
    561     CvPoint pt_s, pt_e;         /*  first and last points  */
    562     CvSeqReader reader;         /*  points reader of contour   */
    563 
    564     int p_max = 2, p_ind;
    565     int lpt, flag, i;
    566     double a00;                 /* unnormalized moments m00    */
    567     double xi, yi, xi_1, yi_1, x0, y0, dxy, sk, sk1, t;
    568     double x_s, y_s, nx, ny, dx, dy, du, dv;
    569     double eps = 1.e-5;
    570     double *p_are1, *p_are2, *p_are;
    571 
    572     assert( contour != NULL );
    573 
    574     if( contour == NULL )
    575         return CV_NULLPTR_ERR;
    576 
    577     if( !CV_IS_SEQ_POLYGON( contour ))
    578         return CV_BADFLAG_ERR;
    579 
    580     lpt = cvSliceLength( slice, contour );
    581     /*if( n2 >= n1 )
    582         lpt = n2 - n1 + 1;
    583     else
    584         lpt = contour->total - n1 + n2 + 1;*/
    585 
    586     if( contour->total && lpt > 2 )
    587     {
    588         a00 = x0 = y0 = xi_1 = yi_1 = 0;
    589         sk1 = 0;
    590         flag = 0;
    591         dxy = 0;
    592         p_are1 = (double *) cvAlloc( p_max * sizeof( double ));
    593 
    594         if( p_are1 == NULL )
    595             return CV_OUTOFMEM_ERR;
    596 
    597         p_are = p_are1;
    598         p_are2 = NULL;
    599 
    600         cvStartReadSeq( contour, &reader, 0 );
    601         cvSetSeqReaderPos( &reader, slice.start_index );
    602         CV_READ_SEQ_ELEM( pt_s, reader );
    603         p_ind = 0;
    604         cvSetSeqReaderPos( &reader, slice.end_index );
    605         CV_READ_SEQ_ELEM( pt_e, reader );
    606 
    607 /*    normal coefficients    */
    608         nx = pt_s.y - pt_e.y;
    609         ny = pt_e.x - pt_s.x;
    610         cvSetSeqReaderPos( &reader, slice.start_index );
    611 
    612         while( lpt-- > 0 )
    613         {
    614             CV_READ_SEQ_ELEM( pt, reader );
    615 
    616             if( flag == 0 )
    617             {
    618                 xi_1 = (double) pt.x;
    619                 yi_1 = (double) pt.y;
    620                 x0 = xi_1;
    621                 y0 = yi_1;
    622                 sk1 = 0;
    623                 flag = 1;
    624             }
    625             else
    626             {
    627                 xi = (double) pt.x;
    628                 yi = (double) pt.y;
    629 
    630 /****************   edges intersection examination   **************************/
    631                 sk = nx * (xi - pt_s.x) + ny * (yi - pt_s.y);
    632                 if( (fabs( sk ) < eps && lpt > 0) || sk * sk1 < -eps )
    633                 {
    634                     if( fabs( sk ) < eps )
    635                     {
    636                         dxy = xi_1 * yi - xi * yi_1;
    637                         a00 = a00 + dxy;
    638                         dxy = xi * y0 - x0 * yi;
    639                         a00 = a00 + dxy;
    640 
    641                         if( p_ind >= p_max )
    642                             icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
    643 
    644                         p_are[p_ind] = a00 / 2.;
    645                         p_ind++;
    646                         a00 = 0;
    647                         sk1 = 0;
    648                         x0 = xi;
    649                         y0 = yi;
    650                         dxy = 0;
    651                     }
    652                     else
    653                     {
    654 /*  define intersection point    */
    655                         dv = yi - yi_1;
    656                         du = xi - xi_1;
    657                         dx = ny;
    658                         dy = -nx;
    659                         if( fabs( du ) > eps )
    660                             t = ((yi_1 - pt_s.y) * du + dv * (pt_s.x - xi_1)) /
    661                                 (du * dy - dx * dv);
    662                         else
    663                             t = (xi_1 - pt_s.x) / dx;
    664                         if( t > eps && t < 1 - eps )
    665                         {
    666                             x_s = pt_s.x + t * dx;
    667                             y_s = pt_s.y + t * dy;
    668                             dxy = xi_1 * y_s - x_s * yi_1;
    669                             a00 += dxy;
    670                             dxy = x_s * y0 - x0 * y_s;
    671                             a00 += dxy;
    672                             if( p_ind >= p_max )
    673                                 icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
    674 
    675                             p_are[p_ind] = a00 / 2.;
    676                             p_ind++;
    677 
    678                             a00 = 0;
    679                             sk1 = 0;
    680                             x0 = x_s;
    681                             y0 = y_s;
    682                             dxy = x_s * yi - xi * y_s;
    683                         }
    684                     }
    685                 }
    686                 else
    687                     dxy = xi_1 * yi - xi * yi_1;
    688 
    689                 a00 += dxy;
    690                 xi_1 = xi;
    691                 yi_1 = yi;
    692                 sk1 = sk;
    693 
    694             }
    695         }
    696 
    697         xi = x0;
    698         yi = y0;
    699         dxy = xi_1 * yi - xi * yi_1;
    700 
    701         a00 += dxy;
    702 
    703         if( p_ind >= p_max )
    704             icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
    705 
    706         p_are[p_ind] = a00 / 2.;
    707         p_ind++;
    708 
    709 /*     common area calculation    */
    710         *area = 0;
    711         for( i = 0; i < p_ind; i++ )
    712             (*area) += fabs( p_are[i] );
    713 
    714         if( p_are1 != NULL )
    715             cvFree( &p_are1 );
    716         else if( p_are2 != NULL )
    717             cvFree( &p_are2 );
    718 
    719         return CV_OK;
    720     }
    721     else
    722         return CV_BADSIZE_ERR;
    723 }
    724 
    725 
    726 /* external contour area function */
    727 CV_IMPL double
    728 cvContourArea( const void *array, CvSlice slice )
    729 {
    730     double area = 0;
    731 
    732     CV_FUNCNAME( "cvContourArea" );
    733 
    734     __BEGIN__;
    735 
    736     CvContour contour_header;
    737     CvSeq* contour = 0;
    738     CvSeqBlock block;
    739 
    740     if( CV_IS_SEQ( array ))
    741     {
    742         contour = (CvSeq*)array;
    743         if( !CV_IS_SEQ_POLYLINE( contour ))
    744             CV_ERROR( CV_StsBadArg, "Unsupported sequence type" );
    745     }
    746     else
    747     {
    748         CV_CALL( contour = cvPointSeqFromMat(
    749             CV_SEQ_KIND_CURVE, array, &contour_header, &block ));
    750     }
    751 
    752     if( cvSliceLength( slice, contour ) == contour->total )
    753     {
    754         IPPI_CALL( icvContourArea( contour, &area ));
    755     }
    756     else
    757     {
    758         if( CV_SEQ_ELTYPE( contour ) != CV_32SC2 )
    759             CV_ERROR( CV_StsUnsupportedFormat,
    760             "Only curves with integer coordinates are supported in case of contour slice" );
    761         IPPI_CALL( icvContourSecArea( contour, slice, &area ));
    762     }
    763 
    764     __END__;
    765 
    766     return area;
    767 }
    768 
    769 
    770 /* for now this function works bad with singular cases
    771    You can see in the code, that when some troubles with
    772    matrices or some variables occur -
    773    box filled with zero values is returned.
    774    However in general function works fine.
    775 */
    776 static void
    777 icvFitEllipse_F( CvSeq* points, CvBox2D* box )
    778 {
    779     CvMat* D = 0;
    780 
    781     CV_FUNCNAME( "icvFitEllipse_F" );
    782 
    783     __BEGIN__;
    784 
    785     double S[36], C[36], T[36];
    786 
    787     int i, j;
    788     double eigenvalues[6], eigenvectors[36];
    789     double a, b, c, d, e, f;
    790     double x0, y0, idet, scale, offx = 0, offy = 0;
    791 
    792     int n = points->total;
    793     CvSeqReader reader;
    794     int is_float = CV_SEQ_ELTYPE(points) == CV_32FC2;
    795 
    796     CvMat _S = cvMat(6,6,CV_64F,S), _C = cvMat(6,6,CV_64F,C), _T = cvMat(6,6,CV_64F,T);
    797     CvMat _EIGVECS = cvMat(6,6,CV_64F,eigenvectors), _EIGVALS = cvMat(6,1,CV_64F,eigenvalues);
    798 
    799     /* create matrix D of  input points */
    800     CV_CALL( D = cvCreateMat( n, 6, CV_64F ));
    801 
    802     cvStartReadSeq( points, &reader );
    803 
    804     /* shift all points to zero */
    805     for( i = 0; i < n; i++ )
    806     {
    807         if( !is_float )
    808         {
    809             offx += ((CvPoint*)reader.ptr)->x;
    810             offy += ((CvPoint*)reader.ptr)->y;
    811         }
    812         else
    813         {
    814             offx += ((CvPoint2D32f*)reader.ptr)->x;
    815             offy += ((CvPoint2D32f*)reader.ptr)->y;
    816         }
    817         CV_NEXT_SEQ_ELEM( points->elem_size, reader );
    818     }
    819 
    820     offx /= n;
    821     offy /= n;
    822 
    823     // fill matrix rows as (x*x, x*y, y*y, x, y, 1 )
    824     for( i = 0; i < n; i++ )
    825     {
    826         double x, y;
    827         double* Dptr = D->data.db + i*6;
    828 
    829         if( !is_float )
    830         {
    831             x = ((CvPoint*)reader.ptr)->x - offx;
    832             y = ((CvPoint*)reader.ptr)->y - offy;
    833         }
    834         else
    835         {
    836             x = ((CvPoint2D32f*)reader.ptr)->x - offx;
    837             y = ((CvPoint2D32f*)reader.ptr)->y - offy;
    838         }
    839         CV_NEXT_SEQ_ELEM( points->elem_size, reader );
    840 
    841         Dptr[0] = x * x;
    842         Dptr[1] = x * y;
    843         Dptr[2] = y * y;
    844         Dptr[3] = x;
    845         Dptr[4] = y;
    846         Dptr[5] = 1.;
    847     }
    848 
    849     // S = D^t*D
    850     cvMulTransposed( D, &_S, 1 );
    851     cvSVD( &_S, &_EIGVALS, &_EIGVECS, 0, CV_SVD_MODIFY_A + CV_SVD_U_T );
    852 
    853     for( i = 0; i < 6; i++ )
    854     {
    855         double a = eigenvalues[i];
    856         a = a < DBL_EPSILON ? 0 : 1./sqrt(sqrt(a));
    857         for( j = 0; j < 6; j++ )
    858             eigenvectors[i*6 + j] *= a;
    859     }
    860 
    861     // C = Q^-1 = transp(INVEIGV) * INVEIGV
    862     cvMulTransposed( &_EIGVECS, &_C, 1 );
    863 
    864     cvZero( &_S );
    865     S[2] = 2.;
    866     S[7] = -1.;
    867     S[12] = 2.;
    868 
    869     // S = Q^-1*S*Q^-1
    870     cvMatMul( &_C, &_S, &_T );
    871     cvMatMul( &_T, &_C, &_S );
    872 
    873     // and find its eigenvalues and vectors too
    874     //cvSVD( &_S, &_EIGVALS, &_EIGVECS, 0, CV_SVD_MODIFY_A + CV_SVD_U_T );
    875     cvEigenVV( &_S, &_EIGVECS, &_EIGVALS, 0 );
    876 
    877     for( i = 0; i < 3; i++ )
    878         if( eigenvalues[i] > 0 )
    879             break;
    880 
    881     if( i >= 3 /*eigenvalues[0] < DBL_EPSILON*/ )
    882     {
    883         box->center.x = box->center.y =
    884         box->size.width = box->size.height =
    885         box->angle = 0.f;
    886         EXIT;
    887     }
    888 
    889     // now find truthful eigenvector
    890     _EIGVECS = cvMat( 6, 1, CV_64F, eigenvectors + 6*i );
    891     _T = cvMat( 6, 1, CV_64F, T );
    892     // Q^-1*eigenvecs[0]
    893     cvMatMul( &_C, &_EIGVECS, &_T );
    894 
    895     // extract vector components
    896     a = T[0]; b = T[1]; c = T[2]; d = T[3]; e = T[4]; f = T[5];
    897 
    898     ///////////////// extract ellipse axes from above values ////////////////
    899 
    900     /*
    901        1) find center of ellipse
    902        it satisfy equation
    903        | a     b/2 | *  | x0 | +  | d/2 | = |0 |
    904        | b/2    c  |    | y0 |    | e/2 |   |0 |
    905 
    906      */
    907     idet = a * c - b * b * 0.25;
    908     idet = idet > DBL_EPSILON ? 1./idet : 0;
    909 
    910     // we must normalize (a b c d e f ) to fit (4ac-b^2=1)
    911     scale = sqrt( 0.25 * idet );
    912 
    913     if( scale < DBL_EPSILON )
    914     {
    915         box->center.x = (float)offx;
    916         box->center.y = (float)offy;
    917         box->size.width = box->size.height = box->angle = 0.f;
    918         EXIT;
    919     }
    920 
    921     a *= scale;
    922     b *= scale;
    923     c *= scale;
    924     d *= scale;
    925     e *= scale;
    926     f *= scale;
    927 
    928     x0 = (-d * c + e * b * 0.5) * 2.;
    929     y0 = (-a * e + d * b * 0.5) * 2.;
    930 
    931     // recover center
    932     box->center.x = (float)(x0 + offx);
    933     box->center.y = (float)(y0 + offy);
    934 
    935     // offset ellipse to (x0,y0)
    936     // new f == F(x0,y0)
    937     f += a * x0 * x0 + b * x0 * y0 + c * y0 * y0 + d * x0 + e * y0;
    938 
    939     if( fabs(f) < DBL_EPSILON )
    940     {
    941         box->size.width = box->size.height = box->angle = 0.f;
    942         EXIT;
    943     }
    944 
    945     scale = -1. / f;
    946     // normalize to f = 1
    947     a *= scale;
    948     b *= scale;
    949     c *= scale;
    950 
    951     // extract axis of ellipse
    952     // one more eigenvalue operation
    953     S[0] = a;
    954     S[1] = S[2] = b * 0.5;
    955     S[3] = c;
    956 
    957     _S = cvMat( 2, 2, CV_64F, S );
    958     _EIGVECS = cvMat( 2, 2, CV_64F, eigenvectors );
    959     _EIGVALS = cvMat( 1, 2, CV_64F, eigenvalues );
    960     cvSVD( &_S, &_EIGVALS, &_EIGVECS, 0, CV_SVD_MODIFY_A + CV_SVD_U_T );
    961 
    962     // exteract axis length from eigenvectors
    963     box->size.width = (float)(2./sqrt(eigenvalues[0]));
    964     box->size.height = (float)(2./sqrt(eigenvalues[1]));
    965 
    966     // calc angle
    967     box->angle = (float)(180 - atan2(eigenvectors[2], eigenvectors[3])*180/CV_PI);
    968 
    969     __END__;
    970 
    971     cvReleaseMat( &D );
    972 }
    973 
    974 
    975 CV_IMPL CvBox2D
    976 cvFitEllipse2( const CvArr* array )
    977 {
    978     CvBox2D box;
    979     double* Ad = 0, *bd = 0;
    980 
    981     CV_FUNCNAME( "cvFitEllipse2" );
    982 
    983     memset( &box, 0, sizeof(box));
    984 
    985     __BEGIN__;
    986 
    987     CvContour contour_header;
    988     CvSeq* ptseq = 0;
    989     CvSeqBlock block;
    990     int n;
    991 
    992     if( CV_IS_SEQ( array ))
    993     {
    994         ptseq = (CvSeq*)array;
    995         if( !CV_IS_SEQ_POINT_SET( ptseq ))
    996             CV_ERROR( CV_StsBadArg, "Unsupported sequence type" );
    997     }
    998     else
    999     {
   1000         CV_CALL( ptseq = cvPointSeqFromMat(
   1001             CV_SEQ_KIND_GENERIC, array, &contour_header, &block ));
   1002     }
   1003 
   1004     n = ptseq->total;
   1005     if( n < 5 )
   1006         CV_ERROR( CV_StsBadSize, "Number of points should be >= 6" );
   1007 #if 1
   1008     icvFitEllipse_F( ptseq, &box );
   1009 #else
   1010     /*
   1011      *	New fitellipse algorithm, contributed by Dr. Daniel Weiss
   1012      */
   1013     {
   1014     double gfp[5], rp[5], t;
   1015     CvMat A, b, x;
   1016     const double min_eps = 1e-6;
   1017     int i, is_float;
   1018     CvSeqReader reader;
   1019 
   1020     CV_CALL( Ad = (double*)cvAlloc( n*5*sizeof(Ad[0]) ));
   1021     CV_CALL( bd = (double*)cvAlloc( n*sizeof(bd[0]) ));
   1022 
   1023     // first fit for parameters A - E
   1024     A = cvMat( n, 5, CV_64F, Ad );
   1025     b = cvMat( n, 1, CV_64F, bd );
   1026     x = cvMat( 5, 1, CV_64F, gfp );
   1027 
   1028     cvStartReadSeq( ptseq, &reader );
   1029     is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2;
   1030 
   1031     for( i = 0; i < n; i++ )
   1032     {
   1033         CvPoint2D32f p;
   1034         if( is_float )
   1035             p = *(CvPoint2D32f*)(reader.ptr);
   1036         else
   1037         {
   1038             p.x = (float)((int*)reader.ptr)[0];
   1039             p.y = (float)((int*)reader.ptr)[1];
   1040         }
   1041         CV_NEXT_SEQ_ELEM( sizeof(p), reader );
   1042 
   1043         bd[i] = 10000.0; // 1.0?
   1044         Ad[i*5] = -(double)p.x * p.x; // A - C signs inverted as proposed by APP
   1045         Ad[i*5 + 1] = -(double)p.y * p.y;
   1046         Ad[i*5 + 2] = -(double)p.x * p.y;
   1047         Ad[i*5 + 3] = p.x;
   1048         Ad[i*5 + 4] = p.y;
   1049     }
   1050 
   1051     cvSolve( &A, &b, &x, CV_SVD );
   1052 
   1053     // now use general-form parameters A - E to find the ellipse center:
   1054     // differentiate general form wrt x/y to get two equations for cx and cy
   1055     A = cvMat( 2, 2, CV_64F, Ad );
   1056     b = cvMat( 2, 1, CV_64F, bd );
   1057     x = cvMat( 2, 1, CV_64F, rp );
   1058     Ad[0] = 2 * gfp[0];
   1059     Ad[1] = Ad[2] = gfp[2];
   1060     Ad[3] = 2 * gfp[1];
   1061     bd[0] = gfp[3];
   1062     bd[1] = gfp[4];
   1063     cvSolve( &A, &b, &x, CV_SVD );
   1064 
   1065     // re-fit for parameters A - C with those center coordinates
   1066     A = cvMat( n, 3, CV_64F, Ad );
   1067     b = cvMat( n, 1, CV_64F, bd );
   1068     x = cvMat( 3, 1, CV_64F, gfp );
   1069     for( i = 0; i < n; i++ )
   1070     {
   1071         CvPoint2D32f p;
   1072         if( is_float )
   1073             p = *(CvPoint2D32f*)(reader.ptr);
   1074         else
   1075         {
   1076             p.x = (float)((int*)reader.ptr)[0];
   1077             p.y = (float)((int*)reader.ptr)[1];
   1078         }
   1079         CV_NEXT_SEQ_ELEM( sizeof(p), reader );
   1080         bd[i] = 1.0;
   1081         Ad[i * 3] = (p.x - rp[0]) * (p.x - rp[0]);
   1082         Ad[i * 3 + 1] = (p.y - rp[1]) * (p.y - rp[1]);
   1083         Ad[i * 3 + 2] = (p.x - rp[0]) * (p.y - rp[1]);
   1084     }
   1085     cvSolve(&A, &b, &x, CV_SVD);
   1086 
   1087     // store angle and radii
   1088     rp[4] = -0.5 * atan2(gfp[2], gfp[1] - gfp[0]); // convert from APP angle usage
   1089     t = sin(-2.0 * rp[4]);
   1090     if( fabs(t) > fabs(gfp[2])*min_eps )
   1091         t = gfp[2]/t;
   1092     else
   1093         t = gfp[1] - gfp[0];
   1094     rp[2] = fabs(gfp[0] + gfp[1] - t);
   1095     if( rp[2] > min_eps )
   1096         rp[2] = sqrt(2.0 / rp[2]);
   1097     rp[3] = fabs(gfp[0] + gfp[1] + t);
   1098     if( rp[3] > min_eps )
   1099         rp[3] = sqrt(2.0 / rp[3]);
   1100 
   1101     box.center.x = (float)rp[0];
   1102     box.center.y = (float)rp[1];
   1103     box.size.width = (float)(rp[2]*2);
   1104     box.size.height = (float)(rp[3]*2);
   1105     if( box.size.width > box.size.height )
   1106     {
   1107         float tmp;
   1108         CV_SWAP( box.size.width, box.size.height, tmp );
   1109         box.angle = (float)(90 + rp[4]*180/CV_PI);
   1110     }
   1111     if( box.angle < -180 )
   1112         box.angle += 360;
   1113     if( box.angle > 360 )
   1114         box.angle -= 360;
   1115     }
   1116 #endif
   1117     __END__;
   1118 
   1119     cvFree( &Ad );
   1120     cvFree( &bd );
   1121 
   1122     return box;
   1123 }
   1124 
   1125 
   1126 /* Calculates bounding rectagnle of a point set or retrieves already calculated */
   1127 CV_IMPL  CvRect
   1128 cvBoundingRect( CvArr* array, int update )
   1129 {
   1130     CvSeqReader reader;
   1131     CvRect  rect = { 0, 0, 0, 0 };
   1132     CvContour contour_header;
   1133     CvSeq* ptseq = 0;
   1134     CvSeqBlock block;
   1135 
   1136     CV_FUNCNAME( "cvBoundingRect" );
   1137 
   1138     __BEGIN__;
   1139 
   1140     CvMat stub, *mat = 0;
   1141     int  xmin = 0, ymin = 0, xmax = -1, ymax = -1, i, j, k;
   1142     int calculate = update;
   1143 
   1144     if( CV_IS_SEQ( array ))
   1145     {
   1146         ptseq = (CvSeq*)array;
   1147         if( !CV_IS_SEQ_POINT_SET( ptseq ))
   1148             CV_ERROR( CV_StsBadArg, "Unsupported sequence type" );
   1149 
   1150         if( ptseq->header_size < (int)sizeof(CvContour))
   1151         {
   1152             /*if( update == 1 )
   1153                 CV_ERROR( CV_StsBadArg, "The header is too small to fit the rectangle, "
   1154                                         "so it could not be updated" );*/
   1155             update = 0;
   1156             calculate = 1;
   1157         }
   1158     }
   1159     else
   1160     {
   1161         CV_CALL( mat = cvGetMat( array, &stub ));
   1162         if( CV_MAT_TYPE(mat->type) == CV_32SC2 ||
   1163             CV_MAT_TYPE(mat->type) == CV_32FC2 )
   1164         {
   1165             CV_CALL( ptseq = cvPointSeqFromMat(
   1166                 CV_SEQ_KIND_GENERIC, mat, &contour_header, &block ));
   1167             mat = 0;
   1168         }
   1169         else if( CV_MAT_TYPE(mat->type) != CV_8UC1 &&
   1170                 CV_MAT_TYPE(mat->type) != CV_8SC1 )
   1171             CV_ERROR( CV_StsUnsupportedFormat,
   1172                 "The image/matrix format is not supported by the function" );
   1173         update = 0;
   1174         calculate = 1;
   1175     }
   1176 
   1177     if( !calculate )
   1178     {
   1179         rect = ((CvContour*)ptseq)->rect;
   1180         EXIT;
   1181     }
   1182 
   1183     if( mat )
   1184     {
   1185         CvSize size = cvGetMatSize(mat);
   1186         xmin = size.width;
   1187         ymin = -1;
   1188 
   1189         for( i = 0; i < size.height; i++ )
   1190         {
   1191             uchar* _ptr = mat->data.ptr + i*mat->step;
   1192             uchar* ptr = (uchar*)cvAlignPtr(_ptr, 4);
   1193             int have_nz = 0, k_min, offset = (int)(ptr - _ptr);
   1194             j = 0;
   1195             offset = MIN(offset, size.width);
   1196             for( ; j < offset; j++ )
   1197                 if( _ptr[j] )
   1198                 {
   1199                     have_nz = 1;
   1200                     break;
   1201                 }
   1202             if( j < offset )
   1203             {
   1204                 if( j < xmin )
   1205                     xmin = j;
   1206                 if( j > xmax )
   1207                     xmax = j;
   1208             }
   1209             if( offset < size.width )
   1210             {
   1211                 xmin -= offset;
   1212                 xmax -= offset;
   1213                 size.width -= offset;
   1214                 j = 0;
   1215                 for( ; j <= xmin - 4; j += 4 )
   1216                     if( *((int*)(ptr+j)) )
   1217                         break;
   1218                 for( ; j < xmin; j++ )
   1219                     if( ptr[j] )
   1220                     {
   1221                         xmin = j;
   1222                         if( j > xmax )
   1223                             xmax = j;
   1224                         have_nz = 1;
   1225                         break;
   1226                     }
   1227                 k_min = MAX(j-1, xmax);
   1228                 k = size.width - 1;
   1229                 for( ; k > k_min && (k&3) != 3; k-- )
   1230                     if( ptr[k] )
   1231                         break;
   1232                 if( k > k_min && (k&3) == 3 )
   1233                 {
   1234                     for( ; k > k_min+3; k -= 4 )
   1235                         if( *((int*)(ptr+k-3)) )
   1236                             break;
   1237                 }
   1238                 for( ; k > k_min; k-- )
   1239                     if( ptr[k] )
   1240                     {
   1241                         xmax = k;
   1242                         have_nz = 1;
   1243                         break;
   1244                     }
   1245                 if( !have_nz )
   1246                 {
   1247                     j &= ~3;
   1248                     for( ; j <= k - 3; j += 4 )
   1249                         if( *((int*)(ptr+j)) )
   1250                             break;
   1251                     for( ; j <= k; j++ )
   1252                         if( ptr[j] )
   1253                         {
   1254                             have_nz = 1;
   1255                             break;
   1256                         }
   1257                 }
   1258                 xmin += offset;
   1259                 xmax += offset;
   1260                 size.width += offset;
   1261             }
   1262             if( have_nz )
   1263             {
   1264                 if( ymin < 0 )
   1265                     ymin = i;
   1266                 ymax = i;
   1267             }
   1268         }
   1269 
   1270         if( xmin >= size.width )
   1271             xmin = ymin = 0;
   1272     }
   1273     else if( ptseq->total )
   1274     {
   1275         int  is_float = CV_SEQ_ELTYPE(ptseq) == CV_32FC2;
   1276         cvStartReadSeq( ptseq, &reader, 0 );
   1277 
   1278         if( !is_float )
   1279         {
   1280             CvPoint pt;
   1281             /* init values */
   1282             CV_READ_SEQ_ELEM( pt, reader );
   1283             xmin = xmax = pt.x;
   1284             ymin = ymax = pt.y;
   1285 
   1286             for( i = 1; i < ptseq->total; i++ )
   1287             {
   1288                 CV_READ_SEQ_ELEM( pt, reader );
   1289 
   1290                 if( xmin > pt.x )
   1291                     xmin = pt.x;
   1292 
   1293                 if( xmax < pt.x )
   1294                     xmax = pt.x;
   1295 
   1296                 if( ymin > pt.y )
   1297                     ymin = pt.y;
   1298 
   1299                 if( ymax < pt.y )
   1300                     ymax = pt.y;
   1301             }
   1302         }
   1303         else
   1304         {
   1305             CvPoint pt;
   1306             Cv32suf v;
   1307             /* init values */
   1308             CV_READ_SEQ_ELEM( pt, reader );
   1309             xmin = xmax = CV_TOGGLE_FLT(pt.x);
   1310             ymin = ymax = CV_TOGGLE_FLT(pt.y);
   1311 
   1312             for( i = 1; i < ptseq->total; i++ )
   1313             {
   1314                 CV_READ_SEQ_ELEM( pt, reader );
   1315                 pt.x = CV_TOGGLE_FLT(pt.x);
   1316                 pt.y = CV_TOGGLE_FLT(pt.y);
   1317 
   1318                 if( xmin > pt.x )
   1319                     xmin = pt.x;
   1320 
   1321                 if( xmax < pt.x )
   1322                     xmax = pt.x;
   1323 
   1324                 if( ymin > pt.y )
   1325                     ymin = pt.y;
   1326 
   1327                 if( ymax < pt.y )
   1328                     ymax = pt.y;
   1329             }
   1330 
   1331             v.i = CV_TOGGLE_FLT(xmin); xmin = cvFloor(v.f);
   1332             v.i = CV_TOGGLE_FLT(ymin); ymin = cvFloor(v.f);
   1333             /* because right and bottom sides of
   1334                the bounding rectangle are not inclusive
   1335                (note +1 in width and height calculation below),
   1336                cvFloor is used here instead of cvCeil */
   1337             v.i = CV_TOGGLE_FLT(xmax); xmax = cvFloor(v.f);
   1338             v.i = CV_TOGGLE_FLT(ymax); ymax = cvFloor(v.f);
   1339         }
   1340     }
   1341 
   1342     rect.x = xmin;
   1343     rect.y = ymin;
   1344     rect.width = xmax - xmin + 1;
   1345     rect.height = ymax - ymin + 1;
   1346 
   1347     if( update )
   1348         ((CvContour*)ptseq)->rect = rect;
   1349 
   1350     __END__;
   1351 
   1352     return rect;
   1353 }
   1354 
   1355 
   1356 /* End of file. */
   1357