%%%%% put_into_same_voxel_space.m
%%%%%
%%%%% In SPM99, put a target image into the same
%%%%% space as an object image.
%%%%% The image-display parts of this program need Matlab 6,
%%%%% because they use the alpha transparency property.
%%%%% 
%%%%% The object image is the one that gets the manipulations done to it:
%%%%% The object image gets resampled so that it lies in the same voxel
%%%%% space as the target image.
%%%%% Written by Rajeev Raizada, May 20, 2003.
%%%%% raj@nmr.mgh.harvard.edu

target_file_name = spm_get(1,'.img','Select target image');
V_target = spm_vol(target_file_name);
target = spm_read_vols(V_target);

disp(['Size of target image: ' num2str(size(target)) ]);

object_file_name = spm_get(1,'.img','Select object image');
V_object = spm_vol(object_file_name);
object = spm_read_vols(V_object);

disp(['Size of object image: ' num2str(size(object)) ]);

%%% Find the part of the object image that corresponds to the target image,
%%% (which might involve extending the object image, if the target is bigger)
%%% and interp the object image to have the same resolution as the target

for dim = 1:3,
  
  %%%% In order to interpolate the object image into the target space,
  %%%% we have to figure out which parts of the object image
  %%%% correspond to the target image.
  %%%% If the target image is bigger, then these parts may extend 
  %%%% beyond the current range of the object image.
  %%%% To find these parts, we need to figure out what voxels
  %%%% in the object-image's space would get taken up by the target
  %%%% image, if we put the target into the object's space.
  %%%% First, we find the range in voxels with respect to
  %%%% the origin the the target image spans,
  %%%% then we convert this range into millimeters, so that we can directly
  %%%% compare its range to that of the object image.
  target_vox_size_in_this_dim = V_target.mat(dim,dim);
  
  %%%% Find out which voxel-number is where the origin is
  target_vox_origin = -V_target.mat(dim,4) / target_vox_size_in_this_dim;
  
  %%%% Find out how many voxels the target image has either side of origin
  target_vox_range_wrt_origin = [ 1 size(target,dim) ] - target_vox_origin;
  
  %%%% Turn this voxel-range into millimeters
  target_range_in_mm = ...
        target_vox_range_wrt_origin * target_vox_size_in_this_dim;
 
  %%%% We know the range in mm that the target image spans in this dim,
  %%%% and this will be the same as the range in mm that it spans in 
  %%%% the space of the object image.
  %%%% So, we need to work out the range in object-space voxels that
  %%%% the target image will span when it gets put into object space.
  object_vox_size_in_this_dim = V_object.mat(dim,dim);
  object_vox_origin = -V_object.mat(dim,4) / object_vox_size_in_this_dim;

  target_range_in_object_vox_wrt_origin = ...
      target_range_in_mm / object_vox_size_in_this_dim;

  target_range_in_object_voxspace = target_range_in_object_vox_wrt_origin ...
                                      + object_vox_origin;
  
  %%%% Now we know the range that the object image needs to span
  %%%% in order for it to fit the target space.
  %%%% All we need now, in order to be able to interpolate the object
  %%%% image into the target space, is the ratio of the voxel sizes
  target_object_size_ratio = ...
      target_vox_size_in_this_dim / object_vox_size_in_this_dim;
 
  %%%% For the interp3 command, we'll make three vectors called
  %%%% range_to_send_object_into1,2,3, one for each dimension.
  %%%% These span the range of the target image in the object space,
  %%%% and go up in steps of target_object_size_ratio
  eval(['range_to_send_object_into' num2str(dim) ...
        ' = [ target_range_in_object_voxspace(1): ' ...
        '     target_object_size_ratio : ' ...
        '     target_range_in_object_voxspace(2)];']);
  
end;

%%% Now we can do the interpolation.
%%% Note that interp3 will put NaN in places where the 
%%% interped object extends beyond the range of the original
%%% object image.
%%% Note that interp3 works in x and y coords, not rows and cols,
%%% hence the orders of the first two interp vecs are switched.

disp('Starting 3D interpolation of object image into target space...');

interped_object = ...
    interp3(object,range_to_send_object_into2, ...
                   range_to_send_object_into1', ...
                   range_to_send_object_into3); 


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% Let's display the interped object overlaid on top of the
%%% target image. This part uses transparancy, so needs Matlab 6

%%% Set how many colour values we want
num_color_vals = 64;

%%% Make the target image go from 0 to num_color_vals
target_0 = target - min(target(:));  %%% Minium value is now zero

target_01 = target_0 / max(target_0(:));  %%% Max value is now 1

target_cvals = num_color_vals * target_01;

%%% Make the interped object go from num_color_vals+1 to 2*num_color_vals 
interped_obj_0 = interped_object - min(interped_object(:));

interped_obj_01 = interped_obj_0 / max(interped_obj_0(:));

interped_obj_cvals = num_color_vals + 1 + num_color_vals * interped_obj_01;

%%% Make a compound colormap
compound_cmap = [ gray(num_color_vals); hot(num_color_vals) ];

%%% Pick some axial slices to show in subplots
num_subplot_rows = 3;
num_subplot_cols = 4;

num_subplots = num_subplot_rows * num_subplot_cols;

slices_to_show = round( linspace( 1, size(target,3), num_subplots ));

figure(1);
clf;

for subplot_idx = 1:num_subplots,
  subplot(num_subplot_rows,num_subplot_cols,subplot_idx),
  
  slice_num = slices_to_show(subplot_idx);
  
  target_slice_cvals = target_cvals(:,:,slice_num);
  %%% Set all the pixels that are 0 or NaN in the target_slice
  %%% to be black. This makes the transparent overlay look nicer.
  target_slice = target(:,:,slice_num);

  zero_entries = find( target_slice==0 );
  nan_entries = find( isnan(target_slice) );
  
  target_slice_cvals( zero_entries ) = 0;
  target_slice_cvals( nan_entries ) = 0;
  
  interped_obj_slice_cvals = interped_obj_cvals(:,:,slice_num);

  h_target = image(target_slice_cvals);
  hold on;
  h_interped_obj = image(interped_obj_slice_cvals);

  colormap( compound_cmap );

  %%% Make the interped object transparent (needs Matlab 6!)
  overlay_opacity = 0.4;    %%% Higher value means more opaque

  %%% Set all the pixels in the overlap to have alpha=overlay_opacity
  opacity_matrix = overlay_opacity * ones(size(interped_obj_slice_cvals));
  
  %%% Set all the pixels that are 0 or NaN in the interped_obj_slice
  %%% to be fully transparent, i.e. with opacity=0
  interped_obj_slice = interped_object(:,:,slice_num);

  zero_entries = find(interped_obj_slice==0);
  nan_entries = find( isnan(interped_obj_slice) );
  
  opacity_matrix( zero_entries ) = 0;
  opacity_matrix( nan_entries ) = 0;
  
  set(h_interped_obj,'alphadata',opacity_matrix);

  axis('image');
  axis('off');
  
end;

%%%%%% Ask whether to write Analyze image of interped object image

write_image_string = ...
    input('Write analyze image of interped object? (y/n): ','s');

if write_image_string == 'y',
  
  new_name = input('Name of new image to write: ','s');
  
  Vnew = V_target;
  Vnew.fname = new_name;
  
  spm_write_vol(Vnew,interped_object);
end;
