/*F/////////////////////////////////////////////////////////////////////////////////////// // Name: icvCalcPGH // Purpose: // Calculates PGH(pairwise geometric histogram) for contour given. // Context: // Parameters: // contour - pointer to input contour object. // pgh - output histogram // ang_dim - number of angle bins (vertical size of histogram) // dist_dim - number of distance bins (horizontal size of histogram) // Returns: // CV_OK or error code // Notes: //F*/ CvStatus icvCalcPGH( CvSeq * contour, float *pgh, int angle_dim, int dist_dim ) { char local_buffer[(1 << 14) + 32]; float *local_buffer_ptr = (float *)icvAlignPtr(local_buffer,32); float *buffer = local_buffer_ptr; double angle_scale = (angle_dim - 0.51) / icv_acos_table[0]; double dist_scale = DBL_EPSILON; int buffer_size; int i, count, pass; int *pghi = (int *) pgh; int hist_size = angle_dim * dist_dim; CvSeqReader reader1, reader2; /* external and internal readers */ if( !contour || !pgh ) return CV_NULLPTR_ERR; if( angle_dim <= 0 || angle_dim > 180 || dist_dim <= 0 ) return CV_BADRANGE_ERR; if( !CV_IS_SEQ_POLYGON( contour )) return CV_BADFLAG_ERR; memset( pgh, 0, hist_size * sizeof( pgh[0] )); count = contour->total; /* allocate buffer for distances */ buffer_size = count * sizeof( float ); if( buffer_size > (int)sizeof(local_buffer) - 32 ) { buffer = (float *) icvAlloc( buffer_size ); if( !buffer ) return CV_OUTOFMEM_ERR; } cvStartReadSeq( contour, &reader1, 0 ); cvStartReadSeq( contour, &reader2, 0 ); /* calc & store squared edge lengths, calculate maximal distance between edges */ for( i = 0; i < count; i++ ) { CvPoint pt1, pt2; int dx, dy; CV_READ_EDGE( pt1, pt2, reader1 ); dx = pt2.x - pt1.x; dy = pt2.y - pt1.y; buffer[i] = (float) (dx * dx + dy * dy); } icvbInvSqrt_32f( buffer, buffer, i ); /* do 2 passes. First calculates maximal distance. Second calculates histogram itself. */ for( pass = 1; pass <= 2; pass++ ) { double dist_coeff = 0, angle_coeff = 0; /* run external loop */ for( i = 0; i < count; i++ ) { CvPoint pt1, pt2; int dx, dy; int dist = 0; CV_READ_EDGE( pt1, pt2, reader1 ); dx = pt2.x - pt1.x; dy = pt2.y - pt1.y; if( (dx | dy) != 0 ) { int j; if( pass == 2 ) { dist_coeff = buffer[i] * dist_scale; angle_coeff = buffer[i] * (_CV_ACOS_TABLE_SIZE / 2); } /* run internal loop (for current edge) */ for( j = 0; j < count; j++ ) { CvPoint pt3, pt4; CV_READ_EDGE( pt3, pt4, reader2 ); if( i != j ) /* process edge pair */ { int d1 = (pt3.y - pt1.y) * dx - (pt3.x - pt1.x) * dy; int d2 = (pt4.y - pt1.y) * dx - (pt2.x - pt1.x) * dy; int cross_flag; int *hist_row = 0; if( pass == 2 ) { int dp = (pt4.x - pt3.x) * dx + (pt4.y - pt3.y) * dy; dp = cvRound( dp * angle_coeff * buffer[j] ) + (_CV_ACOS_TABLE_SIZE / 2); dp = MAX( dp, 0 ); dp = MIN( dp, _CV_ACOS_TABLE_SIZE - 1 ); hist_row = pghi + dist_dim * cvRound( icv_acos_table[dp] * angle_scale ); d1 = cvRound( d1 * dist_coeff ); d2 = cvRound( d2 * dist_coeff ); } cross_flag = (d1 ^ d2) < 0; d1 = CV_IABS( d1 ); d2 = CV_IABS( d2 ); if( pass == 2 ) { if( d1 >= dist_dim ) d1 = dist_dim - 1; if( d2 >= dist_dim ) d2 = dist_dim - 1; if( !cross_flag ) { if( d1 > d2 ) /* make d1 <= d2 */ { d1 ^= d2; d2 ^= d1; d1 ^= d2; } for( ; d1 <= d2; d1++ ) hist_row[d1]++; } else { for( ; d1 >= 0; d1-- ) hist_row[d1]++; for( ; d2 >= 0; d2-- ) hist_row[d2]++; } } else /* 1st pass */ { d1 = CV_IMAX( d1, d2 ); dist = CV_IMAX( dist, d1 ); } } /* end of processing of edge pair */ } /* end of internal loop */ if( pass == 1 ) { double scale = dist * buffer[i]; dist_scale = MAX( dist_scale, scale ); } } } /* end of external loop */ if( pass == 1 ) { dist_scale = (dist_dim - 0.51) / dist_scale; } } /* end of pass on loops */ /* convert hist to floats */ for( i = 0; i < hist_size; i++ ) { ((float *) pghi)[i] = (float) pghi[i]; } if( buffer != local_buffer_ptr ) icvFree( &buffer ); return CV_OK; }
CV_IMPL double cvPointPolygonTest( const CvArr* _contour, CvPoint2D32f pt, int measure_dist ) { double result = 0; CV_FUNCNAME( "cvCheckPointPolygon" ); __BEGIN__; CvSeqBlock block; CvContour header; CvSeq* contour = (CvSeq*)_contour; CvSeqReader reader; int i, total, counter = 0; int is_float; double min_dist_num = FLT_MAX, min_dist_denom = 1; CvPoint ip = {0,0}; if( !CV_IS_SEQ(contour) ) { CV_CALL( contour = cvPointSeqFromMat( CV_SEQ_KIND_CURVE + CV_SEQ_FLAG_CLOSED, _contour, &header, &block )); } else if( CV_IS_SEQ_POLYGON(contour) ) { if( contour->header_size == sizeof(CvContour) && !measure_dist ) { CvRect r = ((CvContour*)contour)->rect; if( pt.x < r.x || pt.y < r.y || pt.x >= r.x + r.width || pt.y >= r.y + r.height ) return -100; } } else if( CV_IS_SEQ_CHAIN(contour) ) { CV_ERROR( CV_StsBadArg, "Chains are not supported. Convert them to polygonal representation using cvApproxChains()" ); } else CV_ERROR( CV_StsBadArg, "Input contour is neither a valid sequence nor a matrix" ); total = contour->total; is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2; cvStartReadSeq( contour, &reader, -1 ); if( !is_float && !measure_dist && (ip.x = cvRound(pt.x)) == pt.x && (ip.y = cvRound(pt.y)) == pt.y ) { // the fastest "pure integer" branch CvPoint v0, v; CV_READ_SEQ_ELEM( v, reader ); for( i = 0; i < total; i++ ) { int dist; v0 = v; CV_READ_SEQ_ELEM( v, reader ); if( (v0.y <= ip.y && v.y <= ip.y) || (v0.y > ip.y && v.y > ip.y) || (v0.x < ip.x && v.x < ip.x) ) { if( ip.y == v.y && (ip.x == v.x || (ip.y == v0.y && ((v0.x <= ip.x && ip.x <= v.x) || (v.x <= ip.x && ip.x <= v0.x)))) ) EXIT; continue; } dist = (ip.y - v0.y)*(v.x - v0.x) - (ip.x - v0.x)*(v.y - v0.y); if( dist == 0 ) EXIT; if( v.y < v0.y ) dist = -dist; counter += dist > 0; } result = counter % 2 == 0 ? -100 : 100; } else { CvPoint2D32f v0, v; CvPoint iv; if( is_float ) { CV_READ_SEQ_ELEM( v, reader ); } else { CV_READ_SEQ_ELEM( iv, reader ); v = cvPointTo32f( iv ); } if( !measure_dist ) { for( i = 0; i < total; i++ ) { double dist; v0 = v; if( is_float ) { CV_READ_SEQ_ELEM( v, reader ); } else { CV_READ_SEQ_ELEM( iv, reader ); v = cvPointTo32f( iv ); } if( (v0.y <= pt.y && v.y <= pt.y) || (v0.y > pt.y && v.y > pt.y) || (v0.x < pt.x && v.x < pt.x) ) { if( pt.y == v.y && (pt.x == v.x || (pt.y == v0.y && ((v0.x <= pt.x && pt.x <= v.x) || (v.x <= pt.x && pt.x <= v0.x)))) ) EXIT; continue; } dist = (double)(pt.y - v0.y)*(v.x - v0.x) - (double)(pt.x - v0.x)*(v.y - v0.y); if( dist == 0 ) EXIT; if( v.y < v0.y ) dist = -dist; counter += dist > 0; } result = counter % 2 == 0 ? -100 : 100; } else { for( i = 0; i < total; i++ ) { double dx, dy, dx1, dy1, dx2, dy2, dist_num, dist_denom = 1; v0 = v; if( is_float ) { CV_READ_SEQ_ELEM( v, reader ); } else { CV_READ_SEQ_ELEM( iv, reader ); v = cvPointTo32f( iv ); } dx = v.x - v0.x; dy = v.y - v0.y; dx1 = pt.x - v0.x; dy1 = pt.y - v0.y; dx2 = pt.x - v.x; dy2 = pt.y - v.y; if( dx1*dx + dy1*dy <= 0 ) dist_num = dx1*dx1 + dy1*dy1; else if( dx2*dx + dy2*dy >= 0 ) dist_num = dx2*dx2 + dy2*dy2; else { dist_num = (dy1*dx - dx1*dy); dist_num *= dist_num; dist_denom = dx*dx + dy*dy; } if( dist_num*min_dist_denom < min_dist_num*dist_denom ) { min_dist_num = dist_num; min_dist_denom = dist_denom; if( min_dist_num == 0 ) break; } if( (v0.y <= pt.y && v.y <= pt.y) || (v0.y > pt.y && v.y > pt.y) || (v0.x < pt.x && v.x < pt.x) ) continue; dist_num = dy1*dx - dx1*dy; if( dy < 0 ) dist_num = -dist_num; counter += dist_num > 0; } result = sqrt(min_dist_num/min_dist_denom); if( counter % 2 == 0 ) result = -result; } } __END__; return result; }
/* area of a contour sector */ static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area ) { CvPoint pt; /* pointer to points */ CvPoint pt_s, pt_e; /* first and last points */ CvSeqReader reader; /* points reader of contour */ int p_max = 2, p_ind; int lpt, flag, i; double a00; /* unnormalized moments m00 */ double xi, yi, xi_1, yi_1, x0, y0, dxy, sk, sk1, t; double x_s, y_s, nx, ny, dx, dy, du, dv; double eps = 1.e-5; double *p_are1, *p_are2, *p_are; assert( contour != NULL ); if( contour == NULL ) return CV_NULLPTR_ERR; if( !CV_IS_SEQ_POLYGON( contour )) return CV_BADFLAG_ERR; lpt = cvSliceLength( slice, contour ); /*if( n2 >= n1 ) lpt = n2 - n1 + 1; else lpt = contour->total - n1 + n2 + 1;*/ if( contour->total && lpt > 2 ) { a00 = x0 = y0 = xi_1 = yi_1 = 0; sk1 = 0; flag = 0; dxy = 0; p_are1 = (double *) cvAlloc( p_max * sizeof( double )); if( p_are1 == NULL ) return CV_OUTOFMEM_ERR; p_are = p_are1; p_are2 = NULL; cvStartReadSeq( contour, &reader, 0 ); cvSetSeqReaderPos( &reader, slice.start_index ); CV_READ_SEQ_ELEM( pt_s, reader ); p_ind = 0; cvSetSeqReaderPos( &reader, slice.end_index ); CV_READ_SEQ_ELEM( pt_e, reader ); /* normal coefficients */ nx = pt_s.y - pt_e.y; ny = pt_e.x - pt_s.x; cvSetSeqReaderPos( &reader, slice.start_index ); while( lpt-- > 0 ) { CV_READ_SEQ_ELEM( pt, reader ); if( flag == 0 ) { xi_1 = (double) pt.x; yi_1 = (double) pt.y; x0 = xi_1; y0 = yi_1; sk1 = 0; flag = 1; } else { xi = (double) pt.x; yi = (double) pt.y; /**************** edges intersection examination **************************/ sk = nx * (xi - pt_s.x) + ny * (yi - pt_s.y); if( fabs( sk ) < eps && lpt > 0 || sk * sk1 < -eps ) { if( fabs( sk ) < eps ) { dxy = xi_1 * yi - xi * yi_1; a00 = a00 + dxy; dxy = xi * y0 - x0 * yi; a00 = a00 + dxy; if( p_ind >= p_max ) icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); p_are[p_ind] = a00 / 2.; p_ind++; a00 = 0; sk1 = 0; x0 = xi; y0 = yi; dxy = 0; } else { /* define intersection point */ dv = yi - yi_1; du = xi - xi_1; dx = ny; dy = -nx; if( fabs( du ) > eps ) t = ((yi_1 - pt_s.y) * du + dv * (pt_s.x - xi_1)) / (du * dy - dx * dv); else t = (xi_1 - pt_s.x) / dx; if( t > eps && t < 1 - eps ) { x_s = pt_s.x + t * dx; y_s = pt_s.y + t * dy; dxy = xi_1 * y_s - x_s * yi_1; a00 += dxy; dxy = x_s * y0 - x0 * y_s; a00 += dxy; if( p_ind >= p_max ) icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); p_are[p_ind] = a00 / 2.; p_ind++; a00 = 0; sk1 = 0; x0 = x_s; y0 = y_s; dxy = x_s * yi - xi * y_s; } } } else dxy = xi_1 * yi - xi * yi_1; a00 += dxy; xi_1 = xi; yi_1 = yi; sk1 = sk; } } xi = x0; yi = y0; dxy = xi_1 * yi - xi * yi_1; a00 += dxy; if( p_ind >= p_max ) icvMemCopy( &p_are1, &p_are2, &p_are, &p_max ); p_are[p_ind] = a00 / 2.; p_ind++; /* common area calculation */ *area = 0; for( i = 0; i < p_ind; i++ ) (*area) += fabs( p_are[i] ); if( p_are1 != NULL ) cvFree( &p_are1 ); else if( p_are2 != NULL ) cvFree( &p_are2 ); return CV_OK; } else return CV_BADSIZE_ERR; }
/*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; }
static CvStatus icvFindDominantPointsIPAN( CvSeq * contour, CvMemStorage * storage, CvSeq ** corners, int dmin2, int dmax2, int dneigh2, float amax ) { CvStatus status = CV_OK; /* variables */ int n = contour->total; float *sharpness; float *distance; icvPointInfo *ptInf; int i, j, k; CvSeqWriter writer; float mincos = (float) cos( 3.14159265359 * amax / 180 ); /* check bad arguments */ if( contour == NULL ) return CV_NULLPTR_ERR; if( storage == NULL ) return CV_NULLPTR_ERR; if( corners == NULL ) return CV_NULLPTR_ERR; if( dmin2 < 0 ) return CV_BADSIZE_ERR; if( dmax2 < dmin2 ) return CV_BADSIZE_ERR; if( (dneigh2 > dmax2) || (dneigh2 < 0) ) return CV_BADSIZE_ERR; if( (amax < 0) || (amax > 180) ) return CV_BADSIZE_ERR; sharpness = (float *) cvAlloc( n * sizeof( float )); distance = (float *) cvAlloc( n * sizeof( float )); ptInf = (icvPointInfo *) cvAlloc( n * sizeof( icvPointInfo )); /*****************************************************************************************/ /* First pass */ /*****************************************************************************************/ if( CV_IS_SEQ_CHAIN_CONTOUR( contour )) { CvChainPtReader reader; cvStartReadChainPoints( (CvChain *) contour, &reader ); for( i = 0; i < n; i++ ) { CV_READ_CHAIN_POINT( ptInf[i].pt, reader ); } } else if( CV_IS_SEQ_POLYGON( contour )) { CvSeqReader reader; cvStartReadSeq( contour, &reader, 0 ); for( i = 0; i < n; i++ ) { CV_READ_SEQ_ELEM( ptInf[i].pt, reader ); } } else { return CV_BADFLAG_ERR; } for( i = 0; i < n; i++ ) { /* find nearest suitable points which satisfy distance constraint >dmin */ int left_near = 0; int right_near = 0; int left_far, right_far; float dist_l = 0; float dist_r = 0; int i_plus = 0; int i_minus = 0; float max_cos_alpha; /* find right minimum */ while( dist_r < dmin2 ) { float dx, dy; int ind; if( i_plus >= n ) goto error; right_near = i_plus; if( dist_r < dneigh2 ) ptInf[i].right_neigh = i_plus; i_plus++; ind = (i + i_plus) % n; dx = (float) (ptInf[i].pt.x - ptInf[ind].pt.x); dy = (float) (ptInf[i].pt.y - ptInf[ind].pt.y); dist_r = dx * dx + dy * dy; } /* find right maximum */ while( dist_r <= dmax2 ) { float dx, dy; int ind; if( i_plus >= n ) goto error; distance[(i + i_plus) % n] = cvSqrt( dist_r ); if( dist_r < dneigh2 ) ptInf[i].right_neigh = i_plus; i_plus++; right_far = i_plus; ind = (i + i_plus) % n; dx = (float) (ptInf[i].pt.x - ptInf[ind].pt.x); dy = (float) (ptInf[i].pt.y - ptInf[ind].pt.y); dist_r = dx * dx + dy * dy; } right_far = i_plus; /* left minimum */ while( dist_l < dmin2 ) { float dx, dy; int ind; if( i_minus <= -n ) goto error; left_near = i_minus; if( dist_l < dneigh2 ) ptInf[i].left_neigh = i_minus; i_minus--; ind = i + i_minus; ind = (ind < 0) ? (n + ind) : ind; dx = (float) (ptInf[i].pt.x - ptInf[ind].pt.x); dy = (float) (ptInf[i].pt.y - ptInf[ind].pt.y); dist_l = dx * dx + dy * dy; } /* find left maximum */ while( dist_l <= dmax2 ) { float dx, dy; int ind; if( i_minus <= -n ) goto error; ind = i + i_minus; ind = (ind < 0) ? (n + ind) : ind; distance[ind] = cvSqrt( dist_l ); if( dist_l < dneigh2 ) ptInf[i].left_neigh = i_minus; i_minus--; left_far = i_minus; ind = i + i_minus; ind = (ind < 0) ? (n + ind) : ind; dx = (float) (ptInf[i].pt.x - ptInf[ind].pt.x); dy = (float) (ptInf[i].pt.y - ptInf[ind].pt.y); dist_l = dx * dx + dy * dy; } left_far = i_minus; if( (i_plus - i_minus) > n + 2 ) goto error; max_cos_alpha = -1; for( j = left_far + 1; j < left_near; j++ ) { float dx, dy; float a, a2; int leftind = i + j; leftind = (leftind < 0) ? (n + leftind) : leftind; a = distance[leftind]; a2 = a * a; for( k = right_near + 1; k < right_far; k++ ) { int ind = (i + k) % n; float c2, cosalpha; float b = distance[ind]; float b2 = b * b; /* compute cosinus */ dx = (float) (ptInf[leftind].pt.x - ptInf[ind].pt.x); dy = (float) (ptInf[leftind].pt.y - ptInf[ind].pt.y); c2 = dx * dx + dy * dy; cosalpha = (a2 + b2 - c2) / (2 * a * b); max_cos_alpha = MAX( max_cos_alpha, cosalpha ); if( max_cos_alpha < mincos ) max_cos_alpha = -1; sharpness[i] = max_cos_alpha; } } } /*****************************************************************************************/ /* Second pass */ /*****************************************************************************************/ cvStartWriteSeq( (contour->flags & ~CV_SEQ_ELTYPE_MASK) | CV_SEQ_ELTYPE_INDEX, sizeof( CvSeq ), sizeof( int ), storage, &writer ); /* second pass - nonmaxima suppression */ /* neighborhood of point < dneigh2 */ for( i = 0; i < n; i++ ) { int suppressed = 0; if( sharpness[i] == -1 ) continue; for( j = 1; (j <= ptInf[i].right_neigh) && (suppressed == 0); j++ ) { if( sharpness[i] < sharpness[(i + j) % n] ) suppressed = 1; } for( j = -1; (j >= ptInf[i].left_neigh) && (suppressed == 0); j-- ) { int ind = i + j; ind = (ind < 0) ? (n + ind) : ind; if( sharpness[i] < sharpness[ind] ) suppressed = 1; } if( !suppressed ) CV_WRITE_SEQ_ELEM( i, writer ); } *corners = cvEndWriteSeq( &writer ); cvFree( &sharpness ); cvFree( &distance ); cvFree( &ptInf ); return status; error: /* dmax is so big (more than contour diameter) that algorithm could become infinite cycle */ cvFree( &sharpness ); cvFree( &distance ); cvFree( &ptInf ); return CV_BADRANGE_ERR; }