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
45typedef 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}
54icvDerProductEx;
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*/
85static CvStatus CV_STDCALL
86icvCalcOpticalFlowHS_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*/
489CV_IMPL void
490cvCalcOpticalFlowHS( 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