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 #define CONV( A, B, C)  ( (float)( A +  (B<<1)  + C ) )
     44 
     45 typedef struct
     46 {
     47     float xx;
     48     float xy;
     49     float yy;
     50     float xt;
     51     float yt;
     52     float alpha;                /* alpha = 1 / ( 1/lambda + xx + yy ) */
     53 }
     54 icvDerProductEx;
     55 
     56 /*F///////////////////////////////////////////////////////////////////////////////////////
     57 //    Name: icvCalcOpticalFlowHS_8u32fR (Horn & Schunck method )
     58 //    Purpose: calculate Optical flow for 2 images using Horn & Schunck algorithm
     59 //    Context:
     60 //    Parameters:
     61 //            imgA          -  pointer to first frame ROI
     62 //            imgB          -  pointer to second frame ROI
     63 //            imgStep       -  width of single row of source images in bytes
     64 //            imgSize       -  size of the source image ROI
     65 //            usePrevious   - use previous (input) velocity field.
     66 //            velocityX     - pointer to horizontal and
     67 //            velocityY     - vertical components of optical flow ROI
     68 //            velStep       - width of single row of velocity frames in bytes
     69 //            lambda        - Lagrangian multiplier
     70 //            criteria      - criteria of termination processmaximum number of iterations
     71 //
     72 //    Returns: CV_OK         - all ok
     73 //             CV_OUTOFMEM_ERR  - insufficient memory for function work
     74 //             CV_NULLPTR_ERR - if one of input pointers is NULL
     75 //             CV_BADSIZE_ERR   - wrong input sizes interrelation
     76 //
     77 //    Notes:  1.Optical flow to be computed for every pixel in ROI
     78 //            2.For calculating spatial derivatives we use 3x3 Sobel operator.
     79 //            3.We use the following border mode.
     80 //              The last row or column is replicated for the border
     81 //              ( IPL_BORDER_REPLICATE in IPL ).
     82 //
     83 //
     84 //F*/
     85 static CvStatus CV_STDCALL
     86 icvCalcOpticalFlowHS_8u32fR( uchar*  imgA,
     87                              uchar*  imgB,
     88                              int     imgStep,
     89                              CvSize imgSize,
     90                              int     usePrevious,
     91                              float*  velocityX,
     92                              float*  velocityY,
     93                              int     velStep,
     94                              float   lambda,
     95                              CvTermCriteria criteria )
     96 {
     97     /* Loops indexes */
     98     int i, j, k, address;
     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 imageWidth = imgSize.width;
    108     int imageHeight = imgSize.height;
    109 
    110     int ConvLine;
    111     int LastLine;
    112 
    113     int BufferSize;
    114 
    115     float Ilambda = 1 / lambda;
    116     int iter = 0;
    117     int Stop;
    118 
    119     /* buffers derivatives product */
    120     icvDerProductEx *II;
    121 
    122     float *VelBufX[2];
    123     float *VelBufY[2];
    124 
    125     /* variables for storing number of first pixel of image line */
    126     int Line1;
    127     int Line2;
    128     int Line3;
    129 
    130     int pixNumber;
    131 
    132     /* auxiliary */
    133     int NoMem = 0;
    134 
    135     /* Checking bad arguments */
    136     if( imgA == NULL )
    137         return CV_NULLPTR_ERR;
    138     if( imgB == NULL )
    139         return CV_NULLPTR_ERR;
    140 
    141     if( imgSize.width <= 0 )
    142         return CV_BADSIZE_ERR;
    143     if( imgSize.height <= 0 )
    144         return CV_BADSIZE_ERR;
    145     if( imgSize.width > imgStep )
    146         return CV_BADSIZE_ERR;
    147 
    148     if( (velStep & 3) != 0 )
    149         return CV_BADSIZE_ERR;
    150 
    151     velStep /= 4;
    152 
    153     /****************************************************************************************/
    154     /* Allocating memory for all buffers                                                    */
    155     /****************************************************************************************/
    156     for( k = 0; k < 2; k++ )
    157     {
    158         MemX[k] = (float *) cvAlloc( (imgSize.height) * sizeof( float ));
    159 
    160         if( MemX[k] == NULL )
    161             NoMem = 1;
    162         MemY[k] = (float *) cvAlloc( (imgSize.width) * sizeof( float ));
    163 
    164         if( MemY[k] == NULL )
    165             NoMem = 1;
    166 
    167         VelBufX[k] = (float *) cvAlloc( imageWidth * sizeof( float ));
    168 
    169         if( VelBufX[k] == NULL )
    170             NoMem = 1;
    171         VelBufY[k] = (float *) cvAlloc( imageWidth * sizeof( float ));
    172 
    173         if( VelBufY[k] == NULL )
    174             NoMem = 1;
    175     }
    176 
    177     BufferSize = imageHeight * imageWidth;
    178 
    179     II = (icvDerProductEx *) cvAlloc( BufferSize * sizeof( icvDerProductEx ));
    180     if( (II == NULL) )
    181         NoMem = 1;
    182 
    183     if( NoMem )
    184     {
    185         for( k = 0; k < 2; k++ )
    186         {
    187             if( MemX[k] )
    188                 cvFree( &MemX[k] );
    189 
    190             if( MemY[k] )
    191                 cvFree( &MemY[k] );
    192 
    193             if( VelBufX[k] )
    194                 cvFree( &VelBufX[k] );
    195 
    196             if( VelBufY[k] )
    197                 cvFree( &VelBufY[k] );
    198         }
    199         if( II )
    200             cvFree( &II );
    201         return CV_OUTOFMEM_ERR;
    202     }
    203 /****************************************************************************************\
    204 *         Calculate first line of memX and memY                                          *
    205 \****************************************************************************************/
    206     MemY[0][0] = MemY[1][0] = CONV( imgA[0], imgA[0], imgA[1] );
    207     MemX[0][0] = MemX[1][0] = CONV( imgA[0], imgA[0], imgA[imgStep] );
    208 
    209     for( j = 1; j < imageWidth - 1; j++ )
    210     {
    211         MemY[0][j] = MemY[1][j] = CONV( imgA[j - 1], imgA[j], imgA[j + 1] );
    212     }
    213 
    214     pixNumber = imgStep;
    215     for( i = 1; i < imageHeight - 1; i++ )
    216     {
    217         MemX[0][i] = MemX[1][i] = CONV( imgA[pixNumber - imgStep],
    218                                         imgA[pixNumber], imgA[pixNumber + imgStep] );
    219         pixNumber += imgStep;
    220     }
    221 
    222     MemY[0][imageWidth - 1] =
    223         MemY[1][imageWidth - 1] = CONV( imgA[imageWidth - 2],
    224                                         imgA[imageWidth - 1], imgA[imageWidth - 1] );
    225 
    226     MemX[0][imageHeight - 1] =
    227         MemX[1][imageHeight - 1] = CONV( imgA[pixNumber - imgStep],
    228                                          imgA[pixNumber], imgA[pixNumber] );
    229 
    230 
    231 /****************************************************************************************\
    232 *     begin scan image, calc derivatives                                                 *
    233 \****************************************************************************************/
    234 
    235     ConvLine = 0;
    236     Line2 = -imgStep;
    237     address = 0;
    238     LastLine = imgStep * (imageHeight - 1);
    239     while( ConvLine < imageHeight )
    240     {
    241         /*Here we calculate derivatives for line of image */
    242         int memYline = (ConvLine + 1) & 1;
    243 
    244         Line2 += imgStep;
    245         Line1 = Line2 - ((Line2 == 0) ? 0 : imgStep);
    246         Line3 = Line2 + ((Line2 == LastLine) ? 0 : imgStep);
    247 
    248         /* Process first pixel */
    249         ConvX = CONV( imgA[Line1 + 1], imgA[Line2 + 1], imgA[Line3 + 1] );
    250         ConvY = CONV( imgA[Line3], imgA[Line3], imgA[Line3 + 1] );
    251 
    252         GradY = (ConvY - MemY[memYline][0]) * 0.125f;
    253         GradX = (ConvX - MemX[1][ConvLine]) * 0.125f;
    254 
    255         MemY[memYline][0] = ConvY;
    256         MemX[1][ConvLine] = ConvX;
    257 
    258         GradT = (float) (imgB[Line2] - imgA[Line2]);
    259 
    260         II[address].xx = GradX * GradX;
    261         II[address].xy = GradX * GradY;
    262         II[address].yy = GradY * GradY;
    263         II[address].xt = GradX * GradT;
    264         II[address].yt = GradY * GradT;
    265 
    266         II[address].alpha = 1 / (Ilambda + II[address].xx + II[address].yy);
    267         address++;
    268 
    269         /* Process middle of line */
    270         for( j = 1; j < imageWidth - 1; j++ )
    271         {
    272             ConvX = CONV( imgA[Line1 + j + 1], imgA[Line2 + j + 1], imgA[Line3 + j + 1] );
    273             ConvY = CONV( imgA[Line3 + j - 1], imgA[Line3 + j], imgA[Line3 + j + 1] );
    274 
    275             GradY = (ConvY - MemY[memYline][j]) * 0.125f;
    276             GradX = (ConvX - MemX[(j - 1) & 1][ConvLine]) * 0.125f;
    277 
    278             MemY[memYline][j] = ConvY;
    279             MemX[(j - 1) & 1][ConvLine] = ConvX;
    280 
    281             GradT = (float) (imgB[Line2 + j] - imgA[Line2 + j]);
    282 
    283             II[address].xx = GradX * GradX;
    284             II[address].xy = GradX * GradY;
    285             II[address].yy = GradY * GradY;
    286             II[address].xt = GradX * GradT;
    287             II[address].yt = GradY * GradT;
    288 
    289             II[address].alpha = 1 / (Ilambda + II[address].xx + II[address].yy);
    290             address++;
    291         }
    292         /* Process last pixel of line */
    293         ConvX = CONV( imgA[Line1 + imageWidth - 1], imgA[Line2 + imageWidth - 1],
    294                       imgA[Line3 + imageWidth - 1] );
    295 
    296         ConvY = CONV( imgA[Line3 + imageWidth - 2], imgA[Line3 + imageWidth - 1],
    297                       imgA[Line3 + imageWidth - 1] );
    298 
    299 
    300         GradY = (ConvY - MemY[memYline][imageWidth - 1]) * 0.125f;
    301         GradX = (ConvX - MemX[(imageWidth - 2) & 1][ConvLine]) * 0.125f;
    302 
    303         MemY[memYline][imageWidth - 1] = ConvY;
    304 
    305         GradT = (float) (imgB[Line2 + imageWidth - 1] - imgA[Line2 + imageWidth - 1]);
    306 
    307         II[address].xx = GradX * GradX;
    308         II[address].xy = GradX * GradY;
    309         II[address].yy = GradY * GradY;
    310         II[address].xt = GradX * GradT;
    311         II[address].yt = GradY * GradT;
    312 
    313         II[address].alpha = 1 / (Ilambda + II[address].xx + II[address].yy);
    314         address++;
    315 
    316         ConvLine++;
    317     }
    318 /****************************************************************************************\
    319 *      Prepare initial approximation                                                     *
    320 \****************************************************************************************/
    321     if( !usePrevious )
    322     {
    323         float *vx = velocityX;
    324         float *vy = velocityY;
    325 
    326         for( i = 0; i < imageHeight; i++ )
    327         {
    328             memset( vx, 0, imageWidth * sizeof( float ));
    329             memset( vy, 0, imageWidth * sizeof( float ));
    330 
    331             vx += velStep;
    332             vy += velStep;
    333         }
    334     }
    335 /****************************************************************************************\
    336 *      Perform iterations                                                                *
    337 \****************************************************************************************/
    338     iter = 0;
    339     Stop = 0;
    340     LastLine = velStep * (imageHeight - 1);
    341     while( !Stop )
    342     {
    343         float Eps = 0;
    344         address = 0;
    345 
    346         iter++;
    347 /****************************************************************************************\
    348 *     begin scan velocity and update it                                                  *
    349 \****************************************************************************************/
    350         Line2 = -velStep;
    351         for( i = 0; i < imageHeight; i++ )
    352         {
    353             /* Here average velocity */
    354 
    355             float averageX;
    356             float averageY;
    357             float tmp;
    358 
    359             Line2 += velStep;
    360             Line1 = Line2 - ((Line2 == 0) ? 0 : velStep);
    361             Line3 = Line2 + ((Line2 == LastLine) ? 0 : velStep);
    362             /* Process first pixel */
    363             averageX = (velocityX[Line2] +
    364                         velocityX[Line2 + 1] + velocityX[Line1] + velocityX[Line3]) / 4;
    365 
    366             averageY = (velocityY[Line2] +
    367                         velocityY[Line2 + 1] + velocityY[Line1] + velocityY[Line3]) / 4;
    368 
    369             VelBufX[i & 1][0] = averageX -
    370                 (II[address].xx * averageX +
    371                  II[address].xy * averageY + II[address].xt) * II[address].alpha;
    372 
    373             VelBufY[i & 1][0] = averageY -
    374                 (II[address].xy * averageX +
    375                  II[address].yy * averageY + II[address].yt) * II[address].alpha;
    376 
    377             /* update Epsilon */
    378             if( criteria.type & CV_TERMCRIT_EPS )
    379             {
    380                 tmp = (float)fabs(velocityX[Line2] - VelBufX[i & 1][0]);
    381                 Eps = MAX( tmp, Eps );
    382                 tmp = (float)fabs(velocityY[Line2] - VelBufY[i & 1][0]);
    383                 Eps = MAX( tmp, Eps );
    384             }
    385             address++;
    386             /* Process middle of line */
    387             for( j = 1; j < imageWidth - 1; j++ )
    388             {
    389                 averageX = (velocityX[Line2 + j - 1] +
    390                             velocityX[Line2 + j + 1] +
    391                             velocityX[Line1 + j] + velocityX[Line3 + j]) / 4;
    392                 averageY = (velocityY[Line2 + j - 1] +
    393                             velocityY[Line2 + j + 1] +
    394                             velocityY[Line1 + j] + velocityY[Line3 + j]) / 4;
    395 
    396                 VelBufX[i & 1][j] = averageX -
    397                     (II[address].xx * averageX +
    398                      II[address].xy * averageY + II[address].xt) * II[address].alpha;
    399 
    400                 VelBufY[i & 1][j] = averageY -
    401                     (II[address].xy * averageX +
    402                      II[address].yy * averageY + II[address].yt) * II[address].alpha;
    403                 /* update Epsilon */
    404                 if( criteria.type & CV_TERMCRIT_EPS )
    405                 {
    406                     tmp = (float)fabs(velocityX[Line2 + j] - VelBufX[i & 1][j]);
    407                     Eps = MAX( tmp, Eps );
    408                     tmp = (float)fabs(velocityY[Line2 + j] - VelBufY[i & 1][j]);
    409                     Eps = MAX( tmp, Eps );
    410                 }
    411                 address++;
    412             }
    413             /* Process last pixel of line */
    414             averageX = (velocityX[Line2 + imageWidth - 2] +
    415                         velocityX[Line2 + imageWidth - 1] +
    416                         velocityX[Line1 + imageWidth - 1] +
    417                         velocityX[Line3 + imageWidth - 1]) / 4;
    418 
    419             averageY = (velocityY[Line2 + imageWidth - 2] +
    420                         velocityY[Line2 + imageWidth - 1] +
    421                         velocityY[Line1 + imageWidth - 1] +
    422                         velocityY[Line3 + imageWidth - 1]) / 4;
    423 
    424 
    425             VelBufX[i & 1][imageWidth - 1] = averageX -
    426                 (II[address].xx * averageX +
    427                  II[address].xy * averageY + II[address].xt) * II[address].alpha;
    428 
    429             VelBufY[i & 1][imageWidth - 1] = averageY -
    430                 (II[address].xy * averageX +
    431                  II[address].yy * averageY + II[address].yt) * II[address].alpha;
    432 
    433             /* update Epsilon */
    434             if( criteria.type & CV_TERMCRIT_EPS )
    435             {
    436                 tmp = (float)fabs(velocityX[Line2 + imageWidth - 1] -
    437                                   VelBufX[i & 1][imageWidth - 1]);
    438                 Eps = MAX( tmp, Eps );
    439                 tmp = (float)fabs(velocityY[Line2 + imageWidth - 1] -
    440                                   VelBufY[i & 1][imageWidth - 1]);
    441                 Eps = MAX( tmp, Eps );
    442             }
    443             address++;
    444 
    445             /* store new velocity from old buffer to velocity frame */
    446             if( i > 0 )
    447             {
    448                 memcpy( &velocityX[Line1], VelBufX[(i - 1) & 1], imageWidth * sizeof( float ));
    449                 memcpy( &velocityY[Line1], VelBufY[(i - 1) & 1], imageWidth * sizeof( float ));
    450             }
    451         }                       /*for */
    452         /* store new velocity from old buffer to velocity frame */
    453         memcpy( &velocityX[imageWidth * (imageHeight - 1)],
    454                 VelBufX[(imageHeight - 1) & 1], imageWidth * sizeof( float ));
    455 
    456         memcpy( &velocityY[imageWidth * (imageHeight - 1)],
    457                 VelBufY[(imageHeight - 1) & 1], imageWidth * sizeof( float ));
    458 
    459         if( (criteria.type & CV_TERMCRIT_ITER) && (iter == criteria.max_iter) )
    460             Stop = 1;
    461         if( (criteria.type & CV_TERMCRIT_EPS) && (Eps < criteria.epsilon) )
    462             Stop = 1;
    463     }
    464     /* Free memory */
    465     for( k = 0; k < 2; k++ )
    466     {
    467         cvFree( &MemX[k] );
    468         cvFree( &MemY[k] );
    469         cvFree( &VelBufX[k] );
    470         cvFree( &VelBufY[k] );
    471     }
    472     cvFree( &II );
    473 
    474     return CV_OK;
    475 } /*icvCalcOpticalFlowHS_8u32fR*/
    476 
    477 
    478 /*F///////////////////////////////////////////////////////////////////////////////////////
    479 //    Name:    cvCalcOpticalFlowHS
    480 //    Purpose: Optical flow implementation
    481 //    Context:
    482 //    Parameters:
    483 //             srcA, srcB - source image
    484 //             velx, vely - destination image
    485 //    Returns:
    486 //
    487 //    Notes:
    488 //F*/
    489 CV_IMPL void
    490 cvCalcOpticalFlowHS( const void* srcarrA, const void* srcarrB, int usePrevious,
    491                      void* velarrx, void* velarry,
    492                      double lambda, CvTermCriteria criteria )
    493 {
    494     CV_FUNCNAME( "cvCalcOpticalFlowHS" );
    495 
    496     __BEGIN__;
    497 
    498     CvMat stubA, *srcA = (CvMat*)srcarrA;
    499     CvMat stubB, *srcB = (CvMat*)srcarrB;
    500     CvMat stubx, *velx = (CvMat*)velarrx;
    501     CvMat stuby, *vely = (CvMat*)velarry;
    502 
    503     CV_CALL( srcA = cvGetMat( srcA, &stubA ));
    504     CV_CALL( srcB = cvGetMat( srcB, &stubB ));
    505 
    506     CV_CALL( velx = cvGetMat( velx, &stubx ));
    507     CV_CALL( vely = cvGetMat( vely, &stuby ));
    508 
    509     if( !CV_ARE_TYPES_EQ( srcA, srcB ))
    510         CV_ERROR( CV_StsUnmatchedFormats, "Source images have different formats" );
    511 
    512     if( !CV_ARE_TYPES_EQ( velx, vely ))
    513         CV_ERROR( CV_StsUnmatchedFormats, "Destination images have different formats" );
    514 
    515     if( !CV_ARE_SIZES_EQ( srcA, srcB ) ||
    516         !CV_ARE_SIZES_EQ( velx, vely ) ||
    517         !CV_ARE_SIZES_EQ( srcA, velx ))
    518         CV_ERROR( CV_StsUnmatchedSizes, "" );
    519 
    520     if( CV_MAT_TYPE( srcA->type ) != CV_8UC1 ||
    521         CV_MAT_TYPE( velx->type ) != CV_32FC1 )
    522         CV_ERROR( CV_StsUnsupportedFormat, "Source images must have 8uC1 type and "
    523                                            "destination images must have 32fC1 type" );
    524 
    525     if( srcA->step != srcB->step || velx->step != vely->step )
    526         CV_ERROR( CV_BadStep, "source and destination images have different step" );
    527 
    528     IPPI_CALL( icvCalcOpticalFlowHS_8u32fR( (uchar*)srcA->data.ptr, (uchar*)srcB->data.ptr,
    529                                             srcA->step, cvGetMatSize( srcA ), usePrevious,
    530                                             velx->data.fl, vely->data.fl,
    531                                             velx->step, (float)lambda, criteria ));
    532     __END__;
    533 }
    534 
    535 /* End of file. */
    536