Move the sources to trunk
[opencv] / cv / src / cvoptflowbm.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 "_cv.h"
43
44 /* 
45    Finds L1 norm between two blocks.
46 */
47 static int
48 icvCmpBlocksL1_8u_C1( const uchar * vec1, const uchar * vec2, int len )
49 {
50     int i, sum = 0;
51
52     for( i = 0; i <= len - 4; i += 4 )
53     {
54         int t0 = abs(vec1[i] - vec2[i]);
55         int t1 = abs(vec1[i + 1] - vec2[i + 1]);
56         int t2 = abs(vec1[i + 2] - vec2[i + 2]);
57         int t3 = abs(vec1[i + 3] - vec2[i + 3]);
58
59         sum += t0 + t1 + t2 + t3;
60     }
61
62     for( ; i < len; i++ )
63     {
64         int t0 = abs(vec1[i] - vec2[i]);
65         sum += t0;
66     }
67
68     return sum;
69 }
70
71
72 static void
73 icvCopyBM_8u_C1R( const uchar* src, int src_step,
74                   uchar* dst, int dst_step, CvSize size )
75 {
76     for( ; size.height--; src += src_step, dst += dst_step )
77         memcpy( dst, src, size.width );
78 }
79
80
81 /*F///////////////////////////////////////////////////////////////////////////////////////
82 //    Name: icvCalcOpticalFlowBM_8u32fR
83 //    Purpose: calculate Optical flow for 2 images using block matching algorithm
84 //    Context:
85 //    Parameters:
86 //            imgA,         // pointer to first frame ROI
87 //            imgB,         // pointer to second frame ROI
88 //            imgStep,      // full width of input images in bytes
89 //            imgSize,      // size of the image
90 //            blockSize,    // size of basic blocks which are compared
91 //            shiftSize,    // coordinates increments.
92 //            maxRange,     // size of the scanned neighborhood.
93 //            usePrevious,  // flag of using previous velocity field
94 //            velocityX,    //  pointer to ROI of horizontal and
95 //            velocityY,    //  vertical components of optical flow
96 //            velStep);     //  full width of velocity frames in bytes
97 //    Returns: CV_OK or error code
98 //    Notes:
99 //F*/
100 #define SMALL_DIFF 2
101 #define BIG_DIFF 128
102
103 static CvStatus CV_STDCALL
104 icvCalcOpticalFlowBM_8u32fR( uchar * imgA, uchar * imgB,
105                              int imgStep, CvSize imgSize,
106                              CvSize blockSize, CvSize shiftSize,
107                              CvSize maxRange, int usePrev,
108                              float *velocityX, float *velocityY,
109                              int velStep )
110 {
111     const float back = 1.f / (float) (1 << 16);
112
113     /* scanning scheme coordinates */
114
115     CvPoint *ss = 0;
116     int ss_count = 0;
117
118     int stand_accept_level = blockSize.height * blockSize.width * SMALL_DIFF;
119     int stand_escape_level = blockSize.height * blockSize.width * BIG_DIFF;
120
121     int i, j;
122
123     int *int_velocityX = (int *) velocityX;
124     int *int_velocityY = (int *) velocityY;
125
126     /* if image sizes can't be divided by block sizes then right blocks will  */
127     /* have not full width  - BorderWidth                                     */
128     /* and bottom blocks will                                                 */
129     /* have not full height - BorderHeight                                    */
130     int BorderWidth;
131     int BorderHeight;
132
133     int CurrentWidth;
134     int CurrentHeight;
135
136     int NumberBlocksX;
137     int NumberBlocksY;
138
139     int Y1 = 0;
140     int X1 = 0;
141
142     int DownStep = blockSize.height * imgStep;
143
144     uchar *blockA = 0;
145     uchar *blockB = 0;
146     uchar *blockZ = 0;
147     int blSize = blockSize.width * blockSize.height;
148     int bufferSize = cvAlign(blSize + 9,16);
149     int cmpSize = cvAlign(blSize,4);
150     int patch_ofs = blSize & -8;
151     int64 patch_mask = (((int64) 1) << (blSize - patch_ofs * 8)) - 1;
152
153     velStep /= sizeof(velocityX[0]);
154
155     if( patch_ofs == blSize )
156         patch_mask = (int64) - 1;
157
158 /****************************************************************************************\
159 *   Checking bad arguments                                                               *
160 \****************************************************************************************/
161     if( imgA == NULL )
162         return CV_NULLPTR_ERR;
163     if( imgB == NULL )
164         return CV_NULLPTR_ERR;
165
166 /****************************************************************************************\
167 *   Allocate buffers                                                                     *
168 \****************************************************************************************/
169     blockA = (uchar *) cvAlloc( bufferSize * 3 );
170     if( !blockA )
171         return CV_OUTOFMEM_ERR;
172
173     blockB = blockA + bufferSize;
174     blockZ = blockB + bufferSize;
175
176     memset( blockZ, 0, bufferSize );
177
178     ss = (CvPoint *) cvAlloc( (2 * maxRange.width + 1) * (2 * maxRange.height + 1) *
179                                sizeof( CvPoint ));
180     if( !ss )
181     {
182         cvFree( &blockA );
183         return CV_OUTOFMEM_ERR;
184     }
185
186 /****************************************************************************************\
187 *   Calculate scanning scheme                                                            *
188 \****************************************************************************************/
189     {
190         int X_shift_count = maxRange.width / shiftSize.width;
191         int Y_shift_count = maxRange.height / shiftSize.height;
192         int min_count = MIN( X_shift_count, Y_shift_count );
193
194         /* cycle by neighborhood rings */
195         /* scanning scheme is 
196
197            . 9  10 11 12
198            . 8  1  2  13
199            . 7  *  3  14
200            . 6  5  4  15      
201            20 19 18 17 16
202          */
203
204         for( i = 0; i < min_count; i++ )
205         {
206             /* four cycles along sides */
207             int y = -(i + 1) * shiftSize.height;
208             int x = -(i + 1) * shiftSize.width;
209
210             /* upper side */
211             for( j = -i; j <= i + 1; j++, ss_count++ )
212             {
213                 x += shiftSize.width;
214                 ss[ss_count].x = x;
215                 ss[ss_count].y = y;
216             }
217
218             /* right side */
219             for( j = -i; j <= i + 1; j++, ss_count++ )
220             {
221                 y += shiftSize.height;
222                 ss[ss_count].x = x;
223                 ss[ss_count].y = y;
224             }
225
226             /* bottom side */
227             for( j = -i; j <= i + 1; j++, ss_count++ )
228             {
229                 x -= shiftSize.width;
230                 ss[ss_count].x = x;
231                 ss[ss_count].y = y;
232             }
233
234             /* left side */
235             for( j = -i; j <= i + 1; j++, ss_count++ )
236             {
237                 y -= shiftSize.height;
238                 ss[ss_count].x = x;
239                 ss[ss_count].y = y;
240             }
241         }
242
243         /* the rest part */
244         if( X_shift_count < Y_shift_count )
245         {
246             int xleft = -min_count * shiftSize.width;
247
248             /* cycle by neighbor rings */
249             for( i = min_count; i < Y_shift_count; i++ )
250             {
251                 /* two cycles by x */
252                 int y = -(i + 1) * shiftSize.height;
253                 int x = xleft;
254
255                 /* upper side */
256                 for( j = -X_shift_count; j <= X_shift_count; j++, ss_count++ )
257                 {
258                     ss[ss_count].x = x;
259                     ss[ss_count].y = y;
260                     x += shiftSize.width;
261                 }
262
263                 x = xleft;
264                 y = -y;
265                 /* bottom side */
266                 for( j = -X_shift_count; j <= X_shift_count; j++, ss_count++ )
267                 {
268                     ss[ss_count].x = x;
269                     ss[ss_count].y = y;
270                     x += shiftSize.width;
271                 }
272             }
273         }
274         else if( X_shift_count > Y_shift_count )
275         {
276             int yupper = -min_count * shiftSize.height;
277
278             /* cycle by neighbor rings */
279             for( i = min_count; i < X_shift_count; i++ )
280             {
281                 /* two cycles by y */
282                 int x = -(i + 1) * shiftSize.width;
283                 int y = yupper;
284
285                 /* left side */
286                 for( j = -Y_shift_count; j <= Y_shift_count; j++, ss_count++ )
287                 {
288                     ss[ss_count].x = x;
289                     ss[ss_count].y = y;
290                     y += shiftSize.height;
291                 }
292
293                 y = yupper;
294                 x = -x;
295                 /* right side */
296                 for( j = -Y_shift_count; j <= Y_shift_count; j++, ss_count++ )
297                 {
298                     ss[ss_count].x = x;
299                     ss[ss_count].y = y;
300                     y += shiftSize.height;
301                 }
302             }
303         }
304
305     }
306
307 /****************************************************************************************\
308 *   Calculate some neeeded variables                                                     *
309 \****************************************************************************************/
310     /* Calculate number of full blocks */
311     NumberBlocksX = (int) imgSize.width / blockSize.width;
312     NumberBlocksY = (int) imgSize.height / blockSize.height;
313
314     /* add 1 if not full border blocks exist */
315     BorderWidth = imgSize.width % blockSize.width;
316     if( BorderWidth )
317         NumberBlocksX++;
318     else
319         BorderWidth = blockSize.width;
320
321     BorderHeight = imgSize.height % blockSize.height;
322     if( BorderHeight )
323         NumberBlocksY++;
324     else
325         BorderHeight = blockSize.height;
326
327 /****************************************************************************************\
328 * Round input velocities integer searching area center position                          *
329 \****************************************************************************************/
330     if( usePrev )
331     {
332         float *velxf = velocityX, *velyf = velocityY;
333         int* velx = (int*)velocityX, *vely = (int*)velocityY;
334
335         for( i = 0; i < NumberBlocksY; i++, velxf += velStep, velyf += velStep,
336                                             velx += velStep, vely += velStep )
337         {
338             for( j = 0; j < NumberBlocksX; j++ )
339             {
340                 int vx = cvRound( velxf[j] ), vy = cvRound( velyf[j] );
341                 velx[j] = vx; vely[j] = vy;
342             }
343         }
344     }
345 /****************************************************************************************\
346 * Main loop                                                                              *
347 \****************************************************************************************/
348     Y1 = 0;
349     for( i = 0; i < NumberBlocksY; i++ )
350     {
351         /* calculate height of current block */
352         CurrentHeight = (i == NumberBlocksY - 1) ? BorderHeight : blockSize.height;
353         X1 = 0;
354
355         for( j = 0; j < NumberBlocksX; j++ )
356         {
357             int accept_level;
358             int escape_level;
359
360             int blDist;
361
362             int VelocityX = 0;
363             int VelocityY = 0;
364
365             int offX = 0, offY = 0;
366
367             int CountDirection = 1;
368
369             int main_flag = i < NumberBlocksY - 1 && j < NumberBlocksX - 1;
370             CvSize CurSize;
371
372             /* calculate width of current block */
373             CurrentWidth = (j == NumberBlocksX - 1) ? BorderWidth : blockSize.width;
374
375             /* compute initial offset */
376             if( usePrev )
377             {
378                 offX = int_velocityX[j];
379                 offY = int_velocityY[j];
380             }
381
382             CurSize.width = CurrentWidth;
383             CurSize.height = CurrentHeight;
384
385             if( main_flag )
386             {
387                 icvCopyBM_8u_C1R( imgA + X1, imgStep, blockA,
388                                   CurSize.width, CurSize );
389                 icvCopyBM_8u_C1R( imgB + (Y1 + offY)*imgStep + (X1 + offX),
390                                   imgStep, blockB, CurSize.width, CurSize );
391
392                 *((int64 *) (blockA + patch_ofs)) &= patch_mask;
393                 *((int64 *) (blockB + patch_ofs)) &= patch_mask;
394             }
395             else
396             {
397                 memset( blockA, 0, bufferSize );
398                 memset( blockB, 0, bufferSize );
399
400                 icvCopyBM_8u_C1R( imgA + X1, imgStep, blockA, blockSize.width, CurSize );
401                 icvCopyBM_8u_C1R( imgB + (Y1 + offY) * imgStep + (X1 + offX), imgStep,
402                                   blockB, blockSize.width, CurSize );
403             }
404
405             if( !main_flag )
406             {
407                 int tmp = CurSize.width * CurSize.height;
408
409                 accept_level = tmp * SMALL_DIFF;
410                 escape_level = tmp * BIG_DIFF;
411             }
412             else
413             {
414                 accept_level = stand_accept_level;
415                 escape_level = stand_escape_level;
416             }
417
418             blDist = icvCmpBlocksL1_8u_C1( blockA, blockB, cmpSize );
419
420             if( blDist > accept_level )
421             {
422                 int k;
423                 int VelX = 0;
424                 int VelY = 0;
425
426                 /* walk around basic block */
427
428                 /* cycle for neighborhood */
429                 for( k = 0; k < ss_count; k++ )
430                 {
431                     int tmpDist;
432
433                     int Y2 = Y1 + offY + ss[k].y;
434                     int X2 = X1 + offX + ss[k].x;
435
436                     /* if we break upper border */
437                     if( Y2 < 0 )
438                     {
439                         continue;
440                     }
441                     /* if we break bottom border */
442                     if( Y2 + CurrentHeight >= imgSize.height )
443                     {
444                         continue;
445                     }
446                     /* if we break left border */
447                     if( X2 < 0 )
448                     {
449                         continue;
450                     }
451                     /* if we break right border */
452                     if( X2 + CurrentWidth >= imgSize.width )
453                     {
454                         continue;
455                     }
456
457                     if( main_flag )
458                     {
459                         icvCopyBM_8u_C1R( imgB + Y2 * imgStep + X2,
460                                           imgStep, blockB, CurSize.width, CurSize );
461
462                         *((int64 *) (blockB + patch_ofs)) &= patch_mask;
463                     }
464                     else
465                     {
466                         memset( blockB, 0, bufferSize );
467                         icvCopyBM_8u_C1R( imgB + Y1 * imgStep + X1, imgStep,
468                                           blockB, blockSize.width, CurSize );
469                     }
470
471                     tmpDist = icvCmpBlocksL1_8u_C1( blockA, blockB, cmpSize );
472
473                     if( tmpDist < accept_level )
474                     {
475                         VelX = ss[k].x;
476                         VelY = ss[k].y;
477                         break;  /*for */
478                     }
479                     else if( tmpDist < blDist )
480                     {
481                         blDist = tmpDist;
482                         VelX = ss[k].x;
483                         VelY = ss[k].y;
484                         CountDirection = 1;
485                     }
486                     else if( tmpDist == blDist )
487                     {
488                         VelX += ss[k].x;
489                         VelY += ss[k].y;
490                         CountDirection++;
491                     }
492                 }
493                 if( blDist > escape_level )
494                 {
495                     VelX = VelY = 0;
496                     CountDirection = 1;
497                 }
498                 if( CountDirection > 1 )
499                 {
500                     int temp = CountDirection == 2 ? 1 << 15 : ((1 << 16) / CountDirection);
501
502                     VelocityX = VelX * temp;
503                     VelocityY = VelY * temp;
504                 }
505                 else
506                 {
507                     VelocityX = VelX << 16;
508                     VelocityY = VelY << 16;
509                 }
510             }                   /*if */
511
512             int_velocityX[j] = VelocityX + (offX << 16);
513             int_velocityY[j] = VelocityY + (offY << 16);
514
515             X1 += blockSize.width;
516
517         }                       /*for */
518         int_velocityX += velStep;
519         int_velocityY += velStep;
520
521         imgA += DownStep;
522         Y1 += blockSize.height;
523     }                           /*for */
524
525 /****************************************************************************************\
526 * Converting fixed point velocities to floating point                                    *
527 \****************************************************************************************/
528     {
529         float *velxf = velocityX, *velyf = velocityY;
530         int* velx = (int*)velocityX, *vely = (int*)velocityY;
531
532         for( i = 0; i < NumberBlocksY; i++, velxf += velStep, velyf += velStep,
533                                             velx += velStep, vely += velStep )
534         {
535             for( j = 0; j < NumberBlocksX; j++ )
536             {
537                 float vx = (float)velx[j]*back, vy = (float)vely[j]*back;
538                 velxf[j] = vx; velyf[j] = vy;
539             }
540         }
541     }
542
543     cvFree( &ss );
544     cvFree( &blockA );
545     
546     return CV_OK;
547 }                               /*cvCalcOpticalFlowBM_8u */
548
549
550 /*F///////////////////////////////////////////////////////////////////////////////////////
551 //    Name:    cvCalcOpticalFlowBM
552 //    Purpose: Optical flow implementation
553 //    Context: 
554 //    Parameters:
555 //             srcA, srcB - source image
556 //             velx, vely - destination image
557 //    Returns:
558 //
559 //    Notes:
560 //F*/
561 CV_IMPL void
562 cvCalcOpticalFlowBM( const void* srcarrA, const void* srcarrB,
563                      CvSize blockSize, CvSize shiftSize,
564                      CvSize maxRange, int usePrevious,
565                      void* velarrx, void* velarry )
566 {
567     CV_FUNCNAME( "cvCalcOpticalFlowBM" );
568
569     __BEGIN__;
570
571     CvMat stubA, *srcA = (CvMat*)srcarrA;
572     CvMat stubB, *srcB = (CvMat*)srcarrB;
573     CvMat stubx, *velx = (CvMat*)velarrx;
574     CvMat stuby, *vely = (CvMat*)velarry;
575
576     CV_CALL( srcA = cvGetMat( srcA, &stubA ));
577     CV_CALL( srcB = cvGetMat( srcB, &stubB ));
578
579     CV_CALL( velx = cvGetMat( velx, &stubx ));
580     CV_CALL( vely = cvGetMat( vely, &stuby ));
581
582     if( !CV_ARE_TYPES_EQ( srcA, srcB ))
583         CV_ERROR( CV_StsUnmatchedFormats, "Source images have different formats" );
584
585     if( !CV_ARE_TYPES_EQ( velx, vely ))
586         CV_ERROR( CV_StsUnmatchedFormats, "Destination images have different formats" );
587
588     if( !CV_ARE_SIZES_EQ( srcA, srcB ) ||
589         !CV_ARE_SIZES_EQ( velx, vely ) ||
590         (unsigned)(velx->width*blockSize.width - srcA->width) >= (unsigned)blockSize.width ||
591         (unsigned)(velx->height*blockSize.height - srcA->height) >= (unsigned)blockSize.height )
592         CV_ERROR( CV_StsUnmatchedSizes, "" );
593
594     if( CV_MAT_TYPE( srcA->type ) != CV_8UC1 ||
595         CV_MAT_TYPE( velx->type ) != CV_32FC1 )
596         CV_ERROR( CV_StsUnsupportedFormat, "Source images must have 8uC1 type and "
597                                            "destination images must have 32fC1 type" );
598
599     if( srcA->step != srcB->step || velx->step != vely->step )
600         CV_ERROR( CV_BadStep, "two source or two destination images have different steps" );
601
602     IPPI_CALL( icvCalcOpticalFlowBM_8u32fR( (uchar*)srcA->data.ptr, (uchar*)srcB->data.ptr,
603                                             srcA->step, cvGetMatSize( srcA ), blockSize,
604                                             shiftSize, maxRange, usePrevious,
605                                             velx->data.fl, vely->data.fl, velx->step ));
606     __END__;
607 }
608
609
610 /* End of file. */