| /*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( &ptr_n ); |
| cvFree( &ptr_p ); |
| cvFree( &num_n ); |
| cvFree( &num_p ); |
| cvFree( &pt_n ); |
| cvFree( &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( &level_buf ); |
| cvFree( &ptr_buf ); |
| |
| return contour; |
| } |
| |