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 
     42 #include "precomp.hpp"
     43 #include <iostream>
     44 
     45 namespace cv
     46 {
     47 
     48 template<typename _Tp>
     49 static int Sklansky_( Point_<_Tp>** array, int start, int end, int* stack, int nsign, int sign2 )
     50 {
     51     int incr = end > start ? 1 : -1;
     52     // prepare first triangle
     53     int pprev = start, pcur = pprev + incr, pnext = pcur + incr;
     54     int stacksize = 3;
     55 
     56     if( start == end ||
     57        (array[start]->x == array[end]->x &&
     58         array[start]->y == array[end]->y) )
     59     {
     60         stack[0] = start;
     61         return 1;
     62     }
     63 
     64     stack[0] = pprev;
     65     stack[1] = pcur;
     66     stack[2] = pnext;
     67 
     68     end += incr; // make end = afterend
     69 
     70     while( pnext != end )
     71     {
     72         // check the angle p1,p2,p3
     73         _Tp cury = array[pcur]->y;
     74         _Tp nexty = array[pnext]->y;
     75         _Tp by = nexty - cury;
     76 
     77         if( CV_SIGN( by ) != nsign )
     78         {
     79             _Tp ax = array[pcur]->x - array[pprev]->x;
     80             _Tp bx = array[pnext]->x - array[pcur]->x;
     81             _Tp ay = cury - array[pprev]->y;
     82             _Tp convexity = ay*bx - ax*by; // if >0 then convex angle
     83 
     84             if( CV_SIGN( convexity ) == sign2 && (ax != 0 || ay != 0) )
     85             {
     86                 pprev = pcur;
     87                 pcur = pnext;
     88                 pnext += incr;
     89                 stack[stacksize] = pnext;
     90                 stacksize++;
     91             }
     92             else
     93             {
     94                 if( pprev == start )
     95                 {
     96                     pcur = pnext;
     97                     stack[1] = pcur;
     98                     pnext += incr;
     99                     stack[2] = pnext;
    100                 }
    101                 else
    102                 {
    103                     stack[stacksize-2] = pnext;
    104                     pcur = pprev;
    105                     pprev = stack[stacksize-4];
    106                     stacksize--;
    107                 }
    108             }
    109         }
    110         else
    111         {
    112             pnext += incr;
    113             stack[stacksize-1] = pnext;
    114         }
    115     }
    116 
    117     return --stacksize;
    118 }
    119 
    120 
    121 template<typename _Tp>
    122 struct CHullCmpPoints
    123 {
    124     bool operator()(const Point_<_Tp>* p1, const Point_<_Tp>* p2) const
    125     { return p1->x < p2->x || (p1->x == p2->x && p1->y < p2->y); }
    126 };
    127 
    128 
    129 void convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool returnPoints )
    130 {
    131     Mat points = _points.getMat();
    132     int i, total = points.checkVector(2), depth = points.depth(), nout = 0;
    133     int miny_ind = 0, maxy_ind = 0;
    134     CV_Assert(total >= 0 && (depth == CV_32F || depth == CV_32S));
    135 
    136     if( total == 0 )
    137     {
    138         _hull.release();
    139         return;
    140     }
    141 
    142     returnPoints = !_hull.fixedType() ? returnPoints : _hull.type() != CV_32S;
    143 
    144     bool is_float = depth == CV_32F;
    145     AutoBuffer<Point*> _pointer(total);
    146     AutoBuffer<int> _stack(total + 2), _hullbuf(total);
    147     Point** pointer = _pointer;
    148     Point2f** pointerf = (Point2f**)pointer;
    149     Point* data0 = points.ptr<Point>();
    150     int* stack = _stack;
    151     int* hullbuf = _hullbuf;
    152 
    153     CV_Assert(points.isContinuous());
    154 
    155     for( i = 0; i < total; i++ )
    156         pointer[i] = &data0[i];
    157 
    158     // sort the point set by x-coordinate, find min and max y
    159     if( !is_float )
    160     {
    161         std::sort(pointer, pointer + total, CHullCmpPoints<int>());
    162         for( i = 1; i < total; i++ )
    163         {
    164             int y = pointer[i]->y;
    165             if( pointer[miny_ind]->y > y )
    166                 miny_ind = i;
    167             if( pointer[maxy_ind]->y < y )
    168                 maxy_ind = i;
    169         }
    170     }
    171     else
    172     {
    173         std::sort(pointerf, pointerf + total, CHullCmpPoints<float>());
    174         for( i = 1; i < total; i++ )
    175         {
    176             float y = pointerf[i]->y;
    177             if( pointerf[miny_ind]->y > y )
    178                 miny_ind = i;
    179             if( pointerf[maxy_ind]->y < y )
    180                 maxy_ind = i;
    181         }
    182     }
    183 
    184     if( pointer[0]->x == pointer[total-1]->x &&
    185         pointer[0]->y == pointer[total-1]->y )
    186     {
    187         hullbuf[nout++] = 0;
    188     }
    189     else
    190     {
    191         // upper half
    192         int *tl_stack = stack;
    193         int tl_count = !is_float ?
    194             Sklansky_( pointer, 0, maxy_ind, tl_stack, -1, 1) :
    195             Sklansky_( pointerf, 0, maxy_ind, tl_stack, -1, 1);
    196         int *tr_stack = stack + tl_count;
    197         int tr_count = !is_float ?
    198             Sklansky_( pointer, total-1, maxy_ind, tr_stack, -1, -1) :
    199             Sklansky_( pointerf, total-1, maxy_ind, tr_stack, -1, -1);
    200 
    201         // gather upper part of convex hull to output
    202         if( !clockwise )
    203         {
    204             std::swap( tl_stack, tr_stack );
    205             std::swap( tl_count, tr_count );
    206         }
    207 
    208         for( i = 0; i < tl_count-1; i++ )
    209             hullbuf[nout++] = int(pointer[tl_stack[i]] - data0);
    210         for( i = tr_count - 1; i > 0; i-- )
    211             hullbuf[nout++] = int(pointer[tr_stack[i]] - data0);
    212         int stop_idx = tr_count > 2 ? tr_stack[1] : tl_count > 2 ? tl_stack[tl_count - 2] : -1;
    213 
    214         // lower half
    215         int *bl_stack = stack;
    216         int bl_count = !is_float ?
    217             Sklansky_( pointer, 0, miny_ind, bl_stack, 1, -1) :
    218             Sklansky_( pointerf, 0, miny_ind, bl_stack, 1, -1);
    219         int *br_stack = stack + bl_count;
    220         int br_count = !is_float ?
    221             Sklansky_( pointer, total-1, miny_ind, br_stack, 1, 1) :
    222             Sklansky_( pointerf, total-1, miny_ind, br_stack, 1, 1);
    223 
    224         if( clockwise )
    225         {
    226             std::swap( bl_stack, br_stack );
    227             std::swap( bl_count, br_count );
    228         }
    229 
    230         if( stop_idx >= 0 )
    231         {
    232             int check_idx = bl_count > 2 ? bl_stack[1] :
    233             bl_count + br_count > 2 ? br_stack[2-bl_count] : -1;
    234             if( check_idx == stop_idx || (check_idx >= 0 &&
    235                                           pointer[check_idx]->x == pointer[stop_idx]->x &&
    236                                           pointer[check_idx]->y == pointer[stop_idx]->y) )
    237             {
    238                 // if all the points lie on the same line, then
    239                 // the bottom part of the convex hull is the mirrored top part
    240                 // (except the exteme points).
    241                 bl_count = MIN( bl_count, 2 );
    242                 br_count = MIN( br_count, 2 );
    243             }
    244         }
    245 
    246         for( i = 0; i < bl_count-1; i++ )
    247             hullbuf[nout++] = int(pointer[bl_stack[i]] - data0);
    248         for( i = br_count-1; i > 0; i-- )
    249             hullbuf[nout++] = int(pointer[br_stack[i]] - data0);
    250     }
    251 
    252     if( !returnPoints )
    253         Mat(nout, 1, CV_32S, hullbuf).copyTo(_hull);
    254     else
    255     {
    256         _hull.create(nout, 1, CV_MAKETYPE(depth, 2));
    257         Mat hull = _hull.getMat();
    258         size_t step = !hull.isContinuous() ? hull.step[0] : sizeof(Point);
    259         for( i = 0; i < nout; i++ )
    260             *(Point*)(hull.ptr() + i*step) = data0[hullbuf[i]];
    261     }
    262 }
    263 
    264 
    265 void convexityDefects( InputArray _points, InputArray _hull, OutputArray _defects )
    266 {
    267     Mat points = _points.getMat();
    268     int i, j = 0, npoints = points.checkVector(2, CV_32S);
    269     CV_Assert( npoints >= 0 );
    270 
    271     if( npoints <= 3 )
    272     {
    273         _defects.release();
    274         return;
    275     }
    276 
    277     Mat hull = _hull.getMat();
    278     int hpoints = hull.checkVector(1, CV_32S);
    279     CV_Assert( hpoints > 2 );
    280 
    281     const Point* ptr = points.ptr<Point>();
    282     const int* hptr = hull.ptr<int>();
    283     std::vector<Vec4i> defects;
    284 
    285     // 1. recognize co-orientation of the contour and its hull
    286     bool rev_orientation = ((hptr[1] > hptr[0]) + (hptr[2] > hptr[1]) + (hptr[0] > hptr[2])) != 2;
    287 
    288     // 2. cycle through points and hull, compute defects
    289     int hcurr = hptr[rev_orientation ? 0 : hpoints-1];
    290     CV_Assert( 0 <= hcurr && hcurr < npoints );
    291 
    292     for( i = 0; i < hpoints; i++ )
    293     {
    294         int hnext = hptr[rev_orientation ? hpoints - i - 1 : i];
    295         CV_Assert( 0 <= hnext && hnext < npoints );
    296 
    297         Point pt0 = ptr[hcurr], pt1 = ptr[hnext];
    298         double dx0 = pt1.x - pt0.x;
    299         double dy0 = pt1.y - pt0.y;
    300         double scale = dx0 == 0 && dy0 == 0 ? 0. : 1./std::sqrt(dx0*dx0 + dy0*dy0);
    301 
    302         int defect_deepest_point = -1;
    303         double defect_depth = 0;
    304         bool is_defect = false;
    305 
    306         for(;;)
    307         {
    308             // go through points to achieve next hull point
    309             j++;
    310             j &= j >= npoints ? 0 : -1;
    311             if( j == hnext )
    312                 break;
    313 
    314             // compute distance from current point to hull edge
    315             double dx = ptr[j].x - pt0.x;
    316             double dy = ptr[j].y - pt0.y;
    317             double dist = fabs(-dy0*dx + dx0*dy) * scale;
    318 
    319             if( dist > defect_depth )
    320             {
    321                 defect_depth = dist;
    322                 defect_deepest_point = j;
    323                 is_defect = true;
    324             }
    325         }
    326 
    327         if( is_defect )
    328         {
    329             int idepth = cvRound(defect_depth*256);
    330             defects.push_back(Vec4i(hcurr, hnext, defect_deepest_point, idepth));
    331         }
    332 
    333         hcurr = hnext;
    334     }
    335 
    336     Mat(defects).copyTo(_defects);
    337 }
    338 
    339 
    340 template<typename _Tp>
    341 static bool isContourConvex_( const Point_<_Tp>* p, int n )
    342 {
    343     Point_<_Tp> prev_pt = p[(n-2+n) % n];
    344     Point_<_Tp> cur_pt = p[n-1];
    345 
    346     _Tp dx0 = cur_pt.x - prev_pt.x;
    347     _Tp dy0 = cur_pt.y - prev_pt.y;
    348     int orientation = 0;
    349 
    350     for( int i = 0; i < n; i++ )
    351     {
    352         _Tp dxdy0, dydx0;
    353         _Tp dx, dy;
    354 
    355         prev_pt = cur_pt;
    356         cur_pt = p[i];
    357 
    358         dx = cur_pt.x - prev_pt.x;
    359         dy = cur_pt.y - prev_pt.y;
    360         dxdy0 = dx * dy0;
    361         dydx0 = dy * dx0;
    362 
    363         // find orientation
    364         // orient = -dy0 * dx + dx0 * dy;
    365         // orientation |= (orient > 0) ? 1 : 2;
    366         orientation |= (dydx0 > dxdy0) ? 1 : ((dydx0 < dxdy0) ? 2 : 3);
    367         if( orientation == 3 )
    368             return false;
    369 
    370         dx0 = dx;
    371         dy0 = dy;
    372     }
    373 
    374     return true;
    375 }
    376 
    377 
    378 bool isContourConvex( InputArray _contour )
    379 {
    380     Mat contour = _contour.getMat();
    381     int total = contour.checkVector(2), depth = contour.depth();
    382     CV_Assert(total >= 0 && (depth == CV_32F || depth == CV_32S));
    383 
    384     if( total == 0 )
    385         return false;
    386 
    387     return depth == CV_32S ?
    388     isContourConvex_(contour.ptr<Point>(), total ) :
    389     isContourConvex_(contour.ptr<Point2f>(), total );
    390 }
    391 
    392 }
    393 
    394 CV_IMPL CvSeq*
    395 cvConvexHull2( const CvArr* array, void* hull_storage,
    396                int orientation, int return_points )
    397 {
    398     union { CvContour* c; CvSeq* s; } hull;
    399     hull.s = 0;
    400 
    401     CvMat* mat = 0;
    402     CvContour contour_header;
    403     CvSeq hull_header;
    404     CvSeqBlock block, hullblock;
    405     CvSeq* ptseq = 0;
    406     CvSeq* hullseq = 0;
    407 
    408     if( CV_IS_SEQ( array ))
    409     {
    410         ptseq = (CvSeq*)array;
    411         if( !CV_IS_SEQ_POINT_SET( ptseq ))
    412             CV_Error( CV_StsBadArg, "Unsupported sequence type" );
    413         if( hull_storage == 0 )
    414             hull_storage = ptseq->storage;
    415     }
    416     else
    417     {
    418         ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block );
    419     }
    420 
    421     if( CV_IS_STORAGE( hull_storage ))
    422     {
    423         if( return_points )
    424         {
    425             hullseq = cvCreateSeq(CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE(ptseq)|
    426                                   CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX,
    427                                   sizeof(CvContour), sizeof(CvPoint),(CvMemStorage*)hull_storage );
    428         }
    429         else
    430         {
    431             hullseq = cvCreateSeq(
    432                                   CV_SEQ_KIND_CURVE|CV_SEQ_ELTYPE_PPOINT|
    433                                   CV_SEQ_FLAG_CLOSED|CV_SEQ_FLAG_CONVEX,
    434                                   sizeof(CvContour), sizeof(CvPoint*), (CvMemStorage*)hull_storage );
    435         }
    436     }
    437     else
    438     {
    439         if( !CV_IS_MAT( hull_storage ))
    440             CV_Error(CV_StsBadArg, "Destination must be valid memory storage or matrix");
    441 
    442         mat = (CvMat*)hull_storage;
    443 
    444         if( (mat->cols != 1 && mat->rows != 1) || !CV_IS_MAT_CONT(mat->type))
    445             CV_Error( CV_StsBadArg,
    446                      "The hull matrix should be continuous and have a single row or a single column" );
    447 
    448         if( mat->cols + mat->rows - 1 < ptseq->total )
    449             CV_Error( CV_StsBadSize, "The hull matrix size might be not enough to fit the hull" );
    450 
    451         if( CV_MAT_TYPE(mat->type) != CV_SEQ_ELTYPE(ptseq) &&
    452            CV_MAT_TYPE(mat->type) != CV_32SC1 )
    453             CV_Error( CV_StsUnsupportedFormat,
    454                      "The hull matrix must have the same type as input or 32sC1 (integers)" );
    455 
    456         hullseq = cvMakeSeqHeaderForArray(
    457                                           CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED,
    458                                           sizeof(hull_header), CV_ELEM_SIZE(mat->type), mat->data.ptr,
    459                                           mat->cols + mat->rows - 1, &hull_header, &hullblock );
    460         cvClearSeq( hullseq );
    461     }
    462 
    463     int hulltype = CV_SEQ_ELTYPE(hullseq);
    464     int total = ptseq->total;
    465     if( total == 0 )
    466     {
    467         if( mat )
    468             CV_Error( CV_StsBadSize,
    469                      "Point sequence can not be empty if the output is matrix" );
    470         return hull.s;
    471     }
    472 
    473     cv::AutoBuffer<double> _ptbuf;
    474     cv::Mat h0;
    475     cv::convexHull(cv::cvarrToMat(ptseq, false, false, 0, &_ptbuf), h0,
    476                    orientation == CV_CLOCKWISE, CV_MAT_CN(hulltype) == 2);
    477 
    478 
    479     if( hulltype == CV_SEQ_ELTYPE_PPOINT )
    480     {
    481         const int* idx = h0.ptr<int>();
    482         int ctotal = (int)h0.total();
    483         for( int i = 0; i < ctotal; i++ )
    484         {
    485             void* ptr = cvGetSeqElem(ptseq, idx[i]);
    486             cvSeqPush( hullseq, &ptr );
    487         }
    488     }
    489     else
    490         cvSeqPushMulti(hullseq, h0.ptr(), (int)h0.total());
    491 
    492     if( mat )
    493     {
    494         if( mat->rows > mat->cols )
    495             mat->rows = hullseq->total;
    496         else
    497             mat->cols = hullseq->total;
    498     }
    499     else
    500     {
    501         hull.s = hullseq;
    502         hull.c->rect = cvBoundingRect( ptseq,
    503                                        ptseq->header_size < (int)sizeof(CvContour) ||
    504                                        &ptseq->flags == &contour_header.flags );
    505     }
    506 
    507     return hull.s;
    508 }
    509 
    510 
    511 /* contour must be a simple polygon */
    512 /* it must have more than 3 points  */
    513 CV_IMPL CvSeq* cvConvexityDefects( const CvArr* array,
    514                                   const CvArr* hullarray,
    515                                   CvMemStorage* storage )
    516 {
    517     CvSeq* defects = 0;
    518 
    519     int i, index;
    520     CvPoint* hull_cur;
    521 
    522     /* is orientation of hull different from contour one */
    523     int rev_orientation;
    524 
    525     CvContour contour_header;
    526     CvSeq hull_header;
    527     CvSeqBlock block, hullblock;
    528     CvSeq *ptseq = (CvSeq*)array, *hull = (CvSeq*)hullarray;
    529 
    530     CvSeqReader hull_reader;
    531     CvSeqReader ptseq_reader;
    532     CvSeqWriter writer;
    533     int is_index;
    534 
    535     if( CV_IS_SEQ( ptseq ))
    536     {
    537         if( !CV_IS_SEQ_POINT_SET( ptseq ))
    538             CV_Error( CV_StsUnsupportedFormat,
    539                      "Input sequence is not a sequence of points" );
    540         if( !storage )
    541             storage = ptseq->storage;
    542     }
    543     else
    544     {
    545         ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block );
    546     }
    547 
    548     if( CV_SEQ_ELTYPE( ptseq ) != CV_32SC2 )
    549         CV_Error( CV_StsUnsupportedFormat, "Floating-point coordinates are not supported here" );
    550 
    551     if( CV_IS_SEQ( hull ))
    552     {
    553         int hulltype = CV_SEQ_ELTYPE( hull );
    554         if( hulltype != CV_SEQ_ELTYPE_PPOINT && hulltype != CV_SEQ_ELTYPE_INDEX )
    555             CV_Error( CV_StsUnsupportedFormat,
    556                      "Convex hull must represented as a sequence "
    557                      "of indices or sequence of pointers" );
    558         if( !storage )
    559             storage = hull->storage;
    560     }
    561     else
    562     {
    563         CvMat* mat = (CvMat*)hull;
    564 
    565         if( !CV_IS_MAT( hull ))
    566             CV_Error(CV_StsBadArg, "Convex hull is neither sequence nor matrix");
    567 
    568         if( (mat->cols != 1 && mat->rows != 1) ||
    569            !CV_IS_MAT_CONT(mat->type) || CV_MAT_TYPE(mat->type) != CV_32SC1 )
    570             CV_Error( CV_StsBadArg,
    571                      "The matrix should be 1-dimensional and continuous array of int's" );
    572 
    573         if( mat->cols + mat->rows - 1 > ptseq->total )
    574             CV_Error( CV_StsBadSize, "Convex hull is larger than the point sequence" );
    575 
    576         hull = cvMakeSeqHeaderForArray(
    577                                        CV_SEQ_KIND_CURVE|CV_MAT_TYPE(mat->type)|CV_SEQ_FLAG_CLOSED,
    578                                        sizeof(CvContour), CV_ELEM_SIZE(mat->type), mat->data.ptr,
    579                                        mat->cols + mat->rows - 1, &hull_header, &hullblock );
    580     }
    581 
    582     is_index = CV_SEQ_ELTYPE(hull) == CV_SEQ_ELTYPE_INDEX;
    583 
    584     if( !storage )
    585         CV_Error( CV_StsNullPtr, "NULL storage pointer" );
    586 
    587     defects = cvCreateSeq( CV_SEQ_KIND_GENERIC, sizeof(CvSeq), sizeof(CvConvexityDefect), storage );
    588 
    589     if( ptseq->total < 4 || hull->total < 3)
    590     {
    591         //CV_ERROR( CV_StsBadSize,
    592         //    "point seq size must be >= 4, convex hull size must be >= 3" );
    593         return defects;
    594     }
    595 
    596     /* recognize co-orientation of ptseq and its hull */
    597     {
    598         int sign = 0;
    599         int index1, index2, index3;
    600 
    601         if( !is_index )
    602         {
    603             CvPoint* pos = *CV_SEQ_ELEM( hull, CvPoint*, 0 );
    604             index1 = cvSeqElemIdx( ptseq, pos );
    605 
    606             pos = *CV_SEQ_ELEM( hull, CvPoint*, 1 );
    607             index2 = cvSeqElemIdx( ptseq, pos );
    608 
    609             pos = *CV_SEQ_ELEM( hull, CvPoint*, 2 );
    610             index3 = cvSeqElemIdx( ptseq, pos );
    611         }
    612         else
    613         {
    614             index1 = *CV_SEQ_ELEM( hull, int, 0 );
    615             index2 = *CV_SEQ_ELEM( hull, int, 1 );
    616             index3 = *CV_SEQ_ELEM( hull, int, 2 );
    617         }
    618 
    619         sign += (index2 > index1) ? 1 : 0;
    620         sign += (index3 > index2) ? 1 : 0;
    621         sign += (index1 > index3) ? 1 : 0;
    622 
    623         rev_orientation = (sign == 2) ? 0 : 1;
    624     }
    625 
    626     cvStartReadSeq( ptseq, &ptseq_reader, 0 );
    627     cvStartReadSeq( hull, &hull_reader, rev_orientation );
    628 
    629     if( !is_index )
    630     {
    631         hull_cur = *(CvPoint**)hull_reader.prev_elem;
    632         index = cvSeqElemIdx( ptseq, (char*)hull_cur, 0 );
    633     }
    634     else
    635     {
    636         index = *(int*)hull_reader.prev_elem;
    637         hull_cur = CV_GET_SEQ_ELEM( CvPoint, ptseq, index );
    638     }
    639     cvSetSeqReaderPos( &ptseq_reader, index );
    640     cvStartAppendToSeq( defects, &writer );
    641 
    642     /* cycle through ptseq and hull with computing defects */
    643     for( i = 0; i < hull->total; i++ )
    644     {
    645         CvConvexityDefect defect;
    646         int is_defect = 0;
    647         double dx0, dy0;
    648         double depth = 0, scale;
    649         CvPoint* hull_next;
    650 
    651         if( !is_index )
    652             hull_next = *(CvPoint**)hull_reader.ptr;
    653         else
    654         {
    655             int t = *(int*)hull_reader.ptr;
    656             hull_next = CV_GET_SEQ_ELEM( CvPoint, ptseq, t );
    657         }
    658 
    659         dx0 = (double)hull_next->x - (double)hull_cur->x;
    660         dy0 = (double)hull_next->y - (double)hull_cur->y;
    661         assert( dx0 != 0 || dy0 != 0 );
    662         scale = 1./std::sqrt(dx0*dx0 + dy0*dy0);
    663 
    664         defect.start = hull_cur;
    665         defect.end = hull_next;
    666 
    667         for(;;)
    668         {
    669             /* go through ptseq to achieve next hull point */
    670             CV_NEXT_SEQ_ELEM( sizeof(CvPoint), ptseq_reader );
    671 
    672             if( ptseq_reader.ptr == (schar*)hull_next )
    673                 break;
    674             else
    675             {
    676                 CvPoint* cur = (CvPoint*)ptseq_reader.ptr;
    677 
    678                 /* compute distance from current point to hull edge */
    679                 double dx = (double)cur->x - (double)hull_cur->x;
    680                 double dy = (double)cur->y - (double)hull_cur->y;
    681 
    682                 /* compute depth */
    683                 double dist = fabs(-dy0*dx + dx0*dy) * scale;
    684 
    685                 if( dist > depth )
    686                 {
    687                     depth = dist;
    688                     defect.depth_point = cur;
    689                     defect.depth = (float)depth;
    690                     is_defect = 1;
    691                 }
    692             }
    693         }
    694         if( is_defect )
    695         {
    696             CV_WRITE_SEQ_ELEM( defect, writer );
    697         }
    698 
    699         hull_cur = hull_next;
    700         if( rev_orientation )
    701         {
    702             CV_PREV_SEQ_ELEM( hull->elem_size, hull_reader );
    703         }
    704         else
    705         {
    706             CV_NEXT_SEQ_ELEM( hull->elem_size, hull_reader );
    707         }
    708     }
    709 
    710     return cvEndWriteSeq( &writer );
    711 }
    712 
    713 
    714 CV_IMPL int
    715 cvCheckContourConvexity( const CvArr* array )
    716 {
    717     CvContour contour_header;
    718     CvSeqBlock block;
    719     CvSeq* contour = (CvSeq*)array;
    720 
    721     if( CV_IS_SEQ(contour) )
    722     {
    723         if( !CV_IS_SEQ_POINT_SET(contour))
    724             CV_Error( CV_StsUnsupportedFormat,
    725                      "Input sequence must be polygon (closed 2d curve)" );
    726     }
    727     else
    728     {
    729         contour = cvPointSeqFromMat(CV_SEQ_KIND_CURVE|
    730             CV_SEQ_FLAG_CLOSED, array, &contour_header, &block );
    731     }
    732 
    733     if( contour->total == 0 )
    734         return -1;
    735 
    736     cv::AutoBuffer<double> _buf;
    737     return cv::isContourConvex(cv::cvarrToMat(contour, false, false, 0, &_buf)) ? 1 : 0;
    738 }
    739 
    740 /* End of file. */
    741