void icvCalcContoursCorrespondence(CvSeq* contour1, CvSeq* contour2, CvSeq** corr, CvMemStorage* storage) { int i,j; // counter of cycles int Ni,Nj; // size of contours _CvWork** W; // graph for search minimum of work CvPoint* point1; // array of first contour point CvPoint* point2; // array of second contour point CvPoint2D32f* edges1; // array of first contour edge CvPoint2D32f* edges2; // array of second contour edge //CvPoint null_edge = {0,0}; // CvPoint2D32f small_edge; //double inf; // infinity CvSeq* corr01; CvSeqWriter writer; char path; // // Find size of contours Ni = contour1->total + 1; Nj = contour2->total + 1; // Create arrays W = (_CvWork**)malloc(sizeof(_CvWork*)*Ni); for(i=0; i<Ni; i++) { W[i] = (_CvWork*)malloc(sizeof(_CvWork)*Nj); } point1 = (CvPoint* )malloc( Ni*sizeof(CvPoint) ); point2 = (CvPoint* )malloc( Nj*sizeof(CvPoint) ); edges1 = (CvPoint2D32f* )malloc( (Ni-1)*sizeof(CvPoint2D32f) ); edges2 = (CvPoint2D32f* )malloc( (Nj-1)*sizeof(CvPoint2D32f) ); // Initialize arrays of point cvCvtSeqToArray( contour1, point1, CV_WHOLE_SEQ ); cvCvtSeqToArray( contour2, point2, CV_WHOLE_SEQ ); point1[Ni-1] = point1[0]; point2[Nj-1] = point2[0]; for(i=0; i<Ni-1; i++) { edges1[i].x = (float)( point1[i+1].x - point1[i].x ); edges1[i].y = (float)( point1[i+1].y - point1[i].y ); }; for(i=0; i<Nj-1; i++) { edges2[i].x = (float)( point2[i+1].x - point2[i].x ); edges2[i].y = (float)( point2[i+1].y - point2[i].y ); }; // Find infinity constant //inf=1; ///////////// //Find min path in graph ///////////// W[0][0].w_east = 0; W[0][0].w_south = 0; W[0][0].w_southeast = 0; W[1][1].w_southeast = _cvStretchingWork( &edges1[0], &edges2[0] ); W[1][1].w_east = inf; W[1][1].w_south = inf; W[1][1].path_se = PATH_TO_SE; W[0][1].w_south = _cvStretchingWork( &null_edge, &edges2[0] ); W[0][1].path_s = 3; W[1][0].w_east = _cvStretchingWork( &edges2[0], &null_edge ); W[1][0].path_e = PATH_TO_E; for( i=1; i<Ni; i++ ) { W[i][0].w_south = inf; W[i][0].w_southeast = inf; } for(j=1; j<Nj; j++) { W[0][j].w_east = inf; W[0][j].w_southeast = inf; } for(i=2; i<Ni; i++) { j=0;///////// W[i][j].w_east = W[i-1][j].w_east; W[i][j].w_east = W[i][j].w_east /*+ _cvBendingWork( &edges1[i-2], &edges1[i-1], &null_edge, &null_edge, NULL )*/; W[i][j].w_east = W[i][j].w_east + _cvStretchingWork( &edges2[i-1], &null_edge ); W[i][j].path_e = PATH_TO_E; j=1;////////// W[i][j].w_south = inf; _cvWorkEast (i, j, W, edges1, edges2); W[i][j].w_southeast = W[i-1][j-1].w_east; W[i][j].w_southeast = W[i][j].w_southeast + _cvStretchingWork( &edges1[i-1], &edges2[j-1] ); small_edge.x = NULL_EDGE*edges1[i-2].x; small_edge.y = NULL_EDGE*edges1[i-2].y; W[i][j].w_southeast = W[i][j].w_southeast + _cvBendingWork( &edges1[i-2], &edges1[i-1], /*&null_edge*/&small_edge, &edges2[j-1]/*, &edges2[Nj-2]*/); W[i][j].path_se = PATH_TO_E; } for(j=2; j<Nj; j++) { i=0;////////// W[i][j].w_south = W[i][j-1].w_south; W[i][j].w_south = W[i][j].w_south + _cvStretchingWork( &null_edge, &edges2[j-1] ); W[i][j].w_south = W[i][j].w_south /*+ _cvBendingWork( &null_edge, &null_edge, &edges2[j-2], &edges2[j-1], NULL )*/; W[i][j].path_s = 3; i=1;/////////// W[i][j].w_east= inf; _cvWorkSouth(i, j, W, edges1, edges2); W[i][j].w_southeast = W[i-1][j-1].w_south; W[i][j].w_southeast = W[i][j].w_southeast + _cvStretchingWork( &edges1[i-1], &edges2[j-1] ); small_edge.x = NULL_EDGE*edges2[j-2].x; small_edge.y = NULL_EDGE*edges2[j-2].y; W[i][j].w_southeast = W[i][j].w_southeast + _cvBendingWork( /*&null_edge*/&small_edge, &edges1[i-1], &edges2[j-2], &edges2[j-1]/*, &edges1[Ni-2]*/); W[i][j].path_se = 3; } for(i=2; i<Ni; i++) for(j=2; j<Nj; j++) { _cvWorkEast (i, j, W, edges1, edges2); _cvWorkSouthEast(i, j, W, edges1, edges2); _cvWorkSouth (i, j, W, edges1, edges2); } i=Ni-1; j=Nj-1; *corr = cvCreateSeq(0, sizeof(CvSeq), sizeof(int), storage ); corr01 = *corr; cvStartAppendToSeq( corr01, &writer ); if( W[i][j].w_east > W[i][j].w_southeast ) { if( W[i][j].w_southeast > W[i][j].w_south ) { path = 3; } else { path = PATH_TO_SE; } } else { if( W[i][j].w_east < W[i][j].w_south ) { path = PATH_TO_E; } else { path = 3; } } do { CV_WRITE_SEQ_ELEM( j, writer ); switch( path ) { case PATH_TO_E: path = W[i][j].path_e; i--; cvFlushSeqWriter( &writer ); corr01->h_next = cvCreateSeq( 0, sizeof(CvSeq), sizeof(int), storage ); corr01 = corr01->h_next; cvStartAppendToSeq( corr01, &writer ); break; case PATH_TO_SE: path = W[i][j].path_se; j--; i--; cvFlushSeqWriter( &writer ); corr01->h_next = cvCreateSeq( 0, sizeof(CvSeq), sizeof(int), storage ); corr01 = corr01->h_next; cvStartAppendToSeq( corr01, &writer ); break; case 3: path = W[i][j].path_s; j--; break; } } while( (i>=0) && (j>=0) ); cvFlushSeqWriter( &writer ); // Free memory for(i=1; i<Ni; i++) { free(W[i]); } free(W); free(point1); free(point2); free(edges1); free(edges2); }
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; }
/***************************************************************************************\ * * This function compute intermediate polygon between contour1 and contour2 * * Correspondence between points of contours specify by corr * * param = [0,1]; 0 correspondence to contour1, 1 - contour2 * \***************************************************************************************/ CvSeq* icvBlendContours(CvSeq* contour1, CvSeq* contour2, CvSeq* corr, double param, CvMemStorage* storage) { int j; CvSeqWriter writer01; CvSeqReader reader01; int Ni,Nj; // size of contours int i; // counter CvPoint* point1; // array of first contour point CvPoint* point2; // array of second contour point CvPoint point_output; // intermediate storage of ouput point int corr_point; // Create output sequence. CvSeq* output = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), storage ); // Find size of contours. Ni = contour1->total + 1; Nj = contour2->total + 1; point1 = (CvPoint* )malloc( Ni*sizeof(CvPoint) ); point2 = (CvPoint* )malloc( Nj*sizeof(CvPoint) ); // Initialize arrays of point cvCvtSeqToArray( contour1, point1, CV_WHOLE_SEQ ); cvCvtSeqToArray( contour2, point2, CV_WHOLE_SEQ ); // First and last point mast be equal. point1[Ni-1] = point1[0]; point2[Nj-1] = point2[0]; // Initializes process of writing to sequence. cvStartAppendToSeq( output, &writer01); i = Ni-1; //correspondence to points of contour1 for( ; corr; corr = corr->h_next ) { //Initializes process of sequential reading from sequence cvStartReadSeq( corr, &reader01, 0 ); for(j=0; j < corr->total; j++) { // Read element from sequence. CV_READ_SEQ_ELEM( corr_point, reader01 ); // Compute point of intermediate polygon. point_output.x = cvRound(point1[i].x + param*( point2[corr_point].x - point1[i].x )); point_output.y = cvRound(point1[i].y + param*( point2[corr_point].y - point1[i].y )); // Write element to sequence. CV_WRITE_SEQ_ELEM( point_output, writer01 ); } i--; } // Updates sequence header. cvFlushSeqWriter( &writer01 ); return output; }