├── 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 | H a i y a n g H A I Y A N G - P C
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------