Update the changelog
[opencv] / cvaux / src / cvmorphcontours.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "_cvaux.h"
43
44 #define PATH_TO_E       1
45 #define PATH_TO_SE      2
46 #define PATH_TO_S       3
47
48 #define K_S         2
49 #define E_S         2
50 #define C_S         .01
51 #define K_Z         5000
52 #define K_NM        50000
53 #define K_B         40
54 #define NULL_EDGE   0.001f
55 #define inf         DBL_MAX
56
57 typedef struct __CvWork
58 {
59     double w_east;
60     double w_southeast;
61     double w_south;
62     char path_e;
63     char path_se;
64     char path_s;
65 }_CvWork;
66
67
68 double _cvBendingWork(  CvPoint2D32f* B0,
69                         CvPoint2D32f* F0,
70                         CvPoint2D32f* B1,
71                         CvPoint2D32f* F1/*,
72                         CvPoint* K */);
73
74 double _cvStretchingWork(CvPoint2D32f* P1,
75                          CvPoint2D32f* P2);
76
77 void _cvWorkEast     (int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2);
78 void _cvWorkSouthEast(int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2);
79 void _cvWorkSouth    (int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2);
80
81 static CvPoint2D32f null_edge = {0,0};
82
83 double _cvStretchingWork(CvPoint2D32f* P1,
84                          CvPoint2D32f* P2)
85 {
86     double L1,L2, L_min, dL;
87
88     L1 = sqrt( (double)P1->x*P1->x + P1->y*P1->y);
89     L2 = sqrt( (double)P2->x*P2->x + P2->y*P2->y);
90     
91     L_min = MIN(L1, L2);
92     dL = fabs( L1 - L2 );
93
94     return K_S * pow( dL, E_S ) / ( L_min + C_S*dL );
95 }
96
97
98 ////////////////////////////////////////////////////////////////////////////////////
99 double _cvBendingWork(  CvPoint2D32f* B0,
100                         CvPoint2D32f* F0,
101                         CvPoint2D32f* B1,
102                         CvPoint2D32f* F1/*,
103                         CvPoint* K*/)
104 {
105     CvPoint2D32f Q( CvPoint2D32f q0, CvPoint2D32f q1, CvPoint2D32f q2, double t );
106     double angle( CvPoint2D32f A, CvPoint2D32f B );
107
108     CvPoint2D32f Q0, Q1, Q2;
109     CvPoint2D32f Q1_nm = { 0, 0 }, Q2_nm = { 0, 0 };
110     double d0, d1, d2, des, t_zero;
111     double k_zero, k_nonmon;
112     CvPoint2D32f center;
113     double check01, check02;
114     char check_origin;
115     double d_angle, d_nm_angle;
116 /*
117     if( (B0->x==0) && (B0->y==0) )
118     {
119         if( (F0->x==0) && (F0->y==0) )
120         {
121             B1->x = -B1->x;
122             B1->y = -B1->y;
123
124             d_angle = acos( (B1->x*F1->x + B1->y*F1->y)/sqrt( (B1->x*B1->x + B1->y*B1->y)*(F1->x*F1->x + F1->y*F1->y) ) );
125             d_angle = CV_PI - d_angle;
126
127             B1->x = -B1->x;
128             B1->y = -B1->y;
129
130             //return d_angle*K_B;
131             return 100;
132         }
133         K->x = -K->x;
134         K->y = -K->y;
135         B1->x = -B1->x;
136         B1->y = -B1->y;
137
138         d_angle = acos( (B1->x*F1->x + B1->y*F1->y)/sqrt( (B1->x*B1->x + B1->y*B1->y)*(F1->x*F1->x + F1->y*F1->y) ) );
139         d_angle = d_angle - acos( (F0->x*K->x + F0->y*K->y)/sqrt( (F0->x*F0->x + F0->y*F0->y)*(K->x*K->x + K->y*K->y) ) );
140         d_angle = d_angle - CV_PI*0.5;
141         d_angle = fabs(d_angle);
142
143         
144         K->x = -K->x;
145         K->y = -K->y;
146         B1->x = -B1->x;
147         B1->y = -B1->y;
148
149         //return d_angle*K_B;
150         return 100;
151     }
152
153
154     if( (F0->x==0) && (F0->y==0) )
155         {
156             K->x = -K->x;
157             K->y = -K->y;
158             B1->x = -B1->x;
159             B1->y = -B1->y;
160
161             d_angle = acos( (B1->x*F1->x + B1->y*F1->y)/sqrt( (B1->x*B1->x + B1->y*B1->y)*(F1->x*F1->x + F1->y*F1->y) ) );
162             d_angle = d_angle - acos( (B0->x*K->x + B0->y*K->y)/sqrt( (B0->x*B0->x + B0->y*B0->y)*(K->x*K->x + K->y*K->y) ) );
163             d_angle = d_angle - CV_PI*0.5;
164             d_angle = fabs(d_angle);
165
166             K->x = -K->x;
167             K->y = -K->y;
168             B1->x = -B1->x;
169             B1->y = -B1->y;
170
171             //return d_angle*K_B;
172             return 100;
173         }
174 ///////////////
175
176     if( (B1->x==0) && (B1->y==0) )
177     {
178         if( (F1->x==0) && (F1->y==0) )
179         {
180             B0->x = -B0->x;
181             B0->y = -B0->y;
182
183             d_angle = acos( (B0->x*F0->x + B0->y*F0->y)/sqrt( (B0->x*B0->x + B0->y*B0->y)*(F0->x*F0->x + F0->y*F0->y) ) );
184             d_angle = CV_PI - d_angle;
185
186             B0->x = -B0->x;
187             B0->y = -B0->y;
188
189             //return d_angle*K_B;
190             return 100;
191         }
192         K->x = -K->x;
193         K->y = -K->y;
194         B0->x = -B0->x;
195         B0->y = -B0->y;
196
197         d_angle = acos( (B0->x*F0->x + B0->y*F0->y)/sqrt( (B0->x*B0->x + B0->y*B0->y)*(F0->x*F0->x + F0->y*F0->y) ) );
198         d_angle = d_angle - acos( (F1->x*K->x + F1->y*K->y)/sqrt( (F1->x*F1->x + F1->y*F1->y)*(K->x*K->x + K->y*K->y) ) );
199         d_angle = d_angle - CV_PI*0.5;
200         d_angle = fabs(d_angle);
201
202         K->x = -K->x;
203         K->y = -K->y;
204         B0->x = -B0->x;
205         B0->y = -B0->y;
206
207         //return d_angle*K_B;
208         return 100;
209     }
210
211
212     if( (F1->x==0) && (F1->y==0) )
213         {
214             K->x = -K->x;
215             K->y = -K->y;
216             B0->x = -B0->x;
217             B0->y = -B0->y;
218
219             d_angle = acos( (B0->x*F0->x + B0->y*F0->y)/sqrt( (B0->x*B0->x + B0->y*B0->y)*(F0->x*F0->x + F0->y*F0->y) ) );
220             d_angle = d_angle - acos( (B1->x*K->x + B1->y*K->y)/sqrt( (B1->x*B1->x + B1->y*B1->y)*(K->x*K->x + K->y*K->y) ) );
221             d_angle = d_angle - CV_PI*0.5;
222             d_angle = fabs(d_angle);
223
224             K->x  = -K->x;
225             K->y  = -K->y;
226             B0->x = -B0->x;
227             B0->y = -B0->y;
228
229             //return d_angle*K_B;
230             return 100;
231         }
232
233 */
234
235 /*
236     B0->x = -B0->x;
237     B0->y = -B0->y;
238     B1->x = -B1->x;
239     B1->y = -B1->y;
240 */
241     Q0.x = F0->x * (-B0->x) + F0->y * (-B0->y);
242     Q0.y = F0->x * (-B0->y) - F0->y * (-B0->x);
243
244     Q1.x = 0.5f*( (F1->x * (-B0->x) + F1->y * (-B0->y)) + (F0->x * (-B1->x) + F0->y * (-B1->y)) );
245     Q1.y = 0.5f*( (F1->x * (-B0->y) - F1->y * (-B0->x)) + (F0->x * (-B1->y) - F0->y * (-B1->x)) );
246
247     Q2.x = F1->x * (-B1->x) + F1->y * (-B1->y);
248     Q2.y = F1->x * (-B1->y) - F1->y * (-B1->x);
249
250     d0 = Q0.x * Q1.y - Q0.y * Q1.x;
251     d1 = 0.5f*(Q0.x * Q2.y - Q0.y * Q2.x);
252     d2 = Q1.x * Q2.y - Q1.y * Q2.x;
253
254     // Check angles goes to zero
255     des = Q1.y*Q1.y - Q0.y*Q2.y;
256
257     k_zero = 0;
258
259     if( des >= 0 )
260     {
261         t_zero = ( Q0.y - Q1.y + sqrt(des) )/( Q0.y - 2*Q1.y + Q2.y );
262
263         if( (0 < t_zero) && (t_zero < 1) && ( Q(Q0, Q1, Q2, t_zero).x > 0 ) )
264         {
265             k_zero = inf;
266         }
267
268         t_zero = ( Q0.y - Q1.y - sqrt(des) )/( Q0.y - 2*Q1.y + Q2.y );
269
270         if( (0 < t_zero) && (t_zero < 1) && ( Q(Q0, Q1, Q2, t_zero).x > 0 ) )
271         {
272             k_zero = inf;
273         }
274     }
275
276     // Check nonmonotonic
277     des = d1*d1 - d0*d2;
278
279     k_nonmon = 0;
280
281     if( des >= 0 )
282     {
283         t_zero = ( d0 - d1 - sqrt(des) )/( d0 - 2*d1 + d2 );
284
285         if( (0 < t_zero) && (t_zero < 1) )
286         {
287             k_nonmon = 1;
288             Q1_nm = Q(Q0, Q1, Q2, t_zero);
289         }
290
291         t_zero = ( d0 - d1 + sqrt(des) )/( d0 - 2*d1 + d2 );
292
293         if( (0 < t_zero) && (t_zero < 1) )
294         {
295             k_nonmon += 2;
296             Q2_nm = Q(Q0, Q1, Q2, t_zero);
297         }
298     }
299
300     // Finde origin lie in Q0Q1Q2
301     check_origin = 1;
302
303     center.x = (Q0.x + Q1.x + Q2.x)/3;
304     center.y = (Q0.y + Q1.y + Q2.y)/3;
305
306     check01 = (center.x - Q0.x)*(Q1.y - Q0.y) + (center.y - Q0.y)*(Q1.x - Q0.x);
307     check02 = (-Q0.x)*(Q1.y - Q0.y) + (-Q0.y)*(Q1.x - Q0.x);
308     if( check01*check02 > 0 )
309     {
310         check01 = (center.x - Q1.x)*(Q2.y - Q1.y) + (center.y - Q1.y)*(Q2.x - Q1.x);
311         check02 = (-Q1.x)*(Q2.y - Q1.y) + (-Q1.y)*(Q2.x - Q1.x);
312         if( check01*check02 > 0 )
313         {
314             check01 = (center.x - Q2.x)*(Q0.y - Q2.y) + (center.y - Q2.y)*(Q0.x - Q2.x);
315             check02 = (-Q2.x)*(Q0.y - Q2.y) + (-Q2.y)*(Q0.x - Q2.x);
316             if( check01*check02 > 0 )
317             {
318                 check_origin = 0;
319             }
320         }
321     }
322
323     // Calculate angle
324     d_nm_angle = 0;
325     d_angle = angle(Q0,Q2);
326     if( k_nonmon == 0 )
327     {
328         if( check_origin == 0 )
329         {
330         }
331         else
332         {
333             d_angle = 2*CV_PI - d_angle;
334         }
335     }
336     else
337     {
338         if( k_nonmon == 1 )
339         {
340             d_nm_angle = angle(Q0,Q1_nm);
341             if(d_nm_angle > d_angle)
342             {
343                 d_nm_angle = d_nm_angle - d_angle;
344             }
345         }
346
347         if( k_nonmon == 2 )
348         {
349             d_nm_angle = angle(Q0,Q2_nm);
350             if(d_nm_angle > d_angle)
351             {
352                 d_nm_angle = d_nm_angle - d_angle;
353             }
354         }
355
356         if( k_nonmon == 3 )
357         {
358             d_nm_angle = angle(Q0,Q1_nm);
359             if(d_nm_angle > d_angle)
360             {
361                 d_nm_angle = d_nm_angle - d_angle;
362                 d_nm_angle = d_nm_angle + angle(Q0, Q2_nm);
363             }
364             else
365             {
366                 d_nm_angle = d_nm_angle + angle(Q2,Q2_nm);
367             }
368         }
369     }
370 /*
371     B0->x = -B0->x;
372     B0->y = -B0->y;
373     B1->x = -B1->x;
374     B1->y = -B1->y;
375 */
376     return d_angle*K_B + d_nm_angle*K_NM + k_zero*K_Z;
377     //return 0;
378 }
379
380
381 /////////////////////////////////////////////////////////////////////////////////
382 void _cvWorkEast(int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2)
383 {
384     double w1,w2;
385     CvPoint2D32f small_edge;
386
387     //W[i,j].w_east
388     w1 = W[i-1][j].w_east /*+ _cvBendingWork(   &edges1[i-2],
389                                             &edges1[i-1],
390                                             &null_edge ,
391                                             &null_edge,
392                                             NULL)*/;
393
394     small_edge.x = NULL_EDGE*edges1[i-1].x;
395     small_edge.y = NULL_EDGE*edges1[i-1].y;
396
397     w2 = W[i-1][j].w_southeast + _cvBendingWork(&edges1[i-2],
398                                                 &edges1[i-1],
399                                                 &edges2[j-1],
400                                                 /*&null_edge*/&small_edge/*,
401                                                 &edges2[j]*/);
402
403     if(w1<w2)
404     {
405         W[i][j].w_east = w1 + _cvStretchingWork( &edges1[i-1], &null_edge );
406         W[i][j].path_e = PATH_TO_E;
407     }
408     else
409     {
410         W[i][j].w_east = w2 + _cvStretchingWork( &edges1[i-1], &null_edge );
411         W[i][j].path_e = PATH_TO_SE;
412     }
413 }
414
415
416
417
418
419 ////////////////////////////////////////////////////////////////////////////////////
420 void _cvWorkSouthEast(int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2)
421 {
422     double w1,w2,w3;
423     CvPoint2D32f small_edge;
424
425     //W[i,j].w_southeast
426     small_edge.x = NULL_EDGE*edges1[i-2].x;
427     small_edge.y = NULL_EDGE*edges1[i-2].y;
428
429     w1 = W[i-1][j-1].w_east + _cvBendingWork(&edges1[i-2],
430                                             &edges1[i-1],                                           
431                                             /*&null_edge*/&small_edge,
432                                             &edges2[j-1]/*,
433                                             &edges2[j-2]*/);
434
435     w2 = W[i-1][j-1].w_southeast + _cvBendingWork(  &edges1[i-2],
436                                                     &edges1[i-1],
437                                                     &edges2[j-2],
438                                                     &edges2[j-1]/*,
439                                                     NULL*/);
440
441     small_edge.x = NULL_EDGE*edges2[j-2].x;
442     small_edge.y = NULL_EDGE*edges2[j-2].y;
443
444     w3 = W[i-1][j-1].w_south + _cvBendingWork(  /*&null_edge*/&small_edge,
445                                                 &edges1[i-1],                                           
446                                                 &edges2[j-2],
447                                                 &edges2[j-1]/*,
448                                                 &edges1[i-2]*/);
449
450     if( w1<w2 )
451     {
452         if(w1<w3)
453         {
454             W[i][j].w_southeast = w1 + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
455             W[i][j].path_se = PATH_TO_E;
456         }
457         else
458         {
459             W[i][j].w_southeast = w3 + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
460             W[i][j].path_se = 3;
461         }
462     }
463     else
464     {
465         if( w2<w3)
466         {
467             W[i][j].w_southeast = w2 + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
468             W[i][j].path_se = PATH_TO_SE;
469         }
470         else
471         {
472             W[i][j].w_southeast = w3 + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
473             W[i][j].path_se = 3;
474         }
475     }
476 }
477
478
479 //////////////////////////////////////////////////////////////////////////////////////
480 void _cvWorkSouth(int i, int j, _CvWork** W, CvPoint2D32f* edges1, CvPoint2D32f* edges2)
481 {
482     double w1,w2;
483     CvPoint2D32f small_edge;
484
485     //W[i,j].w_south
486
487     small_edge.x = NULL_EDGE*edges2[j-1].x;
488     small_edge.y = NULL_EDGE*edges2[j-1].y;
489
490     w1 = W[i][j-1].w_southeast + _cvBendingWork(&edges1[i-1],
491                                                 /*&null_edge*/&small_edge,
492                                                 &edges2[j-2],
493                                                 &edges2[j-1]/*,
494                                                 &edges1[i]*/);
495
496     w2 = W[i][j-1].w_south /*+ _cvBendingWork(  &null_edge ,
497                                             &null_edge,
498                                             &edges2[j-2],
499                                             &edges2[j-1],
500                                             NULL)*/;
501
502     if( w1<w2 )
503     {
504         W[i][j].w_south = w1 + _cvStretchingWork( &null_edge, &edges2[j-1] );
505         W[i][j].path_s = PATH_TO_SE;
506     }
507     else
508     {
509         W[i][j].w_south = w2 + _cvStretchingWork( &null_edge, &edges2[j-1] );
510         W[i][j].path_s = 3;
511     }
512 }
513
514 //===================================================
515 CvPoint2D32f Q(CvPoint2D32f q0,CvPoint2D32f q1,CvPoint2D32f q2,double t)
516 {
517     CvPoint2D32f q;
518
519     q.x = (float)(q0.x*(1-t)*(1-t) + 2*q1.x*t*(1-t) + q2.x*t*t);
520     q.y = (float)(q0.y*(1-t)*(1-t) + 2*q1.y*t*(1-t) + q2.y*t*t);
521
522     return q;       
523 }
524
525 double angle(CvPoint2D32f A, CvPoint2D32f B)
526 {
527     return acos( (A.x*B.x + A.y*B.y)/sqrt( (double)(A.x*A.x + A.y*A.y)*(B.x*B.x + B.y*B.y) ) );
528 }
529
530 /***************************************************************************************\
531 *
532 *   This function compute intermediate polygon between contour1 and contour2
533 *
534 *   Correspondence between points of contours specify by corr
535 *
536 *   param = [0,1];  0 correspondence to contour1, 1 - contour2
537 *
538 \***************************************************************************************/
539 CvSeq* icvBlendContours(CvSeq* contour1, 
540                         CvSeq* contour2,
541                         CvSeq* corr,
542                         double param,
543                         CvMemStorage* storage)
544 {
545     int j;
546     
547     CvSeqWriter writer01;
548     CvSeqReader reader01;
549
550     int Ni,Nj;              // size of contours
551     int i;                  // counter
552
553     CvPoint* point1;        // array of first contour point
554     CvPoint* point2;        // array of second contour point
555
556     CvPoint point_output;   // intermediate storage of ouput point
557
558     int corr_point;
559
560     // Create output sequence.
561     CvSeq* output = cvCreateSeq(0,                      
562                                 sizeof(CvSeq),
563                                 sizeof(CvPoint),
564                                 storage );
565
566     // Find size of contours.
567     Ni = contour1->total + 1;
568     Nj = contour2->total + 1;
569
570     point1 = (CvPoint* )malloc( Ni*sizeof(CvPoint) );
571     point2 = (CvPoint* )malloc( Nj*sizeof(CvPoint) );
572
573     // Initialize arrays of point 
574     cvCvtSeqToArray( contour1, point1, CV_WHOLE_SEQ );
575     cvCvtSeqToArray( contour2, point2, CV_WHOLE_SEQ );
576
577     // First and last point mast be equal.
578     point1[Ni-1] = point1[0];
579     point2[Nj-1] = point2[0];
580
581     // Initializes process of writing to sequence.
582     cvStartAppendToSeq( output, &writer01);
583
584     i = Ni-1; //correspondence to points of contour1
585     for( ; corr; corr = corr->h_next )
586     {       
587         //Initializes process of sequential reading from sequence
588         cvStartReadSeq( corr, &reader01, 0 );
589
590         for(j=0; j < corr->total; j++)
591         {
592             // Read element from sequence.
593             CV_READ_SEQ_ELEM( corr_point, reader01 );
594
595             // Compute point of intermediate polygon.
596             point_output.x = cvRound(point1[i].x + param*( point2[corr_point].x - point1[i].x ));
597             point_output.y = cvRound(point1[i].y + param*( point2[corr_point].y - point1[i].y ));
598             
599             // Write element to sequence.
600             CV_WRITE_SEQ_ELEM( point_output, writer01 );
601         }
602         i--;
603     }
604     // Updates sequence header.
605     cvFlushSeqWriter( &writer01 );
606     
607     return output;
608 }
609
610 /**************************************************************************************************
611 *
612 *
613 *
614 *
615 *
616 *
617 *
618 *
619 *
620 *
621 **************************************************************************************************/
622
623
624 void icvCalcContoursCorrespondence(CvSeq* contour1, 
625                                    CvSeq* contour2, 
626                                    CvSeq** corr, 
627                                    CvMemStorage* storage)
628 {
629     int i,j;                    // counter of cycles
630     int Ni,Nj;                  // size of contours
631     _CvWork** W;                // graph for search minimum of work
632
633     CvPoint* point1;            // array of first contour point
634     CvPoint* point2;            // array of second contour point
635     CvPoint2D32f* edges1;       // array of first contour edge
636     CvPoint2D32f* edges2;       // array of second contour edge
637
638     //CvPoint null_edge = {0,0};    //
639     CvPoint2D32f small_edge;
640     //double inf;                   // infinity
641
642     CvSeq* corr01;
643     CvSeqWriter writer;
644
645     char path;                  //
646
647     // Find size of contours
648     Ni = contour1->total + 1;
649     Nj = contour2->total + 1;
650
651     // Create arrays
652     W = (_CvWork**)malloc(sizeof(_CvWork*)*Ni);
653     for(i=0; i<Ni; i++)
654     {
655         W[i] = (_CvWork*)malloc(sizeof(_CvWork)*Nj);
656     }
657
658     point1 = (CvPoint* )malloc( Ni*sizeof(CvPoint) );
659     point2 = (CvPoint* )malloc( Nj*sizeof(CvPoint) );
660     edges1 = (CvPoint2D32f* )malloc( (Ni-1)*sizeof(CvPoint2D32f) );
661     edges2 = (CvPoint2D32f* )malloc( (Nj-1)*sizeof(CvPoint2D32f) );
662
663     // Initialize arrays of point 
664     cvCvtSeqToArray( contour1, point1, CV_WHOLE_SEQ );
665     cvCvtSeqToArray( contour2, point2, CV_WHOLE_SEQ );
666
667     point1[Ni-1] = point1[0];
668     point2[Nj-1] = point2[0];
669
670     for(i=0;i<Ni-1;i++)
671     {
672         edges1[i].x = (float)( point1[i+1].x - point1[i].x );
673         edges1[i].y = (float)( point1[i+1].y - point1[i].y );
674     };
675
676     for(i=0;i<Nj-1;i++)
677     {
678         edges2[i].x = (float)( point2[i+1].x - point2[i].x );
679         edges2[i].y = (float)( point2[i+1].y - point2[i].y );
680     };
681
682     // Find infinity constant 
683     //inf=1;
684 /////////////
685
686 //Find min path in graph
687
688 /////////////
689     W[0][0].w_east      = 0;
690     W[0][0].w_south     = 0;
691     W[0][0].w_southeast = 0;
692
693     W[1][1].w_southeast = _cvStretchingWork( &edges1[0], &edges2[0] );
694     W[1][1].w_east = inf;
695     W[1][1].w_south = inf;
696     W[1][1].path_se = PATH_TO_SE;
697
698     W[0][1].w_south =  _cvStretchingWork( &null_edge, &edges2[0] );
699     W[0][1].path_s = 3;
700     W[1][0].w_east =  _cvStretchingWork( &edges2[0], &null_edge );
701     W[1][0].path_e = PATH_TO_E;
702
703     for( i=1; i<Ni; i++ )
704     {
705         W[i][0].w_south     = inf;
706         W[i][0].w_southeast = inf;
707     }
708
709     for(j=1; j<Nj; j++)
710     {
711         W[0][j].w_east      = inf;
712         W[0][j].w_southeast = inf;
713     }
714
715     for(i=2; i<Ni; i++)
716     {
717         j=0;/////////
718         W[i][j].w_east = W[i-1][j].w_east;
719         W[i][j].w_east = W[i][j].w_east /*+ 
720             _cvBendingWork( &edges1[i-2], &edges1[i-1], &null_edge, &null_edge, NULL )*/;
721         W[i][j].w_east = W[i][j].w_east + _cvStretchingWork( &edges2[i-1], &null_edge );
722         W[i][j].path_e = PATH_TO_E;
723         
724         j=1;//////////
725         W[i][j].w_south = inf;
726
727         _cvWorkEast (i, j, W, edges1, edges2);
728
729         W[i][j].w_southeast = W[i-1][j-1].w_east;
730         W[i][j].w_southeast = W[i][j].w_southeast + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
731
732         small_edge.x = NULL_EDGE*edges1[i-2].x;
733         small_edge.y = NULL_EDGE*edges1[i-2].y;
734
735         W[i][j].w_southeast = W[i][j].w_southeast + 
736             _cvBendingWork( &edges1[i-2], &edges1[i-1], /*&null_edge*/&small_edge, &edges2[j-1]/*, &edges2[Nj-2]*/);
737
738         W[i][j].path_se = PATH_TO_E;
739     }
740
741     for(j=2; j<Nj; j++)
742     {       
743         i=0;//////////
744         W[i][j].w_south = W[i][j-1].w_south;
745         W[i][j].w_south = W[i][j].w_south + _cvStretchingWork( &null_edge, &edges2[j-1] );
746         W[i][j].w_south = W[i][j].w_south /*+ 
747             _cvBendingWork( &null_edge, &null_edge, &edges2[j-2], &edges2[j-1], NULL )*/;
748         W[i][j].path_s = 3;
749
750         i=1;///////////
751         W[i][j].w_east= inf;
752
753         _cvWorkSouth(i, j, W, edges1, edges2);
754
755         W[i][j].w_southeast = W[i-1][j-1].w_south;
756         W[i][j].w_southeast = W[i][j].w_southeast + _cvStretchingWork( &edges1[i-1], &edges2[j-1] );
757
758         small_edge.x = NULL_EDGE*edges2[j-2].x;
759         small_edge.y = NULL_EDGE*edges2[j-2].y;
760
761         W[i][j].w_southeast = W[i][j].w_southeast + 
762             _cvBendingWork( /*&null_edge*/&small_edge, &edges1[i-1], &edges2[j-2], &edges2[j-1]/*, &edges1[Ni-2]*/);
763         W[i][j].path_se = 3;
764     }
765
766     for(i=2; i<Ni; i++)
767         for(j=2; j<Nj; j++)
768         {
769             _cvWorkEast     (i, j, W, edges1, edges2);
770             _cvWorkSouthEast(i, j, W, edges1, edges2);
771             _cvWorkSouth    (i, j, W, edges1, edges2);
772         }
773
774     i=Ni-1;j=Nj-1;
775
776     *corr = cvCreateSeq(0,                    
777                         sizeof(CvSeq),        
778                         sizeof(int),
779                         storage );
780
781     corr01 = *corr;
782     cvStartAppendToSeq( corr01, &writer );
783     if( W[i][j].w_east > W[i][j].w_southeast )
784         {
785             if( W[i][j].w_southeast > W[i][j].w_south )
786             {
787                 path = 3;
788             }
789             else
790             {
791                 path = PATH_TO_SE;
792             }
793         }
794         else
795         {
796             if( W[i][j].w_east < W[i][j].w_south )
797             {
798                 path = PATH_TO_E;
799             }
800             else
801             {
802                 path = 3;
803             }
804         }
805     do
806     {
807         CV_WRITE_SEQ_ELEM( j, writer );
808
809         switch( path ) 
810         {
811         case PATH_TO_E:
812             path = W[i][j].path_e;
813             i--;
814             cvFlushSeqWriter( &writer );
815             corr01->h_next = cvCreateSeq(   0,                    
816                                             sizeof(CvSeq),        
817                                             sizeof(int),
818                                             storage );
819             corr01 = corr01->h_next;
820             cvStartAppendToSeq( corr01, &writer );
821             break;
822         
823         case PATH_TO_SE:
824             path = W[i][j].path_se;
825             j--; i--;
826             cvFlushSeqWriter( &writer );
827             corr01->h_next = cvCreateSeq(   0,                    
828                                             sizeof(CvSeq),        
829                                             sizeof(int),
830                                             storage );
831             corr01 = corr01->h_next;
832             cvStartAppendToSeq( corr01, &writer );
833             break;
834
835         case 3:
836             path = W[i][j].path_s;
837             j--;
838             break;
839         }
840
841     } while( (i>=0) && (j>=0) );
842     cvFlushSeqWriter( &writer );
843
844     // Free memory
845     for(i=1;i<Ni;i++)
846     {
847         free(W[i]);
848     }
849     free(W);
850     free(point1);
851     free(point2);
852     free(edges1);
853     free(edges2);
854 }
855