Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
function piv_3d_10(piv_parameters);
% This function is designed to process two or three dimensional PIV data using
% the parameters specified by the 'piv_parameters' data structure.
%
% This code is based upon the code 'basic_3d_rpc_processing_05.m'.
%
% Updates on previous versions:
%
% Version 08
%
% Saves the PIV processing parameters data structure to the PIV
% vector field write directory for later reference.
%
% Version 09
%
% Added the ability to use several different outlier vector
% replacement methods including a local mean interpolation (default
% in previous versions), a Laplacian interpolation, and a Delaunay
% interpolation.
%
% Version 10
%
% This updated the order of the spatial and temporal dimensions to be
% consistent with other PIV software versions and to minimize the
% number of overhead operations (since MATLAB prefers some orders
% over others).
%
% The ability to import other data formats was also included. The
% code can now import 2D images in one of the following formats:
% 'bmp', 'jpg', 'jp2', 'png', 'ppm', 'tif', 'mat', 'dcm', 'cdf', or
% 'h5' while 3D images may be one of the following formats: 'mat',
% 'dcm', 'cdf', or 'h5'.
%
% Any NaN velocity vector values that are produced during the
% correlations (likely due to simulated data not being seeded within
% a window) are considered outliers and replaced accordingly.
%
% Things to work on, modify, fix, et cetera:
%
% Change the code that is optimized for C to code that is optimized for
% matlab.
%
% Check on the speed of the if-then statements added to make the code run
% for 2D images as well.
%
% Add peak fitting algorithms besides the 3-point Gaussian.
%
% Add the ability to record multiple correlation peaks, specifically to
% be used during validation. Possibly also record the peak ratio.
%
% Add the ability to do multiple iterations of validation and replacement
% for each pass.
%
% Add in the ability to perform deform correlations.
%
% Authors: Rod La Foy
% First Written On: 31 October 2014
% Last Modified On: 21 November 2014
% This extracts the vector field saving directory from the data processing structure
vector_field_write_directory=piv_parameters.general_parameters.vector_field_write_directory;
% This saves a copy of the processing parameters to the vector field write
% directory for future reference
save([vector_field_write_directory,'piv_processing_parameters.mat'],'piv_parameters');
% This extracts the number of passes to perform
pass_number=piv_parameters.general_parameters.pass_number;
% This is the initial image frame to load
initial_image_frame=piv_parameters.general_parameters.initial_image_frame;
% This is the final image frame to load
final_image_frame=piv_parameters.general_parameters.final_image_frame;
% This is the number of frames to step each iteration
image_frame_step=piv_parameters.general_parameters.image_frame_step;
% This is the number of frames to step between correlation frame pairs
image_correlation_step=piv_parameters.general_parameters.image_correlation_step;
% This is the Boolean value stating whether to perform window deformation
perform_window_deformation=piv_parameters.general_parameters.perform_window_deformation;
% If window deformation is to be performed, this loads the window
% deformation parameters
if perform_window_deformation;
% This is the minimum number of window deformation operations to
% perform
window_deformation_iteration_min=piv_parameters.general_parameters.window_deformation_iteration_min;
% This is the maximum number of window deformation operations to
% perform
window_deformation_iteration_max=piv_parameters.general_parameters.window_deformation_iteration_max;
% This is the convergence threshhold of the window deformation process
window_deformation_threshhold=piv_parameters.general_parameters.window_deformation_threshhold;
end;
% This is a Boolean value stating whether to perform pyramid correlations
perform_pyramid_correlations=piv_parameters.general_parameters.perform_pyramid_correlations;
% This is the image filename extension
image_filename_extension=piv_parameters.general_parameters.image_filename_extension;
% This is the image variable name (if the variable is saved within a data
% object that contain multiple variables, ie a 'mat' file)
image_variable_name=piv_parameters.general_parameters.image_variable_name;
% This is a list of the images within the image read directory
image_filename_list=dir([piv_parameters.general_parameters.image_read_directory,piv_parameters.general_parameters.image_filename_prefix,'*',image_filename_extension]);
% This is the filename of the first image file (for the purpose of determing the image
% file size)
first_image_filename=[piv_parameters.general_parameters.image_read_directory,image_filename_list(1).name];
% This finds the size of the images being loaded which can be 'bmp', 'jpg',
% 'jp2', 'png', 'ppm', or 'tif' images in 2D or 'mat' or 'dcm' images in 3D
if any(strcmpi(image_filename_extension,{'bmp','jpg','jp2','png','ppm','tif'}));
% This loads in the first image
I_First_Image=imread(first_image_filename);
% This measures the image size
image_size=size(I_First_Image);
% This clears the image from memory
clear('I_First_Image');
% This adds the third dimension as 1 if it does not exist
if length(image_size)==2;
% This adds the third dimension of the image size as 1
image_size(3)=1;
end;
% This clears the first image from memory
clear('I_First_Image');
elseif strcmpi(image_filename_extension,'mat');
% This creates a matlab mat object containing information about the image
first_image_object=matfile(first_image_filename);
% This extracts the image size information
image_size=size(first_image_object,image_variable_name);
% This adds the third dimension as 1 if it does not exist
if length(image_size)==2;
% This adds the third dimension of the image size as 1
image_size(3)=1;
end;
elseif strcmpi(image_filename_extension,'dcm');
% This reads int the DICOM image
I_First_Image=dicomread(first_image_filename);
% This extracts the image size information
image_size=size(I_First_Image);
% This adds the third dimension as 1 if it does not exist and removes
% the third dimension if the image is 3D since the 3rd dimension will
% correspond to the colormap
if length(image_size)==2;
% This adds the third dimension of the image size as 1
image_size(3)=1;
elseif length(image_size)==4;
% This removes the 3rd dimension since this corresponds to the
% colormap fod DICOM files which is not used for PIV data
image_size(3)=[];
end;
% This clears the first image from memory
clear('I_First_Image');
elseif strcmpi(image_filename_extension,'cdf');
% This reads in the Common Data Format image into a cell array
I_First_Image=cdfread(first_image_filename,'Variables',image_variable_name);
% This extracts the image size information from the cell array
image_size=size(I_First_Image{1});
% This adds the third dimension as 1 if it does not exist and removes
% the third dimension if the image is 3D since the 3rd dimension will
% correspond to the colormap
if length(image_size)==2;
% This adds the third dimension of the image size as 1
image_size(3)=1;
end;
% This clears the first image from memory
clear('I_First_Image');
elseif strcmpi(image_filename_extension,'h5');
% This reads in the HDF5 image
I_First_Image=hdf5read(first_image_filename,image_variable_name);
% This extracts the image size information
image_size=size(I_First_Image);
% This adds the third dimension as 1 if it does not exist and removes
% the third dimension if the image is 3D since the 3rd dimension will
% correspond to the colormap
if length(image_size)==2;
% This adds the third dimension of the image size as 1
image_size(3)=1;
end;
% This clears the first image from memory
clear('I_First_Image');
end;
% These are the coordinates of the estimated velocities (initially nothing is assummed
% about the velocity field so a zero displacement is used and since the extrapolation value
% is set to 0, only one arbitrary coordinate must be specified)
if image_size(3)==1;
% This calculates the initial interpolation coordinates with only one
% kk coordinate value
[jj_position,ii_position,kk_position]=meshgrid([1,image_size(1)],[1,image_size(2)],[1]);
% This is the estimated (initially zero) velocity for the 2D array
ii_velocity=zeros(2,2,1);
jj_velocity=zeros(2,2,1);
kk_velocity=zeros(2,2,1);
elseif image_size(3)>1;
% This calculates the initial interpolation coordinates with the full
% 3D array of coordinates
[jj_position,ii_position,kk_position]=meshgrid([1,image_size(1)],[1,image_size(2)],[1,image_size(3)]);
% This is the estimated (initially zero) velocity for the 3D array
ii_velocity=zeros(1,1,1); % originally 2,2,2
jj_velocity=zeros(1,1,1); % originally 2,2,2
kk_velocity=zeros(1,1,1); % originally 2,2,2
end;
% This iterates through the passes
for pass_index=1:pass_number;
% This displays that the current pass is being processed
fprintf('\n\nCompleting pass %d of %d passes.\n',pass_index,pass_number);
% This extracts the effective current window resolution
window_resolution=piv_parameters.pass_parameters(pass_index).window_resolution;
% This extracts the full window size
window_size=piv_parameters.pass_parameters(pass_index).window_size;
% This extracts the window gridding method for the current pass
window_gridding_method=piv_parameters.pass_parameters(pass_index).window_gridding_method;
% This is the Boolean value stating whether to perform validation on the vector field
validate_vector_field=piv_parameters.pass_parameters(pass_index).validate_vector_field;
% This is the Boolean value stating whether to perform smoothing of the velocity vector field
smooth_vector_field=piv_parameters.pass_parameters(pass_index).smooth_vector_field;
% If specified by the user to perform smoothing of the velocity field, this loads the
% smoothing specific parameters
if smooth_vector_field;
% This loads the Gaussian smoothing standard deviation
gaussian_smoothing_kernal_std=piv_parameters.pass_parameters(pass_index).gaussian_smoothing_kernal_std;
% This loads the Gaussian smoothing kernal size
gaussian_smoothing_kernal_size=piv_parameters.pass_parameters(pass_index).gaussian_smoothing_kernal_size;
end;
% If specified by the user to perform validation, this loads the loads the validation
% specific parameters
if validate_vector_field;
% This loads the vector outlier threshhold limits
minimum_outlier_threshhold=piv_parameters.pass_parameters(pass_index).minimum_outlier_threshhold;
maximum_outlier_threshhold=piv_parameters.pass_parameters(pass_index).maximum_outlier_threshhold;
% This loads the UOD kernal size
uod_kernal_size=piv_parameters.pass_parameters(pass_index).uod_kernal_size;
% This loads the UOD expected error
uod_epsilon=piv_parameters.pass_parameters(pass_index).uod_epsilon;
% This loads the UOD residual threshhold value
uod_residual_threshhold=piv_parameters.pass_parameters(pass_index).uod_residual_threshhold;
% This loads the outlier vector replacement method
vector_replacement_method=piv_parameters.pass_parameters(pass_index).vector_replacement_method;
% This loads the relevant vector replacement parameters based upon
% the interpolation method
if strcmp(vector_replacement_method,'local_mean');
% This loads the minimum number of local vectors used to
% calculate the local mean
local_mean_minimum_valid_vector_number=piv_parameters.pass_parameters(pass_index).local_mean_minimum_valid_vector_number;
elseif strcmp(vector_replacement_method,'laplacian_interpolation');
% This loads the number of adjacent points to use in
% calculating the interpolated values (this can be either 4 or
% 8 in 2D and 6, 18, or 26 in 3D)
laplacian_interpolation_adjacent_connectivity=piv_parameters.pass_parameters(pass_index).laplacian_interpolation_adjacent_connectivity;
elseif strcmp(vector_replacement_method,'delaunay_interpolation');
% This loads the Delaunay interpolation weighting method to be
% used in interpolating values
delaunay_interpolation_weighting_method=piv_parameters.pass_parameters(pass_index).delaunay_interpolation_weighting_method;
end;
end;
% This calculates the grid spacing for the current pass using either
% the amount of window overlap or the window spacing
if strcmp(window_gridding_method,'window_overlap');
% This is the ratio of the window overlap distance
window_overlap=piv_parameters.pass_parameters(pass_index).window_overlap;
% This is the spacing between the centers of the windows
grid_spacing=round(window_resolution.*(1-window_overlap)); %originally grid_spacing=round(window_resolution.*(1-window_overlap));
% This checks if the overlap percentage is so high that grid spacing is zero (although
% this should actually never be done)
if grid_spacing==0;
% This sets the grid spacing to 1 voxel
grid_spacing=ones(size(grid_spacing));
end;
elseif strcmp(window_gridding_method,'window_spacing');
% This extracts the window grid spacing from the parameters structure
grid_spacing=piv_parameters.pass_parameters(pass_index).window_spacing;
end;
% This calculates the window domains
[window_min,window_max,window_center,window_number]=calculate_window_domains(image_size,window_resolution,window_size,grid_spacing);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This iterates through the frames calculating the velocity fields. %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Z_ensemble = zeros(window_size);
% This iterates through the image frames calculating the vector fields
for frame_index=initial_image_frame:image_frame_step:final_image_frame;
% This displays that the current frame is being processed
fprintf('\nProcessing frame %d of %d frames.\n',frame_index,final_image_frame);
% If this is the second or higher pass, this loads the
% previously calculated vector field which is used to deform
% the images in the pyramid correlations
if pass_index>1;
% This is the filename to load the data from
data_filename_read=[vector_field_write_directory,'pass_',sprintf('%02.0f',pass_index-1),'_frame_',sprintf('%04.0f',frame_index),'_x_',sprintf('%04.0f',frame_index+image_correlation_step),'.mat'];
% This loads in the data file
load(data_filename_read);
% This renames the data loaded from memory to be conistent
% with the variables names within this code (ie Prana uses X,
% Y, Z, U, V, W for the position and velocity values and this
% code uses the index dimensions ii, jj, kk)
ii_position=Y;
jj_position=X;
kk_position=Z;
ii_velocity=V;
jj_velocity=U;
kk_velocity=W;
end;
% This checks whether standard correlations are supposed to be
% performed
if not(perform_pyramid_correlations);
% This performs the standard correlations of the current frame
[Z,ii_position,jj_position,kk_position,ii_velocity,jj_velocity,kk_velocity]=standard_correlations(piv_parameters,pass_index,frame_index,window_number,window_min,window_max,window_center,ii_position,jj_position,kk_position,ii_velocity,jj_velocity,kk_velocity);
%ensemble correlation addition
Z_ensemble = Z_ensemble + Z;
C=ifftn(Z_ensemble,'symmetric');
displacement_vector=subpixel_displacement_vector(C,window_size);
elseif perform_pyramid_correlations;
% This performs the pyramid correlations of the current frame
[ii_position,jj_position,kk_position,ii_velocity,jj_velocity,kk_velocity]=pyramid_correlations(piv_parameters,pass_index,frame_index,window_number,window_min,window_max,window_center,ii_position,jj_position,kk_position,ii_velocity,jj_velocity,kk_velocity);
end;
% This performs validation of the vector field if specified by the user
if validate_vector_field;
% This displays that the vector field is being validated
disp('Validating the vector field . . . ');
% This determines the outliers of the vector field based upon several metrics
outlier_vector_array=locate_vector_outliers(ii_velocity,jj_velocity,kk_velocity,minimum_outlier_threshhold,maximum_outlier_threshhold,uod_kernal_size,uod_epsilon,uod_residual_threshhold);
% This replaces the outlier vectors using the specified method
if strcmp(vector_replacement_method,'local_mean');
% This replaces the outlier vectors using a local mean of valid vectors
[ii_velocity,jj_velocity,kk_velocity]=local_mean_replacement(ii_position,jj_position,kk_position,ii_velocity,jj_velocity,kk_velocity,outlier_vector_array,local_mean_minimum_valid_vector_number);
elseif strcmp(vector_replacement_method,'laplacian_interpolation');
% This replaces the outlier vectors using Laplacian interpolation
[ii_velocity,jj_velocity,kk_velocity]=laplacian_replacement(ii_position,jj_position,kk_position,ii_velocity,jj_velocity,kk_velocity,outlier_vector_array,laplacian_interpolation_adjacent_connectivity);
elseif strcmp(vector_replacement_method,'delaunay_interpolation');
% This replaces the outlier vectors using a weighted sum based upon the
% Delaunay triangulation of the valid vectors
[ii_velocity,jj_velocity,kk_velocity]=delaunay_replacement(ii_position,jj_position,kk_position,ii_velocity,jj_velocity,kk_velocity,outlier_vector_array,delaunay_interpolation_weighting_method);
end;
end;
% This performs smoothing of the vector field if specified by the users
if smooth_vector_field;
% This displays that the vector field is being smoothed
disp('Smoothing the vector field . . . ');
% This smooths the vector fields
[ii_velocity,jj_velocity,kk_velocity]=smooth_velocity_field(ii_velocity,jj_velocity,kk_velocity,gaussian_smoothing_kernal_size,gaussian_smoothing_kernal_std*ones(1,3));
end;
% This is the filename to save the data as
data_filename_write=[vector_field_write_directory,'pass_',sprintf('%02.0f',pass_index),'_frame_',sprintf('%04.0f',frame_index),'_x_',sprintf('%04.0f',frame_index+image_correlation_step),'.mat'];
% This renames the data from the current vector field to be
% conistent with the variables names used by other vector field
% code (ie Prana uses X, Y, Z, U, V, W for the position and
% velocity values and this code uses the index dimensions ii, jj,
% kk)
Y=ii_position;
X=jj_position;
Z=kk_position;
V=ii_velocity;
U=jj_velocity;
W=kk_velocity;
% This renames the validation array to be consistent with the
% variables used by other vector field code (ie Prana uses Valid as
% the name for the valid vectors and this code uses
% outlier_vector_array)
if validate_vector_field;
% This creates the binary array variable 'Valid' which gives
% the locations of the vectors that were considered valid
Valid=not(outlier_vector_array);
else;
% This creates an array of NaNs for the variable 'Valid' since
% validation was not performed on the vector field
Valid=NaN(size(X));
end;
% This saves the vector field data to memory
save(data_filename_write,'X','Y','Z','U','V','W','Valid','-v7.3');
end;
end;
function [Z,ii_position,jj_position,kk_position,ii_velocity,jj_velocity,kk_velocity]=standard_correlations(piv_parameters,pass_index,frame_index,window_number,window_min,window_max,window_center,ii_position,jj_position,kk_position,ii_velocity,jj_velocity,kk_velocity);
% This function calculates standard pair correlations of the data set listed
% within the parameters variable 'piv_parameters'. The standard correlation
% consists of taking pair-wise correlations from a time series of images.
% The input parameters of this function are given by
%
% piv_parameters A data structure containing all the necessary
% parameters required to perform the PIV processing
%
% pass_index A scalar integer giving the current pass of the PIV
% processing
%
% frame_index A scalar integer giving the index of the current
% frame being processed from the directory of images.
% For pyramid correlations, the velocity field will
% always be calculated for the frame_index and
% frame_index + 1 froms, ie the changing the
% correlation step does nothing.
%
% window_number A 1 x 3 vector giving the number of PIV windows to
% process in the first, second, and third dimensions
% respectively. If the images are 2D then
% window_number(3) should always equal 1.
%
% window_min A L x 3 vector giving the minimum indices of the
% window domains in each respective dimension where L
% is the total number of windows to process.
%
% window_max A L x 3 vector giving the maximum indices of the
% window domains in each respective dimension where L
% is the total number of windows to process.
%
% window_center A L x 3 vector giving the coordinates of the center
% of the window domains in each respective dimension
% where L is the total number of windows to process.
%
% ii_position A M x N x P array giving the 1st dimension
% coordinates of the previously measured vector field
% if this is at least the second pass. If this is
% the first pass then the coordinates correspond to
% an all-zero vector field.
%
% jj_position A M x N x P array giving the 2nd dimension
% coordinates of the previously measured vector field
% if this is at least the second pass. If this is
% the first pass then the coordinates correspond to
% an all-zero vector field.
%
% kk_position A M x N x P array giving the 3rd dimension
% coordinates of the previously measured vector field
% if this is at least the second pass. If this is
% the first pass then the coordinates correspond to
% an all-zero vector field.
%
% ii_velocity A M x N x P array giving the 1st dimension velocity
% of the previously measured vector field if this is
% at least the second pass. If this is the first
% pass then the velocity will be set to all zeros.
%
% jj_velocity A M x N x P array giving the 2nd dimension velocity
% of the previously measured vector field if this is
% at least the second pass. If this is the first
% pass then the velocity will be set to all zeros.
%
% kk_velocity A M x N x P array giving the 3rd dimension velocity
% of the previously measured vector field if this is
% at least the second pass. If this is the first
% pass then the velocity will be set to all zeros.
%
% The output parameters give the measured (un-validated, un-smoothed)
% velocity field of the current frame pair and are described by
%
% ii_position A Q x R x S array giving the 1st dimension
% coordinates of the measured vector field, ie the
% center of the correlation window in the 1st
% dimension.
%
% jj_position A Q x R x S array giving the 2nd dimension
% coordinates of the measured vector field, ie the
% center of the correlation window in the 1st
% dimension.
%
% kk_position A Q x R x S array giving the 3rd dimension
% coordinates of the measured vector field, ie the
% center of the correlation window in the 1st
% dimension.
%
% ii_velocity A Q x R x S array giving the 1st dimension velocity
% of the current vector field measured at each
% correlation window.
%
% jj_velocity A Q x R x S array giving the 1st dimension velocity
% of the current vector field measured at each
% correlation window.
%
% kk_velocity A Q x R x S array giving the 1st dimension velocity
% of the current vector field measured at each
% correlation window.
%
% Authors: Rod La Foy
% First Created On: 14 March 2014
% Last Modified On: 14 March 2014
% This is the image filename extension
image_filename_extension=piv_parameters.general_parameters.image_filename_extension;
% This is the image variable name (if the variable is saved within a data
% object that contain multiple variables, ie a 'mat' file)
image_variable_name=piv_parameters.general_parameters.image_variable_name;
% This is a list of the images within the image read directory
image_filename_list=dir([piv_parameters.general_parameters.image_read_directory,piv_parameters.general_parameters.image_filename_prefix,'*',image_filename_extension]);
% This extracts the effective current window resolution
window_resolution=piv_parameters.pass_parameters(pass_index).window_resolution;
% This extracts the full window size
window_size=piv_parameters.pass_parameters(pass_index).window_size;
% This is the number of frames to step between correlation frame pairs
image_correlation_step=piv_parameters.general_parameters.image_correlation_step;
% This is the bulk window offset distance
bulk_window_offset=piv_parameters.pass_parameters(pass_index).bulk_window_offset;
% This is the correlation method to use for the current pass
correlation_method=piv_parameters.pass_parameters(pass_index).correlation_method;
% If the correlation method is the RPC method, this creates the RPC filter
if strcmp(correlation_method,'RPC');
% This extracts the size of the particles in the images
particle_diameter=piv_parameters.general_parameters.particle_diameter;
% This creates the spectral energy filter
spectral_filter=single(fftshift(create_spectral_filter(window_size,particle_diameter)));
elseif strcmp(correlation_method,'SCC');
% This sets the spectral filter to a null value
spectral_filter=[];
end;
% This is a Boolean value stating whether to zero-mean the correlation
% windows
zero_mean_windows=piv_parameters.pass_parameters(pass_index).zero_mean_windows;
% This sets the fft library for optimal speed calculation
fftw('planner','measure');
% This determines the size of the Gaussian function to use for the window masking
gaussian_width=determine_gaussian_size_2(window_size,window_resolution);
% This creates a Gaussian windowing function
gaussian_filter=single(create_gaussian_filter(window_size,gaussian_width));
% These are the coordinate vectors
ii_position_current=reshape(window_center(:,1),window_number);
jj_position_current=reshape(window_center(:,2),window_number);
kk_position_current=reshape(window_center(:,3),window_number);
% This initializes the velocity vectors
ii_velocity_current=zeros(size(ii_position_current));
jj_velocity_current=zeros(size(ii_position_current));
kk_velocity_current=zeros(size(ii_position_current));
% This determines the domain over which the known velocity field should be
% extrapolated
% ii_extrap_min=min(ii_position_current(:))-ceil(window_size(1)/2);
% ii_extrap_max=max(ii_position_current(:))+ceil(window_size(1)/2);
% jj_extrap_min=min(jj_position_current(:))-ceil(window_size(2)/2);
% jj_extrap_max=max(jj_position_current(:))+ceil(window_size(2)/2);
% kk_extrap_min=min(kk_position_current(:))-ceil(window_size(3)/2);
% kk_extrap_max=max(kk_position_current(:))+ceil(window_size(3)/2);
% % This adds extrapolated points to the previously measured vector field so
% % that if the vector field is interpolated at points near the edge of the
% % image, the interpolated points will have approximately correct values (as
% % opposed to zero or NaNs)
% [~,~,~,ii_velocity]=extrapolate_velocity_field(ii_position,jj_position,kk_position,ii_velocity,ii_extrap_min,ii_extrap_max,jj_extrap_min,jj_extrap_max,kk_extrap_min,kk_extrap_max);
% [~,~,~,jj_velocity]=extrapolate_velocity_field(ii_position,jj_position,kk_position,jj_velocity,ii_extrap_min,ii_extrap_max,jj_extrap_min,jj_extrap_max,kk_extrap_min,kk_extrap_max);
% [ii_position,jj_position,kk_position,kk_velocity]=extrapolate_velocity_field(ii_position,jj_position,kk_position,kk_velocity,ii_extrap_min,ii_extrap_max,jj_extrap_min,jj_extrap_max,kk_extrap_min,kk_extrap_max);
% If the bulk window offset is non-zero, this adds it to the previous pass
% velocity field estimate
if any(bulk_window_offset);
% This adds the bulk window offset to the previously measured velocity
% field
ii_velocity=ii_velocity+bulk_window_offset(1);
jj_velocity=jj_velocity+bulk_window_offset(2);
kk_velocity=kk_velocity+bulk_window_offset(3);
% This creates a Boolean value stating to apply the bulk window offset
perform_bulk_window_offset=true;
else;
% This creates a Boolean value stating to apply the bulk window offset
perform_bulk_window_offset=false;
end;
% If this is the second pass or higher, this calculates the discrete window
% offset, otherwise the offset is just set to zero
if (pass_index==1)&&(not(perform_bulk_window_offset));
% This sets the first frame minimum and maximum values to the
% non-offset values
frame_1_window_min=window_min;
frame_1_window_max=window_max;
% This sets the second frame minimum and maximum values to the
% non-offset values
frame_2_window_min=window_min;
frame_2_window_max=window_max;
% This sets the displacement offset array to all zeros
displacement_offset=zeros(size(window_min));
else;
% This function adds the known velocity field to the window domains, ie
% accounts for the discrete window offset
[frame_1_window_min,frame_1_window_max,frame_2_window_min,frame_2_window_max,displacement_offset]=dwo_window_domains(window_min,window_max,window_center,image_correlation_step,ii_position,jj_position,kk_position,ii_velocity,jj_velocity,kk_velocity);
end;
% This is the filename of the first image to load
image_1_filename=[piv_parameters.general_parameters.image_read_directory,image_filename_list(frame_index).name];
% This is the filename of the first image to load
image_2_filename=[piv_parameters.general_parameters.image_read_directory,image_filename_list(frame_index+image_correlation_step).name];
% This finds the size of the images being loaded which can be 'bmp', 'jpg',
% 'jp2', 'png', 'ppm', or 'tif' images in 2D or 'mat images in 3D
if any(strcmpi(image_filename_extension,{'bmp','jpg','jp2','png','ppm','tif'}));
% This loads the first image
I1=double(imread(image_1_filename));
% This loads the second image
I2=double(imread(image_2_filename));
elseif strcmpi(image_filename_extension,'mat');
% This creates a matlab file object of the first image of the correlation pairs
image_1_object=matfile(image_1_filename);
% This loads the first image
eval(['I1=double(image_1_object.',image_variable_name,');']);
% This creates a matlab file object of the second image of the correlation pairs
image_2_object=matfile(image_2_filename);
% This loads the second image
eval(['I2=double(image_2_object.',image_variable_name,');']);
elseif strcmpi(image_filename_extension,'dcm');
% This loads the first image
I1=double(squeeze(dicomread(image_1_filename)));
% This loads the second image
I2=double(squeeze(dicomread(image_2_filename)));
elseif strcmpi(image_filename_extension,'cdf');
% This loads the first image cell array
I1_Temp=double(cdfread(image_1_filename,'Variables',image_variable_name));
% This loads the image from the cell array
I1=I1_Temp{1};
% This clears the cell array from memory
clear('I1_Temp');
% This loads the second image
I2_Temp=double(cdfread(image_2_filename,'Variables',image_variable_name));
% This loads the image from the cell array
I2=I2_Temp{1};
% This clears the cell array from memory
clear('I2_Temp');
elseif strcmpi(image_filename_extension,'h5');
% This loads the first image
I1=double(hdf5read(image_1_filename,image_variable_name));
% This loads the second image
I2=double(hdf5read(image_2_filename,image_variable_name));
end;
% This determines the image size
image_size=zeros(1,3);
image_size(1)=size(I1,1);
image_size(2)=size(I1,2);
image_size(3)=size(I1,3);
% This iterates through the windows performing the cross-correlations
for window_index=1:prod(window_number);
% This displays the calculation progress
display_calculation_progress(window_index,1:size(window_min,1));
% This extracts the correlation window from the first frame
I1_Window=extract_correlation_window(I1,window_size,frame_1_window_min(window_index,:),frame_1_window_max(window_index,:),image_size);
% This extracts the correlation window from the second frame
I2_Window=extract_correlation_window(I2,window_size,frame_2_window_min(window_index,:),frame_2_window_max(window_index,:),image_size);
% This subtracts the mean value from the windows if specified by the
% user
if zero_mean_windows;
% This subtracts the mean value from the first image window
I1_Window=I1_Window-mean(I1_Window(:));
% This subtracts the mean value from the second image window
I2_Window=I2_Window-mean(I2_Window(:));
end;
% This performs the cross-correlation measurement
[Z,displacement_vector]=calculate_window_correlation(I1_Window,I2_Window,gaussian_filter,spectral_filter,window_size,correlation_method);
% These are the velocities of the current correlation volume
ii_velocity_current(window_index)=displacement_vector(1)+displacement_offset(window_index,1);
jj_velocity_current(window_index)=displacement_vector(2)+displacement_offset(window_index,2);
kk_velocity_current(window_index)=displacement_vector(3)+displacement_offset(window_index,3);
end;
% This overwrites the input velocity field coordinates with the current
% pass's coordinates
ii_position=ii_position_current;
jj_position=jj_position_current;
kk_position=kk_position_current;
% This overwrites the input velocity field vectors with the current
% pass's vectors
ii_velocity=ii_velocity_current/image_correlation_step;
size(ii_velocity_current)
jj_velocity=jj_velocity_current/image_correlation_step;
kk_velocity=kk_velocity_current/image_correlation_step;
%pyramid correlation location - originally
function [Z,displacement_vector]=calculate_window_correlation(I1,I2,gaussian_window_filter,spectral_filter,window_size,method);
% This performs the volumetric correlation between windows I1 and I2. The
% gaussian filter is applied to the windows, the correlation is performed,
% and a sub-pixel fit is made to the correlation volume.
% This calculates the correlation volumes using either the SCC or RPC
% correlations
if strcmp(method,'SCC');
% This performs the SCC correlation on the two windows
[Z,C]=scc_correlation(I1,I2,gaussian_window_filter);
elseif strcmp(method,'RPC');
% This performs the RPC correlation on the two windows
C=rpc_correlation(I1,I2,gaussian_window_filter,spectral_filter);
end;
% This calculates the displacement vector from the correlation volumes
displacement_vector=subpixel_displacement_vector(C,window_size);
function [Z,C]=scc_correlation(I1,I2,gaussian_window_filter);
% This function performs the standard cross-correlation on the two windows 'I1' and 'I2'
% after masking the windows with a Gaussian function given by 'gaussian_window_filter'.
% This applies the Gaussian filter to the first window
I1=I1.*gaussian_window_filter;
% This applies the Gaussian filter to the second window
I2=I2.*gaussian_window_filter;
% This calculates the FFT of the first window
Y1=fftn(I1);
% This calculates the FFT of the second window
Y2=fftn(I2);
% This performs the cross-correlation in the spectral domain
Z= Y2.*conj(Y1); % originally Y2.*conj(Y1)
% This performs the inverse FFT to return the correlation volume
C=ifftn(Z,'symmetric');
function C=rpc_correlation(I1,I2,gaussian_window_filter,spectral_filter);
% This function performs the robust phase correlation on the two windows 'I1' and 'I2'
% after masking the windows with a Gaussian function given by 'gaussian_window_filter' and
% using the RPC spectral filter defined by 'spectral_filter'.
% This applies the Gaussian filter to the first window
I1=I1.*gaussian_window_filter;
% This applies the Gaussian filter to the second window
I2=I2.*gaussian_window_filter;
% This calculates the FFT of the first window
Y1=fftn(I1);
% This calculates the FFT of the second window
Y2=fftn(I2);
% This performs the cross-correlation in the spectral domain
YC=Y2.*conj(Y1);
% This is the magnitude of the cross-correlation in the spectral domain
YC_Magnitude=sqrt(YC.*conj(YC));
% These are the indices of the non-zero magnitude components of the
% cross-correlation
non_zero_indices=(YC_Magnitude(:)~=0);
% This initializes the phase correlation array
R=YC;
% THis is the phase correlation in the spectral domain
R(non_zero_indices)=YC(non_zero_indices)./YC_Magnitude(non_zero_indices);
% This applies the spectral filter
R=R.*spectral_filter;
% This performs the inverse FFT to return the correlation volume
C=ifftn(R,'symmetric');
% This takes the absolute value of the correlation volume to ensure positive values
C=abs(C);
function displacement_vector=subpixel_displacement_vector(C,window_size);
% This function finds the subpixel fit to the correlation volume given by C.
% This is the linear index of the correlation maximum (this only takes the first maximum
% value if multiple are found - this is unlikely, but should be addressed)
max_linear_index=find(C==max(C(:)),1);
% This converts the linear index to a set of subscripted indices
[ii_max,jj_max,kk_max]=ind2sub(window_size,max_linear_index);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This performs the three-point Gaussian fitting in the ii-direction. %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% These are the three points to fit in the ii-direction
if (ii_max>1)&&(ii_max<window_size(1));
% These are the three points to fit if the maximum is not on an edge
C_ii_n1=C(ii_max-1,jj_max,kk_max);
C_ii_00=C(ii_max,jj_max,kk_max);
C_ii_p1=C(ii_max+1,jj_max,kk_max);
elseif (ii_max==1);
% These are the three points to fit if the maximum is on the lower edge
C_ii_n1=C(window_size(1),jj_max,kk_max);
C_ii_00=C(ii_max,jj_max,kk_max);
C_ii_p1=C(ii_max+1,jj_max,kk_max);
elseif (ii_max==window_size(1));
% These are the three points to fit if the maximum is on the upper edge
C_ii_n1=C(ii_max-1,jj_max,kk_max);
C_ii_00=C(ii_max,jj_max,kk_max);
C_ii_p1=C(1,jj_max,kk_max);
end;
% This is the numerator of the subpixel three-point Gaussian fit in the ii direction
ii_num_fit=log(C_ii_n1)-log(C_ii_p1);
% This is the denominator of the subpixel three-point Gaussian fit in the ii direction
ii_den_fit=2*log(C_ii_n1)-4*log(C_ii_00)+2*log(C_ii_p1);
% This is the subpixel three-point Gaussian fit in the ii direction
ii_fit=ii_max+ii_num_fit/ii_den_fit;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This performs the three-point Gaussian fitting in the jj-direction. %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% These are the three points to fit in the jj-direction
if (jj_max>1)&&(jj_max<window_size(2));
% These are the three points to fit if the maximum is not on an edge
C_jj_n1=C(ii_max,jj_max-1,kk_max);
C_jj_00=C(ii_max,jj_max,kk_max);
C_jj_p1=C(ii_max,jj_max+1,kk_max);
elseif (jj_max==1);
% These are the three points to fit if the maximum is on the lower edge
C_jj_n1=C(ii_max,window_size(2),kk_max);
C_jj_00=C(ii_max,jj_max,kk_max);
C_jj_p1=C(ii_max,jj_max+1,kk_max);
elseif (jj_max==window_size(2));
% These are the three points to fit if the maximum is on the upper edge
C_jj_n1=C(ii_max,jj_max-1,kk_max);
C_jj_00=C(ii_max,jj_max,kk_max);
C_jj_p1=C(ii_max,1,kk_max);
end;
% This is the numerator of the subpixel three-point Gaussian fit in the jj direction
jj_num_fit=log(C_jj_n1)-log(C_jj_p1);
% This is the denominator of the subpixel three-point Gaussian fit in the jj direction
jj_den_fit=2*log(C_jj_n1)-4*log(C_jj_00)+2*log(C_jj_p1);
% This is the subpixel three-point Gaussian fit in the jj direction
jj_fit=jj_max+jj_num_fit/jj_den_fit;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This performs the three-point Gaussian fitting in the kk-direction. %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This checks whether the array is 3D and if not, sets the sub-pixel fit
% value to 1 (which transforms to zero velocity)
if size(C,3)==1;
% This sets the subpixel fit value in the 3rd dimension to one
kk_fit=1;
else;
% These are the three points to fit in the kk-direction
if (kk_max>1)&&(kk_max<window_size(3));
% These are the three points to fit if the maximum is not on an edge
C_kk_n1=C(ii_max,jj_max,kk_max-1);
C_kk_00=C(ii_max,jj_max,kk_max);
C_kk_p1=C(ii_max,jj_max,kk_max+1);
elseif (kk_max==1);
% These are the three points to fit if the maximum is on the lower edge
C_kk_n1=C(ii_max,jj_max,window_size(3));
C_kk_00=C(ii_max,jj_max,kk_max);
C_kk_p1=C(ii_max,jj_max,kk_max+1);
elseif (kk_max==window_size(3));
% These are the three points to fit if the maximum is on the upper edge
C_kk_n1=C(ii_max,jj_max,kk_max-1);
C_kk_00=C(ii_max,jj_max,kk_max);
C_kk_p1=C(ii_max,jj_max,1);
end;
% This is the numerator of the subpixel three-point Gaussian fit in the kk direction
kk_num_fit=log(C_kk_n1)-log(C_kk_p1);
% This is the denominator of the subpixel three-point Gaussian fit in the kk direction
kk_den_fit=2*log(C_kk_n1)-4*log(C_kk_00)+2*log(C_kk_p1);
% This is the subpixel three-point Gaussian fit in the kk direction
kk_fit=kk_max+kk_num_fit/kk_den_fit;
end;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This calculates the displacement vector from the sub-pixel fits. %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% This accounts for the origin being located at the (1,1,1) index
ii_fit=ii_fit-1;
jj_fit=jj_fit-1;
kk_fit=kk_fit-1;
% This accounts for the periodicity of the correlation volume for the ii displacement
if ii_fit>(window_size(1)/2);
ii_fit=ii_fit-window_size(1);
end;
% This accounts for the periodicity of the correlation volume for the jj displacement
if jj_fit>(window_size(2)/2);
jj_fit=jj_fit-window_size(2);
end;
% This accounts for the periodicity of the correlation volume for the kk displacement
if kk_fit>(window_size(3)/2);
kk_fit=kk_fit-window_size(3);
end;
% This is the displacement vector of the current window
displacement_vector=[ii_fit,jj_fit,kk_fit];
function I_Window=extract_correlation_window(I,window_size,window_min,window_max,image_size);
% This function extracts the current windows from the frame 'I' where
% 'window_size' is the size of the correlation window, 'window_min' and
% 'window_max' are the 1 x 3 vectors of the window minimum and maximum
% indices, and 'image_size' is the the size of the frame 'I'.
% These are the coordinate domains to extract
ii_min=window_min(1);
ii_max=window_max(1);
jj_min=window_min(2);
jj_max=window_max(2);
kk_min=window_min(3);
kk_max=window_max(3);
% This checks if the ii indices are outside the domain of the image and sets them to the
% domain of the image if true
if ii_min<1;
ii_min=1;
end;
if ii_max>image_size(1);
ii_max=image_size(1);
end;
% This checks if the jj indices are outside the domain of the image and sets them to the
% domain of the image if true
if jj_min<1;
jj_min=1;
end;
if jj_max>image_size(2);
jj_max=image_size(2);
end;
% This checks if the kk indices are outside the domain of the image and sets them to the
% domain of the image if true
if kk_min<1;
kk_min=1;
end;
if kk_max>image_size(3);
kk_max=image_size(3);
end;
% This extracts the current window from the frame
I_Window=I(ii_min:ii_max,jj_min:jj_max,kk_min:kk_max);
% This initilizes the image size vector
I_Window_Size=zeros(1,3);
% This is the size of the extracted image
I_Window_Size(1)=size(I_Window,1);
I_Window_Size(2)=size(I_Window,2);
I_Window_Size(3)=size(I_Window,3);
% If the extracted image is smaller than the full window size (due to the window being
% on the edge of the full image) this pads the image with zeros
if any(I_Window_Size~=window_size);
% This initializes an array of zeros the size of the full window
I_Window_Temp=zeros(window_size);
% These are the indices to insert the image into the zero padded image (the
% indices are centered in the window so that information is not lost during the
% masking process)
window_insert_min=floor((window_size-I_Window_Size)/2)+1;
window_insert_max=window_insert_min+I_Window_Size-1;
% This copies the current image from the frame into the window
I_Window_Temp(window_insert_min(1):window_insert_max(1),window_insert_min(2):window_insert_max(2),window_insert_min(3):window_insert_max(3))=I_Window;
% This renames the variable so that the zero-padded image is used
I_Window=I_Window_Temp;
end;
function p=determine_gaussian_size_2(window_size,resolution_size);
% This function is used to determine the diameter of a Gaussian function
% used to mask PIV windows to prevent aliasing during the Fourier
% transform.
%
% The input argument 'window_size' refers to the full size of
% the PIV window prior to performing the masking operation and may be a
% scaler or a vector. The input argument 'resolution_size' refers to the
% effective resolution that the user wants to attain from the masked PIV
% window, ie the window may be 64 x 64 in size (window_size=[64,64]) but
% the user wants the effective resolution after masking to be equal to 32 x
% 32 (resolution_size=[32,32]).
%
% The output argument 'p' is used to contruct the Gaussian masking function
% of the following form
%
% G(x) = exp(-((p*x)^2)/2) (1)
%
% where the independent variable lies in the domain
%
% -(window_size-1)/2 <= x <= (window_size-1)/2 (2)
%
% The variable 'p' is calculated by solving the integral equation
%
% resolution_size = int(G(x),-(window_size-1)/2,(window_size-1)/2) (3)
%
% or the equivalent expression
%
% resolution_size = sqrt(2*pi)*erf(window_size*p/(2*sqrt(2))/p (4)
%
% given by simplifying the integral. These equations are taken from
% "Assessment of advanced windowing techniques for digital particle image
% velocimetry (DPIV)" Eckstein 2009.
%
% This function is written to replace the 'findwidth' function in prana.
% The equation is solved by re-writing equation (4) in the form
%
% 0 = f(x) = erf(b*x)/x-a (5)
%
% and solving for the independent variable using Halley's method.
%
% Written By: Rod La Foy
% Written On: 6 June 2013
% These are the ratios of the resolution size to window size
size_ratio=resolution_size./window_size;
% This initializes the output vector p
p=zeros(size(window_size));
% This pre-computes the square root of pi for later use
pi_sqrt=sqrt(pi);
% This is the tolerance with which to find the root
tolerance=1e-4;
% This iterates through the number of dimensions to solve for (probably
% either 2 or 3)
for dimension_number=1:length(window_size);
% This checks if the size ratio is equal to one or greater
if size_ratio(dimension_number)>=1;
% This sets the Gaussian width variable to 0
p(dimension_number)=0;
else;
% This is the first constant term in the equation
a=resolution_size(dimension_number)/sqrt(2*pi);
% This is the second constant term in the equation
b=window_size(dimension_number)/(2*sqrt(2));
% This is the initial guess of value of the Gaussian width term
p_temp=1;
% This iterates to the root
while true;
% This is the error function of the b*p term
bp_erf=erf(b*p_temp);
% This is the exponential term of the (b*p)^2 term
bp_exp=exp((b*p_temp)^2);
% This is the numerator of the difference term
dp_numerator=a*p_temp-bp_erf;
% This initializes the denominator term
dp_denominator=0;
% This adds the first term to the denominator
dp_denominator=dp_denominator+a;
% This adds the second term to the denominator
dp_denominator=dp_denominator+2*b/(pi_sqrt*bp_exp);
% This adds the third term to the denominator
dp_denominator=dp_denominator+(2*b^3*p_temp^2*dp_numerator)/(2*b*p_temp-bp_exp*pi_sqrt*bp_erf);
% This is the expected difference to the root
dp=dp_numerator/dp_denominator;
% This is the new root approximation
p_temp=p_temp-dp;
% This breaks if the error is less then the tolerance
if abs(erf(b*p_temp)/p_temp-a)<tolerance;
% This breaks the loop
break;
end;
end;
% This is the Gaussian function diameter term
p(dimension_number)=p_temp;
end;
end;
function gaussian_window_filter=create_gaussian_filter(window_size,gaussian_width);
% This function creates a Gaussian filter to apply in the spatial domain to
% the correlation windows to remove the effects of aliasing
% This is the standard deviation of the filter
sigma=1./gaussian_width;
% These are the vectors of coordinates used to create the Gaussian function
ii_index_vector=linspace(-(window_size(1)-1)/2,(window_size(1)-1)/2,window_size(1));
jj_index_vector=linspace(-(window_size(2)-1)/2,(window_size(2)-1)/2,window_size(2));
kk_index_vector=linspace(-(window_size(3)-1)/2,(window_size(3)-1)/2,window_size(3));
% These are the full array of coordinates
[ii_index_array,jj_index_array,kk_index_array]=ndgrid(ii_index_vector,jj_index_vector,kk_index_vector);
% This creates the Gaussian function
gaussian_window_filter=exp(-(ii_index_array.^2)/(2*sigma(1)^2)-(jj_index_array.^2)/(2*sigma(2)^2)-(kk_index_array.^2)/(2*sigma(3)^2));
function [frame_1_window_min,frame_1_window_max,frame_2_window_min,frame_2_window_max,displacement_offset]=dwo_window_domains(window_min,window_max,window_center,image_correlation_step,ii_coordinates,jj_coordinates,kk_coordinates,ii_displacement,jj_displacement,kk_displacement);
% This function adds the discrete window offset to the window positions
% based upon the known velocity field. The non-offset window positions are
% given by the variables
%
% 'window_min'
% 'window_max'
% 'window_center'
%
% where these variables are N x 3 arrays where N is the total number of
% windows and column vectors correspond to the 1st, 2nd, and 3rd dimension
% coordinates. The known velocity field is given at the coordinates
%
% 'ii_coordinates'
% 'jj_coordinates'
% 'kk_coordinates'
%
% which are I x J x K arrays where I is the number of known vector
% coordinates in the 1st dimension, J is the number of known vector
% coordinates in the 2nd dimension, and K is the number of known vector
% coordinates in teh 3rd dimension. The known velocity field values are
% given by the arrays
%
% 'ii_displacement'
% 'jj_displacement'
% 'kk_displacement'
%
% which are also I x J x K in size. The output arrays
%
% 'frame_1_window_min'
% 'frame_1_window_max'
% 'frame_2_window_min'
% 'frame_2_window_max'
%
% are N x 3 vectors in size and given the minimum and maximum range of the
% first and second frames respectively. The output array
%
% 'displacement_offset'
%
% is also N x 3 in size and corresponds to the offset that must be added
% back to the measured velocity field due to the discrete window offset.
% This scales the velocity estimates by the number of number of frames
% between the correlations
ii_displacement=image_correlation_step*ii_displacement;
jj_displacement=image_correlation_step*jj_displacement;
kk_displacement=image_correlation_step*kk_displacement;
% This checks whether the array of velocity values is 2D or 3D and chooses
% the appropriate interpolotion function
if size(ii_coordinates,3)==1;
% If the vector field is greater then 3 x 3, then a cubic interpolation
% is performed, otherwise a linear interpolation is performed
if (size(ii_coordinates,1)>2)&&(size(ii_coordinates,2)>2);
% This is the estimated ii-displacement at the center of the windows
estimated_window_dii=interp2(ii_coordinates,jj_coordinates,ii_displacement,window_center(:,1),window_center(:,2),'cubic',0);
% This is the estimated jj-displacement at the center of the windows
estimated_window_djj=interp2(ii_coordinates,jj_coordinates,jj_displacement,window_center(:,1),window_center(:,2),'cubic',0);
% This is the estimated kk-displacement at the center of the windows
estimated_window_dkk=interp2(ii_coordinates,jj_coordinates,kk_displacement,window_center(:,1),window_center(:,2),'cubic',0);
else;
% This is the estimated ii-displacement at the center of the windows
estimated_window_dii=interp2(ii_coordinates,jj_coordinates,ii_displacement,window_center(:,1),window_center(:,2),'linear',0);
% This is the estimated jj-displacement at the center of the windows
estimated_window_djj=interp2(ii_coordinates,jj_coordinates,jj_displacement,window_center(:,1),window_center(:,2),'linear',0);
% This is the estimated kk-displacement at the center of the windows
estimated_window_dkk=interp2(ii_coordinates,jj_coordinates,kk_displacement,window_center(:,1),window_center(:,2),'linear',0);
end;
else;
% If the vector field is greater then 3 x 3, then a cubic interpolation
% is performed, otherwise a linear interpolation is performed
if (size(ii_coordinates,1)>2)&&(size(ii_coordinates,2)>2)&&(size(ii_coordinates,3)>2);
% This is the estimated ii-displacement at the center of the windows
estimated_window_dii=interp3(ii_coordinates,jj_coordinates,kk_coordinates,ii_displacement,window_center(:,1),window_center(:,2),window_center(:,3),'cubic',0);
% This is the estimated jj-displacement at the center of the windows
estimated_window_djj=interp3(ii_coordinates,jj_coordinates,kk_coordinates,jj_displacement,window_center(:,1),window_center(:,2),window_center(:,3),'cubic',0);
% This is the estimated kk-displacement at the center of the windows
estimated_window_dkk=interp3(ii_coordinates,jj_coordinates,kk_coordinates,kk_displacement,window_center(:,1),window_center(:,2),window_center(:,3),'cubic',0);
else;
% This is the estimated ii-displacement at the center of the windows
estimated_window_dii=interp3(ii_coordinates,jj_coordinates,kk_coordinates,ii_displacement,window_center(:,1),window_center(:,2),window_center(:,3),'linear',0);
% This is the estimated jj-displacement at the center of the windows
estimated_window_djj=interp3(ii_coordinates,jj_coordinates,kk_coordinates,jj_displacement,window_center(:,1),window_center(:,2),window_center(:,3),'linear',0);
% This is the estimated kk-displacement at the center of the windows
estimated_window_dkk=interp3(ii_coordinates,jj_coordinates,kk_coordinates,kk_displacement,window_center(:,1),window_center(:,2),window_center(:,3),'linear',0);
end;
end;
% This is half of the measured velocity at the window coordinates
rounded_half_estimated_displacement=round([estimated_window_dii,estimated_window_djj,estimated_window_dkk]/2);
% This calculates the first frame minimum domain values
frame_1_window_min=window_min-floor(rounded_half_estimated_displacement);
% This calculates the first frame maximum domain values
frame_1_window_max=window_max-floor(rounded_half_estimated_displacement);
% This calculates the second frame minimum domain values
frame_2_window_min=window_min+ceil(rounded_half_estimated_displacement);
% This calculates the second frame maximum domain values
frame_2_window_max=window_max+ceil(rounded_half_estimated_displacement);
% This is the offset that must be added back onto the measured velocity
% field of the current pass to account for the dicrete window offset
displacement_offset=ceil(rounded_half_estimated_displacement)+floor(rounded_half_estimated_displacement);
function [window_min,window_max,window_center,window_number]=calculate_window_domains(image_size,window_resolution,window_size,grid_spacing);
% This function calculates the minimum and maximum values of the window
% indices to extract from the image.
% These are the number of windows in each dimension
window_number=ceil((image_size-window_resolution)./grid_spacing); %ORIGINALLY window_number=ceil((image_size-window_resolution)./grid_spacing)+1
% This initializes the window indices
window_min=zeros(prod(window_number),3);
window_max=zeros(prod(window_number),3);
% This initializes the window centers
window_center=zeros(prod(window_number),3);
% This is the full resolution covered by the PIV windows (which will be equal to or larger
% than the resolution of the full image)
full_resolution=grid_spacing.*(window_number-1)+window_resolution;
% This is the distance in indices below 1 to start the windows
negative_index_distance=floor((full_resolution-image_size)/2);
% This is a counting variable for indexing the window domains
count=0;
% This calculates the window domains
for kk=1:window_number(3);
for jj=1:window_number(2);
for ii=1:window_number(1);
% This increments the counting variable
count=count+1;
% These are the minimum window indices
window_min(count,:)=([ii,jj,kk]-1).*grid_spacing-ceil((window_size-window_resolution)/2)-negative_index_distance+1;
% These are the maximum window indices
window_max(count,:)=window_min(count,:)+window_size-1;
% These are the window center indices
window_center(count,:)=(window_min(count,:)+window_max(count,:))/2 - 0.5;
window_min(count,:)
window_max(count,:)
end;
end;
end;
function spectral_filter=create_spectral_filter(window_size,particle_diameter);
% This function creates the RPC spectral energy filter with a size of 'window_size' using
% a particle diameter given by 'particle_diameter' where 'bit_depth' is the bit depth of
% the three-dimensional image to be processed.
% These are the wavenumber vectors
k_ii_vector=-pi:2*pi/window_size(1):pi-2*pi/window_size(1);
k_jj_vector=-pi:2*pi/window_size(2):pi-2*pi/window_size(2);
k_kk_vector=-pi:2*pi/window_size(3):pi-2*pi/window_size(3);
% These are the wavenumber coordinates
[k_ii,k_jj,k_kk]=ndgrid(k_ii_vector,k_jj_vector,k_kk_vector);
% This is the squared radius of the wavenumber
rho=k_ii.^2+k_jj.^2+k_kk.^2;
% None of the coefficients actually matter . . . so RPC filter is just a low pass filter . . .
spectral_filter=exp(-(rho*particle_diameter^2)/16);
function display_calculation_progress(current_value,value_vector);
% This function displays a progress bar showing the percent complete of the
% currently running calculation where the calculation is being iterated
% over the vector 'value_vector' and the current iteration's value is equal
% to 'current_value'. For example in the for loop
%
% for ii=1:10;
% commands . . .
% end;
%
% the arguments would be equal to
%
% current_value=ii;
% value_vector=1:10;
%
% This convention holds for non-integer or non-monotonic vectors, although
% to work correctly all values of value_vector must be unique.
% This is the number of characters to display in the pogress bar (denoted
% by either '#' or '-' characters)
progress_bar_character_number=50;
% This is the index of the value_vector that corresponds to the
% current_value
[null_variable,value_index]=min(abs(current_value-value_vector));
% This is the percentage of the calculation that is completed
current_progress_decimal=value_index/length(value_vector);
% This creates the character string showing the numerical and graphical
% progress for the current iteration
current_text_string=generate_progress_string(current_progress_decimal,progress_bar_character_number);
% If this is the first iteration, then a new line is added, the progress
% bar is displayed, and the function is exited
if value_index==1;
% This displays the portion of the string showing the percentage of
% the calculation that is complete that is new to this iteration
fprintf(current_text_string);
% This ends the function
return;
end;
% This is the percentage of the calculation that was completed during the
% last iteration
previous_progress_decimal=(value_index-1)/length(value_vector);
% This creates the character string showing the numerical and graphical
% progress for the previous iteration
previous_text_string=generate_progress_string(previous_progress_decimal,progress_bar_character_number);
% This compares the current progress string with the previous string and if
% they are the same, then the function exits. If they are different, then
% only the text after the difference is displayed.
if strcmp(current_text_string,previous_text_string);
% If this is the last time that the progress bar will be displayed, this
% prints a new line
if value_index==length(value_vector);
% This prints a new line after the progress bar
fprintf('\n');
end;
% This exits the function without changing the progress bar
return;
else;
% This is the total number of charcters to be displayed
string_character_number=length(current_text_string);
% This is the index into the string where the strings first differ
first_difference_index=find(not(current_text_string==previous_text_string),1,'first');
% These are the locations of the double percent signs '%%'
double_percent_indices=strfind(current_text_string,'%%');
% This removes the double percent indices that are before the first
% difference index
double_percent_indices(double_percent_indices<first_difference_index)=[];
% This is the number of characters of the previous line to delete
delete_character_number=string_character_number-first_difference_index+1-length(double_percent_indices);
% If this is the first iteration, then no characters are deleted
if value_index==1;
% This sets the number of characters to be deleted to zero
delete_character_number=0;
% This sets the first difference character to one
first_difference_index=1;
end;
% This deletes the previously displayed characters back to the first
% differing character (by displaying the 'backspace' character)
fprintf(1,repmat('\b',1,delete_character_number));
% This displays the portion of the string showing the percentage of
% the calculation that is complete that is new to this iteration
fprintf(current_text_string(first_difference_index:end));
% If this is the last time that the progress bar will be displayed, this
% prints a new line
if value_index==length(value_vector);
% This prints a new line after the progress bar
fprintf('\n');
end;
end;
function text_string=generate_progress_string(progress_decimal,progress_bar_character_number);
% This function generates the progress bar text that will be displayed for
% the current percentage of the calculation that is completed.
% This is a string giving a numerical value of the percentage of the
% calculation completed
numerical_progress_string=sprintf('% 4.0f',round(100*progress_decimal));
% This is the prefix to the progress bar showing the numerical value of the
% percent complete
string_prefix=['Calculation',numerical_progress_string,'%% Complete: 0%% ['];
% This is the suffix to the progress bar
string_suffix='] 100%%';
% This is the number of '#' signs to display corresponding to the graphical
% representation of the percent of the calculation that is complete
completed_character_number=round(progress_decimal*progress_bar_character_number);
% This is the number of '-' signs to display corresponding to the graphical
% representation of the percent of the calculation that remains
remaining_character_number=progress_bar_character_number-completed_character_number;
% This creates the string of characters representing the graphical
% percentage of the calculation that is complete
progress_bar_string=[repmat('#',1,completed_character_number),repmat('-',1,remaining_character_number)];
% This is the total text string to be displayed
text_string=[string_prefix,progress_bar_string,string_suffix];