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 #include "_cv.h"
     42 
     43 typedef struct
     44 {
     45     float xx;
     46     float xy;
     47     float yy;
     48     float xt;
     49     float yt;
     50 }
     51 icvDerProduct;
     52 
     53 
     54 #define CONV( A, B, C)  ((float)( A +  (B<<1)  + C ))
     55 /*F///////////////////////////////////////////////////////////////////////////////////////
     56 //    Name: icvCalcOpticalFlowLK_8u32fR ( Lucas & Kanade method )
     57 //    Purpose: calculate Optical flow for 2 images using Lucas & Kanade algorithm
     58 //    Context:
     59 //    Parameters:
     60 //            imgA,         // pointer to first frame ROI
     61 //            imgB,         // pointer to second frame ROI
     62 //            imgStep,      // width of single row of source images in bytes
     63 //            imgSize,      // size of the source image ROI
     64 //            winSize,      // size of the averaging window used for grouping
     65 //            velocityX,    // pointer to horizontal and
     66 //            velocityY,    // vertical components of optical flow ROI
     67 //            velStep       // width of single row of velocity frames in bytes
     68 //
     69 //    Returns: CV_OK         - all ok
     70 //             CV_OUTOFMEM_ERR  - insufficient memory for function work
     71 //             CV_NULLPTR_ERR - if one of input pointers is NULL
     72 //             CV_BADSIZE_ERR   - wrong input sizes interrelation
     73 //
     74 //    Notes:  1.Optical flow to be computed for every pixel in ROI
     75 //            2.For calculating spatial derivatives we use 3x3 Sobel operator.
     76 //            3.We use the following border mode.
     77 //              The last row or column is replicated for the border
     78 //              ( IPL_BORDER_REPLICATE in IPL ).
     79 //
     80 //
     81 //F*/
     82 static CvStatus CV_STDCALL
     83 icvCalcOpticalFlowLK_8u32fR( uchar * imgA,
     84                              uchar * imgB,
     85                              int imgStep,
     86                              CvSize imgSize,
     87                              CvSize winSize,
     88                              float *velocityX,
     89                              float *velocityY, int velStep )
     90 {
     91     /* Loops indexes */
     92     int i, j, k;
     93 
     94     /* Gaussian separable kernels */
     95     float GaussX[16];
     96     float GaussY[16];
     97     float *KerX;
     98     float *KerY;
     99 
    100     /* Buffers for Sobel calculations */
    101     float *MemX[2];
    102     float *MemY[2];
    103 
    104     float ConvX, ConvY;
    105     float GradX, GradY, GradT;
    106 
    107     int winWidth = winSize.width;
    108     int winHeight = winSize.height;
    109 
    110     int imageWidth = imgSize.width;
    111     int imageHeight = imgSize.height;
    112 
    113     int HorRadius = (winWidth - 1) >> 1;
    114     int VerRadius = (winHeight - 1) >> 1;
    115 
    116     int PixelLine;
    117     int ConvLine;
    118 
    119     int BufferAddress;
    120 
    121     int BufferHeight = 0;
    122     int BufferWidth;
    123     int BufferSize;
    124 
    125     /* buffers derivatives product */
    126     icvDerProduct *II;
    127 
    128     /* buffers for gaussian horisontal convolution */
    129     icvDerProduct *WII;
    130 
    131     /* variables for storing number of first pixel of image line */
    132     int Line1;
    133     int Line2;
    134     int Line3;
    135 
    136     /* we must have 2*2 linear system coeffs
    137        | A1B2  B1 |  {u}   {C1}   {0}
    138        |          |  { } + {  } = { }
    139        | A2  A1B2 |  {v}   {C2}   {0}
    140      */
    141     float A1B2, A2, B1, C1, C2;
    142 
    143     int pixNumber;
    144 
    145     /* auxiliary */
    146     int NoMem = 0;
    147 
    148     velStep /= sizeof(velocityX[0]);
    149 
    150     /* Checking bad arguments */
    151     if( imgA == NULL )
    152         return CV_NULLPTR_ERR;
    153     if( imgB == NULL )
    154         return CV_NULLPTR_ERR;
    155 
    156     if( imageHeight < winHeight )
    157         return CV_BADSIZE_ERR;
    158     if( imageWidth < winWidth )
    159         return CV_BADSIZE_ERR;
    160 
    161     if( winHeight >= 16 )
    162         return CV_BADSIZE_ERR;
    163     if( winWidth >= 16 )
    164         return CV_BADSIZE_ERR;
    165 
    166     if( !(winHeight & 1) )
    167         return CV_BADSIZE_ERR;
    168     if( !(winWidth & 1) )
    169         return CV_BADSIZE_ERR;
    170 
    171     BufferHeight = winHeight;
    172     BufferWidth = imageWidth;
    173 
    174     /****************************************************************************************/
    175     /* Computing Gaussian coeffs                                                            */
    176     /****************************************************************************************/
    177     GaussX[0] = 1;
    178     GaussY[0] = 1;
    179     for( i = 1; i < winWidth; i++ )
    180     {
    181         GaussX[i] = 1;
    182         for( j = i - 1; j > 0; j-- )
    183         {
    184             GaussX[j] += GaussX[j - 1];
    185         }
    186     }
    187     for( i = 1; i < winHeight; i++ )
    188     {
    189         GaussY[i] = 1;
    190         for( j = i - 1; j > 0; j-- )
    191         {
    192             GaussY[j] += GaussY[j - 1];
    193         }
    194     }
    195     KerX = &GaussX[HorRadius];
    196     KerY = &GaussY[VerRadius];
    197 
    198     /****************************************************************************************/
    199     /* Allocating memory for all buffers                                                    */
    200     /****************************************************************************************/
    201     for( k = 0; k < 2; k++ )
    202     {
    203         MemX[k] = (float *) cvAlloc( (imgSize.height) * sizeof( float ));
    204 
    205         if( MemX[k] == NULL )
    206             NoMem = 1;
    207         MemY[k] = (float *) cvAlloc( (imgSize.width) * sizeof( float ));
    208 
    209         if( MemY[k] == NULL )
    210             NoMem = 1;
    211     }
    212 
    213     BufferSize = BufferHeight * BufferWidth;
    214 
    215     II = (icvDerProduct *) cvAlloc( BufferSize * sizeof( icvDerProduct ));
    216     WII = (icvDerProduct *) cvAlloc( BufferSize * sizeof( icvDerProduct ));
    217 
    218 
    219     if( (II == NULL) || (WII == NULL) )
    220         NoMem = 1;
    221 
    222     if( NoMem )
    223     {
    224         for( k = 0; k < 2; k++ )
    225         {
    226             if( MemX[k] )
    227                 cvFree( &MemX[k] );
    228 
    229             if( MemY[k] )
    230                 cvFree( &MemY[k] );
    231         }
    232         if( II )
    233             cvFree( &II );
    234         if( WII )
    235             cvFree( &WII );
    236 
    237         return CV_OUTOFMEM_ERR;
    238     }
    239 
    240     /****************************************************************************************/
    241     /*        Calculate first line of memX and memY                                         */
    242     /****************************************************************************************/
    243     MemY[0][0] = MemY[1][0] = CONV( imgA[0], imgA[0], imgA[1] );
    244     MemX[0][0] = MemX[1][0] = CONV( imgA[0], imgA[0], imgA[imgStep] );
    245 
    246     for( j = 1; j < imageWidth - 1; j++ )
    247     {
    248         MemY[0][j] = MemY[1][j] = CONV( imgA[j - 1], imgA[j], imgA[j + 1] );
    249     }
    250 
    251     pixNumber = imgStep;
    252     for( i = 1; i < imageHeight - 1; i++ )
    253     {
    254         MemX[0][i] = MemX[1][i] = CONV( imgA[pixNumber - imgStep],
    255                                         imgA[pixNumber], imgA[pixNumber + imgStep] );
    256         pixNumber += imgStep;
    257     }
    258 
    259     MemY[0][imageWidth - 1] =
    260         MemY[1][imageWidth - 1] = CONV( imgA[imageWidth - 2],
    261                                         imgA[imageWidth - 1], imgA[imageWidth - 1] );
    262 
    263     MemX[0][imageHeight - 1] =
    264         MemX[1][imageHeight - 1] = CONV( imgA[pixNumber - imgStep],
    265                                          imgA[pixNumber], imgA[pixNumber] );
    266 
    267 
    268     /****************************************************************************************/
    269     /*    begin scan image, calc derivatives and solve system                               */
    270     /****************************************************************************************/
    271 
    272     PixelLine = -VerRadius;
    273     ConvLine = 0;
    274     BufferAddress = -BufferWidth;
    275 
    276     while( PixelLine < imageHeight )
    277     {
    278         if( ConvLine < imageHeight )
    279         {
    280             /*Here we calculate derivatives for line of image */
    281             int address;
    282 
    283             i = ConvLine;
    284             int L1 = i - 1;
    285             int L2 = i;
    286             int L3 = i + 1;
    287 
    288             int memYline = L3 & 1;
    289 
    290             if( L1 < 0 )
    291                 L1 = 0;
    292             if( L3 >= imageHeight )
    293                 L3 = imageHeight - 1;
    294 
    295             BufferAddress += BufferWidth;
    296             BufferAddress -= ((BufferAddress >= BufferSize) ? 0xffffffff : 0) & BufferSize;
    297 
    298             address = BufferAddress;
    299 
    300             Line1 = L1 * imgStep;
    301             Line2 = L2 * imgStep;
    302             Line3 = L3 * imgStep;
    303 
    304             /* Process first pixel */
    305             ConvX = CONV( imgA[Line1 + 1], imgA[Line2 + 1], imgA[Line3 + 1] );
    306             ConvY = CONV( imgA[Line3], imgA[Line3], imgA[Line3 + 1] );
    307 
    308             GradY = ConvY - MemY[memYline][0];
    309             GradX = ConvX - MemX[1][L2];
    310 
    311             MemY[memYline][0] = ConvY;
    312             MemX[1][L2] = ConvX;
    313 
    314             GradT = (float) (imgB[Line2] - imgA[Line2]);
    315 
    316             II[address].xx = GradX * GradX;
    317             II[address].xy = GradX * GradY;
    318             II[address].yy = GradY * GradY;
    319             II[address].xt = GradX * GradT;
    320             II[address].yt = GradY * GradT;
    321             address++;
    322             /* Process middle of line */
    323             for( j = 1; j < imageWidth - 1; j++ )
    324             {
    325                 ConvX = CONV( imgA[Line1 + j + 1], imgA[Line2 + j + 1], imgA[Line3 + j + 1] );
    326                 ConvY = CONV( imgA[Line3 + j - 1], imgA[Line3 + j], imgA[Line3 + j + 1] );
    327 
    328                 GradY = ConvY - MemY[memYline][j];
    329                 GradX = ConvX - MemX[(j - 1) & 1][L2];
    330 
    331                 MemY[memYline][j] = ConvY;
    332                 MemX[(j - 1) & 1][L2] = ConvX;
    333 
    334                 GradT = (float) (imgB[Line2 + j] - imgA[Line2 + j]);
    335 
    336                 II[address].xx = GradX * GradX;
    337                 II[address].xy = GradX * GradY;
    338                 II[address].yy = GradY * GradY;
    339                 II[address].xt = GradX * GradT;
    340                 II[address].yt = GradY * GradT;
    341 
    342                 address++;
    343             }
    344             /* Process last pixel of line */
    345             ConvX = CONV( imgA[Line1 + imageWidth - 1], imgA[Line2 + imageWidth - 1],
    346                           imgA[Line3 + imageWidth - 1] );
    347 
    348             ConvY = CONV( imgA[Line3 + imageWidth - 2], imgA[Line3 + imageWidth - 1],
    349                           imgA[Line3 + imageWidth - 1] );
    350 
    351 
    352             GradY = ConvY - MemY[memYline][imageWidth - 1];
    353             GradX = ConvX - MemX[(imageWidth - 2) & 1][L2];
    354 
    355             MemY[memYline][imageWidth - 1] = ConvY;
    356 
    357             GradT = (float) (imgB[Line2 + imageWidth - 1] - imgA[Line2 + imageWidth - 1]);
    358 
    359             II[address].xx = GradX * GradX;
    360             II[address].xy = GradX * GradY;
    361             II[address].yy = GradY * GradY;
    362             II[address].xt = GradX * GradT;
    363             II[address].yt = GradY * GradT;
    364             address++;
    365 
    366             /* End of derivatives for line */
    367 
    368             /****************************************************************************************/
    369             /* ---------Calculating horizontal convolution of processed line----------------------- */
    370             /****************************************************************************************/
    371             address -= BufferWidth;
    372             /* process first HorRadius pixels */
    373             for( j = 0; j < HorRadius; j++ )
    374             {
    375                 int jj;
    376 
    377                 WII[address].xx = 0;
    378                 WII[address].xy = 0;
    379                 WII[address].yy = 0;
    380                 WII[address].xt = 0;
    381                 WII[address].yt = 0;
    382 
    383                 for( jj = -j; jj <= HorRadius; jj++ )
    384                 {
    385                     float Ker = KerX[jj];
    386 
    387                     WII[address].xx += II[address + jj].xx * Ker;
    388                     WII[address].xy += II[address + jj].xy * Ker;
    389                     WII[address].yy += II[address + jj].yy * Ker;
    390                     WII[address].xt += II[address + jj].xt * Ker;
    391                     WII[address].yt += II[address + jj].yt * Ker;
    392                 }
    393                 address++;
    394             }
    395             /* process inner part of line */
    396             for( j = HorRadius; j < imageWidth - HorRadius; j++ )
    397             {
    398                 int jj;
    399                 float Ker0 = KerX[0];
    400 
    401                 WII[address].xx = 0;
    402                 WII[address].xy = 0;
    403                 WII[address].yy = 0;
    404                 WII[address].xt = 0;
    405                 WII[address].yt = 0;
    406 
    407                 for( jj = 1; jj <= HorRadius; jj++ )
    408                 {
    409                     float Ker = KerX[jj];
    410 
    411                     WII[address].xx += (II[address - jj].xx + II[address + jj].xx) * Ker;
    412                     WII[address].xy += (II[address - jj].xy + II[address + jj].xy) * Ker;
    413                     WII[address].yy += (II[address - jj].yy + II[address + jj].yy) * Ker;
    414                     WII[address].xt += (II[address - jj].xt + II[address + jj].xt) * Ker;
    415                     WII[address].yt += (II[address - jj].yt + II[address + jj].yt) * Ker;
    416                 }
    417                 WII[address].xx += II[address].xx * Ker0;
    418                 WII[address].xy += II[address].xy * Ker0;
    419                 WII[address].yy += II[address].yy * Ker0;
    420                 WII[address].xt += II[address].xt * Ker0;
    421                 WII[address].yt += II[address].yt * Ker0;
    422 
    423                 address++;
    424             }
    425             /* process right side */
    426             for( j = imageWidth - HorRadius; j < imageWidth; j++ )
    427             {
    428                 int jj;
    429 
    430                 WII[address].xx = 0;
    431                 WII[address].xy = 0;
    432                 WII[address].yy = 0;
    433                 WII[address].xt = 0;
    434                 WII[address].yt = 0;
    435 
    436                 for( jj = -HorRadius; jj < imageWidth - j; jj++ )
    437                 {
    438                     float Ker = KerX[jj];
    439 
    440                     WII[address].xx += II[address + jj].xx * Ker;
    441                     WII[address].xy += II[address + jj].xy * Ker;
    442                     WII[address].yy += II[address + jj].yy * Ker;
    443                     WII[address].xt += II[address + jj].xt * Ker;
    444                     WII[address].yt += II[address + jj].yt * Ker;
    445                 }
    446                 address++;
    447             }
    448         }
    449 
    450         /****************************************************************************************/
    451         /*  Calculating velocity line                                                           */
    452         /****************************************************************************************/
    453         if( PixelLine >= 0 )
    454         {
    455             int USpace;
    456             int BSpace;
    457             int address;
    458 
    459             if( PixelLine < VerRadius )
    460                 USpace = PixelLine;
    461             else
    462                 USpace = VerRadius;
    463 
    464             if( PixelLine >= imageHeight - VerRadius )
    465                 BSpace = imageHeight - PixelLine - 1;
    466             else
    467                 BSpace = VerRadius;
    468 
    469             address = ((PixelLine - USpace) % BufferHeight) * BufferWidth;
    470             for( j = 0; j < imageWidth; j++ )
    471             {
    472                 int addr = address;
    473 
    474                 A1B2 = 0;
    475                 A2 = 0;
    476                 B1 = 0;
    477                 C1 = 0;
    478                 C2 = 0;
    479 
    480                 for( i = -USpace; i <= BSpace; i++ )
    481                 {
    482                     A2 += WII[addr + j].xx * KerY[i];
    483                     A1B2 += WII[addr + j].xy * KerY[i];
    484                     B1 += WII[addr + j].yy * KerY[i];
    485                     C2 += WII[addr + j].xt * KerY[i];
    486                     C1 += WII[addr + j].yt * KerY[i];
    487 
    488                     addr += BufferWidth;
    489                     addr -= ((addr >= BufferSize) ? 0xffffffff : 0) & BufferSize;
    490                 }
    491                 /****************************************************************************************\
    492                 * Solve Linear System                                                                    *
    493                 \****************************************************************************************/
    494                 {
    495                     float delta = (A1B2 * A1B2 - A2 * B1);
    496 
    497                     if( delta )
    498                     {
    499                         /* system is not singular - solving by Kramer method */
    500                         float deltaX;
    501                         float deltaY;
    502                         float Idelta = 8 / delta;
    503 
    504                         deltaX = -(C1 * A1B2 - C2 * B1);
    505                         deltaY = -(A1B2 * C2 - A2 * C1);
    506 
    507                         velocityX[j] = deltaX * Idelta;
    508                         velocityY[j] = deltaY * Idelta;
    509                     }
    510                     else
    511                     {
    512                         /* singular system - find optical flow in gradient direction */
    513                         float Norm = (A1B2 + A2) * (A1B2 + A2) + (B1 + A1B2) * (B1 + A1B2);
    514 
    515                         if( Norm )
    516                         {
    517                             float IGradNorm = 8 / Norm;
    518                             float temp = -(C1 + C2) * IGradNorm;
    519 
    520                             velocityX[j] = (A1B2 + A2) * temp;
    521                             velocityY[j] = (B1 + A1B2) * temp;
    522 
    523                         }
    524                         else
    525                         {
    526                             velocityX[j] = 0;
    527                             velocityY[j] = 0;
    528                         }
    529                     }
    530                 }
    531                 /****************************************************************************************\
    532                 * End of Solving Linear System                                                           *
    533                 \****************************************************************************************/
    534             }                   /*for */
    535             velocityX += velStep;
    536             velocityY += velStep;
    537         }                       /*for */
    538         PixelLine++;
    539         ConvLine++;
    540     }
    541 
    542     /* Free memory */
    543     for( k = 0; k < 2; k++ )
    544     {
    545         cvFree( &MemX[k] );
    546         cvFree( &MemY[k] );
    547     }
    548     cvFree( &II );
    549     cvFree( &WII );
    550 
    551     return CV_OK;
    552 } /*icvCalcOpticalFlowLK_8u32fR*/
    553 
    554 
    555 /*F///////////////////////////////////////////////////////////////////////////////////////
    556 //    Name:    cvCalcOpticalFlowLK
    557 //    Purpose: Optical flow implementation
    558 //    Context:
    559 //    Parameters:
    560 //             srcA, srcB - source image
    561 //             velx, vely - destination image
    562 //    Returns:
    563 //
    564 //    Notes:
    565 //F*/
    566 CV_IMPL void
    567 cvCalcOpticalFlowLK( const void* srcarrA, const void* srcarrB, CvSize winSize,
    568                      void* velarrx, void* velarry )
    569 {
    570     CV_FUNCNAME( "cvCalcOpticalFlowLK" );
    571 
    572     __BEGIN__;
    573 
    574     CvMat stubA, *srcA = (CvMat*)srcarrA;
    575     CvMat stubB, *srcB = (CvMat*)srcarrB;
    576     CvMat stubx, *velx = (CvMat*)velarrx;
    577     CvMat stuby, *vely = (CvMat*)velarry;
    578 
    579     CV_CALL( srcA = cvGetMat( srcA, &stubA ));
    580     CV_CALL( srcB = cvGetMat( srcB, &stubB ));
    581 
    582     CV_CALL( velx = cvGetMat( velx, &stubx ));
    583     CV_CALL( vely = cvGetMat( vely, &stuby ));
    584 
    585     if( !CV_ARE_TYPES_EQ( srcA, srcB ))
    586         CV_ERROR( CV_StsUnmatchedFormats, "Source images have different formats" );
    587 
    588     if( !CV_ARE_TYPES_EQ( velx, vely ))
    589         CV_ERROR( CV_StsUnmatchedFormats, "Destination images have different formats" );
    590 
    591     if( !CV_ARE_SIZES_EQ( srcA, srcB ) ||
    592         !CV_ARE_SIZES_EQ( velx, vely ) ||
    593         !CV_ARE_SIZES_EQ( srcA, velx ))
    594         CV_ERROR( CV_StsUnmatchedSizes, "" );
    595 
    596     if( CV_MAT_TYPE( srcA->type ) != CV_8UC1 ||
    597         CV_MAT_TYPE( velx->type ) != CV_32FC1 )
    598         CV_ERROR( CV_StsUnsupportedFormat, "Source images must have 8uC1 type and "
    599                                            "destination images must have 32fC1 type" );
    600 
    601     if( srcA->step != srcB->step || velx->step != vely->step )
    602         CV_ERROR( CV_BadStep, "source and destination images have different step" );
    603 
    604     IPPI_CALL( icvCalcOpticalFlowLK_8u32fR( (uchar*)srcA->data.ptr, (uchar*)srcB->data.ptr,
    605                                             srcA->step, cvGetMatSize( srcA ), winSize,
    606                                             velx->data.fl, vely->data.fl, velx->step ));
    607 
    608     __END__;
    609 }
    610 
    611 /* End of file. */
    612