/*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; }
CV_IMPL CvBox2D cvMinAreaRect2( const CvArr* array, CvMemStorage* storage ) { CvMemStorage* temp_storage = 0; CvBox2D box; CvPoint2D32f* points = 0; CV_FUNCNAME( "cvMinAreaRect2" ); memset(&box, 0, sizeof(box)); __BEGIN__; int i, n; CvSeqReader reader; CvContour contour_header; CvSeqBlock block; CvSeq* ptseq = (CvSeq*)array; CvPoint2D32f out[3]; if( CV_IS_SEQ(ptseq) ) { if( !CV_IS_SEQ_POINT_SET(ptseq) && (CV_SEQ_KIND(ptseq) != CV_SEQ_KIND_CURVE || !CV_IS_SEQ_CONVEX(ptseq) || CV_SEQ_ELTYPE(ptseq) != CV_SEQ_ELTYPE_PPOINT )) CV_ERROR( CV_StsUnsupportedFormat, "Input sequence must consist of 2d points or pointers to 2d points" ); if( !storage ) storage = ptseq->storage; } else { CV_CALL( ptseq = cvPointSeqFromMat( CV_SEQ_KIND_GENERIC, array, &contour_header, &block )); } if( storage ) { CV_CALL( temp_storage = cvCreateChildMemStorage( storage )); } else { CV_CALL( temp_storage = cvCreateMemStorage(1 << 10)); } if( !CV_IS_SEQ_CONVEX( ptseq )) { CV_CALL( ptseq = cvConvexHull2( ptseq, temp_storage, CV_CLOCKWISE, 1 )); } else if( !CV_IS_SEQ_POINT_SET( ptseq )) { CvSeqWriter writer; if( !CV_IS_SEQ(ptseq->v_prev) || !CV_IS_SEQ_POINT_SET(ptseq->v_prev)) CV_ERROR( CV_StsBadArg, "Convex hull must have valid pointer to point sequence stored in v_prev" ); cvStartReadSeq( ptseq, &reader ); cvStartWriteSeq( CV_SEQ_KIND_CURVE|CV_SEQ_FLAG_CONVEX|CV_SEQ_ELTYPE(ptseq->v_prev), sizeof(CvContour), CV_ELEM_SIZE(ptseq->v_prev->flags), temp_storage, &writer ); for( i = 0; i < ptseq->total; i++ ) { CvPoint pt = **(CvPoint**)(reader.ptr); CV_WRITE_SEQ_ELEM( pt, writer ); } ptseq = cvEndWriteSeq( &writer ); } n = ptseq->total; CV_CALL( points = (CvPoint2D32f*)cvAlloc( n*sizeof(points[0]) )); cvStartReadSeq( ptseq, &reader ); if( CV_SEQ_ELTYPE( ptseq ) == CV_32SC2 ) { for( i = 0; i < n; i++ ) { CvPoint pt; CV_READ_SEQ_ELEM( pt, reader ); points[i].x = (float)pt.x; points[i].y = (float)pt.y; } } else { for( i = 0; i < n; i++ ) { CV_READ_SEQ_ELEM( points[i], reader ); } } if( n > 2 ) { icvRotatingCalipers( points, n, CV_CALIPERS_MINAREARECT, (float*)out ); box.center.x = out[0].x + (out[1].x + out[2].x)*0.5f; box.center.y = out[0].y + (out[1].y + out[2].y)*0.5f; box.size.height = (float)sqrt((double)out[1].x*out[1].x + (double)out[1].y*out[1].y); box.size.width = (float)sqrt((double)out[2].x*out[2].x + (double)out[2].y*out[2].y); box.angle = (float)atan2( -(double)out[1].y, (double)out[1].x ); } else if( n == 2 ) { box.center.x = (points[0].x + points[1].x)*0.5f; box.center.y = (points[0].y + points[1].y)*0.5f; double dx = points[1].x - points[0].x; double dy = points[1].y - points[0].y; box.size.height = (float)sqrt(dx*dx + dy*dy); box.size.width = 0; box.angle = (float)atan2( -dy, dx ); } else { if( n == 1 ) box.center = points[0]; } box.angle = (float)(box.angle*180/CV_PI); __END__; cvReleaseMemStorage( &temp_storage ); cvFree( &points ); return box; }
static CvSeq* icvGetComponent(uchar* img, int step, CvRect rect, CvMemStorage* storage) { const char nbd = 4; int deltas[16]; int x, y; CvSeq* exterior = 0; char* ptr; /* initialize local state */ CV_INIT_3X3_DELTAS(deltas, step, 1); memcpy(deltas + 8, deltas, 8 * sizeof(deltas[0])); ptr = (char*)(img + step * rect.y); rect.width += rect.x; rect.height += rect.y; for (y = rect.y; y < rect.height; y++, ptr += step) { int prev = ptr[rect.x - 1] & -2; for (x = rect.x; x < rect.width; x++) { int p = ptr[x] & -2; //assert( exterior || ((p | prev) & -4) == 0 ); if (p != prev) { CvSeq* seq = 0; int is_hole = 0; CvSeqWriter writer; char* i0, *i1, *i3, *i4 = 0; int prev_s = -1, s, s_end; CvPoint pt = { x, y }; if (!(prev == 0 && p == 2)) { /* if not external contour */ /* check hole */ if (p != 0 || prev < 1) { prev = p; continue; } is_hole = 1; if (!exterior) { assert(0); return 0; } } cvStartWriteSeq(CV_SEQ_CONTOUR | (is_hole ? CV_SEQ_FLAG_HOLE : 0), sizeof(CvContour), sizeof(CvPoint), storage, &writer); s_end = s = is_hole ? 0 : 4; i0 = ptr + x - is_hole; do { s = (s - 1) & 7; i1 = i0 + deltas[s]; if ((*i1 & -2) != 0) { break; } } while (s != s_end); if (s == s_end) { /* single pixel domain */ *i0 = (char)(nbd | -128); CV_WRITE_SEQ_ELEM(pt, writer); } else { i3 = i0; prev_s = s ^ 4; /* follow border */ for (;;) { s_end = s; for (;;) { i4 = i3 + deltas[++s]; if ((*i4 & -2) != 0) { break; } } s &= 7; /* check "right" bound */ if ((unsigned)(s - 1) < (unsigned) s_end) { *i3 = (char)(nbd | -128); } else if (*i3 > 0) { *i3 = nbd; } if (s != prev_s) { CV_WRITE_SEQ_ELEM(pt, writer); prev_s = s; } pt.x += icvCodeDeltas[s].x; pt.y += icvCodeDeltas[s].y; if (i4 == i0 && i3 == i1) { break; } i3 = i4; s = (s + 4) & 7; } /* end of border following loop */ } seq = cvEndWriteSeq(&writer); cvContourBoundingRect(seq, 1); if (!is_hole) { exterior = seq; } else { seq->v_prev = exterior; seq->h_next = exterior->v_next; if (seq->h_next) { seq->h_next->h_prev = seq; } exterior->v_next = seq; } prev = ptr[x] & -2; } } } return exterior; }
/*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 int icvFindContoursInInterval( const CvArr* src, /*int minValue, int maxValue,*/ CvMemStorage* storage, CvSeq** result, int contourHeaderSize ) { int count = 0; CvMemStorage* storage00 = 0; CvMemStorage* storage01 = 0; CvSeq* first = 0; CV_FUNCNAME( "icvFindContoursInInterval" ); __BEGIN__; int i, j, k, n; uchar* src_data = 0; int img_step = 0; CvSize img_size; int connect_flag; int lower_total; int upper_total; int all_total; CvSeq* runs; CvLinkedRunPoint tmp; CvLinkedRunPoint* tmp_prev; CvLinkedRunPoint* upper_line = 0; CvLinkedRunPoint* lower_line = 0; CvLinkedRunPoint* last_elem; CvLinkedRunPoint* upper_run = 0; CvLinkedRunPoint* lower_run = 0; CvLinkedRunPoint* prev_point = 0; CvSeqWriter writer_ext; CvSeqWriter writer_int; CvSeqWriter writer; CvSeqReader reader; CvSeq* external_contours; CvSeq* internal_contours; CvSeq* prev = 0; if( !storage ) CV_ERROR( CV_StsNullPtr, "NULL storage pointer" ); if( !result ) CV_ERROR( CV_StsNullPtr, "NULL double CvSeq pointer" ); if( contourHeaderSize < (int)sizeof(CvContour)) CV_ERROR( CV_StsBadSize, "Contour header size must be >= sizeof(CvContour)" ); CV_CALL( storage00 = cvCreateChildMemStorage(storage)); CV_CALL( storage01 = cvCreateChildMemStorage(storage)); { CvMat stub, *mat; CV_CALL( mat = cvGetMat( src, &stub )); if( !CV_IS_MASK_ARR(mat)) CV_ERROR( CV_StsBadArg, "Input array must be 8uC1 or 8sC1" ); src_data = mat->data.ptr; img_step = mat->step; img_size = cvGetMatSize( mat ); } // Create temporary sequences runs = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvLinkedRunPoint), storage00 ); cvStartAppendToSeq( runs, &writer ); cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_ext ); cvStartWriteSeq( 0, sizeof(CvSeq), sizeof(CvLinkedRunPoint*), storage01, &writer_int ); tmp_prev = &(tmp); tmp_prev->next = 0; tmp_prev->link = 0; // First line. None of runs is binded tmp.pt.y = 0; i = 0; CV_WRITE_SEQ_ELEM( tmp, writer ); upper_line = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer ); tmp_prev = upper_line; for( j = 0; j < img_size.width; ) { for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ ) ; if( j == img_size.width ) break; tmp.pt.x = j; CV_WRITE_SEQ_ELEM( tmp, writer ); tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer ); tmp_prev = tmp_prev->next; for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ ) ; tmp.pt.x = j-1; CV_WRITE_SEQ_ELEM( tmp, writer ); tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer ); tmp_prev->link = tmp_prev->next; // First point of contour CV_WRITE_SEQ_ELEM( tmp_prev, writer_ext ); tmp_prev = tmp_prev->next; } cvFlushSeqWriter( &writer ); upper_line = upper_line->next; upper_total = runs->total - 1; last_elem = tmp_prev; tmp_prev->next = 0; for( i = 1; i < img_size.height; i++ ) { //------// Find runs in next line src_data += img_step; tmp.pt.y = i; all_total = runs->total; for( j = 0; j < img_size.width; ) { for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ ) ; if( j == img_size.width ) break; tmp.pt.x = j; CV_WRITE_SEQ_ELEM( tmp, writer ); tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer ); tmp_prev = tmp_prev->next; for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ ) ; tmp.pt.x = j-1; CV_WRITE_SEQ_ELEM( tmp, writer ); tmp_prev = tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer ); }//j cvFlushSeqWriter( &writer ); lower_line = last_elem->next; lower_total = runs->total - all_total; last_elem = tmp_prev; tmp_prev->next = 0; //------// //------// Find links between runs of lower_line and upper_line upper_run = upper_line; lower_run = lower_line; connect_flag = ICV_SINGLE; for( k = 0, n = 0; k < upper_total/2 && n < lower_total/2; ) { switch( connect_flag ) { case ICV_SINGLE: if( upper_run->next->pt.x < lower_run->next->pt.x ) { if( upper_run->next->pt.x >= lower_run->pt.x -1 ) { lower_run->link = upper_run; connect_flag = ICV_CONNECTING_ABOVE; prev_point = upper_run->next; } else upper_run->next->link = upper_run; k++; upper_run = upper_run->next->next; } else { if( upper_run->pt.x <= lower_run->next->pt.x +1 ) { lower_run->link = upper_run; connect_flag = ICV_CONNECTING_BELOW; prev_point = lower_run->next; } else { lower_run->link = lower_run->next; // First point of contour CV_WRITE_SEQ_ELEM( lower_run, writer_ext ); } n++; lower_run = lower_run->next->next; } break; case ICV_CONNECTING_ABOVE: if( upper_run->pt.x > lower_run->next->pt.x +1 ) { prev_point->link = lower_run->next; connect_flag = ICV_SINGLE; n++; lower_run = lower_run->next->next; } else { prev_point->link = upper_run; if( upper_run->next->pt.x < lower_run->next->pt.x ) { k++; prev_point = upper_run->next; upper_run = upper_run->next->next; } else { connect_flag = ICV_CONNECTING_BELOW; prev_point = lower_run->next; n++; lower_run = lower_run->next->next; } } break; case ICV_CONNECTING_BELOW: if( lower_run->pt.x > upper_run->next->pt.x +1 ) { upper_run->next->link = prev_point; connect_flag = ICV_SINGLE; k++; upper_run = upper_run->next->next; } else { // First point of contour CV_WRITE_SEQ_ELEM( lower_run, writer_int ); lower_run->link = prev_point; if( lower_run->next->pt.x < upper_run->next->pt.x ) { n++; prev_point = lower_run->next; lower_run = lower_run->next->next; } else { connect_flag = ICV_CONNECTING_ABOVE; k++; prev_point = upper_run->next; upper_run = upper_run->next->next; } } break; } }// k, n for( ; n < lower_total/2; n++ ) { if( connect_flag != ICV_SINGLE ) { prev_point->link = lower_run->next; connect_flag = ICV_SINGLE; lower_run = lower_run->next->next; continue; } lower_run->link = lower_run->next; //First point of contour CV_WRITE_SEQ_ELEM( lower_run, writer_ext ); lower_run = lower_run->next->next; } for( ; k < upper_total/2; k++ ) { if( connect_flag != ICV_SINGLE ) { upper_run->next->link = prev_point; connect_flag = ICV_SINGLE; upper_run = upper_run->next->next; continue; } upper_run->next->link = upper_run; upper_run = upper_run->next->next; } upper_line = lower_line; upper_total = lower_total; }//i upper_run = upper_line; //the last line of image for( k = 0; k < upper_total/2; k++ ) { upper_run->next->link = upper_run; upper_run = upper_run->next->next; } //------// //------//Find end read contours external_contours = cvEndWriteSeq( &writer_ext ); internal_contours = cvEndWriteSeq( &writer_int ); for( k = 0; k < 2; k++ ) { CvSeq* contours = k == 0 ? external_contours : internal_contours; cvStartReadSeq( contours, &reader ); for( j = 0; j < contours->total; j++, count++ ) { CvLinkedRunPoint* p_temp; CvLinkedRunPoint* p00; CvLinkedRunPoint* p01; CvSeq* contour; CV_READ_SEQ_ELEM( p00, reader ); p01 = p00; if( !p00->link ) continue; cvStartWriteSeq( CV_SEQ_ELTYPE_POINT | CV_SEQ_POLYLINE | CV_SEQ_FLAG_CLOSED, contourHeaderSize, sizeof(CvPoint), storage, &writer ); do { CV_WRITE_SEQ_ELEM( p00->pt, writer ); p_temp = p00; p00 = p00->link; p_temp->link = 0; } while( p00 != p01 ); contour = cvEndWriteSeq( &writer ); cvBoundingRect( contour, 1 ); if( k != 0 ) contour->flags |= CV_SEQ_FLAG_HOLE; if( !first ) prev = first = contour; else { contour->h_prev = prev; prev = prev->h_next = contour; } } } __END__; if( !first ) count = -1; if( result ) *result = first; cvReleaseMemStorage(&storage00); cvReleaseMemStorage(&storage01); return count; }
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; }
void Gesture1::trackMarker (IplImage* destImg, CvPoint _r, CvPoint _b, CvPoint _g, CvPoint _y) { // find tissue box! CvPoint* objPoints = objectDetector->detect(destImg); // draw world->Step(1.0F/6.0F, 10, 10); cvLine(destImg, cvPoint(0,HEIGHT), cvPoint(1000,HEIGHT), CV_RGB(0,255,0), 3); for (b2Body* b = world->GetBodyList(); b; b = b->GetNext()) { //printf("**draw body\n"); Box2DData* userData = (Box2DData*)b->GetUserData(); if (userData != NULL) { if (strcmp(userData->type, "Circle") == 0) { //b2Vec2 v = b->GetWorldCenter(); b2Vec2 v = b->GetPosition(); //printf("** x=%f y=%f r=%f\n", v.x, v.y, userData->radius); CvPoint center = cvPoint(v.x*WORLD_SCALE, v.y*WORLD_SCALE); cvCircle(destImg, center, userData->radius*WORLD_SCALE, CV_RGB(255,0,0), -1); } else if (strcmp(userData->type, "Box") == 0) { world->DestroyBody(b); } } } if (objPoints != NULL) { printf("construct body\n"); b2PolygonShape cs; b2Vec2 vertices[4] = { b2Vec2((float)(objPoints[0].x)/WORLD_SCALE, (float)(objPoints[0].y)/WORLD_SCALE), b2Vec2((float)(objPoints[1].x)/WORLD_SCALE, (float)(objPoints[1].y)/WORLD_SCALE), b2Vec2((float)(objPoints[2].x)/WORLD_SCALE, (float)(objPoints[2].y)/WORLD_SCALE), b2Vec2((float)(objPoints[3].x)/WORLD_SCALE, (float)(objPoints[3].y)/WORLD_SCALE) }; cs.Set(vertices, 4); b2BodyDef bd; //bd.type = b2_staticBody; Box2DData* obj = new Box2DData(); strcpy(obj->type, "Box"); bd.userData = obj; b2Body* body1 = world->CreateBody(&bd); body1->CreateFixture(&cs, 0.0f); } if (_r.x < 0) return; Point2D r = toPoint2D(_r); // if marker is not moving for a while, reset the path int len = path.size(); if (len > KEEP_MAX) { path.erase(path.begin()); } int nearCount = 0; int actual = min(KEEP_COUNT, len); /* for(int i=0; i<actual; i++){ Point2D p = path[len-1-i]; double d = dist(p, r); //printf("dist=%f\n", d); if (d < NEAR_THRESHOLD) ++nearCount; } if (nearCount > (double)actual * DONT_MOVE_THRESHOLD_RATE) { // marker is not moving, so clear the path printf("cleared\n"); path.clear(); } */ path.push_back(r); // decide if we should recognize time_t current; time(¤t); double interval = difftime(current, lastTime); printf("interval=%f\n", interval); if (interval < INTERVAL_SEC) return; len = path.size(); if (len < 5) return; RecognitionResult res = g.recognize(path); printf("%s:%f\n", res.name.c_str(), res.score); if (res.name == "Circle" && res.score > SCORE_THRESHOLD) { printf("##circle detect##\n"); // convert to vector<Point2D> to CvSeq<CvPoint> CvSeqWriter writer; CvMemStorage* storage = cvCreateMemStorage(0); cvStartWriteSeq( CV_32SC2, sizeof(CvSeq), sizeof(CvPoint), storage, &writer); for (int i=0; i<len; i++) { CvPoint pt = toCvPoint(path[i]); CV_WRITE_SEQ_ELEM(pt, writer); } CvSeq* seq = cvEndWriteSeq(&writer); CvBox2D ellipse = cvFitEllipse2(seq); float radius = std::min(ellipse.size.width, ellipse.size.height)/(4.0F*WORLD_SCALE); cvEllipseBox(destImg, ellipse, CV_RGB(0,255,255), -1); // add Box2D object { b2CircleShape cs; cs.m_radius = radius; printf(" x=%f y=%f radius:%f\n", ellipse.center.x/WORLD_SCALE, ellipse.center.y/WORLD_SCALE, radius); b2BodyDef bd; bd.type = b2_dynamicBody; bd.position.Set(ellipse.center.x/WORLD_SCALE, ellipse.center.y/WORLD_SCALE); Box2DData* obj = new Box2DData(); strcpy(obj->type, "Circle"); obj->radius = radius; bd.userData = obj; b2Body* body1 = world->CreateBody(&bd); b2FixtureDef fixtureDef; fixtureDef.shape = &cs; fixtureDef.density = 1.0f; fixtureDef.friction = 0.3f; fixtureDef.restitution = 0.6f; body1->CreateFixture(&fixtureDef); } time(&lastTime); //cvEllipseBox(destImg, ellipse, CV_RGB(125,125,255)); } }
//makes vertical list of segments for 1 contour CvSeq* icvCutContourRaster(CvSeq* current, CvMemStorage* storage, IplImage* image /*tmp image*/) { //iplSet(image, 0 ); // this can cause double edges if two contours have common edge // for example if object is circle with 1 pixel width // to remove such problem - remove this iplSet //approx contour by single edges CvSeqReader reader; CvSeqWriter writer; int writing = 0; cvStartReadSeq(current, &reader, 0); //below line just to avoid warning cvStartWriteSeq(current->flags, sizeof(CvContour), sizeof(CvPoint), storage, &writer); CvSeq* output = 0; CvSeq* tail = 0; //first pass through contour - compute number of branches at every point int i; for (i = 0; i < current->total; i++) { CvPoint cur; CV_READ_SEQ_ELEM(cur, reader); //mark point ((uchar*)image->imageData)[image->widthStep * cur.y + cur.x]++; assert(((uchar*)image->imageData)[image->widthStep* cur.y + cur.x] != 255); } //second pass - create separate edges for (i = 0; i < current->total; i++) { CvPoint cur; CV_READ_SEQ_ELEM(cur, reader); //get pixel at this point uchar flag = image->imageData[image->widthStep * cur.y + cur.x]; if (flag != 255 && flag < 3) { // if (!writing) { cvStartWriteSeq(current->flags, sizeof(CvContour), sizeof(CvPoint), storage, &writer); writing = 1 ; } //mark point if (flag < 3) { ((uchar*)image->imageData)[image->widthStep* cur.y + cur.x] = 255; } //add it to another seq CV_WRITE_SEQ_ELEM(cur, writer); } else { //exclude this point from contour if (writing) { CvSeq* newseq = cvEndWriteSeq(&writer); writing = 0; if (tail) { tail->v_next = newseq; newseq->v_prev = tail; tail = newseq; } else { output = tail = newseq; } } } } if (writing) { //if were not self intersections CvSeq* newseq = cvEndWriteSeq(&writer); writing = 0; if (tail) { tail->v_next = newseq; newseq->v_prev = tail; tail = newseq; } else { output = tail = newseq; } } return output; }
static int fmaConvexHullContour(void* prm) { long lErrors = 0; static int read_param = 0; int i,j; CvRect rect; int minx = 1000000, maxx = -10000; int miny = 1000000, maxy = -10000; long lParam = (long)prm; CvPoint* points; CvPoint** pointers; CvSeqWriter writer; CvSeqReader reader; CvSeq* contour; CvSeq* hull = NULL; CvMemStorage* storage; if(!read_param) { read_param=1; /* Reading test-parameters */ trslRead( &lNumPoints, "4096", "Maximal number of points" ); trslRead( &lLoopsProp, "100", "Loops" ); } storage = cvCreateMemStorage(0); cvClearMemStorage( storage ); points = (CvPoint*)icvAlloc( lNumPoints * sizeof(CvPoint) ); pointers = (CvPoint**)icvAlloc( lNumPoints * sizeof(CvPoint*) ); for( j = 0; j < lLoopsProp; j++ ) { int numpts; /* Allocating points */ cvStartWriteSeq( CV_SEQ_SIMPLE_POLYGON , sizeof(CvSeq), sizeof(CvPoint), storage, &writer ); ats1iInitRandom( 5, lNumPoints, &numpts, 1 ); /* init points */ ats1iInitRandom( 5, 1024, &lScreenSize, 1 ); for( i = 0; i < numpts ; i++ ) { CvPoint pt; ats1iInitRandom( 0, lScreenSize, (int*)&pt, 2 ); CV_WRITE_SEQ_ELEM( pt, writer ); minx = MIN(pt.x, minx ); maxx = MAX(pt.x, maxx ); miny = MIN(pt.y, miny ); maxy = MAX(pt.y, maxy ); } contour = cvEndWriteSeq( &writer ); rect.x = minx; rect.y = miny; rect.width = maxx- minx + 1; rect.height = maxy- miny + 1; switch (lParam) { case APPROX: hull = cvContourConvexHullApprox( contour, 1, CV_COUNTER_CLOCKWISE, storage ); break; case EXACT: hull = cvContourConvexHull( contour,CV_COUNTER_CLOCKWISE, storage ); break; }/*switch */ /* check errors */ cvStartReadSeq( contour, &reader, 0 ); for( i = 0; i < contour->total; i++ ) { CV_READ_SEQ_ELEM( points[i], reader ); } cvStartReadSeq( hull, &reader, 0 ); for( i = 0; i < hull->total; i++ ) { CV_READ_SEQ_ELEM( pointers[i], reader ); } cvClearMemStorage( storage ); lErrors += atsCheckConvexHullP( points, contour->total, pointers, hull->total, CV_COUNTER_CLOCKWISE ); } /* for */ icvFree(&points); icvFree(&pointers); cvReleaseMemStorage(&storage); if( lErrors == 0 ) return trsResult( TRS_OK, "No errors fixed for this test" ); else return trsResult( TRS_FAIL, "Total fixed %d errors", lErrors ); }