Files
fold_slice/+beamline/tune_valid_mask.m
T
2026-08-07 15:56:42 +09:00

415 lines
16 KiB
Matlab
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
% Call function without arguments for instructions on how to use it
% Filename: $RCSfile: tune_valid_mask.m,v $
%
% $Revision: 1.5 $ $Date: 2012/09/02 15:13:40 $
% $Author: bunk $
% $Tag: $
%
% Description:
% remove outlyers of intensity that deviates from the azimuthal integration
% from the valid pixel mask
%
% Note:
% Call without arguments for a brief help text.
%
% Dependencies:
% - image_read
%
% history:
%
% May 21st 2010, Oliver Bunk:
% 1st version
%*-----------------------------------------------------------------------*
%|                                                                       |
%|  Except where otherwise noted, this work is licensed under a          |
%|  Creative Commons Attribution-NonCommercial-ShareAlike 4.0            |
%|  International (CC BY-NC-SA 4.0) license.                             |
%|                                                                       |
%|  Copyright (c) 2017 by Paul Scherrer Institute (http://www.psi.ch)    |
%|                                                                       |
%|      Author: CXS group, PSI  |
%*-----------------------------------------------------------------------*
% You may use this code with the following provisions:
%
% If the code is fully or partially redistributed, or rewritten in another
% computing language this notice should be included in the redistribution.
%
% If this code, or subfunctions or parts of it, is used for research in a
% publication or if it is fully or partially rewritten for another
% computing language the authors and institution should be acknowledged
% in written form in the publication: “Data processing was carried out
% using the “cSAXS matlab package” developed by the CXS group,
% Paul Scherrer Institut, Switzerland.”
% Variations on the latter text can be incorporated upon discussion with
% the CXS group if needed to more specifically reflect the use of the package
% for the published work.
%
% A publication that focuses on describing features, or parameters, that
% are already existing in the code should be first discussed with the
% authors.
%
% This code and subroutines are part of a continuous development, they
% are provided “as they are” without guarantees or liability on part
% of PSI or the authors. It is the user responsibility to ensure its
% proper use and the correctness of the results.
function [valid_mask] = tune_valid_mask(data_dir, varargin)
import beamline.radial_integ
import io.image_read
import plotting.display_valid_mask
import utils.find_files
% set default values for the variable input arguments:
% directory with the integrated data files
indir_integ_data = '~/Data10/analysis/radial_integration/';
% filename of the integrated data, empty to determine it from the raw data
% file name
filename_integ_data = [];
% use all cbf files
filename_mask = '*.cbf';
% filename for loading and saving the valid pixel mask
filename_valid_mask = '~/Data10/analysis/data/pilatus_valid_mask.mat';
% integration masks
filename_integ_masks = '~/Data10/analysis/data/pilatus_integration_masks.mat';
% size of the median filter that is use to smooth the data for identifying
% outlyers
median_size = 11;
% first pixel to start at
radius_from = 20;
% last pixel to check
radius_to = 0;
% only intensities above this threshold are considered for being hot
threshold_hot = 5;
% this value times the standard deviation of the intensity is used as hot pixel
% threshold
threshold_median = 3.0;
% save the updated mask
save_data = 0;
% display result in this figure
fig_no = 201;
% matching files to use
point_range = [];
% check minimum number of input arguments
if (nargin < 1)
fprintf('\nUsage:\n');
fprintf('[valid_mask]=%s(data_dir [[,<name>,<value>]...]);\n',mfilename);
fprintf('Remove outlyers from the valid pixel mask by comparing azimuthally integrated data\n');
fprintf('against the same data median filtered and rejecting pixels with a deviation\n');
fprintf('in intensity specified in multiples of the standard deviation.\n');
fprintf('\n');
fprintf('The optional <name>,<value> pairs are:\n');
fprintf('''FilenameMask'',<file specifier> specify the files to be used from the data directory, empty string for all, default is ''%s''\n',...
filename_mask);
fprintf('''PointRange'',<vector or []> matching files to use, default is [] for all files\n');
fprintf('''IndirIntegData'',<filename.mat> directory with the azimuthally integrated data, default is %s\n',...
indir_integ_data);
fprintf('''FilenameIntegData'',<filename.mat> filename for the azimuthally integrated data, empty to determine the name\n');
fprintf(' from the first raw data file name, default is ''%s''\n',...
filename_integ_data);
fprintf('''FilenameIntegMasks'',<filename> Matlab file containing the integration masks, default is ''%s''\n',filename_integ_masks);
fprintf('''RadiusFrom'',<integer> no. of the pixel to start with, default is %.0f\n',radius_from);
fprintf('''RadiusTo'',<integer> no. of the last pixel to check, default is %.0f\n',radius_to);
fprintf('''MedianSize'',<integer> size of the median filter in pixels, default is %.0f\n',...
median_size);
fprintf('''ThresholdHot'',<float> pixels above this value are considered for being hot, default is %d\n',...
threshold_hot);
fprintf('''ThresholdMedian'',<float> pixels outside the range (I+/-threshold_median*sqrt(I))\n');
fprintf(' of the median filtered data are considered to be hot,\n');
fprintf(' default is %.1f\n',...
threshold_median);
fprintf('''SaveData'',<0-no,1-yes> save the valid pixel mask, default is %d\n',save_data);
fprintf('''FilenameValidMask'',<path and filename> Matlab file with the valid pixel indices,\n');
fprintf(' default is %s\n',filename_valid_mask);
fprintf('''FigNo'',<integer> number of the figure in which the result is displayed, default is %d\n',...
fig_no);
fprintf('\n');
fprintf('Examples:\n');
fprintf('[valid_mask]=%s(''~/Data10/pilatus/S05000-05999/S05715/e12612_1_05715_00000_00000.cbf'');\n',...
mfilename);
fprintf('[valid_mask]=%s(''~/Data10/pilatus/S05000-05999/S05715/*.cbf'');\n',...
mfilename);
error('At least the filename of the raw data has to be specified as input parameter.');
end
% accept cell array with name/value pairs as well
no_of_in_arg = nargin;
if (nargin == 2)
if (isempty(varargin))
% ignore empty cell array
no_of_in_arg = no_of_in_arg -1;
else
if (iscell(varargin{1}))
% use a filled one given as first and only variable parameter
varargin = varargin{1};
no_of_in_arg = no_of_in_arg -1 + length(varargin);
end
end
end
% check number of input arguments
if (rem(no_of_in_arg,2) ~= 1)
error('The optional parameters have to be specified as ''name'',''value'' pairs');
end
% parse the variable input arguments:
% initialize the list of unhandled parameters
vararg_remain = cell(0,0);
for ind = 1:2:length(varargin)
name = varargin{ind};
value = varargin{ind+1};
switch name
case 'FilenameIntegMasks'
filename_integ_masks = value;
case 'FilenameMask'
filename_mask = value;
case 'PointRange'
point_range = value;
case 'IndirIntegData'
indir_integ_data = value;
case 'FilenameIntegData'
filename_integ_data = value;
case 'RadiusFrom',
radius_from = round(value);
case 'RadiusTo',
radius_to = round(value);
case 'MedianSize'
median_size = round(value);
case 'ThresholdMedian'
threshold_median = value;
case 'ThresholdHot'
threshold_hot = value;
case 'FilenameValidMask'
filename_valid_mask = value;
case 'SaveData'
save_data = value;
case 'FigNo'
fig_no = value;
otherwise
vararg_remain{end+1} = name; %#ok<AGROW>
vararg_remain{end+1} = value; %#ok<AGROW>
end
end
vararg_remain{end+1} = 'UnhandledParError';
vararg_remain{end+1} = 0;
vararg_remain{end+1} = 'DisplayFilename';
vararg_remain{end+1} = 0;
% set some default values for the plot window
set(0, 'DefaultAxesfontsize', 12);
set(0, 'DefaultAxeslinewidth', 1, 'DefaultAxesfontsize', 12);
set(0, 'DefaultLinelinewidth', 1);
% get all matching filenames
if (data_dir(end) ~= '/')
data_dir(end+1) = '/';
end
[data_dir,fnames,vararg_remain] = ...
find_files( [ data_dir filename_mask ], vararg_remain );
if (length(fnames) < 1)
error('No matching files found for %s%s.\n',data_dir,filename_mask);
end
% load the current valid pixel mask in variable valid_mask
fprintf('loading the existing valid mask %s\n',filename_valid_mask);
load(filename_valid_mask);
framesize = valid_mask.framesize(1) * valid_mask.framesize(2);
% load the integration masks in variable integ_masks
fprintf('Loading the integration masks from %s\n',filename_integ_masks);
load(filename_integ_masks);
no_of_radii = length(integ_masks.radius);
if ((radius_to < radius_from) || (radius_to > no_of_radii))
radius_to = no_of_radii;
end
% process the frames
ind_hot = [];
ind_dark = [];
integ_data = [];
fprintf('data directory is %s\n',data_dir);
if (isempty(point_range))
point_range = 1:length(fnames);
else
ind = find(point_range <= length(fnames));
if (length(point_range) ~= length(ind))
fprintf('Warning, %d value(s) from the specified point range are out of the range [1,%.0f] and not used.\n',...
length(point_range)-length(ind),length(fnames));
point_range = point_range(ind);
end
end
for (point_ind=1:length(point_range))
f_ind = point_range(point_ind);
% read the raw data
fprintf('%3d/%3d: reading %s%s\n',f_ind,length(point_range),...
data_dir,fnames(f_ind).name);
filename_raw = [data_dir fnames(f_ind).name ];
[frame] = image_read(filename_raw,vararg_remain);
% check that the files have identical dimensions
if ((size(frame.data,1) ~= valid_mask.framesize(1)) || ...
(size(frame.data,2) ~= valid_mask.framesize(2)))
error('The valid pixel mask has %d x %d pixels, this frame has %d x %d pixels',...
valid_mask.framesize(1),valid_mask.framesize(2),...
size(frame.data,1),size(frame.data,2));
end
% read the radially integrated data
if (isempty(integ_data))
% determine filename for the integrated data from the first raw
% data filename
if (isempty(filename_integ_data))
[pathstr, filename_integ_data] = fileparts(fnames(f_ind).name);
filename_integ_data = [ filename_integ_data '_integ.mat' ]; %#ok<AGROW>
end
filename_integ_data = fullfile(indir_integ_data,filename_integ_data);
fprintf('Loading the integrated intensities from %s\n',...
filename_integ_data);
integ_data = load(filename_integ_data);
% take the median of all segments with positive intensities, i.e.,
% skip negative intensities
I_all_prev = integ_data.I_all;
no_of_segments = size(I_all_prev,2);
no_of_points = size(I_all_prev,3);
I_all = zeros(no_of_radii,no_of_points);
I_std = zeros(no_of_radii,no_of_points);
if (no_of_segments > 1)
fprintf('Using the median of %d segments.\n',no_of_segments);
end
for (ind1=1:no_of_radii)
for (ind3=1:no_of_points)
no_of_el = 0;
I_use = zeros(1,no_of_segments);
ind_I_use = zeros(1,no_of_segments);
for (ind2=1:no_of_segments)
if (I_all_prev(ind1,ind2,ind3) >= 0)
no_of_el = no_of_el +1;
I_use(no_of_el) = I_all_prev(ind1,ind2,ind3);
ind_I_use(no_of_el) = ind2;
end
end
if (no_of_el > 1)
[I_sorted,ind_sorted] = sort(I_use(1:no_of_el));
ind_median = round(0.5*no_of_el);
I_all(ind1,ind3) = I_sorted(ind_median);
% get the standard deviation of this intensity
I_std(ind1,ind3) = integ_data.I_std(ind1,ind_I_use(ind_sorted(ind_median)),ind3);
end
end
end
% print this information once rather than for each file
fprintf('Checking radii from %d to %d.\n',radius_from,radius_to);
end
% get the index to the integrated data
ind = 1;
ind_max = length(integ_data.filenames_all);
while ((ind <= ind_max) && ...
(isempty(strfind(integ_data.filenames_all{ind},fnames(f_ind).name))))
ind = ind +1;
end
if (ind > ind_max)
error('Could not find integrated data for raw data file %s in %s.',...
filename_raw,filename_integ_data);
end
data_integ = squeeze(I_all(:,ind));
data_integ_std = squeeze(I_std(:,ind));
% median filtered data for comparison
data_integ_med = medfilt1(data_integ,median_size,size(data_integ,1),1);
% figure(fig_no+2);
% hold off;
% clf;
% semilogy(data_integ);
% hold all;
% semilogy(data_integ_med);
% semilogy(data_integ_med+data_integ_std*threshold_median);
% semilogy(data_integ_med-data_integ_std*threshold_median);
frame_cmp = ones(valid_mask.framesize) -2;
frame_cmp_std = zeros(valid_mask.framesize);
for (ind_r = radius_from:radius_to)
for (ind_seg = 1:no_of_segments)
if (integ_masks.norm_sum(ind_r,ind_seg) > 0)
frame_cmp(integ_masks.indices{ind_r,ind_seg}) = ...
data_integ_med(ind_r);
frame_cmp_std(integ_masks.indices{ind_r,ind_seg}) = ...
data_integ_std(ind_r);
end
end
end
%
ind_dark = union(ind_dark, ...
find((frame.data >= 0) & ...
(frame_cmp >= 0) & ...
(frame.data < frame_cmp - threshold_median*frame_cmp_std)));
% only consider pixels of sufficient intensity for being hot
ind_hot = union(ind_hot, ...
find((frame.data > threshold_hot) & ...
(frame_cmp >= 0) & ...
(frame.data > frame_cmp + threshold_median*frame_cmp_std)));
end
% calculate the complementary masks of the valid pixels
valid_mask.indices = intersect(valid_mask.indices,...
setdiff(1:framesize,union(ind_dark,ind_hot)));
fprintf('In total %d dark and %d hot pixels found.\n',...
length(ind_dark),length(ind_hot));
fprintf('%d valid pixels remain.\n',length(valid_mask.indices));
if (save_data)
% create a backup of the mask
if (exist(filename_valid_mask,'file'))
filename_mask_backup = [ filename_valid_mask '.bak' ];
fprintf('Copying the current mask %s to %s\n',filename_valid_mask,...
filename_mask_backup);
copyfile(filename_valid_mask,filename_mask_backup);
end
% save the masks
fprintf('Saving valid_mask to %s\n',filename_valid_mask);
save(filename_valid_mask,'valid_mask');
% plot new valid pixel mask
display_valid_mask('FilenameValidMask',filename_valid_mask,...
'NoHelp',1,'FigNo',fig_no);
else
fprintf('The updated valid pixel mask is NOT saved.\n');
end
% plot the additional invalid pixels
figure(fig_no+1);
% mark the valid pixels as 1, leave the invalid at 0
frame = zeros(valid_mask.framesize);
frame(valid_mask.indices) = 1;
frame(ind_dark) = -10;
frame(ind_hot) = 10;
imagesc(frame);
caxis([-10 10]);
axis xy;
axis equal;
axis tight;
colorbar;
title_str = ['valid pixels, ' ...
num2str(length(ind_dark)+length(ind_hot),'%d') ...
' update(s) marked with intensity -10/10'];
title(title_str);
set(gcf,'Name','valid pixels, updates marked');