gtForwardSimulate_v2.m 29.71 KiB
function out = gtForwardSimulate_v2(first, last, workingdirectory, phaseID, varargin)
% GTFORWARDSIMULATE_V2 Finds missing diffraction spots and updates grain structure
% out = gtForwardSimulate_v2(first, last, workingdirectory, phaseID, varargin)
% ----------------------------------------------------------------------------
%
% INPUT:
% first = <int> first grainid
% last = <int> last grainid
% workingdirectory = <string> working directory
% phaseID = <int> phase number {1}
%
% OPTIONAL INPUT (varargin):
% bb_size = <int> size of search area ([] will use default projection size)
% assemble_figure = <logical> collects all difspots and assembles them into a fullimage
% save_grain = <logical> flag to save grain_###.mat {true}
%
% OUTPUT:
% out = <struct> : updated grain structure. Fields:
% - difstack <double XxYxN> stack of normalized difspots
% - proj_geom <double Nx12> input for grain reconstruction
% / forward projection using roi (hsize, vsize)
% - proj_geom_full <double Nx12> input for grain reconstruction
% / forward projection (full images)
% - proj_geom_abs <double Nx12> input for grain reconstruction
% / forward projection of extinction spots
% - ondet <double N> indices of those spots (from the list in allblobs)
% which are expected on the detector
% - uvw <double Nx3> spot positions on the detector
% - hklsp <double Nx3(4)> signed hk(i)l of reflection
% - flag <int Nx3> status flag indicating result of forward simulation
% - allblobs <struct> forward simulation output produced by gtFedGenerateRandomGrain
%
% We will classify spots with a flag [1...5]:
% - 1 : 'No intensity at expected spot position'
% - 2 : 'Found intensity in FULL images at predicted position'
% - 3 : 'Found segmented difspot at expected position - but position
% / size do not match strict criteria'
% - 4 : 'Found segmented difspot in database matching the strict
% search criteria' - we will use theoretically predicted
% angles for reconstruction
% - 5 : 'Difspot is part of a pair identified by INDEXTER' - use
% Friedelpair information for reconstruction
%
% Version 003 14-06-2012 by LNervo
% Use gtFsimDefaultParameters
%
% Version 004 21/06/2012 by AKing
% Trivial change to make segbb zeros(1,6)
%
% Version 005 05/03/2013 by Nicola Vigano (nicola.vigano@esrf.fr)
% Re-structured completely, to be more clear and easy to debug.
%
% SUB-FUNCTIONS:
%[sub]- sfGetRoi
if isdeployed
global GT_DB
global GT_MATLAB_HOME
load('workspaceGlobal.mat');
end
cd(workingdirectory);
gtDBConnect();
parameters = [];
load('parameters.mat');
acq = parameters.acq;
samgeo = parameters.samgeo;
labgeo = parameters.labgeo;
if isfield(parameters,'fsim')
fsim = parameters.fsim;
else
fsim = gtFsimDefaultParameters();
end
if ~isfield(fsim, 'save_grain')
fsim.save_grain = true;
end
if (~exist('phaseID', 'var') || isempty(phaseID))
phaseID = 1;
end
if isdeployed
first = str2double(first);
last = str2double(last);
phaseID = str2double(phaseID);
fsim.display_figure = false;
else
% in interactive mode we can modify parameters
fsim = parse_pv_pairs(fsim, varargin);
end
phaseID_str = sprintf('phase_%02d', phaseID);
phases_num = length(parameters.cryst); % number of phases in the material
grainfilename = fullfile(parameters.acq.dir, '4_grains', phaseID_str, 'index.mat');
fprintf('\nLoading indexing results...\n');
grains = load(grainfilename);
totGrains = length(grains.grain);
if (last > totGrains)
warning('gtForwardSimulate_v2:wrong_parameter', ...
'Last was bigger than the total number of grains, setting it to max')
last = totGrains;
end
difspotfile = fullfile(parameters.acq.dir, '2_difspot', 'difspot00001.edf');
if exist(difspotfile, 'file');
info = edf_info(difspotfile);
else
info = [];
end
%%% this section should be replaced with a function dealing with different
% versions of parameters names: fed, v1, v2...
detdiru0 = labgeo.detdiru; % will use detdiru0 to distinguish from rotated version of this vector
detdirv0 = labgeo.detdirv;
% !!! using a mean pixel size is uncertain; ideally fwd simulation should
% use mm-s
pixelsize = mean([labgeo.pixelsizeu, labgeo.pixelsizev]);
% detector reference position in pixels
detrefpos = labgeo.detrefpos ./ pixelsize;
% the (0,0) corner of the detector in Lab system (edge of detector pixel)
detposcorner = gtGeoDetOrig(labgeo) ./ pixelsize;
rotComp = gtMathsRotationMatrixComp(labgeo.rotdir, 'row');
getRotationTensor = @(x)gtMathsRotationTensor(-x, rotComp);
fprintf('\nLoading reflections from database...\n');
% Initialization of spot table and info about pairs
segmentedSpots = initializeSpotsRecords(parameters.acq.name);
pairsTable = getPairsTable(parameters.acq.pair_tablename);
difspot_num = numel(segmentedSpots.difspotID); % number of difspots in database
spot2grain = cell(difspot_num, 1); % cell array linking difspots with grainids
spot2phase = cell(difspot_num, 1);
filetable = [parameters.acq.name '_filetable'];
filename = fullfile(parameters.acq.dir, '4_grains', 'spot2grain.mat');
spotTable = GtMergeTable(filetable, filename, {'spot2grain', 'spot2phase'});
samplefile = fullfile(parameters.acq.dir, '4_grains', 'sample.mat');
sample = GtSample.loadFromLockedFile(filetable, samplefile);
% initialise sample structure
phase = GtPhase(parameters.cryst(phaseID).name, totGrains);
sample.phases{phaseID} = phase;
for n = first : last
fprintf('\nRunning forward simulation for grain %d...\n',n);
gr = grains.grain{n}; % output from INDEXTER
% graincenter contains COM coordinates in pixels
graincenter_pix = gr.center ./ pixelsize;
%%% Predict spot positions
gr = gtCalculateGrain(gr, parameters);
u = gr.allblobs.uv(:, 1);
v = gr.allblobs.uv(:, 2);
%%% Get:
% - average difspot X and Y sizes for the current spots in the grain
% - theshold values used during the database search
% - offset in possible lateral grain orientation
% - diffstack Vertical and Horizontal sizes
spotsCommProps = getDiffractionSpotsCommonProperties(gr, fsim, detrefpos);
% radial distances of spot center from detector center
% !!! to be corrected: detrefu and detrefv can be anywhere, not
% necessarily in the center
radiuses = sqrt((u - labgeo.detrefu).^2 + (v - labgeo.detrefv).^2);
%%% Get the indices of all spots which fully intersect the active
% region of the detector
onDet = findSpotsOnDetector(parameters, spotsCommProps, u, v, radiuses);
% Maximum offset (in number of images) from the predicted omega position
% allow for a 1/sin(eta) dependency of this value - limited to a
% maximum angular offset of fsim.MaxOmegaOffset degrees: this could be
% improved...
maxOffsetThrs = getThresholdsMaxOffset(fsim, gr, getOmegaStepSize(parameters));
image_nums = round(gr.allblobs.omega / getOmegaStepSize(parameters));
% Converts from SoA to AoS
spotsPositions = buildSpotsPositions(onDet, u, v, image_nums, maxOffsetThrs);
numspots = numel(onDet); % number of exspected diffraction spots
flag = ones(numspots, 1); % see above
% stack of zero padded diffraction spots (projections used for 3D reconstruction)
difstack = zeros(spotsCommProps.stackHSize, numspots, spotsCommProps.stackVSize);
bb = zeros(numspots, 4); % difspot BoundingBox from database
spotid = zeros(numspots, 1); % Mysql difspottable difspotID
check = zeros(numspots, 2);
omega = zeros(numspots, 1); % rotation angle in degrees
% Vector used for ROI grain reconstruction in ASTRA (grain shifted to center of roi volume)
proj_geom = zeros(numspots, 12);
% Vector describing full projection geometry (full images, grain at nominal position in sample volume)
proj_geom_full = zeros(numspots, 12);
% Vector describung absorption image projection geometry
proj_geom_abs = zeros(numspots, 12);
U = zeros(numspots, 1); % COM u positions of difspots from difspottable
V = zeros(numspots, 1); % COM v positions of difspots from difspottable
full = zeros(acq.ydet, acq.xdet);
tempIsSpotA = false(numspots, 1);
%%% Forward simulation:
% We try to match the reflections with the segmented spots, so we
% examine all hklsp and search corresponding spots / intensity on the
% detector..
for ii = 1 : numspots
reflectionPos = spotsPositions(ii);
% Look for difspots appying loose search criteria - is there any intensity at the predicted spot
% position ? Choose the one which is closest to the expected size
candidateIDs = findCandidates(spotsCommProps, reflectionPos, segmentedSpots);
if isempty(candidateIDs)
% NO CANDIDATES FOUND:
% segmentation / overlap / intensity / ... problem ?
% If requested, we will check into the raw images later.
continue;
end
% in case there are several candidates, take the one which has
% the Area close to the expected Area. This selection "rule"
% could be improved... err appears to be not respected!
[~, area_index] = sort(abs( ...
segmentedSpots.BoundingBoxXsize(candidateIDs) .* segmentedSpots.BoundingBoxYsize(candidateIDs) ...
- spotsCommProps.Xsize * spotsCommProps.Ysize));
[~, image_index] = sort(abs(segmentedSpots.CentroidImage(candidateIDs) - reflectionPos.img_num));
matchedID = candidateIDs(image_index(1));
U(ii) = segmentedSpots.CentroidX(matchedID);
V(ii) = segmentedSpots.CentroidY(matchedID);
bb(ii, :) = [...
segmentedSpots.BoundingBoxXorigin(matchedID), segmentedSpots.BoundingBoxYorigin(matchedID), ...
segmentedSpots.BoundingBoxXsize(matchedID), segmentedSpots.BoundingBoxYsize(matchedID) ];
% Found a segmented difspot at expected position - we will check if it does match strict criteria
cent_ok = sqrt( (U(ii) - reflectionPos.u).^2 + (V(ii) - reflectionPos.v).^2 ) <= spotsCommProps.Offset;
size_ok = all( [...
between(bb(ii, 3), spotsCommProps.XsizeMin, spotsCommProps.XsizeMax), ...
between(bb(ii, 4), spotsCommProps.YsizeMin, spotsCommProps.YsizeMax) ] );
check(ii, :) = [cent_ok, size_ok];
isSpotA = ~isempty(find(gr.difspotidA == matchedID, 1));
isSpotB = ~isempty(find(gr.difspotidB == matchedID, 1));
if (isSpotA || isSpotB)
% This spot is part of a pair and has been used by INDEXTER
flag(ii) = 5;
tempIsSpotA(ii) = isSpotA;
elseif all(check(ii,:))
flag(ii) = 4;
else
flag(ii) = 3;
end
spotid(ii) = matchedID;
end
%%% Re-check flag == 1, to see if there's intensity at the predicted
% position, if requesred.
if (fsim.check_spot)
toBeChecked = find(flag == 1);
for ii = reshape(toBeChecked, [1 numel(toBeChecked)]);
reflectionPos = spotsPositions(onDet(ii));
[full, found_intensity] = checkSpotInRawImages(full, ...
reflectionPos, fsim, spotsCommProps, parameters);
if (found_intensity)
% Found intensity in FULL images at predicted position
flag(ii) = 2;
end
end
end
% Reflections that have been matched to segmented spots
matched = find(flag >= 3);
%%% We now build the diffraction stack
for ii = reshape(matched, [1 numel(matched)])
spot = buildSpot(spotid(ii), parameters, info, spotsCommProps, bb(ii, :));
if (fsim.assemble_figure)
full = gtPlaceSubImage2(spot, full, bb(ii, 1), bb(ii, 2), 'summed');
end
% Essentially zero pads the spot to make it fit into ASTRA's
% diffraction stack
shifts = getDiffStackShifts(spotsCommProps, bb(ii, :));
spot = gtPlaceSubImage2(spot, ...
zeros(spotsCommProps.stackVSize, spotsCommProps.stackHSize), ...
shifts.h + 1, shifts.v + 1, 'summed');
difstack(:, ii, :) = spot';
end
%%% We now Build ASTRA's geometry
for ii = reshape(matched, [1 numel(matched)])
% If available, we want to use the angles as determined from
% the Friedel pairs - interrogate spotpair table
%
% diffBeamDir: direction of diffracted beam used in ASTRA
if (flag(ii) == 5)
[diffBeamDir, omega(ii)] = getFriedelPair(pairsTable, spotid(ii), tempIsSpotA(ii));
omegaRotTens = getRotationTensor(omega(ii));
else
% we found a segmentedd spot - can use the theoretically
% predicted direction or apparent direction (based on COM of
% grain and spot) for backprojection
% theoretically prediceted omega angle
if (fsim.use_th)
currentReflection = onDet(ii);
% use theoretically predited directions (default)
omega(ii) = gr.allblobs.omega(currentReflection);
omegaRotTens = getRotationTensor(omega(ii));
pl = gr.allblobs.pl(currentReflection, :);
theta = gr.allblobs.theta(currentReflection);
% theoretically predicted beam direction
diffBeamDir = labgeo.beamdir * omegaRotTens + 2 * sind(theta) * pl;
else
% use experimentally determined omega angles
omega(ii) = segmentedSpots.CentroidImage(spotid(ii)) * getOmegaStepSize(parameters);
omegaRotTens = getRotationTensor(omega(ii));
% projection direction as inferred from grain / spot
% center positions
diffBeamDir = gtGeoDiffVecInSample([U(ii), V(ii)], omega(ii), gr.center, labgeo, samgeo);
end
end
%%% Now we actually build the geometry
shifts = getDiffStackShifts(spotsCommProps, bb(ii, :));
% position of Detector
detPos = detposcorner ...
+ (bb(ii, 1) - shifts.h - 1 + spotsCommProps.stackHSize/2) * detdiru0 ...
+ (bb(ii, 2) - shifts.v - 1 + spotsCommProps.stackVSize/2) * detdirv0;
detAbs = detposcorner ...
+ (acq.bb(1) - 1 + acq.bb(3)/2) * detdiru0 ...
+ (acq.bb(2) - 1 + acq.bb(4)/2) * detdirv0;
detdiru = detdiru0 * omegaRotTens;
detdirv = detdirv0 * omegaRotTens;
% take into account the coordinate shift corresponding to the offset
% of the reconstructed volume
detPos = detPos * omegaRotTens - graincenter_pix;
detAbs = detAbs * omegaRotTens;
absBeamDir = labgeo.beamdir * omegaRotTens;
% Compact version, since they're all <1x3> vectors, so we can read
% them easily
proj_geom(ii, :) = [diffBeamDir, detPos, detdiru, detdirv];
proj_geom_abs(ii, :) = [absBeamDir, detAbs, detdiru, detdirv];
% Calculate the projection geometry for the full images as well
% labgeo.detrefu: detector u (line direction) reference point (center) in lab
% labgeo.detrefv: detector v (column direction )reference point (center) in lab
detposFull = detposcorner + labgeo.detrefu * detdiru0 + labgeo.detrefv * detdirv0;
proj_geom_full(ii, :) = proj_geom(ii,:);
proj_geom_full(ii, 4:6) = (detposFull * omegaRotTens);
end % loop over predicted spot positions
included = find(flag >= fsim.included);
% indices of the selected spots in list of included spots
selected = find(flag(included) >= fsim.selected);
%%% Now fill in the information for the output
% remove reflections for which no segmented spot has been found
out.selected = selected; % vector of logicals with pre-selected spots active
out.id = gr.id;
out.phaseid = phaseID;
out.center = graincenter_pix;
out.ondet = onDet;
out.allblobs = gr.allblobs;
out.full = full;
out.flag = flag;
out.check = check;
out.pairid = gr.pairid;
out.difspotID = spotid(included);
out.omega = omega(included);
% signed hk(i)l indices of reflection
hklsp = gr.allblobs.hklsp(out.ondet, :);
out.hklsp = hklsp(included, :);
out.uvw = gr.allblobs.uvw(out.ondet(included), :);
out.uv_exp = [U(included), V(included)];
out.bb = bb(included, :);
found_reflections = length(find(flag > 1));
out.completeness = found_reflections / numspots;
out.proj.stack = difstack(:, included, :);
out.proj.geom = proj_geom(included, :);
out.proj.geom_full = proj_geom_full(included, :);
out.proj.geom_abs = proj_geom_abs(included, :);
out.proj.num_rows = spotsCommProps.stackVSize;
out.proj.num_cols = spotsCommProps.stackHSize;
% We should in the future handle properly vertical detector (general geometry)
oversizeVol = fsim.oversizeVol / fsim.oversize;
out.proj.vol_size_x = round(spotsCommProps.stackHSize * oversizeVol);
out.proj.vol_size_y = round(spotsCommProps.stackHSize * oversizeVol);
out.proj.vol_size_z = round(spotsCommProps.stackVSize * oversizeVol);
out.proj.num_iter = parameters.rec.num_iter;
out.vol = [];
out.segbb = zeros(1,6);
out.threshold = 0;
out.shift(1) = round((acq.bb(3)-out.proj.vol_size_x)/2 + out.center(1)) + 1;
out.shift(2) = round((acq.bb(3)-out.proj.vol_size_y)/2 + out.center(2)) + 1;
out.shift(3) = round((acq.bb(4)-out.proj.vol_size_z)/2 + out.center(3)) + 1;
if (fsim.display_figure)
out.full = full;
gtShowFsim(out)
end
if (fsim.save_grain)
filename = fullfile(acq.dir, '4_grains', phaseID_str, ...
sprintf('grain_%04d.mat', gr.id));
save(filename, '-struct', 'out');
end
spot2grain(out.difspotID) = {n};
spot2phase(out.difspotID) = {phaseID};
sample.phases{phaseID}.setR_vector(n, gr.R_vector);
sample.phases{phaseID}.setCompleteness(n, out.completeness);
sample.phases{phaseID}.setCenter(n, out.center);
sample.phases{phaseID}.setSelectedDiffspots(n, out.selected);
if (isempty(out.selected))
warning('gtForwardSimulate_v2:bad_value', ...
'No spot was selected! This will make reconstruction impossible')
elseif (numel(out.selected) < 10)
warning('gtForwardSimulate_v2:bad_value', ...
'Too few selected spots! This will give a very bad reconstruction')
end
if (~fsim.check_spot)
fprintf(['Completeness estimates may be too pessimistic - activate ' ...
'option ''check_spot'' for more reliable results\n'])
end
fprintf('\n Grain number %d:\n', n);
newspots = length(find(flag == 4));
fprintf(['Forward simulation found intensity at %d out of %d expected ' ...
'spot positions \n'], found_reflections, numspots);
fprintf('Completeness estimate: %f\n', out.completeness);
fprintf('%d spots will be used for reconstruction\n', length(out.selected));
fprintf(['%d new spots have been detected in addition to the %d ' ...
'spotpairs identified by INDEXTER\n'], newspots, gr.nof_pairs);
end
spotTable.fillTable(spot2grain, 'spot2grain');
spotTable.fillTable(spot2phase, 'spot2phase');
sample.mergeToFile(filetable, samplefile, 'sample');
end % end of function
%%% sub-functions
function [spot, m] = getRawRoi(start_image, end_image, acq, bb)
% GTFORWARDSIMULATE/SFGETROI Sums a roi in raw images
nimages = end_image - start_image + 1;
spot = zeros(bb(4), bb(3), nimages);
m = zeros(nimages, 1);
centerx = round((bb(3)/2 -5) : (bb(3)/2 +5));
centery = round((bb(4)/2 -5) : (bb(4)/2 +5));
if all([bb(1) > 0, bb(2) > 0, bb(1)+bb(3) < acq.xdet, bb(2)+bb(4) < acq.ydet])
fullImgsDir = fullfile(acq.dir, '1_preprocessing', 'full');
indexes = start_image : end_image;
filename = fullfile(fullImgsDir, sprintf('full%04d.edf', indexes(1)));
info = edf_info(filename);
for img_n = 1:nimages
fullImgName = fullfile(fullImgsDir, sprintf('full%04d.edf', indexes(img_n)));
spot(:, :, img_n) = edf_read(fullImgName, bb, [], info);
m(img_n) = gtImgMeanValue(spot(centery, centerx, img_n));
end
end
end
function spotsRecords = initializeSpotsRecords(dataset_name)
difspottable = [dataset_name 'difspot'];
% Load difspot data in 'allspots' / spotpair data in 'allpairs'
query = [ ...
'SELECT difspotID, CentroidX, CentroidY, CentroidImage, '...
'BoundingBoxXsize, BoundingBoxYsize, BoundingBoxXorigin, ' ...
'BoundingBoxYorigin'...
' FROM ' difspottable ];
[difspotIDs, CentroidXs, CentroidYs, CentroidImages, BoundingBoxXsizes, ...
BoundingBoxYsizes, BoundingBoxXorigins, BoundingBoxYorigins] = mym(query);
% create vectors of size (numspots,1) (these will have some empty elements since
% not all difspotIDs exist (some are filtered out because fo size
% restrictions, for example)
numspots = max(difspotIDs);
spotsRecords = [];
spotsRecords.difspotID = NaN(numspots, 1);
spotsRecords.CentroidX = NaN(numspots, 1);
spotsRecords.CentroidY = NaN(numspots, 1);
spotsRecords.CentroidImage = NaN(numspots, 1);
spotsRecords.BoundingBoxXsize = NaN(numspots, 1);
spotsRecords.BoundingBoxYsize = NaN(numspots, 1);
spotsRecords.BoundingBoxXorigin = NaN(numspots, 1);
spotsRecords.BoundingBoxYorigin = NaN(numspots, 1);
orderedPositions = 1:numspots;
spotsRecords.difspotID(difspotIDs) = difspotIDs;
spotsRecords.CentroidX(difspotIDs) = CentroidXs(orderedPositions);
spotsRecords.CentroidY(difspotIDs) = CentroidYs(orderedPositions);
spotsRecords.CentroidImage(difspotIDs) = CentroidImages(orderedPositions);
spotsRecords.BoundingBoxXsize(difspotIDs) = BoundingBoxXsizes(orderedPositions);
spotsRecords.BoundingBoxYsize(difspotIDs) = BoundingBoxYsizes(orderedPositions);
spotsRecords.BoundingBoxXorigin(difspotIDs) = BoundingBoxXorigins(orderedPositions);
spotsRecords.BoundingBoxYorigin(difspotIDs) = BoundingBoxYorigins(orderedPositions);
end
function pairsTable = getPairsTable(pairtable_name)
query = [ ...
'SELECT ldirX, ldirY, ldirZ, omega, omegaB, difAID, difBID' ...
' FROM ' pairtable_name ];
[pairsTable.ldirX, pairsTable.ldirY, pairsTable.ldirZ, ...
pairsTable.omegaA, pairsTable.omegaB, ...
pairsTable.difAID, pairsTable.difBID ] = mym(query);
end
function thrs_max_offset = getThresholdsMaxOffset(fsim, gr, omstep)
maxOff = fsim.MaxOmegaOffset;
omegarange = fsim.omegarange;
etas = sind(gr.allblobs.eta);
spotsOff = omegarange ./ abs( etas );
thrs_max_offset = round(min(maxOff, spotsOff) / omstep);
end
function spotsProps = getDiffractionSpotsCommonProperties(gr, fsim, detrefpos_pix)
%%% Get the average difspot X and Y sizes for the current spots in the grain,
spotsProps = [];
spotsProps.Xsize = gr.stat.bbxsmean; % average X Size of difspots
spotsProps.Ysize = gr.stat.bbysmean; % average Y Size of difspots
% define theshold values which will be used during the database search later
% - limit to 5 pixels minimum width
spotsProps.XsizeMin = max(5, spotsProps.Xsize - fsim.bbsize_factor * gr.stat.bbxsstd);
spotsProps.XsizeMax = spotsProps.Xsize + fsim.bbsize_factor * gr.stat.bbxsstd;
spotsProps.YsizeMin = max(5, spotsProps.Ysize - fsim.bbsize_factor * gr.stat.bbysstd);
spotsProps.YsizeMax = spotsProps.Ysize + fsim.bbsize_factor * gr.stat.bbysstd;
% allow for a lateral deviation of spot postions based on grain orientation statics
% dif_props.Offset = fsim.Rdist_factor * gr.stat.Rdiststd * norm(detrefpos_pix)
% !!! detrefpos is not necessarily the distance; depends on definition by user
spotsProps.Offset = fsim.Rdist_factor * deg2rad(gr.stat.dangstd) * norm(detrefpos_pix);
grainBBox = [max(gr.bbxs), max(gr.bbys)];
% take the biggest spot and add a relative extra margin (multiplicative factor oversize)
spotsProps.stackHSize = round(grainBBox(1) * fsim.oversize);
% ...same for vertical direction
spotsProps.stackVSize = round(grainBBox(2) * fsim.oversize);
end
function ondet = findSpotsOnDetector(parameters, dif_props, u, v, radius)
%%% Get the indices of all spots which fully intersect the active region of the detector
ondet = find(all([u > dif_props.Xsize/2, u < parameters.acq.xdet - dif_props.Xsize/2 , ...
v > dif_props.Ysize/2, v < parameters.acq.ydet - dif_props.Ysize/2, ...
radius < parameters.acq.maxradius], 2));
% Exclude spots which overlap with segmentation boundingbox
seg = find(all([( (u + dif_props.Xsize/2 > parameters.seg.bbox(1)) ...
& (u - dif_props.Xsize/2 < parameters.seg.bbox(1) + parameters.seg.bbox(3))), ...
( (v + dif_props.Ysize/2 > parameters.seg.bbox(2)) ...
& (v - dif_props.Ysize/2 < parameters.seg.bbox(2) + parameters.seg.bbox(4)))], 2));
ondet = setdiff(ondet, seg); % indices of spots intersection active area of detector
end
function [full, found_intensity] = checkSpotInRawImages(full, spotPos, ...
fsim, spotsCommProps, parameters)
% number of images summed up when searching raw data for a missing spot
imagerange = round(fsim.omegarange / getOmegaStepSize(parameters));
% in case bb_size for search BoundingBox (used for check of
% completeness) is empty, use the same size as the difspot stack
if isempty(fsim.bb_size)
bbhsize = spotsCommProps.stackHSize;
bbvsize = spotsCommProps.stackVSize;
else
bbhsize = fsim.bb_size(1);
bbvsize = fsim.bb_size(2);
end
% Adjust search bbox in order to avoid reading information
% stemming from regions outside the image border
bbox_ustart = round(spotPos.u - bbhsize/2);
bbox_vstart = round(spotPos.v - bbvsize/2);
bbox_uend = min(parameters.acq.xdet, bbox_ustart + bbhsize);
bbox_vend = min(parameters.acq.ydet, bbox_vstart + bbvsize);
bbox(1) = max(1, bbox_ustart);
bbox(2) = max(1, bbox_vstart);
bbox(3) = (bbox_uend - bbox_ustart + 1);
bbox(4) = (bbox_vend - bbox_vstart + 1);
start_image = max(0, spotPos.img_num - imagerange);
end_image = min(spotPos.img_num + imagerange, 2*parameters.acq.nproj - 1);
% read in small image stack at predicted position read ROI from
% raw images - meanVals are the mean value for each image in the stack
[raw_img, meanVals] = getRawRoi(start_image, end_image, parameters.acq, bbox);
[intensity, ~] = max(meanVals);
meanIntensity = sum(raw_img(:)) / (spotsCommProps.Xsize * spotsCommProps.Xsize * spotsCommProps.Ysize);
raw_img = sum(raw_img, 3) / meanIntensity;
if (fsim.assemble_figure)
full = gtPlaceSubImage2(raw_img, full, bbox(1), bbox(2), 'summed');
end % app.assemble_figure
% Checks if found intensity in FULL images at predicted position
found_intensity = (intensity > parameters.seg.thr_grow_low);
end
function [diffBeamDir, omega] = getFriedelPair(pairsTab, spotID, isSpotA)
if (isSpotA)
idx = find(pairsTab.difAID == spotID);
omega = pairsTab.omegaA(idx);
diffBeamDir = [pairsTab.ldirX(idx), pairsTab.ldirY(idx), pairsTab.ldirZ(idx)];
else
idx = find(pairsTab.difBID == spotID);
omega = pairsTab.omegaB(idx);
% in this case we have to reverse the line direction
diffBeamDir = -[pairsTab.ldirX(idx), pairsTab.ldirY(idx), pairsTab.ldirZ(idx)];
end
end
function spotsPositions = buildSpotsPositions(ondet, u, v, image_nums, thrs_max_offset)
spotsPositions = arrayfun(@(x)assignEntry(x, u, v, image_nums, thrs_max_offset), ondet);
function spotPos = assignEntry(currentSpotID, u, v, image_nums, thrs_max_offset)
spotPos = [];
spotPos.u = u(currentSpotID);
spotPos.v = v(currentSpotID);
spotPos.img_num = image_nums(currentSpotID);
spotPos.thr_max_offset = thrs_max_offset(currentSpotID);
end
end
function spot = buildSpot(candidateID, parameters, info, spotsCommProps, bb)
info.dim_1 = bb(3);
info.dim_2 = bb(4);
spot = gtGetSummedDifSpot(candidateID, parameters, 1, info);
% here we force the intensity to be the same in all spots -
volume = spotsCommProps.Xsize * spotsCommProps.Xsize * spotsCommProps.Ysize;
spot = spot / sum(spot(:)) * volume;
end
function candidateIDs = findCandidates(spotsProps, reflPos, segmentedSpots)
image_ok = find(...
(segmentedSpots.CentroidImage >= (reflPos.img_num - reflPos.thr_max_offset) ) ...
& (segmentedSpots.CentroidImage <= (reflPos.img_num + reflPos.thr_max_offset) ));
spotsXsize = abs(segmentedSpots.CentroidX(image_ok) - reflPos.u);
spotsYsize = abs(segmentedSpots.CentroidY(image_ok) - reflPos.v);
maxXsize = max(spotsProps.Xsize, segmentedSpots.BoundingBoxXsize(image_ok) - spotsProps.Xsize) / 2;
maxYsize = max(spotsProps.Ysize, segmentedSpots.BoundingBoxYsize(image_ok) - spotsProps.Ysize) / 2;
intensity_ok = (spotsXsize < maxXsize) & (spotsYsize < maxYsize);
candidateIDs = image_ok(intensity_ok);
end
function omstep = getOmegaStepSize(parameters)
omstep = 180 / parameters.acq.nproj;
end
function shifts = getDiffStackShifts(spotsCommProps, bb)
shifts.h = round((spotsCommProps.stackHSize - bb(3)) / 2);
shifts.v = round((spotsCommProps.stackVSize - bb(4)) / 2);
end