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#define CV_MATCH_CHECK( status, cvFun )                                    \
44  {                                                                        \
45    status = cvFun;                                                        \
46    if( status != CV_OK )                                                  \
47     goto M_END;                                                           \
48  }
49
50static CvStatus
51icvCalcTriAttr( const CvSeq * contour, CvPoint t2, CvPoint t1, int n1,
52                CvPoint t3, int n3, double *s, double *s_c,
53                double *h, double *a, double *b );
54
55/*F///////////////////////////////////////////////////////////////////////////////////////
56//    Name: icvCreateContourTree
57//    Purpose:
58//    Create binary tree representation for the contour
59//    Context:
60//    Parameters:
61//      contour - pointer to input contour object.
62//      storage - pointer to the current storage block
63//      tree   -  output pointer to the binary tree representation
64//      threshold - threshold for the binary tree building
65//
66//F*/
67static CvStatus
68icvCreateContourTree( const CvSeq * contour, CvMemStorage * storage,
69                      CvContourTree ** tree, double threshold )
70{
71    CvPoint *pt_p;              /*  pointer to previos points   */
72    CvPoint *pt_n;              /*  pointer to next points      */
73    CvPoint *pt1, *pt2;         /*  pointer to current points   */
74
75    CvPoint t, tp1, tp2, tp3, tn1, tn2, tn3;
76    int lpt, flag, i, j, i_tree, j_1, j_3, i_buf;
77    double s, sp1, sp2, sn1, sn2, s_c, sp1_c, sp2_c, sn1_c, sn2_c, h, hp1, hp2, hn1, hn2,
78        a, ap1, ap2, an1, an2, b, bp1, bp2, bn1, bn2;
79    double a_s_c, a_sp1_c;
80
81    _CvTrianAttr **ptr_p, **ptr_n, **ptr1, **ptr2;      /*  pointers to pointers of triangles  */
82    _CvTrianAttr *cur_adr;
83
84    int *num_p, *num_n, *num1, *num2;   /*   numbers of input contour points   */
85    int nm, nmp1, nmp2, nmp3, nmn1, nmn2, nmn3;
86    int seq_flags = 1, i_end, prev_null, prev2_null;
87    double koef = 1.5;
88    double eps = 1.e-7;
89    double e;
90    CvStatus status;
91    int hearder_size;
92    _CvTrianAttr tree_one, tree_two, *tree_end, *tree_root;
93
94    CvSeqWriter writer;
95
96    assert( contour != NULL && contour->total >= 4 );
97    status = CV_OK;
98
99    if( contour == NULL )
100        return CV_NULLPTR_ERR;
101    if( contour->total < 4 )
102        return CV_BADSIZE_ERR;
103
104    if( !CV_IS_SEQ_POLYGON( contour ))
105        return CV_BADFLAG_ERR;
106
107
108/*   Convert Sequence to array    */
109    lpt = contour->total;
110    pt_p = pt_n = NULL;
111    num_p = num_n = NULL;
112    ptr_p = ptr_n = ptr1 = ptr2 = NULL;
113    tree_end = NULL;
114
115    pt_p = (CvPoint *) cvAlloc( lpt * sizeof( CvPoint ));
116    pt_n = (CvPoint *) cvAlloc( lpt * sizeof( CvPoint ));
117
118    num_p = (int *) cvAlloc( lpt * sizeof( int ));
119    num_n = (int *) cvAlloc( lpt * sizeof( int ));
120
121    hearder_size = sizeof( CvContourTree );
122    seq_flags = CV_SEQ_POLYGON_TREE;
123    cvStartWriteSeq( seq_flags, hearder_size, sizeof( _CvTrianAttr ), storage, &writer );
124
125    ptr_p = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * ));
126    ptr_n = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * ));
127
128    memset( ptr_p, 0, lpt * sizeof( _CvTrianAttr * ));
129    memset( ptr_n, 0, lpt * sizeof( _CvTrianAttr * ));
130
131    if( pt_p == NULL || pt_n == NULL )
132        return CV_OUTOFMEM_ERR;
133    if( ptr_p == NULL || ptr_n == NULL )
134        return CV_OUTOFMEM_ERR;
135
136/*     write fild for the binary tree root   */
137/*  start_writer = writer;   */
138
139    tree_one.pt.x = tree_one.pt.y = 0;
140    tree_one.sign = 0;
141    tree_one.area = 0;
142    tree_one.r1 = tree_one.r2 = 0;
143    tree_one.next_v1 = tree_one.next_v2 = tree_one.prev_v = NULL;
144
145    CV_WRITE_SEQ_ELEM( tree_one, writer );
146    tree_root = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
147
148    if( cvCvtSeqToArray( contour, (char *) pt_p ) == (char *) contour )
149        return CV_BADPOINT_ERR;
150
151    for( i = 0; i < lpt; i++ )
152        num_p[i] = i;
153
154    i = lpt;
155    flag = 0;
156    i_tree = 0;
157    e = 20.;                    /*  initial threshold value   */
158    ptr1 = ptr_p;
159    ptr2 = ptr_n;
160    pt1 = pt_p;
161    pt2 = pt_n;
162    num1 = num_p;
163    num2 = num_n;
164/*  binary tree constraction    */
165    while( i > 4 )
166    {
167        if( flag == 0 )
168        {
169            ptr1 = ptr_p;
170            ptr2 = ptr_n;
171            pt1 = pt_p;
172            pt2 = pt_n;
173            num1 = num_p;
174            num2 = num_n;
175            flag = 1;
176        }
177        else
178        {
179            ptr1 = ptr_n;
180            ptr2 = ptr_p;
181            pt1 = pt_n;
182            pt2 = pt_p;
183            num1 = num_n;
184            num2 = num_p;
185            flag = 0;
186        }
187        t = pt1[0];
188        nm = num1[0];
189        tp1 = pt1[i - 1];
190        nmp1 = num1[i - 1];
191        tp2 = pt1[i - 2];
192        nmp2 = num1[i - 2];
193        tp3 = pt1[i - 3];
194        nmp3 = num1[i - 3];
195        tn1 = pt1[1];
196        nmn1 = num1[1];
197        tn2 = pt1[2];
198        nmn2 = num1[2];
199
200        i_buf = 0;
201        i_end = -1;
202        CV_MATCH_CHECK( status,
203                        icvCalcTriAttr( contour, t, tp1, nmp1, tn1, nmn1, &s, &s_c, &h, &a,
204                                        &b ));
205        CV_MATCH_CHECK( status,
206                        icvCalcTriAttr( contour, tp1, tp2, nmp2, t, nm, &sp1, &sp1_c, &hp1,
207                                        &ap1, &bp1 ));
208        CV_MATCH_CHECK( status,
209                        icvCalcTriAttr( contour, tp2, tp3, nmp3, tp1, nmp1, &sp2, &sp2_c, &hp2,
210                                        &ap2, &bp2 ));
211        CV_MATCH_CHECK( status,
212                        icvCalcTriAttr( contour, tn1, t, nm, tn2, nmn2, &sn1, &sn1_c, &hn1,
213                                        &an1, &bn1 ));
214
215
216        j_3 = 3;
217        prev_null = prev2_null = 0;
218        for( j = 0; j < i; j++ )
219        {
220            tn3 = pt1[j_3];
221            nmn3 = num1[j_3];
222            if( j == 0 )
223                j_1 = i - 1;
224            else
225                j_1 = j - 1;
226
227            CV_MATCH_CHECK( status, icvCalcTriAttr( contour, tn2, tn1, nmn1, tn3, nmn3,
228                                                    &sn2, &sn2_c, &hn2, &an2, &bn2 ));
229
230            if( (s_c < sp1_c && s_c < sp2_c && s_c <= sn1_c && s_c <= sn2_c && s_c < e) ||
231                (((s_c == sp1_c && s_c <= sp2_c) || (s_c == sp2_c && s_c <= sp1_c)) &&
232                s_c <= sn1_c && s_c <= sn2_c && s_c < e && j > 1 && prev2_null == 0) ||
233                (s_c < eps && j > 0 && prev_null == 0) )
234            {
235                prev_null = prev2_null = 1;
236                if( s_c < threshold )
237                {
238                    if( ptr1[j_1] == NULL && ptr1[j] == NULL )
239                    {
240                        if( i_buf > 0 )
241                            ptr2[i_buf - 1] = NULL;
242                        else
243                            i_end = 0;
244                    }
245                    else
246                    {
247/*   form next vertex  */
248                        tree_one.pt = t;
249                        tree_one.sign = (char) (CV_SIGN( s ));
250                        tree_one.r1 = h / a;
251                        tree_one.r2 = b / a;
252                        tree_one.area = fabs( s );
253                        tree_one.next_v1 = ptr1[j_1];
254                        tree_one.next_v2 = ptr1[j];
255
256                        CV_WRITE_SEQ_ELEM( tree_one, writer );
257                        cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
258
259                        if( ptr1[j_1] != NULL )
260                            ptr1[j_1]->prev_v = cur_adr;
261                        if( ptr1[j] != NULL )
262                            ptr1[j]->prev_v = cur_adr;
263
264                        if( i_buf > 0 )
265                            ptr2[i_buf - 1] = cur_adr;
266                        else
267                        {
268                            tree_end = (_CvTrianAttr *) writer.ptr;
269                            i_end = 1;
270                        }
271                        i_tree++;
272                    }
273                }
274                else
275/*   form next vertex    */
276                {
277                    tree_one.pt = t;
278                    tree_one.sign = (char) (CV_SIGN( s ));
279                    tree_one.area = fabs( s );
280                    tree_one.r1 = h / a;
281                    tree_one.r2 = b / a;
282                    tree_one.next_v1 = ptr1[j_1];
283                    tree_one.next_v2 = ptr1[j];
284
285                    CV_WRITE_SEQ_ELEM( tree_one, writer );
286                    cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
287
288                    if( ptr1[j_1] != NULL )
289                        ptr1[j_1]->prev_v = cur_adr;
290                    if( ptr1[j] != NULL )
291                        ptr1[j]->prev_v = cur_adr;
292
293                    if( i_buf > 0 )
294                        ptr2[i_buf - 1] = cur_adr;
295                    else
296                    {
297                        tree_end = cur_adr;
298                        i_end = 1;
299                    }
300                    i_tree++;
301                }
302            }
303            else
304/*   the current triangle is'not LMIAT    */
305            {
306                prev_null = 0;
307                switch (prev2_null)
308                {
309                case 0:
310                    break;
311                case 1:
312                    {
313                        prev2_null = 2;
314                        break;
315                    }
316                case 2:
317                    {
318                        prev2_null = 0;
319                        break;
320                    }
321                }
322                if( j != i - 1 || i_end == -1 )
323                    ptr2[i_buf] = ptr1[j];
324                else if( i_end == 0 )
325                    ptr2[i_buf] = NULL;
326                else
327                    ptr2[i_buf] = tree_end;
328                pt2[i_buf] = t;
329                num2[i_buf] = num1[j];
330                i_buf++;
331            }
332/*    go to next vertex    */
333            tp3 = tp2;
334            tp2 = tp1;
335            tp1 = t;
336            t = tn1;
337            tn1 = tn2;
338            tn2 = tn3;
339            nmp3 = nmp2;
340            nmp2 = nmp1;
341            nmp1 = nm;
342            nm = nmn1;
343            nmn1 = nmn2;
344            nmn2 = nmn3;
345
346            sp2 = sp1;
347            sp1 = s;
348            s = sn1;
349            sn1 = sn2;
350            sp2_c = sp1_c;
351            sp1_c = s_c;
352            s_c = sn1_c;
353            sn1_c = sn2_c;
354
355            ap2 = ap1;
356            ap1 = a;
357            a = an1;
358            an1 = an2;
359            bp2 = bp1;
360            bp1 = b;
361            b = bn1;
362            bn1 = bn2;
363            hp2 = hp1;
364            hp1 = h;
365            h = hn1;
366            hn1 = hn2;
367            j_3++;
368            if( j_3 >= i )
369                j_3 = 0;
370        }
371
372        i = i_buf;
373        e = e * koef;
374    }
375
376/*  constract tree root  */
377    if( i != 4 )
378        return CV_BADFACTOR_ERR;
379
380    t = pt2[0];
381    tn1 = pt2[1];
382    tn2 = pt2[2];
383    tp1 = pt2[3];
384    nm = num2[0];
385    nmn1 = num2[1];
386    nmn2 = num2[2];
387    nmp1 = num2[3];
388/*   first pair of the triangles   */
389    CV_MATCH_CHECK( status,
390                    icvCalcTriAttr( contour, t, tp1, nmp1, tn1, nmn1, &s, &s_c, &h, &a, &b ));
391    CV_MATCH_CHECK( status,
392                    icvCalcTriAttr( contour, tn2, tn1, nmn1, tp1, nmp1, &sn2, &sn2_c, &hn2,
393                                    &an2, &bn2 ));
394/*   second pair of the triangles   */
395    CV_MATCH_CHECK( status,
396                    icvCalcTriAttr( contour, tn1, t, nm, tn2, nmn2, &sn1, &sn1_c, &hn1, &an1,
397                                    &bn1 ));
398    CV_MATCH_CHECK( status,
399                    icvCalcTriAttr( contour, tp1, tn2, nmn2, t, nm, &sp1, &sp1_c, &hp1, &ap1,
400                                    &bp1 ));
401
402    a_s_c = fabs( s_c - sn2_c );
403    a_sp1_c = fabs( sp1_c - sn1_c );
404
405    if( a_s_c > a_sp1_c )
406/*   form child vertexs for the root     */
407    {
408        tree_one.pt = t;
409        tree_one.sign = (char) (CV_SIGN( s ));
410        tree_one.area = fabs( s );
411        tree_one.r1 = h / a;
412        tree_one.r2 = b / a;
413        tree_one.next_v1 = ptr2[3];
414        tree_one.next_v2 = ptr2[0];
415
416        tree_two.pt = tn2;
417        tree_two.sign = (char) (CV_SIGN( sn2 ));
418        tree_two.area = fabs( sn2 );
419        tree_two.r1 = hn2 / an2;
420        tree_two.r2 = bn2 / an2;
421        tree_two.next_v1 = ptr2[1];
422        tree_two.next_v2 = ptr2[2];
423
424        CV_WRITE_SEQ_ELEM( tree_one, writer );
425        cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
426
427        if( s_c > sn2_c )
428        {
429            if( ptr2[3] != NULL )
430                ptr2[3]->prev_v = cur_adr;
431            if( ptr2[0] != NULL )
432                ptr2[0]->prev_v = cur_adr;
433            ptr1[0] = cur_adr;
434
435            i_tree++;
436
437            CV_WRITE_SEQ_ELEM( tree_two, writer );
438            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
439
440            if( ptr2[1] != NULL )
441                ptr2[1]->prev_v = cur_adr;
442            if( ptr2[2] != NULL )
443                ptr2[2]->prev_v = cur_adr;
444            ptr1[1] = cur_adr;
445
446            i_tree++;
447
448            pt1[0] = tp1;
449            pt1[1] = tn1;
450        }
451        else
452        {
453            CV_WRITE_SEQ_ELEM( tree_two, writer );
454            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
455
456            if( ptr2[1] != NULL )
457                ptr2[1]->prev_v = cur_adr;
458            if( ptr2[2] != NULL )
459                ptr2[2]->prev_v = cur_adr;
460            ptr1[0] = cur_adr;
461
462            i_tree++;
463
464            CV_WRITE_SEQ_ELEM( tree_one, writer );
465            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
466
467            if( ptr2[3] != NULL )
468                ptr2[3]->prev_v = cur_adr;
469            if( ptr2[0] != NULL )
470                ptr2[0]->prev_v = cur_adr;
471            ptr1[1] = cur_adr;
472
473            i_tree++;
474
475            pt1[0] = tn1;
476            pt1[1] = tp1;
477        }
478    }
479    else
480    {
481        tree_one.pt = tp1;
482        tree_one.sign = (char) (CV_SIGN( sp1 ));
483        tree_one.area = fabs( sp1 );
484        tree_one.r1 = hp1 / ap1;
485        tree_one.r2 = bp1 / ap1;
486        tree_one.next_v1 = ptr2[2];
487        tree_one.next_v2 = ptr2[3];
488
489        tree_two.pt = tn1;
490        tree_two.sign = (char) (CV_SIGN( sn1 ));
491        tree_two.area = fabs( sn1 );
492        tree_two.r1 = hn1 / an1;
493        tree_two.r2 = bn1 / an1;
494        tree_two.next_v1 = ptr2[0];
495        tree_two.next_v2 = ptr2[1];
496
497        CV_WRITE_SEQ_ELEM( tree_one, writer );
498        cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
499
500        if( sp1_c > sn1_c )
501        {
502            if( ptr2[2] != NULL )
503                ptr2[2]->prev_v = cur_adr;
504            if( ptr2[3] != NULL )
505                ptr2[3]->prev_v = cur_adr;
506            ptr1[0] = cur_adr;
507
508            i_tree++;
509
510            CV_WRITE_SEQ_ELEM( tree_two, writer );
511            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
512
513            if( ptr2[0] != NULL )
514                ptr2[0]->prev_v = cur_adr;
515            if( ptr2[1] != NULL )
516                ptr2[1]->prev_v = cur_adr;
517            ptr1[1] = cur_adr;
518
519            i_tree++;
520
521            pt1[0] = tn2;
522            pt1[1] = t;
523        }
524        else
525        {
526            CV_WRITE_SEQ_ELEM( tree_two, writer );
527            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
528
529            if( ptr2[0] != NULL )
530                ptr2[0]->prev_v = cur_adr;
531            if( ptr2[1] != NULL )
532                ptr2[1]->prev_v = cur_adr;
533            ptr1[0] = cur_adr;
534
535            i_tree++;
536
537            CV_WRITE_SEQ_ELEM( tree_one, writer );
538            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size);
539
540            if( ptr2[2] != NULL )
541                ptr2[2]->prev_v = cur_adr;
542            if( ptr2[3] != NULL )
543                ptr2[3]->prev_v = cur_adr;
544            ptr1[1] = cur_adr;
545
546            i_tree++;
547
548            pt1[0] = t;
549            pt1[1] = tn2;
550
551        }
552    }
553
554/*    form root   */
555    s = cvContourArea( contour );
556
557    tree_root->pt = pt1[1];
558    tree_root->sign = 0;
559    tree_root->area = fabs( s );
560    tree_root->r1 = 0;
561    tree_root->r2 = 0;
562    tree_root->next_v1 = ptr1[0];
563    tree_root->next_v2 = ptr1[1];
564    tree_root->prev_v = NULL;
565
566    ptr1[0]->prev_v = (_CvTrianAttr *) tree_root;
567    ptr1[1]->prev_v = (_CvTrianAttr *) tree_root;
568
569/*     write binary tree root   */
570/*    CV_WRITE_SEQ_ELEM (tree_one, start_writer);   */
571    i_tree++;
572/*  create Sequence hearder     */
573    *((CvSeq **) tree) = cvEndWriteSeq( &writer );
574/*   write points for the main segment into sequence header   */
575    (*tree)->p1 = pt1[0];
576
577  M_END:
578
579    cvFree( &ptr_n );
580    cvFree( &ptr_p );
581    cvFree( &num_n );
582    cvFree( &num_p );
583    cvFree( &pt_n );
584    cvFree( &pt_p );
585
586    return status;
587}
588
589/****************************************************************************************\
590
591 triangle attributes calculations
592
593\****************************************************************************************/
594static CvStatus
595icvCalcTriAttr( const CvSeq * contour, CvPoint t2, CvPoint t1, int n1,
596                CvPoint t3, int n3, double *s, double *s_c,
597                double *h, double *a, double *b )
598{
599    double x13, y13, x12, y12, l_base, nx, ny, qq;
600    double eps = 1.e-5;
601
602    x13 = t3.x - t1.x;
603    y13 = t3.y - t1.y;
604    x12 = t2.x - t1.x;
605    y12 = t2.y - t1.y;
606    qq = x13 * x13 + y13 * y13;
607    l_base = cvSqrt( (float) (qq) );
608    if( l_base > eps )
609    {
610        nx = y13 / l_base;
611        ny = -x13 / l_base;
612
613        *h = nx * x12 + ny * y12;
614
615        *s = (*h) * l_base / 2.;
616
617        *b = nx * y12 - ny * x12;
618
619        *a = l_base;
620/*   calculate interceptive area   */
621        *s_c = cvContourArea( contour, cvSlice(n1, n3+1));
622    }
623    else
624    {
625        *h = 0;
626        *s = 0;
627        *s_c = 0;
628        *b = 0;
629        *a = 0;
630    }
631
632    return CV_OK;
633}
634
635/*F///////////////////////////////////////////////////////////////////////////////////////
636//    Name: cvCreateContourTree
637//    Purpose:
638//    Create binary tree representation for the contour
639//    Context:
640//    Parameters:
641//      contour - pointer to input contour object.
642//      storage - pointer to the current storage block
643//      tree   -  output pointer to the binary tree representation
644//      threshold - threshold for the binary tree building
645//
646//F*/
647CV_IMPL CvContourTree*
648cvCreateContourTree( const CvSeq* contour, CvMemStorage* storage, double threshold )
649{
650    CvContourTree* tree = 0;
651
652    CV_FUNCNAME( "cvCreateContourTree" );
653    __BEGIN__;
654
655    IPPI_CALL( icvCreateContourTree( contour, storage, &tree, threshold ));
656
657    __CLEANUP__;
658    __END__;
659
660    return tree;
661}
662
663
664/*F///////////////////////////////////////////////////////////////////////////////////////
665//    Name: icvContourFromContourTree
666//    Purpose:
667//    reconstracts contour from binary tree representation
668//    Context:
669//    Parameters:
670//      tree   -  pointer to the input binary tree representation
671//      storage - pointer to the current storage block
672//      contour - pointer to output contour object.
673//      criteria - criteria for the definition threshold value
674//                 for the contour reconstracting (level or precision)
675//F*/
676CV_IMPL CvSeq*
677cvContourFromContourTree( const CvContourTree*  tree,
678                          CvMemStorage*  storage,
679                          CvTermCriteria  criteria )
680{
681    CvSeq* contour = 0;
682    _CvTrianAttr **ptr_buf = 0;     /*  pointer to the pointer's buffer  */
683    int *level_buf = 0;
684    int i_buf;
685
686    int lpt;
687    double area_all;
688    double threshold;
689    int cur_level;
690    int level;
691    int seq_flags;
692    char log_iter, log_eps;
693    int out_hearder_size;
694    _CvTrianAttr *tree_one = 0, tree_root;  /*  current vertex  */
695
696    CvSeqReader reader;
697    CvSeqWriter writer;
698
699    CV_FUNCNAME("cvContourFromContourTree");
700
701    __BEGIN__;
702
703    if( !tree )
704        CV_ERROR( CV_StsNullPtr, "" );
705
706    if( !CV_IS_SEQ_POLYGON_TREE( tree ))
707        CV_ERROR_FROM_STATUS( CV_BADFLAG_ERR );
708
709    criteria = cvCheckTermCriteria( criteria, 0., 100 );
710
711    lpt = tree->total;
712    ptr_buf = NULL;
713    level_buf = NULL;
714    i_buf = 0;
715    cur_level = 0;
716    log_iter = (char) (criteria.type == CV_TERMCRIT_ITER ||
717                       (criteria.type == CV_TERMCRIT_ITER + CV_TERMCRIT_EPS));
718    log_eps = (char) (criteria.type == CV_TERMCRIT_EPS ||
719                      (criteria.type == CV_TERMCRIT_ITER + CV_TERMCRIT_EPS));
720
721    cvStartReadSeq( (CvSeq *) tree, &reader, 0 );
722
723    out_hearder_size = sizeof( CvContour );
724
725    seq_flags = CV_SEQ_POLYGON;
726    cvStartWriteSeq( seq_flags, out_hearder_size, sizeof( CvPoint ), storage, &writer );
727
728    ptr_buf = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * ));
729    if( ptr_buf == NULL )
730        CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
731    if( log_iter )
732    {
733        level_buf = (int *) cvAlloc( lpt * (sizeof( int )));
734
735        if( level_buf == NULL )
736            CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR );
737    }
738
739    memset( ptr_buf, 0, lpt * sizeof( _CvTrianAttr * ));
740
741/*     write the first tree root's point as a start point of the result contour  */
742    CV_WRITE_SEQ_ELEM( tree->p1, writer );
743/*     write the second tree root"s point into buffer    */
744
745/*     read the root of the tree   */
746    CV_READ_SEQ_ELEM( tree_root, reader );
747
748    tree_one = &tree_root;
749    area_all = tree_one->area;
750
751    if( log_eps )
752        threshold = criteria.epsilon * area_all;
753    else
754        threshold = 10 * area_all;
755
756    if( log_iter )
757        level = criteria.max_iter;
758    else
759        level = -1;
760
761/*  contour from binary tree constraction    */
762    while( i_buf >= 0 )
763    {
764        if( tree_one != NULL && (cur_level <= level || tree_one->area >= threshold) )
765/*   go to left sub tree for the vertex and save pointer to the right vertex   */
766/*   into the buffer     */
767        {
768            ptr_buf[i_buf] = tree_one;
769            if( log_iter )
770            {
771                level_buf[i_buf] = cur_level;
772                cur_level++;
773            }
774            i_buf++;
775            tree_one = tree_one->next_v1;
776        }
777        else
778        {
779            i_buf--;
780            if( i_buf >= 0 )
781            {
782                CvPoint pt = ptr_buf[i_buf]->pt;
783                CV_WRITE_SEQ_ELEM( pt, writer );
784                tree_one = ptr_buf[i_buf]->next_v2;
785                if( log_iter )
786                {
787                    cur_level = level_buf[i_buf] + 1;
788                }
789            }
790        }
791    }
792
793    contour = cvEndWriteSeq( &writer );
794    cvBoundingRect( contour, 1 );
795
796    __CLEANUP__;
797    __END__;
798
799    cvFree( &level_buf );
800    cvFree( &ptr_buf );
801
802    return contour;
803}
804
805