Home | History | Annotate | Download | only in src
      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. */
    611