55
66Jamie McClelland
77UCL
8+
9+ Changes has been done by:
10+ Zakaria Senousy
11+ ARC, UCL
812"""
913import matplotlib
1014matplotlib .use ('TkAgg' )
1115import matplotlib .pyplot as plt
1216
17+
1318import numpy as np
1419from skimage .transform import rescale , resize
1520from scipy .ndimage import gaussian_filter
16- from utils3 import dispImage , resampImageWithDefField , calcMSD , dispDefField
21+ from utils3 import dispImage , resampImageWithDefField , calcMSD , dispDefField , calcJacobian
1722
1823def demonsReg (source , target , sigma_elastic = 1 , sigma_fluid = 1 , num_lev = 3 , use_composition = False ,
19- use_target_grad = False , max_it = 1000 , check_MSD = True , disp_freq = 5 , disp_spacing = 2 ,
24+ use_target_grad = False , max_it = 1000 , check_MSD = True , disp_freq = 3 , disp_spacing = 2 ,
2025 scale_update_for_display = 10 , disp_method_df = 'grid' , disp_method_up = 'arrows' ):
2126 """
2227 SYNTAX:
@@ -64,7 +69,7 @@ def demonsReg(source, target, sigma_elastic=1, sigma_fluid=1, num_lev=3, use_com
6469 MSD will be evaluated at each iteration, and if there is no
6570 improvement since the previous iteration the registration will move
6671 to the next resolution level or finish if it is on the final level.
67- disp_freq = 5
72+ disp_freq = 3
6873 the frequency with which to update the displayed images. the images
6974 will be updated every disp_freq iterations. If disp_freq is set to
7075 0 the images will not be updated during the registration
@@ -84,6 +89,10 @@ def demonsReg(source, target, sigma_elastic=1, sigma_fluid=1, num_lev=3, use_com
8489 source_full = source ;
8590 target_full = target ;
8691
92+ #Preparing function for live update during registration process
93+ fig , axs = plt .subplots (1 , 3 , figsize = (12 , 6 ))
94+ iteration_text = fig .text (0.5 , 0.92 , '' , ha = 'center' , va = 'top' , fontsize = 10 , color = 'black' )
95+
8796 # loop over resolution levels
8897 for lev in range (1 , num_lev + 1 ):
8998
@@ -131,55 +140,48 @@ def demonsReg(source, target, sigma_elastic=1, sigma_fluid=1, num_lev=3, use_com
131140 # not change during the registration
132141 if use_target_grad :
133142 [img_grad_x , img_grad_y ] = np .gradient (target )
134-
135- # DISPLAY RESULTS
136- # figure 1 - source image (does not change during registration)
137- # figure 2 - target image (does not change during registration)
138- # figure 3 - source image transformed by current deformation field
139- # figure 4 - deformation field
140- # figure 5 - update
141-
142- # Create a single figure with 5 subplots in one row
143- fig , axs = plt .subplots (1 , 5 , figsize = (12 , 5 ))
144143
145- plt .sca (axs [0 ])
146- dispImage (source , title = 'Source Image' )
147144
148- plt .sca (axs [1 ])
149- dispImage (target , title = 'Target Image' )
145+
146+ # Function to update the display
147+ def live_update ():
148+ # Clear the axes
149+ for ax in axs :
150+ ax .clear ()
150151
151- plt .sca (axs [2 ])
152- dispImage (warped_image , title = 'Warped Image' )
153- x_lims = plt .xlim ()
154- y_lims = plt .ylim ()
152+ # Plotting the warped image in the first subplot
153+ plt .sca (axs [0 ])
154+ dispImage (warped_image , title = 'Warped Image' )
155+ x_lims = plt .xlim ()
156+ y_lims = plt .ylim ()
157+ # Plotting the deformation field in the second subplot
158+ plt .sca (axs [1 ])
159+ dispDefField (def_field , spacing = disp_spacing , plot_type = disp_method_df )
160+ axs [1 ].set_xlim (x_lims )
161+ axs [1 ].set_ylim (y_lims )
162+ axs [1 ].set_title ('Deformation Field' )
155163
156- # Plotting the deformation field in the second subplot
157- plt .sca (axs [3 ])
158- dispDefField (def_field , spacing = disp_spacing , plot_type = disp_method_df )
159- plt .xlim (x_lims )
160- plt .ylim (y_lims )
161- plt .title ('Deformation Field' )
164+ # Plotting the updated deformation field in the third subplot
165+ plt .sca (axs [2 ])
166+ up_field_to_display = scale_update_for_display * np .dstack ((update_x , update_y ))
167+ up_field_to_display += np .dstack ((X , Y ))
168+ dispDefField (up_field_to_display , spacing = disp_spacing , plot_type = disp_method_up )
169+ axs [2 ].set_xlim (x_lims )
170+ axs [2 ].set_ylim (y_lims )
171+ axs [2 ].set_title ('Update Field' )
162172
163- # Plotting the updated deformation field in the third subplot
164- plt .sca (axs [4 ])
165- up_field_to_display = scale_update_for_display * np .dstack ((update_x , update_y ))
166- up_field_to_display += np .dstack ((X , Y ))
167- dispDefField (up_field_to_display , spacing = disp_spacing , plot_type = disp_method_up )
168- plt .xlim (x_lims )
169- plt .ylim (y_lims )
170- plt .title ('Updated Deformation Field' )
171-
172- # Adjust layout for better spacing
173- plt .tight_layout ()
174- plt .subplots_adjust (top = 0.95 )
173+ # Update the iteration text
174+ iteration_text .set_text ('Level {0:d}, Iteration {1:d}: MSD = {2:.6f}' .format (lev , it , prev_MSD ))
175+
176+ # Adjust layout for better spacing
177+ plt .tight_layout ()
175178
176- # Display the figure
177- plt .show ()
179+ # Redraw the figure
180+ fig .canvas .draw ()
181+ fig .canvas .flush_events () # Ensure the figure updates immediately
178182
183+ plt .pause (0.5 )
179184
180- # if first level pause so user can position figure
181- if lev == 1 :
182- input ('position the figures as desired and then push enter to run the registration' )
183185
184186 # main iterative loop - repeat until max number of iterations reached
185187 for it in range (max_it ):
@@ -256,38 +258,7 @@ def demonsReg(source, target, sigma_elastic=1, sigma_fluid=1, num_lev=3, use_com
256258 # update images if required for this iteration
257259 if disp_freq > 0 and it % disp_freq == 0 :
258260 # Create a single figure with 3 subplots in one row and three columns
259- fig , axs = plt .subplots (1 , 3 , figsize = (12 , 6 ))
260-
261- # Plotting the warped image in the first subplot
262- plt .sca (axs [0 ])
263- dispImage (warped_image , title = 'Warped Image' )
264- plt .pause (0.05 )
265-
266- # Plotting the deformation field in the second subplot
267- plt .sca (axs [1 ])
268- dispDefField (def_field , spacing = disp_spacing , plot_type = disp_method_df )
269- plt .xlim (x_lims )
270- plt .ylim (y_lims )
271- plt .title ('Deformation Field' )
272- plt .pause (0.05 )
273-
274- # Plotting the updated deformation field in the third subplot
275- plt .sca (axs [2 ])
276- up_field_to_display = scale_update_for_display * np .dstack ((update_x , update_y ))
277- up_field_to_display += np .dstack ((X , Y ))
278- dispDefField (up_field_to_display , spacing = disp_spacing , plot_type = disp_method_up )
279- plt .xlim (x_lims )
280- plt .ylim (y_lims )
281- plt .title ('Updated Deformation Field' )
282- plt .pause (0.1 )
283-
284- plt .figtext (0.5 , 0.92 , 'Level {0:d}, Iteration {1:d}: MSD = {2:.6f}' .format (lev , it , prev_MSD ), ha = 'center' , va = 'top' , fontsize = 10 , color = 'black' )
285-
286- # Adjust layout for better spacing
287- plt .tight_layout ()
288-
289- # Display the figure
290- plt .show ()
261+ live_update ()
291262
292263 # calculate MSD between target and warped image
293264 MSD = calcMSD (target , warped_image )
@@ -306,36 +277,79 @@ def demonsReg(source, target, sigma_elastic=1, sigma_fluid=1, num_lev=3, use_com
306277 # update previous values of def_field and MSD
307278 def_field_prev = def_field .copy ()
308279 prev_MSD = MSD .copy ()
280+
281+ #plt.show()
282+
283+ if lev == num_lev :
284+ # Initialise global variables for current index tracking
285+ current_image_index = [0 ]
286+ current_mode_index = [0 ]
287+
288+ # Define the images and titles
289+ images = [source , target , warped_image ]
290+ image_titles = ['Source Image' , 'Target Image' , 'Warped Image' ]
291+ modes = ['Deformation Field' , 'Jacobian' ]
292+
293+
294+ def on_key (event ):
295+ if event .key == 'right' :
296+ current_image_index [0 ] = (current_image_index [0 ] + 1 ) % len (images )
297+ elif event .key == 'left' :
298+ current_image_index [0 ] = (current_image_index [0 ] - 1 ) % len (images )
299+ elif event .key == 'up' or event .key == 'down' :
300+ current_mode_index [0 ] = (current_mode_index [0 ] + 1 ) % len (modes )
301+ update_display ()
309302
310- # display the final results
311- # Create a single figure with 3 subplots in one row
312- fig , axs = plt .subplots (1 , 3 , figsize = (12 , 5 ))
313303
314- # Plotting the warped image in the first subplot
315- plt .sca (axs [0 ])
316- dispImage (warped_image , title = 'Warped Image' )
317304
318- # Plotting the deformation field in the second subplot
319- plt .sca (axs [1 ])
320- dispDefField (def_field , spacing = disp_spacing , plot_type = disp_method_df )
321- plt .xlim (x_lims )
322- plt .ylim (y_lims )
323- plt .title ('Deformation Field' )
305+ def update_display ():
306+ axs_combined [0 ].clear ()
307+ plt .sca (axs_combined [0 ])
308+ dispImage (images [current_image_index [0 ]], title = image_titles [current_image_index [0 ]])
309+
310+ axs_combined [1 ].clear ()
311+ plt .sca (axs_combined [1 ])
312+ if modes [current_mode_index [0 ]] == 'Deformation Field' :
313+ dispDefField (def_field , spacing = disp_spacing , plot_type = disp_method_df )
314+ axs_combined [1 ].set_title ('Deformation Field' )
315+
316+ else :
317+ [jacobian , _ ] = calcJacobian (def_field )
318+ dispImage (jacobian , title = 'Jacobian' )
319+ plt .set_cmap ('jet' )
320+ #plt.colorbar()
321+
322+ axs_combined [2 ].clear ()
323+ plt .sca (axs_combined [2 ])
324+ diff_image = images [current_image_index [0 ]] - target
325+ dispImage (diff_image , title = 'Difference Image' )
326+
327+ fig_combined .canvas .draw ()
328+
329+
330+ # Create a single figure with 3 subplots
331+ fig_combined , axs_combined = plt .subplots (1 , 3 , figsize = (12 , 6 ))
332+
333+ # Display initial images
334+ plt .sca (axs_combined [0 ])
335+ dispImage (images [current_image_index [0 ]], title = image_titles [current_image_index [0 ]])
336+
337+ plt .sca (axs_combined [1 ])
338+ dispDefField (def_field , spacing = disp_spacing , plot_type = disp_method_df )
339+ axs_combined [1 ].set_title ('Deformation Field' )
340+
341+ plt .sca (axs_combined [2 ])
342+ diff_image = images [current_image_index [0 ]] - target
343+ dispImage (diff_image , title = 'Difference Image' )
324344
325- # Plotting the updated deformation field in the third subplot
326- plt .sca (axs [2 ])
327- up_field_to_display = scale_update_for_display * np .dstack ((update_x , update_y ))
328- up_field_to_display += np .dstack ((X , Y ))
329- dispDefField (up_field_to_display , spacing = disp_spacing , plot_type = disp_method_up )
330- plt .xlim (x_lims )
331- plt .ylim (y_lims )
332- plt .title ('Updated Deformation Field' )
345+ # Add instructions for navigating images
346+ fig_combined .text (0.5 , 0.02 , 'Press <- or -> to navigate between source, target and warped images, Press Up or Down to switch between deformation field and Jacobian' , ha = 'center' , va = 'top' , fontsize = 12 , color = 'black' )
333347
334- # Adjust layout for better spacing
335- plt . tight_layout ( )
348+ # Connect the key event handler to the figure
349+ fig_combined . canvas . mpl_connect ( 'key_press_event' , on_key )
336350
337- # Display the figure
338- plt .show ()
351+ plt . tight_layout ()
352+ plt .show ()
339353
340354 # return the transformed image and the deformation field
341355 return warped_image , def_field
0 commit comments