diff --git a/zUtil_Deformation/Gt6DReconstructionAlgorithmFactory.m b/zUtil_Deformation/Gt6DReconstructionAlgorithmFactory.m index 2465838c51e4131ba99030ddb81e6b8bf6320c64..55410bbccad6c17f91bafae69de8c009819d03e9 100644 --- a/zUtil_Deformation/Gt6DReconstructionAlgorithmFactory.m +++ b/zUtil_Deformation/Gt6DReconstructionAlgorithmFactory.m @@ -47,6 +47,39 @@ classdef Gt6DReconstructionAlgorithmFactory < handle good_orients = algo_params.good_orients; blobs = algo_params.blobs; + % merging all the orientation-space super-sampling projection + % coefficients into one structure per orientation. This is needed in + % order to fwd/bwd-project all the different sub-orientations + % together. + if (~isempty(algo_params.geometries_ss)) + for ii_o = 1:numel(algo_params.offsets_ss) + offsets_ss = algo_params.offsets_ss{ii_o}; + new_offsets_ss = offsets_ss{1}; + cumulative_offs = numel(new_offsets_ss.proj); + + for ii_ss = 2:numel(offsets_ss) + new_offsets_ss.sino_offsets ... + = cat(2, new_offsets_ss.sino_offsets, offsets_ss{ii_ss}.sino_offsets + cumulative_offs); + new_offsets_ss.blob_offsets ... + = cat(2, new_offsets_ss.blob_offsets, offsets_ss{ii_ss}.blob_offsets); + new_offsets_ss.proj_offsets ... + = cat(2, new_offsets_ss.proj_offsets, offsets_ss{ii_ss}.proj_offsets); + new_offsets_ss.proj_coeffs ... + = cat(2, new_offsets_ss.proj_coeffs, offsets_ss{ii_ss}.proj_coeffs); + + num_projs = numel(offsets_ss{ii_ss}.proj); + for ii_p = 1:num_projs + offsets_ss{ii_ss}.proj(ii_p).sino_offset ... + = offsets_ss{ii_ss}.proj(ii_p).sino_offset + cumulative_offs; + end + new_offsets_ss.proj = cat(2, new_offsets_ss.proj, offsets_ss{ii_ss}.proj); + + cumulative_offs = cumulative_offs + num_projs; + end + algo_params.offsets_ss{ii_o} = new_offsets_ss; + end + end + algo = Gt6DBlobReconstructor(volume_size, blobs, ... 'data_type', self.data_type, ... 'geometries', algo_params.geometries, ... @@ -139,6 +172,8 @@ classdef Gt6DReconstructionAlgorithmFactory < handle end offsets = cat(1, offsets, orient_offsets); + % Shifting projection to the concatenated blobs, unless that + % blob was shared between parent and twin if (~isempty(geometries_ss)) orient_offsets_ss = algo_params(ii_g).offsets_ss; for ii_o = 1:numel(orient_offsets_ss) diff --git a/zUtil_Deformation/Gt6DVolumeProjector.m b/zUtil_Deformation/Gt6DVolumeProjector.m index 18fddd9932281235fcf69505f6d16f68ae14aa1c..8ca5b2491a9f872a23179e7b617d5ff5ce6500c4 100644 --- a/zUtil_Deformation/Gt6DVolumeProjector.m +++ b/zUtil_Deformation/Gt6DVolumeProjector.m @@ -52,14 +52,6 @@ classdef Gt6DVolumeProjector < handle if (~self.use_astra_projectors) self.volume_id = astra_mex_data3d('create', '-vol', self.astra_volume_geometry, 0); - else - if (~isempty(self.ss_geometries)) - try - self.use_astra_oss_projectors = astra_mex_direct_c('supports', 'FP3D_OSS') ... - && astra_mex_direct_c('supports', 'BP3D_OSS'); - catch - end - end end try @@ -143,19 +135,14 @@ classdef Gt6DVolumeProjector < handle 'GPUindex', -1 ); for g_ii = 1:num_ss_geoms - num_sub_ss_geoms = numel(self.ss_geometries{g_ii}); - self.astra_ss_projection_geometries{g_ii} = cell(num_sub_ss_geoms, 1); + ss_geom = cat(1, self.ss_geometries{g_ii}{:}); + + self.astra_ss_projection_geometries{g_ii} = astra_create_proj_geom(... + 'parallel3d_vec', self.proj_size(2), self.proj_size(1), ss_geom); + if (self.use_astra_projectors) - self.astra_ss_projectors{g_ii} = cell(num_sub_ss_geoms, 1); - end - for g_ss_ii = 1:num_sub_ss_geoms - self.astra_ss_projection_geometries{g_ii}{g_ss_ii} = astra_create_proj_geom(... - 'parallel3d_vec', self.proj_size(2), self.proj_size(1), self.ss_geometries{g_ii}{g_ss_ii}); - - if (self.use_astra_projectors) - self.astra_ss_projectors{g_ii}{g_ss_ii} = astra_create_projector('cuda3d', ... - self.astra_ss_projection_geometries{g_ii}{g_ss_ii}, self.astra_volume_geometry, opts); - end + self.astra_ss_projectors{g_ii} = astra_create_projector('cuda3d', ... + self.astra_ss_projection_geometries{g_ii}, self.astra_volume_geometry, opts); end end end @@ -171,74 +158,54 @@ classdef Gt6DVolumeProjector < handle methods (Access = protected) function ss_sinogram = fwd_project_single_volume_ss(self, volume, ii) - ss_geoms = self.astra_ss_projection_geometries{ii}; - num_ss_geoms = numel(ss_geoms); if (self.use_astra_projectors) if (numel(volume) == 1) volume = volume * ones(self.volume_geometry, 'single'); end - ss_projectors = self.astra_ss_projectors{ii}; else astra_mex_data3d('store', self.volume_id, volume); end - if (self.use_astra_oss_projectors) - ss_sinogram = astra_mex_direct_c('FP3D_OSS', [ss_projectors{:}], volume); + num_ss_geoms = numel(self.ss_geometries{ii}); + volume = volume ./ num_ss_geoms; + if (self.use_astra_projectors) + ss_sinogram = astra_mex_direct_c('FP3D', self.astra_ss_projectors{ii}, volume); else - volume = volume ./ num_ss_geoms; - ss_sinogram = cell(num_ss_geoms, 1); - for ii_ss = 1:num_ss_geoms - if (self.use_astra_projectors) - ss_sinogram{ii_ss} = astra_mex_direct_c('FP3D', ss_projectors{ii_ss}, volume); - else - sino_id = astra_mex_data3d('create', '-proj3d', ss_geoms{ii_ss}, 0); - - cfg = astra_struct('FP3D_CUDA'); - cfg.ProjectionDataId = sino_id; - cfg.VolumeDataId = self.volume_id; - - algo_id = astra_mex_algorithm('create', cfg); - astra_mex_algorithm('iterate', algo_id); - astra_mex_algorithm('delete', algo_id); - - ss_sinogram{ii_ss} = astra_mex_data3d('get_single', sino_id); - astra_mex_data3d('delete', sino_id); - end - end + sino_id = astra_mex_data3d('create', '-proj3d', self.astra_ss_projection_geometries{ii}, 0); + + cfg = astra_struct('FP3D_CUDA'); + cfg.ProjectionDataId = sino_id; + cfg.VolumeDataId = self.volume_id; + + algo_id = astra_mex_algorithm('create', cfg); + astra_mex_algorithm('iterate', algo_id); + astra_mex_algorithm('delete', algo_id); + + ss_sinogram = astra_mex_data3d('get_single', sino_id); + astra_mex_data3d('delete', sino_id); end end function volume = bwd_project_single_volume_ss(self, ss_sinogram, ii) - ss_geoms = self.astra_ss_projection_geometries{ii}; - num_ss_geoms = numel(ss_geoms); if (self.use_astra_projectors) - ss_projectors = self.astra_ss_projectors{ii}; - end - - if (self.use_astra_oss_projectors) - volume = astra_mex_direct_c('BP3D_OSS', [ss_projectors{:}], ss_sinogram); + volume = astra_mex_direct_c('BP3D', self.astra_ss_projectors{ii}, ss_sinogram); else - volume = cell(num_ss_geoms, 1); - for ii_ss = 1:num_ss_geoms - if (self.use_astra_projectors) - volume{ii_ss} = astra_mex_direct_c('BP3D', ss_projectors{ii_ss}, ss_sinogram{ii_ss}); - else - sino_id = astra_mex_data3d('create', '-proj3d', ss_geoms{ii_ss}, ss_sinogram{ii_ss}); - - cfg = astra_struct('BP3D_CUDA'); - cfg.ProjectionDataId = sino_id; - cfg.ReconstructionDataId = self.volume_id; - - algo_id = astra_mex_algorithm('create', cfg); - astra_mex_algorithm('iterate', algo_id); - astra_mex_algorithm('delete', algo_id); - - volume{ii_ss} = astra_mex_data3d('get_single', self.volume_id); - astra_mex_data3d('delete', sino_id); - end - end - volume = gtMathsSumCellVolumes(volume) ./ num_ss_geoms; + sino_id = astra_mex_data3d('create', '-proj3d', self.astra_ss_projection_geometries{ii}, ss_sinogram); + + cfg = astra_struct('BP3D_CUDA'); + cfg.ProjectionDataId = sino_id; + cfg.ReconstructionDataId = self.volume_id; + + algo_id = astra_mex_algorithm('create', cfg); + astra_mex_algorithm('iterate', algo_id); + astra_mex_algorithm('delete', algo_id); + + volume = astra_mex_data3d('get_single', self.volume_id); + astra_mex_data3d('delete', sino_id); end + + num_ss_geoms = numel(self.ss_geometries{ii}); + volume = volume ./ num_ss_geoms; end function sinogram = fwd_project_single_volume(self, volume, geom_idx) diff --git a/zUtil_Deformation/Gt6DVolumeToBlobProjector.m b/zUtil_Deformation/Gt6DVolumeToBlobProjector.m index f926af49bf9324a67419d3fe7fe71b2544304a7b..2a16699a01f3b7c59d014068dd35d474b59f95c8 100644 --- a/zUtil_Deformation/Gt6DVolumeToBlobProjector.m +++ b/zUtil_Deformation/Gt6DVolumeToBlobProjector.m @@ -115,14 +115,13 @@ classdef Gt6DVolumeToBlobProjector < Gt6DVolumeProjector c = tic(); ss_offsets_n = self.ss_offsets{n}; - for ii = 1:numel(sinos_ss) - if (self.blob_sinogram_c_functions) - blobs = gt6DSingleSinoToBlobs_c(... - blobs, sinos_ss{ii}, ss_offsets_n{ii}, self.num_threads); - else - blobs = self.single_sinogram_to_blobs(... - blobs, sinos_ss{ii}, ss_offsets_n{ii}); - end + + if (self.blob_sinogram_c_functions) + blobs = gt6DSingleSinoToBlobs_c(... + blobs, sinos_ss, ss_offsets_n, self.num_threads); + else + blobs = self.single_sinogram_to_blobs(... + blobs, sinos_ss, ss_offsets_n); end bs_time = toc(c); end @@ -132,24 +131,18 @@ classdef Gt6DVolumeToBlobProjector < Gt6DVolumeProjector % difference that in this case the input is blobs and we want to % transform them into stack of sinograms - geoms_ss = self.ss_geometries{n}; ss_offsets_n = self.ss_offsets{n}; - num_sub_ss_geoms = numel(geoms_ss); - sinos_ss = cell(num_sub_ss_geoms, 1); - c = tic(); - for ii = 1:num_sub_ss_geoms - sinogram_size = [ ... - self.proj_size(1), size(geoms_ss{ii}, 1), self.proj_size(2)]; - - if (self.blob_sinogram_c_functions) - sinos_ss{ii} = gt6DBlobsToSingleSino_c( ... - sinogram_size, blobs, ss_offsets_n{ii}, self.num_threads); - else - sinos_ss{ii} = self.blobs_to_single_sinogram(... - sinogram_size, blobs, ss_offsets_n{ii}); - end + sinogram_size = [ ... + self.proj_size(1), numel(ss_offsets_n.proj), self.proj_size(2)]; + + if (self.blob_sinogram_c_functions) + sinos_ss = gt6DBlobsToSingleSino_c( ... + sinogram_size, blobs, ss_offsets_n, self.num_threads); + else + sinos_ss = self.blobs_to_single_sinogram(... + sinogram_size, blobs, ss_offsets_n); end bs_time = toc(c);