├── optical flow ├── optical flow.opensdf ├── example.cpp ├── OpticalFlow.h ├── iOpticalFlow.h ├── OpticalFlow.cpp ├── optical flow.suo ├── Data │ ├── yos_img_08.jpg │ └── yos_img_09.jpg ├── optical flow.vcxproj.user ├── debug.h ├── optical flow.sln ├── debug.cpp ├── ProfTimer.h ├── VarFlow.h ├── optical flow.vcxproj └── VarFlow.cpp ├── .gitattributes └── .gitignore /optical flow/optical flow.opensdf: -------------------------------------------------------------------------------- 1 | HaiyangHAIYANG-PC -------------------------------------------------------------------------------- /optical flow/example.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Algorithm2D/OpticalFlow/HEAD/optical flow/example.cpp -------------------------------------------------------------------------------- /optical flow/OpticalFlow.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Algorithm2D/OpticalFlow/HEAD/optical flow/OpticalFlow.h -------------------------------------------------------------------------------- /optical flow/iOpticalFlow.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Algorithm2D/OpticalFlow/HEAD/optical flow/iOpticalFlow.h -------------------------------------------------------------------------------- /optical flow/OpticalFlow.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Algorithm2D/OpticalFlow/HEAD/optical flow/OpticalFlow.cpp -------------------------------------------------------------------------------- /optical flow/optical flow.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Algorithm2D/OpticalFlow/HEAD/optical flow/optical flow.suo -------------------------------------------------------------------------------- /optical flow/Data/yos_img_08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Algorithm2D/OpticalFlow/HEAD/optical flow/Data/yos_img_08.jpg -------------------------------------------------------------------------------- /optical flow/Data/yos_img_09.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Algorithm2D/OpticalFlow/HEAD/optical flow/Data/yos_img_09.jpg -------------------------------------------------------------------------------- /optical flow/optical flow.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /optical flow/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef _DEBUG_H_ 2 | #define _DEBUG_H_ 3 | #include 4 | #include 5 | using namespace cv; 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | 12 | void _print_mat(Mat& m,string f_name); 13 | inline void print_mat(IplImage* m,string f_name){ 14 | Mat _m(m); 15 | _print_mat(_m,f_name); 16 | } 17 | 18 | inline void print_mat(Mat& m,string f_name) 19 | { 20 | _print_mat(m,f_name); 21 | } 22 | #endif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /optical flow/optical flow.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "optical flow", "optical flow.vcxproj", "{EB5651E2-0849-482A-BB05-582729A06996}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {EB5651E2-0849-482A-BB05-582729A06996}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {EB5651E2-0849-482A-BB05-582729A06996}.Debug|Win32.Build.0 = Debug|Win32 14 | {EB5651E2-0849-482A-BB05-582729A06996}.Release|Win32.ActiveCfg = Release|Win32 15 | {EB5651E2-0849-482A-BB05-582729A06996}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /optical flow/debug.cpp: -------------------------------------------------------------------------------- 1 | #include"debug.h" 2 | 3 | void _print_mat(Mat& m,string f_name) 4 | { 5 | ofstream f(f_name.c_str ()); 6 | cv::Size size=m.size (); 7 | int type=m.type (); 8 | int depth=m.depth (); 9 | int channel=m.channels (); 10 | /*f<<"size: ("< (y); 34 | for(x=0;x 8 | #include 9 | 10 | class ProfTimer { 11 | 12 | public: 13 | 14 | ProfTimer(){ 15 | }; 16 | 17 | void Start(void) { 18 | QueryPerformanceCounter(&mTimeStart); 19 | }; 20 | 21 | void Stop(void) { 22 | QueryPerformanceCounter(&mTimeStop); 23 | }; 24 | 25 | float GetDurationInSecs(void) 26 | { 27 | LARGE_INTEGER freq; 28 | QueryPerformanceFrequency(&freq); 29 | float duration = (float)(mTimeStop.QuadPart-mTimeStart.QuadPart)/(float)freq.QuadPart; 30 | return duration; 31 | } 32 | 33 | private: 34 | 35 | LARGE_INTEGER mTimeStart; 36 | LARGE_INTEGER mTimeStop; 37 | 38 | }; 39 | 40 | #else 41 | 42 | #include 43 | 44 | class ProfTimer { 45 | 46 | public: 47 | 48 | ProfTimer(){ 49 | }; 50 | 51 | void Start(void) { 52 | gettimeofday(&timeStart, NULL); 53 | }; 54 | 55 | void Stop(void) { 56 | gettimeofday(&timeStop, NULL); 57 | }; 58 | 59 | float GetDurationInSecs(void) 60 | { 61 | float dur = (timeStop.tv_sec - timeStart.tv_sec) + (timeStop.tv_usec - timeStart.tv_usec)/1000000.0; 62 | 63 | return dur; 64 | }; 65 | 66 | private: 67 | 68 | timeval timeStart; 69 | timeval timeStop; 70 | 71 | }; 72 | 73 | #endif 74 | 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /optical flow/VarFlow.h: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------ 2 | // Released under the BDS License 3 | // 4 | // Located at http://sourceforge.net/projects/varflow 5 | // 6 | //------------------------------------------------------------------ 7 | 8 | #ifndef VARFLOW_H 9 | #define VARFLOW_H 10 | 11 | #include 12 | #include 13 | 14 | /** 15 | * @brief Calculates dense optical flow using a variational method. 16 | * 17 | * The VarFlow class implements the method described in "Real-Time Optic Flow Computation with Variational Methods" by 18 | * Bruhn et al. (Lecture Notes in Computer Science, Volume 2756/2003, pp 222-229). It uses a recursive multigrid algorithm to 19 | * minimize the energy functional, leading to increased performance. This implementation uses an uncoupled Gauss-Seidel algorithm 20 | * and the temporal derivative of an image is calculated using a simple difference instead of a two point stencil as described 21 | * in the original paper. 22 | * 23 | * Date: April 2009 24 | * 25 | * @author Adam Harmat 26 | */ 27 | 28 | #define M_PI (3.14159265) 29 | class VarFlow{ 30 | 31 | public: 32 | 33 | VarFlow(int width_in, int height_in, int max_level_in, int start_level_in, int n1_in, int n2_in, 34 | float rho_in, float alpha_in, float sigma_in); 35 | ~VarFlow(); 36 | int CalcFlow(IplImage* imgA, IplImage* imgB, IplImage* imgU, IplImage* imgV, bool saved_data); 37 | 38 | private: 39 | 40 | void gauss_seidel_recursive(int current_level, int max_level, int first_level, float h, IplImage** J13_array, IplImage** J23_array); 41 | void gauss_seidel_iteration(int current_level, float h, int num_iter, IplImage** J13_array, IplImage** J23_array); 42 | float gauss_seidel_step(IplImage* u, int x, int y, float h, float J11, float J12, float J13, float vi); 43 | float residual_part_step(IplImage* u, int x, int y, float h, float J11, float J12, float vi); 44 | void calculate_residual(int current_level, float h, IplImage** J13_array, IplImage** J23_array); 45 | 46 | 47 | float mask_x[5]; 48 | float mask_y[5]; 49 | CvMat fx_mask; 50 | CvMat fy_mask; 51 | 52 | IplImage* imgAsmall; 53 | IplImage* imgBsmall; 54 | 55 | IplImage* imgAfloat; 56 | IplImage* imgBfloat; 57 | 58 | IplImage* imgAfx; 59 | IplImage* imgAfy; 60 | IplImage* imgAft; 61 | 62 | IplImage** imgAfxfx_array; 63 | IplImage** imgAfxfy_array; 64 | IplImage** imgAfxft_array; 65 | IplImage** imgAfyfy_array; 66 | IplImage** imgAfyft_array; 67 | 68 | IplImage** imgU_array; 69 | IplImage** imgV_array; 70 | IplImage** imgU_res_err_array; 71 | IplImage** imgV_res_err_array; 72 | 73 | int initialized; 74 | 75 | int max_level; 76 | int start_level; 77 | 78 | int n1; 79 | int n2; 80 | 81 | float rho; 82 | float alpha; 83 | float sigma; 84 | }; 85 | 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /optical flow/optical flow.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {EB5651E2-0849-482A-BB05-582729A06996} 15 | opticalflow 16 | Win32Proj 17 | 18 | 19 | 20 | Application 21 | Unicode 22 | true 23 | 24 | 25 | Application 26 | Unicode 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | <_ProjectFileVersion>10.0.30319.1 40 | $(SolutionDir)$(Configuration)\ 41 | $(Configuration)\ 42 | true 43 | $(SolutionDir)$(Configuration)\ 44 | $(Configuration)\ 45 | false 46 | AllRules.ruleset 47 | 48 | 49 | AllRules.ruleset 50 | 51 | 52 | 53 | 54 | 55 | Disabled 56 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 57 | true 58 | EnableFastChecks 59 | MultiThreadedDebugDLL 60 | 61 | 62 | Level3 63 | EditAndContinue 64 | 65 | 66 | opencv_imgproc220d.lib;opencv_highgui220d.lib;opencv_core220d.lib;%(AdditionalDependencies) 67 | true 68 | Console 69 | MachineX86 70 | 71 | 72 | 73 | 74 | MaxSpeed 75 | true 76 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 77 | MultiThreadedDLL 78 | true 79 | 80 | 81 | Level3 82 | ProgramDatabase 83 | E:\Library\opencv249\build\include;E:\Library\opencv249\build\include\opencv;E:\Library\opencv249\build\include\opencv2;%(AdditionalIncludeDirectories) 84 | 85 | 86 | opencv_imgproc249.lib;opencv_highgui249.lib;opencv_core249.lib;%(AdditionalDependencies) 87 | true 88 | Console 89 | true 90 | true 91 | MachineX86 92 | E:\Library\opencv249\build\x86\vc10\lib;%(AdditionalLibraryDirectories) 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /optical flow/VarFlow.cpp: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------ 2 | // Released under the BDS License 3 | // 4 | // Located at http://sourceforge.net/projects/varflow 5 | // 6 | //------------------------------------------------------------------ 7 | 8 | #include "VarFlow.h" 9 | #include 10 | 11 | using namespace std; 12 | /** 13 | Initializes all variables that don't need to get updated for each flow calculation. 14 | Note: Not much error checking is done, all inputs should be > 0 15 | 16 | @param[in] width_in Width of images that will be used for calculation 17 | @param[in] height_in Height of images that will be used for calculation 18 | @param[in] max_level_in The maximum level that will be reached in the multigrid algorithm, higher maximum level = coarser level reached 19 | @param[in] start_level_in The starting level used as the base in the multigrid algorithm, higher start level = coarser starting level 20 | @param[in] n1_in Number of pre-smoothing steps in the multigrid cycle 21 | @param[in] n2_in Number of post-smoothing steps in the multigrid cycle 22 | @param[in] rho_in Gaussian smoothing parameter 23 | @param[in] alpha_in Regularisation parameter in the energy functional 24 | @param[in] sigma_in Gaussian smoothing parameter 25 | 26 | */ 27 | VarFlow::VarFlow(int width_in, int height_in, int max_level_in, int start_level_in, int n1_in, int n2_in, 28 | float rho_in, float alpha_in, float sigma_in){ 29 | 30 | max_level = max_level_in; 31 | start_level = start_level_in; 32 | 33 | if(max_level < start_level) 34 | { 35 | max_level = start_level; 36 | cout<<"Warning: input max_level < start_level, correcting (new value = "< -1){ 245 | 246 | temp_u += *((float*)(u->imageData + start_y*u->widthStep) + x); 247 | 248 | N_num++; 249 | 250 | } 251 | 252 | // Sum bottom neighbor 253 | if(end_y < u->height){ 254 | 255 | temp_u += *((float*)(u->imageData + end_y*u->widthStep) + x); 256 | 257 | N_num++; 258 | 259 | } 260 | 261 | // Sum left neighbor 262 | if(start_x > -1){ 263 | 264 | temp_u += *((float*)(u->imageData + y*u->widthStep) + start_x); 265 | 266 | N_num++; 267 | 268 | } 269 | 270 | // Sum right neighbor 271 | if(end_x < u->width){ 272 | 273 | temp_u += *((float*)(u->imageData + y*u->widthStep) + end_x); 274 | 275 | N_num++; 276 | 277 | } 278 | 279 | temp_u = temp_u - (h*h/alpha)*(J12*vi + J13); 280 | temp_u = temp_u / (N_num + (h*h/alpha)*J11); 281 | 282 | 283 | return temp_u; 284 | 285 | } 286 | 287 | /** 288 | Uses the Gauss-Seidel method to calculate the horizontal and vertical flow fields at a certain level in the multigrid 289 | process. 290 | 291 | @param[in] current_level The current level of the multigrid algorithm (higher level = coarser) 292 | @param[in] h Current pixel grid spacing 293 | @param[in] num_iter Number of times to iterate at the current level 294 | @param[in] J13_array Array of images representing the (1,3) component of the structure tensor 295 | @param[in] J23_array Array of images representing the (2,3) component of the structure tensor 296 | 297 | */ 298 | void VarFlow::gauss_seidel_iteration(int current_level, float h, int num_iter, IplImage** J13_array, IplImage** J23_array){ 299 | 300 | 301 | IplImage* imgU = imgU_array[current_level]; 302 | IplImage* imgV = imgV_array[current_level]; 303 | IplImage* imgAfxfx = imgAfxfx_array[current_level]; 304 | IplImage* imgAfxfy = imgAfxfy_array[current_level]; 305 | IplImage* imgAfxft = J13_array[current_level]; 306 | IplImage* imgAfyfy = imgAfyfy_array[current_level]; 307 | IplImage* imgAfyft = J23_array[current_level]; 308 | 309 | 310 | int i, k; 311 | int x; 312 | int y; 313 | float *u_ptr, *v_ptr, *fxfx_ptr, *fxfy_ptr, *fxft_ptr, *fyfy_ptr, *fyft_ptr; 314 | 315 | int max_i = imgU->height * imgU->width; 316 | 317 | u_ptr = (float*)(imgU->imageData); 318 | v_ptr = (float*)(imgV->imageData); 319 | 320 | fxfx_ptr = (float*)(imgAfxfx->imageData); 321 | fxfy_ptr = (float*)(imgAfxfy->imageData); 322 | fxft_ptr = (float*)(imgAfxft->imageData); 323 | fyfy_ptr = (float*)(imgAfyfy->imageData); 324 | fyft_ptr = (float*)(imgAfyft->imageData); 325 | 326 | for(k = 0; k < num_iter; k++){ 327 | 328 | x = 0; 329 | y = 0; 330 | 331 | for(i = 0; i < max_i; i++){ 332 | 333 | // Update flow fields 334 | u_ptr[i] = gauss_seidel_step(imgU, x, y, h, fxfx_ptr[i], fxfy_ptr[i], fxft_ptr[i], v_ptr[i]); 335 | v_ptr[i] = gauss_seidel_step(imgV, x, y, h, fyfy_ptr[i], fxfy_ptr[i], fyft_ptr[i], u_ptr[i]); 336 | 337 | x++; 338 | if(x == imgU->width){ 339 | x = 0; 340 | y++; 341 | } 342 | 343 | 344 | } // End for loop, image traversal 345 | 346 | } // End for loop, number of iterations 347 | 348 | } 349 | 350 | 351 | /** 352 | Calculates part of the value of a residual field at a single pixel 353 | 354 | Note that this function was written based on the calculation for the horizontal (u) residual field, so the remarks for 355 | gauss_seidel_step(...) apply here as well. 356 | 357 | Also note that this function doesn't calculate the "residual" field exactly, rather it calcualtes A^h * x_tilde ^ h from 358 | equation 10 of the paper by Bruhn et al. The final residual field is calculated by calculate_residual(...) which implements 359 | equation 10 fully. 360 | 361 | @param[in] u Flow field component currently being operated on (horizontal or vertical) 362 | @param[in] x X coordinate of pixel being calculated 363 | @param[in] y Y coordinate of pixel being calculated 364 | @param[in] h Current pixel grid size 365 | @param[in] J11 The (1,1) component of the current structure tensor 366 | @param[in] J12 The (1,2) component of the current structure tensor 367 | @param[in] vi The value of the opposite flow field at the current pixel 368 | 369 | @return Part of the residual field at the current coordinates 370 | 371 | */ 372 | 373 | float VarFlow::residual_part_step(IplImage* u, int x, int y, float h, float J11, float J12, float vi){ 374 | 375 | int start_y, end_y, start_x, end_x; 376 | 377 | start_y = y - 1; 378 | end_y = y + 1; 379 | start_x = x - 1; 380 | end_x = x+1; 381 | 382 | float ih2 = 1 / (h*h); 383 | 384 | float temp_res = 0; 385 | int N_num = 0; 386 | float curr_u = *((float*)(u->imageData + y*u->widthStep) + x); 387 | 388 | // Sum top neighbor 389 | 390 | if(start_y > -1){ 391 | 392 | temp_res += *((float*)(u->imageData + start_y*u->widthStep) + x); 393 | N_num++; 394 | 395 | } 396 | 397 | if(end_y < u->height){ // Sum bottom neighbor 398 | 399 | temp_res += *((float*)(u->imageData + end_y*u->widthStep) + x); 400 | N_num++; 401 | 402 | } 403 | 404 | // Sum left neighbor 405 | 406 | if(start_x > -1){ 407 | 408 | temp_res += *((float*)(u->imageData + y*u->widthStep) + start_x); 409 | N_num++; 410 | 411 | } 412 | 413 | // Sum right neighbor 414 | 415 | if(end_x < u->width){ 416 | 417 | temp_res += *((float*)(u->imageData + y*u->widthStep) + end_x); 418 | N_num++; 419 | 420 | } 421 | 422 | temp_res = N_num*curr_u - temp_res; 423 | 424 | temp_res *= ih2; 425 | 426 | temp_res -= (1/alpha)*(J11*curr_u + J12*vi); 427 | 428 | return temp_res; 429 | } 430 | 431 | /** 432 | Calculates the full residual of the current flow field based on equation 10 in Bruhn et al. 433 | 434 | @param[in] current_level The current level of the multigrid algorithm (higher level = coarser) 435 | @param[in] h Current pixel grid spacing 436 | @param[in] J13_array Array of images representing the (1,3) component of the structure tensor 437 | @param[in] J23_array Array of images representing the (2,3) component of the structure tensor 438 | 439 | */ 440 | 441 | void VarFlow::calculate_residual(int current_level, float h, IplImage** J13_array, IplImage** J23_array){ 442 | 443 | 444 | IplImage* imgU = imgU_array[current_level]; 445 | IplImage* imgV = imgV_array[current_level]; 446 | IplImage* imgAfxfx = imgAfxfx_array[current_level]; 447 | IplImage* imgAfxfy = imgAfxfy_array[current_level]; 448 | IplImage* imgAfxft = J13_array[current_level]; 449 | IplImage* imgAfyfy = imgAfyfy_array[current_level]; 450 | IplImage* imgAfyft = J23_array[current_level]; 451 | IplImage* imgU_res_err = imgU_res_err_array[current_level]; 452 | IplImage* imgV_res_err = imgV_res_err_array[current_level]; 453 | 454 | int i; 455 | float *u_ptr, *v_ptr, *fxfx_ptr, *fxfy_ptr, *fyfy_ptr, *u_res_err_ptr, *v_res_err_ptr; 456 | 457 | int max_i = imgU->height * imgU->width; 458 | int x, y; 459 | 460 | u_res_err_ptr = (float*)(imgU_res_err->imageData); 461 | v_res_err_ptr = (float*)(imgV_res_err->imageData); 462 | 463 | u_ptr = (float*)(imgU->imageData); 464 | v_ptr = (float*)(imgV->imageData); 465 | 466 | fxfx_ptr = (float*)(imgAfxfx->imageData); 467 | fxfy_ptr = (float*)(imgAfxfy->imageData); 468 | fyfy_ptr = (float*)(imgAfyfy->imageData); 469 | 470 | x = 0; 471 | y = 0; 472 | 473 | for(i = 0; i < max_i; i++){ 474 | 475 | // Get A^h * x_tilde^h (equation 10) 476 | u_res_err_ptr[i] = residual_part_step(imgU, x, y, h, fxfx_ptr[i], fxfy_ptr[i], v_ptr[i] ); 477 | v_res_err_ptr[i] = residual_part_step(imgV, x, y, h, fyfy_ptr[i], fxfy_ptr[i], u_ptr[i] ); 478 | 479 | x++; 480 | if(x == imgU->width){ 481 | x = 0; 482 | y++; 483 | } 484 | 485 | } 486 | 487 | // Get full residual 488 | cvAddWeighted( imgAfxft, (1/alpha), imgU_res_err, -1, 0, imgU_res_err ); 489 | cvAddWeighted( imgAfyft, (1/alpha), imgV_res_err, -1, 0, imgV_res_err ); 490 | } 491 | 492 | 493 | /** 494 | This recursive function implements two V cycles of the Gauss-Seidel algorithm to calculate the flow field at a given level. 495 | One V cycle calculates the flow field, then the residual, applying a restriction operator to the residual, which then 496 | becomes the input to the next stage of the recursive algorithm. Once the maximum level is reached, the function propagates 497 | back up to the start, comleting one V cycle. The process is then repeated for the second V cycle. 498 | 499 | @param[in] current_level The current level of the multigrid algorithm (higher level = coarser) 500 | @param[in] max_level The maximum level the algorithm will reach 501 | @param[in] first_level The starting level 502 | @param[in] h Current pixel grid spacing 503 | @param[in] J13_array Array of images representing the (1,3) component of the structure tensor 504 | @param[in] J23_array Array of images representing the (2,3) component of the structure tensor 505 | 506 | */ 507 | 508 | void VarFlow::gauss_seidel_recursive(int current_level, int max_level, int first_level, float h, 509 | IplImage** J13_array, IplImage** J23_array){ 510 | 511 | if(current_level == max_level){ 512 | 513 | // Iterate normally n1 times and that's it 514 | gauss_seidel_iteration(current_level, h, n1, J13_array, J23_array); 515 | 516 | } 517 | 518 | else{ 519 | 520 | //---------------------------- Start 1st V cycle ------------------------------------- 521 | 522 | // Iterate n1 times 523 | gauss_seidel_iteration(current_level, h, n1, J13_array, J23_array); 524 | 525 | // Calculate residual 526 | calculate_residual(current_level, h, J13_array, J23_array); 527 | 528 | // Apply restriction operator to residual 529 | cvResize(imgU_res_err_array[current_level], imgU_res_err_array[current_level+1], CV_INTER_LINEAR); 530 | cvResize(imgV_res_err_array[current_level], imgV_res_err_array[current_level+1], CV_INTER_LINEAR); 531 | 532 | // Initialize new u and v images to zero 533 | cvZero(imgU_array[current_level+1]); 534 | cvZero(imgV_array[current_level+1]); 535 | 536 | // Pass residual down recursively (Important: switch J13 and J23 with imgU_res_err and imgV_res_err, increase h!!) 537 | gauss_seidel_recursive(current_level+1, max_level, first_level, 2*h, imgU_res_err_array, imgV_res_err_array); 538 | 539 | // Prolong solution to get error at current level 540 | cvResize(imgU_array[current_level+1], imgU_res_err_array[current_level], CV_INTER_LINEAR); 541 | cvResize(imgV_array[current_level+1], imgV_res_err_array[current_level], CV_INTER_LINEAR); 542 | 543 | // Correct original solution with error 544 | cvAdd(imgU_array[current_level], imgU_res_err_array[current_level], imgU_array[current_level], NULL); 545 | cvAdd(imgV_array[current_level], imgV_res_err_array[current_level], imgV_array[current_level], NULL); 546 | 547 | // Iterate n1+n2 times to smooth new solution 548 | gauss_seidel_iteration(current_level, h, n1+n2, J13_array, J23_array); 549 | 550 | 551 | //---------------------------- End 1st V cycle, Start 2nd V cycle ------------------------------------- 552 | 553 | // Calculate residual again 554 | calculate_residual(current_level,h, J13_array, J23_array); 555 | 556 | // Apply restriction operator to residual 557 | cvResize(imgU_res_err_array[current_level], imgU_res_err_array[current_level+1], CV_INTER_LINEAR); 558 | cvResize(imgV_res_err_array[current_level], imgV_res_err_array[current_level+1], CV_INTER_LINEAR); 559 | 560 | // Initialize new u and v images to zero 561 | cvZero(imgU_array[current_level+1]); 562 | cvZero(imgV_array[current_level+1]); 563 | 564 | 565 | // Pass residual down recursively (Important: switch J13 and J23 with imgU_res_err and imgV_res_err, increase h!!) 566 | gauss_seidel_recursive(current_level+1, max_level, first_level, 2*h, imgU_res_err_array, imgV_res_err_array); 567 | 568 | // Prolong solution to get error at current level 569 | cvResize(imgU_array[current_level+1], imgU_res_err_array[current_level], CV_INTER_LINEAR); 570 | cvResize(imgV_array[current_level+1], imgV_res_err_array[current_level], CV_INTER_LINEAR); 571 | 572 | // Correct original solution with error 573 | cvAdd(imgU_array[current_level], imgU_res_err_array[current_level], imgU_array[current_level], NULL); 574 | cvAdd(imgV_array[current_level], imgV_res_err_array[current_level], imgV_array[current_level], NULL); 575 | 576 | // Iterate n2 times to smooth new solution 577 | gauss_seidel_iteration(current_level, h, n2, J13_array, J23_array); 578 | 579 | 580 | //---------------------------- End 2nd V cycle ------------------------------------- 581 | 582 | } 583 | 584 | } 585 | 586 | 587 | 588 | /** 589 | Calculates the optical flow between two images. 590 | 591 | @param[in] imgA First input image 592 | @param[in] imgB Second input image, the flow is calculated from imgA to imgB 593 | @param[out] imgU Horizontal flow field 594 | @param[out] imgV Vertical flow field 595 | @param[in] saved_data Flag indicates previous imgB is now imgA (ie subsequent frames), save some time in calculation 596 | 597 | @return Flag to indicate succesful completion 598 | 599 | */ 600 | 601 | void _cvConvertScale( const void* srcarr, void* dstarr, 602 | double scale, double shift ) 603 | { 604 | cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr); 605 | int types=src.type (); 606 | int typed1=dst.type (); 607 | CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() ); 608 | src.convertTo(dst, dst.type(), scale, shift); 609 | int typed2=dst.type (); 610 | } 611 | #define _cvConvert( src, dst ) _cvConvertScale( (src), (dst), 1, 0 ) 612 | int VarFlow::CalcFlow(IplImage* imgA, IplImage* imgB, IplImage* imgU, IplImage* imgV, bool saved_data = false){ 613 | 614 | if(!initialized) 615 | return 0; 616 | 617 | IplImage* swap_img; 618 | 619 | //Don't recalculate imgAfloat, just swap with imgBfloat 620 | if(saved_data){ 621 | 622 | CV_SWAP(imgAfloat, imgBfloat, swap_img); 623 | 624 | cvResize(imgB, imgBsmall, CV_INTER_LINEAR); 625 | cvConvert(imgBsmall, imgBfloat); // Calculate new imgBfloat 626 | cvSmooth(imgBfloat, imgBfloat, CV_GAUSSIAN, 0, 0, sigma, 0 ); 627 | 628 | } 629 | 630 | //Calculate imgAfloat as well as imgBfloat 631 | else{ 632 | 633 | cvResize(imgA, imgAsmall, CV_INTER_LINEAR); 634 | cvResize(imgB, imgBsmall, CV_INTER_LINEAR); 635 | 636 | _cvConvert(imgAsmall, imgAfloat); 637 | _cvConvert(imgBsmall, imgBfloat); 638 | 639 | cvSmooth(imgAfloat, imgAfloat, CV_GAUSSIAN, 0, 0, sigma, 0 ); 640 | cvSmooth(imgBfloat, imgBfloat, CV_GAUSSIAN, 0, 0, sigma, 0 ); 641 | 642 | } 643 | 644 | cvFilter2D(imgAfloat, imgAfx, &fx_mask, cvPoint(-1,-1)); // X spacial derivative 645 | cvFilter2D(imgAfloat, imgAfy, &fy_mask, cvPoint(-1,-1)); // Y spacial derivative 646 | 647 | cvSub(imgBfloat, imgAfloat, imgAft, NULL); // Temporal derivative 648 | 649 | cvMul(imgAfx,imgAfx,imgAfxfx_array[0], 1); 650 | cvMul(imgAfx,imgAfy,imgAfxfy_array[0], 1); 651 | cvMul(imgAfx,imgAft,imgAfxft_array[0], 1); 652 | cvMul(imgAfy,imgAfy,imgAfyfy_array[0], 1); 653 | cvMul(imgAfy,imgAft,imgAfyft_array[0], 1); 654 | 655 | cvSmooth(imgAfxfx_array[0], imgAfxfx_array[0], CV_GAUSSIAN, 0, 0, rho, 0 ); 656 | cvSmooth(imgAfxfy_array[0], imgAfxfy_array[0], CV_GAUSSIAN, 0, 0, rho, 0 ); 657 | cvSmooth(imgAfxft_array[0], imgAfxft_array[0], CV_GAUSSIAN, 0, 0, rho, 0 ); 658 | cvSmooth(imgAfyfy_array[0], imgAfyfy_array[0], CV_GAUSSIAN, 0, 0, rho, 0 ); 659 | cvSmooth(imgAfyft_array[0], imgAfyft_array[0], CV_GAUSSIAN, 0, 0, rho, 0 ); 660 | 661 | int i; 662 | 663 | //Fill all the levels of the multigrid algorithm with resized images 664 | for(i = 1; i < (max_level - start_level + 1); i++){ 665 | 666 | cvResize(imgAfxfx_array[i-1], imgAfxfx_array[i], CV_INTER_LINEAR); 667 | cvResize(imgAfxfy_array[i-1], imgAfxfy_array[i], CV_INTER_LINEAR); 668 | cvResize(imgAfxft_array[i-1], imgAfxft_array[i], CV_INTER_LINEAR); 669 | cvResize(imgAfyfy_array[i-1], imgAfyfy_array[i], CV_INTER_LINEAR); 670 | cvResize(imgAfyft_array[i-1], imgAfyft_array[i], CV_INTER_LINEAR); 671 | 672 | } 673 | 674 | int k = (max_level - start_level); 675 | 676 | while(1){ 677 | 678 | gauss_seidel_recursive(k, (max_level - start_level), k, powf(2.0,(float)(k)), imgAfxft_array, imgAfyft_array); 679 | 680 | 681 | if(k > 0){ 682 | 683 | // Transfer velocity from coarse to fine 684 | cvResize(imgU_array[k], imgU_array[k-1], CV_INTER_LINEAR); 685 | cvResize(imgV_array[k], imgV_array[k-1], CV_INTER_LINEAR); 686 | 687 | k--; 688 | 689 | } 690 | else 691 | break; 692 | 693 | 694 | } 695 | 696 | // Transfer to output image, resize if necessary 697 | cvResize(imgU_array[0], imgU, CV_INTER_LINEAR); 698 | cvResize(imgV_array[0], imgV, CV_INTER_LINEAR); 699 | 700 | // If started algorithm with smaller image than original, scale the flow field 701 | if(start_level > 0){ 702 | 703 | cvScale(imgU, imgU, powf(2.0, start_level)); 704 | cvScale(imgV, imgV, powf(2.0, start_level)); 705 | 706 | } 707 | 708 | return 1; 709 | } 710 | --------------------------------------------------------------------------------