www.pudn.com > OpenCV-Intel.zip > cvcontourtree.cpp


/*M/////////////////////////////////////////////////////////////////////////////////////// 
// 
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 
// 
//  By downloading, copying, installing or using the software you agree to this license. 
//  If you do not agree to this license, do not download, install, 
//  copy or use the software. 
// 
// 
//                        Intel License Agreement 
//                For Open Source Computer Vision Library 
// 
// Copyright (C) 2000, Intel Corporation, all rights reserved. 
// Third party copyrights are property of their respective owners. 
// 
// Redistribution and use in source and binary forms, with or without modification, 
// are permitted provided that the following conditions are met: 
// 
//   * Redistribution's of source code must retain the above copyright notice, 
//     this list of conditions and the following disclaimer. 
// 
//   * Redistribution's in binary form must reproduce the above copyright notice, 
//     this list of conditions and the following disclaimer in the documentation 
//     and/or other materials provided with the distribution. 
// 
//   * The name of Intel Corporation may not be used to endorse or promote products 
//     derived from this software without specific prior written permission. 
// 
// This software is provided by the copyright holders and contributors "as is" and 
// any express or implied warranties, including, but not limited to, the implied 
// warranties of merchantability and fitness for a particular purpose are disclaimed. 
// In no event shall the Intel Corporation or contributors be liable for any direct, 
// indirect, incidental, special, exemplary, or consequential damages 
// (including, but not limited to, procurement of substitute goods or services; 
// loss of use, data, or profits; or business interruption) however caused 
// and on any theory of liability, whether in contract, strict liability, 
// or tort (including negligence or otherwise) arising in any way out of 
// the use of this software, even if advised of the possibility of such damage. 
// 
//M*/ 
#include "_cv.h" 
 
#define CV_MATCH_CHECK( status, cvFun )                                    \ 
  {                                                                        \ 
    status = cvFun;                                                        \ 
    if( status != CV_OK )                                                  \ 
     goto M_END;                                                           \ 
  } 
 
static CvStatus 
icvCalcTriAttr( const CvSeq * contour, CvPoint t2, CvPoint t1, int n1, 
                CvPoint t3, int n3, double *s, double *s_c, 
                double *h, double *a, double *b ); 
 
/*F/////////////////////////////////////////////////////////////////////////////////////// 
//    Name: icvCreateContourTree 
//    Purpose: 
//    Create binary tree representation for the contour  
//    Context: 
//    Parameters: 
//      contour - pointer to input contour object. 
//      storage - pointer to the current storage block 
//      tree   -  output pointer to the binary tree representation  
//      threshold - threshold for the binary tree building  
// 
//F*/ 
static CvStatus 
icvCreateContourTree( const CvSeq * contour, CvMemStorage * storage, 
                      CvContourTree ** tree, double threshold ) 
{ 
    CvPoint *pt_p;              /*  pointer to previos points   */ 
    CvPoint *pt_n;              /*  pointer to next points      */ 
    CvPoint *pt1, *pt2;         /*  pointer to current points   */ 
 
    CvPoint t, tp1, tp2, tp3, tn1, tn2, tn3; 
    int lpt, flag, i, j, i_tree, j_1, j_3, i_buf; 
    double s, sp1, sp2, sn1, sn2, s_c, sp1_c, sp2_c, sn1_c, sn2_c, h, hp1, hp2, hn1, hn2, 
        a, ap1, ap2, an1, an2, b, bp1, bp2, bn1, bn2; 
    double a_s_c, a_sp1_c; 
 
    _CvTrianAttr **ptr_p, **ptr_n, **ptr1, **ptr2;      /*  pointers to pointers of triangles  */ 
    _CvTrianAttr *cur_adr; 
 
    int *num_p, *num_n, *num1, *num2;   /*   numbers of input contour points   */ 
    int nm, nmp1, nmp2, nmp3, nmn1, nmn2, nmn3; 
    int seq_flags = 1, i_end, prev_null, prev2_null; 
    double koef = 1.5; 
    double eps = 1.e-7; 
    double e; 
    CvStatus status; 
    int hearder_size; 
    _CvTrianAttr tree_one, tree_two, *tree_end, *tree_root; 
 
    CvSeqWriter writer; 
 
    assert( contour != NULL && contour->total >= 4 ); 
    status = CV_OK; 
 
    if( contour == NULL ) 
        return CV_NULLPTR_ERR; 
    if( contour->total < 4 ) 
        return CV_BADSIZE_ERR; 
 
    if( !CV_IS_SEQ_POLYGON( contour )) 
        return CV_BADFLAG_ERR; 
 
 
/*   Convert Sequence to array    */ 
    lpt = contour->total; 
    pt_p = pt_n = NULL; 
    num_p = num_n = NULL; 
    ptr_p = ptr_n = ptr1 = ptr2 = NULL; 
    tree_end = NULL; 
 
    pt_p = (CvPoint *) cvAlloc( lpt * sizeof( CvPoint )); 
    pt_n = (CvPoint *) cvAlloc( lpt * sizeof( CvPoint )); 
 
    num_p = (int *) cvAlloc( lpt * sizeof( int )); 
    num_n = (int *) cvAlloc( lpt * sizeof( int )); 
 
    hearder_size = sizeof( CvContourTree ); 
    seq_flags = CV_SEQ_POLYGON_TREE; 
    cvStartWriteSeq( seq_flags, hearder_size, sizeof( _CvTrianAttr ), storage, &writer ); 
 
    ptr_p = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * )); 
    ptr_n = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * )); 
 
    memset( ptr_p, 0, lpt * sizeof( _CvTrianAttr * )); 
    memset( ptr_n, 0, lpt * sizeof( _CvTrianAttr * )); 
 
    if( pt_p == NULL || pt_n == NULL ) 
        return CV_OUTOFMEM_ERR; 
    if( ptr_p == NULL || ptr_n == NULL ) 
        return CV_OUTOFMEM_ERR; 
 
/*     write fild for the binary tree root   */ 
/*  start_writer = writer;   */ 
 
    tree_one.pt.x = tree_one.pt.y = 0; 
    tree_one.sign = 0; 
    tree_one.area = 0; 
    tree_one.r1 = tree_one.r2 = 0; 
    tree_one.next_v1 = tree_one.next_v2 = tree_one.prev_v = NULL; 
 
    CV_WRITE_SEQ_ELEM( tree_one, writer ); 
    tree_root = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size); 
 
    if( cvCvtSeqToArray( contour, (char *) pt_p ) == (char *) contour ) 
        return CV_BADPOINT_ERR; 
 
    for( i = 0; i < lpt; i++ ) 
        num_p[i] = i; 
 
    i = lpt; 
    flag = 0; 
    i_tree = 0; 
    e = 20.;                    /*  initial threshold value   */ 
    ptr1 = ptr_p; 
    ptr2 = ptr_n; 
    pt1 = pt_p; 
    pt2 = pt_n; 
    num1 = num_p; 
    num2 = num_n; 
/*  binary tree constraction    */ 
    while( i > 4 ) 
    { 
        if( flag == 0 ) 
        { 
            ptr1 = ptr_p; 
            ptr2 = ptr_n; 
            pt1 = pt_p; 
            pt2 = pt_n; 
            num1 = num_p; 
            num2 = num_n; 
            flag = 1; 
        } 
        else 
        { 
            ptr1 = ptr_n; 
            ptr2 = ptr_p; 
            pt1 = pt_n; 
            pt2 = pt_p; 
            num1 = num_n; 
            num2 = num_p; 
            flag = 0; 
        } 
        t = pt1[0]; 
        nm = num1[0]; 
        tp1 = pt1[i - 1]; 
        nmp1 = num1[i - 1]; 
        tp2 = pt1[i - 2]; 
        nmp2 = num1[i - 2]; 
        tp3 = pt1[i - 3]; 
        nmp3 = num1[i - 3]; 
        tn1 = pt1[1]; 
        nmn1 = num1[1]; 
        tn2 = pt1[2]; 
        nmn2 = num1[2]; 
 
        i_buf = 0; 
        i_end = -1; 
        CV_MATCH_CHECK( status, 
                        icvCalcTriAttr( contour, t, tp1, nmp1, tn1, nmn1, &s, &s_c, &h, &a, 
                                        &b )); 
        CV_MATCH_CHECK( status, 
                        icvCalcTriAttr( contour, tp1, tp2, nmp2, t, nm, &sp1, &sp1_c, &hp1, 
                                        &ap1, &bp1 )); 
        CV_MATCH_CHECK( status, 
                        icvCalcTriAttr( contour, tp2, tp3, nmp3, tp1, nmp1, &sp2, &sp2_c, &hp2, 
                                        &ap2, &bp2 )); 
        CV_MATCH_CHECK( status, 
                        icvCalcTriAttr( contour, tn1, t, nm, tn2, nmn2, &sn1, &sn1_c, &hn1, 
                                        &an1, &bn1 )); 
 
 
        j_3 = 3; 
        prev_null = prev2_null = 0; 
        for( j = 0; j < i; j++ ) 
        { 
            tn3 = pt1[j_3]; 
            nmn3 = num1[j_3]; 
            if( j == 0 ) 
                j_1 = i - 1; 
            else 
                j_1 = j - 1; 
 
            CV_MATCH_CHECK( status, icvCalcTriAttr( contour, tn2, tn1, nmn1, tn3, nmn3, 
                                                    &sn2, &sn2_c, &hn2, &an2, &bn2 )); 
 
            if( (s_c < sp1_c && s_c < sp2_c && s_c <= sn1_c && s_c <= sn2_c && s_c < e) || 
                (s_c == sp1_c && s_c <= sp2_c || s_c == sp2_c && s_c <= sp1_c) && s_c <= sn1_c 
                && s_c <= sn2_c && s_c < e && j > 1 && prev2_null == 0 || (s_c < eps && j > 0 
                                                                           && prev_null == 0) ) 
 
            { 
                prev_null = prev2_null = 1; 
                if( s_c < threshold ) 
                { 
                    if( ptr1[j_1] == NULL && ptr1[j] == NULL ) 
                    { 
                        if( i_buf > 0 ) 
                            ptr2[i_buf - 1] = NULL; 
                        else 
                            i_end = 0; 
                    } 
                    else 
                    { 
/*   form next vertex  */ 
                        tree_one.pt = t; 
                        tree_one.sign = (char) (CV_SIGN( s )); 
                        tree_one.r1 = h / a; 
                        tree_one.r2 = b / a; 
                        tree_one.area = fabs( s ); 
                        tree_one.next_v1 = ptr1[j_1]; 
                        tree_one.next_v2 = ptr1[j]; 
 
                        CV_WRITE_SEQ_ELEM( tree_one, writer ); 
                        cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size); 
 
                        if( ptr1[j_1] != NULL ) 
                            ptr1[j_1]->prev_v = cur_adr; 
                        if( ptr1[j] != NULL ) 
                            ptr1[j]->prev_v = cur_adr; 
 
                        if( i_buf > 0 ) 
                            ptr2[i_buf - 1] = cur_adr; 
                        else 
                        { 
                            tree_end = (_CvTrianAttr *) writer.ptr; 
                            i_end = 1; 
                        } 
                        i_tree++; 
                    } 
                } 
                else 
/*   form next vertex    */ 
                { 
                    tree_one.pt = t; 
                    tree_one.sign = (char) (CV_SIGN( s )); 
                    tree_one.area = fabs( s ); 
                    tree_one.r1 = h / a; 
                    tree_one.r2 = b / a; 
                    tree_one.next_v1 = ptr1[j_1]; 
                    tree_one.next_v2 = ptr1[j]; 
 
                    CV_WRITE_SEQ_ELEM( tree_one, writer ); 
                    cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size); 
 
                    if( ptr1[j_1] != NULL ) 
                        ptr1[j_1]->prev_v = cur_adr; 
                    if( ptr1[j] != NULL ) 
                        ptr1[j]->prev_v = cur_adr; 
 
                    if( i_buf > 0 ) 
                        ptr2[i_buf - 1] = cur_adr; 
                    else 
                    { 
                        tree_end = cur_adr; 
                        i_end = 1; 
                    } 
                    i_tree++; 
                } 
            } 
            else 
/*   the current triangle is'not LMIAT    */ 
            { 
                prev_null = 0; 
                switch (prev2_null) 
                { 
                case 0: 
                    break; 
                case 1: 
                    { 
                        prev2_null = 2; 
                        break; 
                    } 
                case 2: 
                    { 
                        prev2_null = 0; 
                        break; 
                    } 
                } 
                if( j != i - 1 || i_end == -1 ) 
                    ptr2[i_buf] = ptr1[j]; 
                else if( i_end == 0 ) 
                    ptr2[i_buf] = NULL; 
                else 
                    ptr2[i_buf] = tree_end; 
                pt2[i_buf] = t; 
                num2[i_buf] = num1[j]; 
                i_buf++; 
            } 
/*    go to next vertex    */ 
            tp3 = tp2; 
            tp2 = tp1; 
            tp1 = t; 
            t = tn1; 
            tn1 = tn2; 
            tn2 = tn3; 
            nmp3 = nmp2; 
            nmp2 = nmp1; 
            nmp1 = nm; 
            nm = nmn1; 
            nmn1 = nmn2; 
            nmn2 = nmn3; 
 
            sp2 = sp1; 
            sp1 = s; 
            s = sn1; 
            sn1 = sn2; 
            sp2_c = sp1_c; 
            sp1_c = s_c; 
            s_c = sn1_c; 
            sn1_c = sn2_c; 
 
            ap2 = ap1; 
            ap1 = a; 
            a = an1; 
            an1 = an2; 
            bp2 = bp1; 
            bp1 = b; 
            b = bn1; 
            bn1 = bn2; 
            hp2 = hp1; 
            hp1 = h; 
            h = hn1; 
            hn1 = hn2; 
            j_3++; 
            if( j_3 >= i ) 
                j_3 = 0; 
        } 
 
        i = i_buf; 
        e = e * koef; 
    } 
 
/*  constract tree root  */ 
    if( i != 4 ) 
        return CV_BADFACTOR_ERR; 
 
    t = pt2[0]; 
    tn1 = pt2[1]; 
    tn2 = pt2[2]; 
    tp1 = pt2[3]; 
    nm = num2[0]; 
    nmn1 = num2[1]; 
    nmn2 = num2[2]; 
    nmp1 = num2[3]; 
/*   first pair of the triangles   */ 
    CV_MATCH_CHECK( status, 
                    icvCalcTriAttr( contour, t, tp1, nmp1, tn1, nmn1, &s, &s_c, &h, &a, &b )); 
    CV_MATCH_CHECK( status, 
                    icvCalcTriAttr( contour, tn2, tn1, nmn1, tp1, nmp1, &sn2, &sn2_c, &hn2, 
                                    &an2, &bn2 )); 
/*   second pair of the triangles   */ 
    CV_MATCH_CHECK( status, 
                    icvCalcTriAttr( contour, tn1, t, nm, tn2, nmn2, &sn1, &sn1_c, &hn1, &an1, 
                                    &bn1 )); 
    CV_MATCH_CHECK( status, 
                    icvCalcTriAttr( contour, tp1, tn2, nmn2, t, nm, &sp1, &sp1_c, &hp1, &ap1, 
                                    &bp1 )); 
 
    a_s_c = fabs( s_c - sn2_c ); 
    a_sp1_c = fabs( sp1_c - sn1_c ); 
 
    if( a_s_c > a_sp1_c ) 
/*   form child vertexs for the root     */ 
    { 
        tree_one.pt = t; 
        tree_one.sign = (char) (CV_SIGN( s )); 
        tree_one.area = fabs( s ); 
        tree_one.r1 = h / a; 
        tree_one.r2 = b / a; 
        tree_one.next_v1 = ptr2[3]; 
        tree_one.next_v2 = ptr2[0]; 
 
        tree_two.pt = tn2; 
        tree_two.sign = (char) (CV_SIGN( sn2 )); 
        tree_two.area = fabs( sn2 ); 
        tree_two.r1 = hn2 / an2; 
        tree_two.r2 = bn2 / an2; 
        tree_two.next_v1 = ptr2[1]; 
        tree_two.next_v2 = ptr2[2]; 
 
        CV_WRITE_SEQ_ELEM( tree_one, writer ); 
        cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size); 
 
        if( s_c > sn2_c ) 
        { 
            if( ptr2[3] != NULL ) 
                ptr2[3]->prev_v = cur_adr; 
            if( ptr2[0] != NULL ) 
                ptr2[0]->prev_v = cur_adr; 
            ptr1[0] = cur_adr; 
 
            i_tree++; 
 
            CV_WRITE_SEQ_ELEM( tree_two, writer ); 
            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size); 
 
            if( ptr2[1] != NULL ) 
                ptr2[1]->prev_v = cur_adr; 
            if( ptr2[2] != NULL ) 
                ptr2[2]->prev_v = cur_adr; 
            ptr1[1] = cur_adr; 
 
            i_tree++; 
 
            pt1[0] = tp1; 
            pt1[1] = tn1; 
        } 
        else 
        { 
            CV_WRITE_SEQ_ELEM( tree_two, writer ); 
            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size); 
 
            if( ptr2[1] != NULL ) 
                ptr2[1]->prev_v = cur_adr; 
            if( ptr2[2] != NULL ) 
                ptr2[2]->prev_v = cur_adr; 
            ptr1[0] = cur_adr; 
 
            i_tree++; 
 
            CV_WRITE_SEQ_ELEM( tree_one, writer ); 
            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size); 
 
            if( ptr2[3] != NULL ) 
                ptr2[3]->prev_v = cur_adr; 
            if( ptr2[0] != NULL ) 
                ptr2[0]->prev_v = cur_adr; 
            ptr1[1] = cur_adr; 
 
            i_tree++; 
 
            pt1[0] = tn1; 
            pt1[1] = tp1; 
        } 
    } 
    else 
    { 
        tree_one.pt = tp1; 
        tree_one.sign = (char) (CV_SIGN( sp1 )); 
        tree_one.area = fabs( sp1 ); 
        tree_one.r1 = hp1 / ap1; 
        tree_one.r2 = bp1 / ap1; 
        tree_one.next_v1 = ptr2[2]; 
        tree_one.next_v2 = ptr2[3]; 
 
        tree_two.pt = tn1; 
        tree_two.sign = (char) (CV_SIGN( sn1 )); 
        tree_two.area = fabs( sn1 ); 
        tree_two.r1 = hn1 / an1; 
        tree_two.r2 = bn1 / an1; 
        tree_two.next_v1 = ptr2[0]; 
        tree_two.next_v2 = ptr2[1]; 
 
        CV_WRITE_SEQ_ELEM( tree_one, writer ); 
        cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size); 
 
        if( sp1_c > sn1_c ) 
        { 
            if( ptr2[2] != NULL ) 
                ptr2[2]->prev_v = cur_adr; 
            if( ptr2[3] != NULL ) 
                ptr2[3]->prev_v = cur_adr; 
            ptr1[0] = cur_adr; 
 
            i_tree++; 
 
            CV_WRITE_SEQ_ELEM( tree_two, writer ); 
            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size); 
 
            if( ptr2[0] != NULL ) 
                ptr2[0]->prev_v = cur_adr; 
            if( ptr2[1] != NULL ) 
                ptr2[1]->prev_v = cur_adr; 
            ptr1[1] = cur_adr; 
 
            i_tree++; 
 
            pt1[0] = tn2; 
            pt1[1] = t; 
        } 
        else 
        { 
            CV_WRITE_SEQ_ELEM( tree_two, writer ); 
            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size); 
 
            if( ptr2[0] != NULL ) 
                ptr2[0]->prev_v = cur_adr; 
            if( ptr2[1] != NULL ) 
                ptr2[1]->prev_v = cur_adr; 
            ptr1[0] = cur_adr; 
 
            i_tree++; 
 
            CV_WRITE_SEQ_ELEM( tree_one, writer ); 
            cur_adr = (_CvTrianAttr *) (writer.ptr - writer.seq->elem_size); 
 
            if( ptr2[2] != NULL ) 
                ptr2[2]->prev_v = cur_adr; 
            if( ptr2[3] != NULL ) 
                ptr2[3]->prev_v = cur_adr; 
            ptr1[1] = cur_adr; 
 
            i_tree++; 
 
            pt1[0] = t; 
            pt1[1] = tn2; 
 
        } 
    } 
 
/*    form root   */ 
    s = cvContourArea( contour ); 
 
    tree_root->pt = pt1[1]; 
    tree_root->sign = 0; 
    tree_root->area = fabs( s ); 
    tree_root->r1 = 0; 
    tree_root->r2 = 0; 
    tree_root->next_v1 = ptr1[0]; 
    tree_root->next_v2 = ptr1[1]; 
    tree_root->prev_v = NULL; 
 
    ptr1[0]->prev_v = (_CvTrianAttr *) tree_root; 
    ptr1[1]->prev_v = (_CvTrianAttr *) tree_root; 
 
/*     write binary tree root   */ 
/*    CV_WRITE_SEQ_ELEM (tree_one, start_writer);   */ 
    i_tree++; 
/*  create Sequence hearder     */ 
    *((CvSeq **) tree) = cvEndWriteSeq( &writer ); 
/*   write points for the main segment into sequence header   */ 
    (*tree)->p1 = pt1[0]; 
 
  M_END: 
 
    cvFree( (void**)&ptr_n ); 
    cvFree( (void**)&ptr_p ); 
    cvFree( (void**)&num_n ); 
    cvFree( (void**)&num_p ); 
    cvFree( (void**)&pt_n ); 
    cvFree( (void**)&pt_p ); 
 
    return status; 
} 
 
/****************************************************************************************\ 
 
 triangle attributes calculations  
 
\****************************************************************************************/ 
static CvStatus 
icvCalcTriAttr( const CvSeq * contour, CvPoint t2, CvPoint t1, int n1, 
                CvPoint t3, int n3, double *s, double *s_c, 
                double *h, double *a, double *b ) 
{ 
    double x13, y13, x12, y12, l_base, nx, ny, qq; 
    double eps = 1.e-5; 
 
    x13 = t3.x - t1.x; 
    y13 = t3.y - t1.y; 
    x12 = t2.x - t1.x; 
    y12 = t2.y - t1.y; 
    qq = x13 * x13 + y13 * y13; 
    l_base = cvSqrt( (float) (qq) ); 
    if( l_base > eps ) 
    { 
        nx = y13 / l_base; 
        ny = -x13 / l_base; 
 
        *h = nx * x12 + ny * y12; 
 
        *s = (*h) * l_base / 2.; 
 
        *b = nx * y12 - ny * x12; 
 
        *a = l_base; 
/*   calculate interceptive area   */ 
        *s_c = cvContourArea( contour, cvSlice(n1, n3+1)); 
    } 
    else 
    { 
        *h = 0; 
        *s = 0; 
        *s_c = 0; 
        *b = 0; 
        *a = 0; 
    } 
 
    return CV_OK; 
} 
 
/*F/////////////////////////////////////////////////////////////////////////////////////// 
//    Name: cvCreateContourTree 
//    Purpose: 
//    Create binary tree representation for the contour  
//    Context: 
//    Parameters: 
//      contour - pointer to input contour object. 
//      storage - pointer to the current storage block 
//      tree   -  output pointer to the binary tree representation  
//      threshold - threshold for the binary tree building  
// 
//F*/ 
CV_IMPL CvContourTree* 
cvCreateContourTree( const CvSeq* contour, CvMemStorage* storage, double threshold ) 
{ 
    CvContourTree* tree = 0; 
     
    CV_FUNCNAME( "cvCreateContourTree" ); 
    __BEGIN__; 
 
    IPPI_CALL( icvCreateContourTree( contour, storage, &tree, threshold )); 
 
    __CLEANUP__; 
    __END__; 
 
    return tree; 
} 
 
 
/*F/////////////////////////////////////////////////////////////////////////////////////// 
//    Name: icvContourFromContourTree 
//    Purpose: 
//    reconstracts contour from binary tree representation   
//    Context: 
//    Parameters: 
//      tree   -  pointer to the input binary tree representation  
//      storage - pointer to the current storage block 
//      contour - pointer to output contour object. 
//      criteria - criteria for the definition threshold value 
//                 for the contour reconstracting (level or precision) 
//F*/ 
CV_IMPL CvSeq* 
cvContourFromContourTree( const CvContourTree*  tree, 
                          CvMemStorage*  storage, 
                          CvTermCriteria  criteria ) 
{ 
    CvSeq* contour = 0; 
    _CvTrianAttr **ptr_buf = 0;     /*  pointer to the pointer's buffer  */ 
    int *level_buf = 0; 
    int i_buf; 
 
    int lpt; 
    double area_all; 
    double threshold; 
    int cur_level; 
    int level; 
    int seq_flags; 
    char log_iter, log_eps; 
    int out_hearder_size; 
    _CvTrianAttr *tree_one = 0, tree_root;  /*  current vertex  */ 
 
    CvSeqReader reader; 
    CvSeqWriter writer; 
 
    CV_FUNCNAME("cvContourFromContourTree"); 
 
    __BEGIN__; 
 
    if( !tree ) 
        CV_ERROR( CV_StsNullPtr, "" ); 
 
    if( !CV_IS_SEQ_POLYGON_TREE( tree )) 
        CV_ERROR_FROM_STATUS( CV_BADFLAG_ERR ); 
 
    criteria = cvCheckTermCriteria( criteria, 0., 100 ); 
 
    lpt = tree->total; 
    ptr_buf = NULL; 
    level_buf = NULL; 
    i_buf = 0; 
    cur_level = 0; 
    log_iter = (char) (criteria.type == CV_TERMCRIT_ITER || 
                       (criteria.type == CV_TERMCRIT_ITER + CV_TERMCRIT_EPS)); 
    log_eps = (char) (criteria.type == CV_TERMCRIT_EPS || 
                      (criteria.type == CV_TERMCRIT_ITER + CV_TERMCRIT_EPS)); 
 
    cvStartReadSeq( (CvSeq *) tree, &reader, 0 ); 
 
    out_hearder_size = sizeof( CvContour ); 
 
    seq_flags = CV_SEQ_POLYGON; 
    cvStartWriteSeq( seq_flags, out_hearder_size, sizeof( CvPoint ), storage, &writer ); 
 
    ptr_buf = (_CvTrianAttr **) cvAlloc( lpt * sizeof( _CvTrianAttr * )); 
    if( ptr_buf == NULL ) 
        CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR ); 
    if( log_iter ) 
    { 
        level_buf = (int *) cvAlloc( lpt * (sizeof( int ))); 
 
        if( level_buf == NULL ) 
            CV_ERROR_FROM_STATUS( CV_OUTOFMEM_ERR ); 
    } 
 
    memset( ptr_buf, 0, lpt * sizeof( _CvTrianAttr * )); 
 
/*     write the first tree root's point as a start point of the result contour  */ 
    CV_WRITE_SEQ_ELEM( tree->p1, writer ); 
/*     write the second tree root"s point into buffer    */ 
 
/*     read the root of the tree   */ 
    CV_READ_SEQ_ELEM( tree_root, reader ); 
 
    tree_one = &tree_root; 
    area_all = tree_one->area; 
 
    if( log_eps ) 
        threshold = criteria.epsilon * area_all; 
    else 
        threshold = 10 * area_all; 
 
    if( log_iter ) 
        level = criteria.max_iter; 
    else 
        level = -1; 
 
/*  contour from binary tree constraction    */ 
    while( i_buf >= 0 ) 
    { 
        if( tree_one != NULL && (cur_level <= level || tree_one->area >= threshold) ) 
/*   go to left sub tree for the vertex and save pointer to the right vertex   */ 
/*   into the buffer     */ 
        { 
            ptr_buf[i_buf] = tree_one; 
            if( log_iter ) 
            { 
                level_buf[i_buf] = cur_level; 
                cur_level++; 
            } 
            i_buf++; 
            tree_one = tree_one->next_v1; 
        } 
        else 
        { 
            i_buf--; 
            if( i_buf >= 0 ) 
            { 
                CvPoint pt = ptr_buf[i_buf]->pt; 
                CV_WRITE_SEQ_ELEM( pt, writer ); 
                tree_one = ptr_buf[i_buf]->next_v2; 
                if( log_iter ) 
                { 
                    cur_level = level_buf[i_buf] + 1; 
                } 
            } 
        } 
    } 
 
    contour = cvEndWriteSeq( &writer ); 
    cvBoundingRect( contour, 1 ); 
 
    __CLEANUP__; 
    __END__; 
 
    cvFree( (void**)&level_buf ); 
    cvFree( (void**)&ptr_buf ); 
 
    return contour; 
}