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