From 798ed7c70ed509c9d2dce95e2c3df40e71f7fe62 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 15 Nov 2018 17:04:51 +0100 Subject: add geometry draw files without changes --- matlab/algorithms/plot_geom/__main.m | 44 ++++ matlab/algorithms/plot_geom/create_example_cone.m | 165 ++++++++++++++ .../algorithms/plot_geom/create_example_fanflat.m | 50 ++++ .../plot_geom/create_example_parallel3d.m | 30 +++ .../algorithms/plot_geom/draw/create_gui_figure.m | 58 +++++ .../algorithms/plot_geom/draw/draw_cad_phantom.m | 37 +++ matlab/algorithms/plot_geom/draw/draw_cone_geom.m | 73 ++++++ .../algorithms/plot_geom/draw/draw_cone_vec_geom.m | 108 +++++++++ .../algorithms/plot_geom/draw/draw_detector_vec.m | 42 ++++ .../algorithms/plot_geom/draw/draw_fanflat_geom.m | 25 ++ .../plot_geom/draw/draw_fanflat_vec_geom.m | 103 +++++++++ .../plot_geom/draw/draw_parallel3d_geom.m | 88 +++++++ .../plot_geom/draw/draw_parallel3d_vec_geom.m | 100 ++++++++ .../algorithms/plot_geom/draw/draw_proj_geometry.m | 142 ++++++++++++ matlab/algorithms/plot_geom/draw/draw_vol_geom.m | 99 ++++++++ matlab/algorithms/plot_geom/stl/bunny.stl | Bin 0 -> 47484 bytes .../algorithms/plot_geom/util/cone_to_cone_vec.m | 41 ++++ matlab/algorithms/plot_geom/util/eucl_dist3d.m | 16 ++ .../plot_geom/util/fanflat_to_fanflat_vec.m | 4 + matlab/algorithms/plot_geom/util/magnify_proj.m | 23 ++ .../plot_geom/util/parseargs/license.txt | 27 +++ .../plot_geom/util/parseargs/parseargs.m | 97 ++++++++ matlab/algorithms/plot_geom/util/rotate_around3d.m | 27 +++ matlab/algorithms/plot_geom/util/rotate_detector.m | 19 ++ matlab/algorithms/plot_geom/util/rotate_euler3d.m | 35 +++ .../algorithms/plot_geom/util/stlTools/license.txt | 34 +++ .../algorithms/plot_geom/util/stlTools/readme.txt | 16 ++ .../plot_geom/util/stlTools/stlAddVerts.m | 15 ++ .../plot_geom/util/stlTools/stlDelVerts.m | 26 +++ .../algorithms/plot_geom/util/stlTools/stlDemo.m | 39 ++++ .../plot_geom/util/stlTools/stlGetFormat.m | 38 ++++ .../plot_geom/util/stlTools/stlGetVerts.m | 31 +++ .../algorithms/plot_geom/util/stlTools/stlPlot.m | 23 ++ .../algorithms/plot_geom/util/stlTools/stlRead.m | 13 ++ .../plot_geom/util/stlTools/stlReadAscii.m | 56 +++++ .../plot_geom/util/stlTools/stlReadBinary.m | 60 +++++ .../plot_geom/util/stlTools/stlSlimVerts.m | 29 +++ .../algorithms/plot_geom/util/stlTools/stlWrite.m | 252 +++++++++++++++++++++ matlab/algorithms/plot_geom/util/translate_3d.m | 18 ++ 39 files changed, 2103 insertions(+) create mode 100644 matlab/algorithms/plot_geom/__main.m create mode 100644 matlab/algorithms/plot_geom/create_example_cone.m create mode 100644 matlab/algorithms/plot_geom/create_example_fanflat.m create mode 100644 matlab/algorithms/plot_geom/create_example_parallel3d.m create mode 100644 matlab/algorithms/plot_geom/draw/create_gui_figure.m create mode 100644 matlab/algorithms/plot_geom/draw/draw_cad_phantom.m create mode 100644 matlab/algorithms/plot_geom/draw/draw_cone_geom.m create mode 100644 matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m create mode 100644 matlab/algorithms/plot_geom/draw/draw_detector_vec.m create mode 100644 matlab/algorithms/plot_geom/draw/draw_fanflat_geom.m create mode 100644 matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m create mode 100644 matlab/algorithms/plot_geom/draw/draw_parallel3d_geom.m create mode 100644 matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m create mode 100644 matlab/algorithms/plot_geom/draw/draw_proj_geometry.m create mode 100644 matlab/algorithms/plot_geom/draw/draw_vol_geom.m create mode 100644 matlab/algorithms/plot_geom/stl/bunny.stl create mode 100644 matlab/algorithms/plot_geom/util/cone_to_cone_vec.m create mode 100644 matlab/algorithms/plot_geom/util/eucl_dist3d.m create mode 100644 matlab/algorithms/plot_geom/util/fanflat_to_fanflat_vec.m create mode 100644 matlab/algorithms/plot_geom/util/magnify_proj.m create mode 100644 matlab/algorithms/plot_geom/util/parseargs/license.txt create mode 100644 matlab/algorithms/plot_geom/util/parseargs/parseargs.m create mode 100644 matlab/algorithms/plot_geom/util/rotate_around3d.m create mode 100644 matlab/algorithms/plot_geom/util/rotate_detector.m create mode 100644 matlab/algorithms/plot_geom/util/rotate_euler3d.m create mode 100644 matlab/algorithms/plot_geom/util/stlTools/license.txt create mode 100644 matlab/algorithms/plot_geom/util/stlTools/readme.txt create mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlAddVerts.m create mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlDelVerts.m create mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlDemo.m create mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlGetFormat.m create mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlGetVerts.m create mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlPlot.m create mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlRead.m create mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlReadAscii.m create mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlReadBinary.m create mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlSlimVerts.m create mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlWrite.m create mode 100644 matlab/algorithms/plot_geom/util/translate_3d.m diff --git a/matlab/algorithms/plot_geom/__main.m b/matlab/algorithms/plot_geom/__main.m new file mode 100644 index 0000000..607a242 --- /dev/null +++ b/matlab/algorithms/plot_geom/__main.m @@ -0,0 +1,44 @@ +%% main.m +% brief small tool to render astra geometries in matlab +% +% date 20.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% +% - last update 09.07.2018 +%% +% close all; + +[h_gui, is_running] = create_gui_figure(); + +%proj_geom = create_example_cone('vec'); +%proj_geom = create_example_cone('normal'); +%proj_geom = create_example_cone('helix'); +proj_geom = create_example_parallel3d('vec'); +%proj_geom = create_example_fanflat('vec'); +%proj_geom = create_example_fanflat(); +%proj_geom = create_example_parallel3d(); + +draw_proj_geometry(proj_geom, h_gui); +hold on; + +vol_magn = 10; +phantom_size = 5; +phantom_px = 1500; +vx_size = phantom_size / phantom_px; % voxel size +vol_geom = astra_create_vol_geom(phantom_px, phantom_px, phantom_px); +line_width = 1; % line width for phantom +draw_vol_geom(vol_geom, vx_size, h_gui, 'Magnification', vol_magn,... + 'LineWidth', line_width, 'Color', 'r'); + +% this magnification is empirically chosen to fit the stl file +cad_magn = 350; +draw_cad_phantom('stl/bunny.stl', cad_magn, h_gui); + +proj_geom = create_example_cone('deform_vec'); +draw_proj_geometry(proj_geom, h_gui, 'VectorIdx', 3, 'Color', 'b',... + 'RotationAxis', [0,0,1]); + +hold off; +axis equal; diff --git a/matlab/algorithms/plot_geom/create_example_cone.m b/matlab/algorithms/plot_geom/create_example_cone.m new file mode 100644 index 0000000..598899f --- /dev/null +++ b/matlab/algorithms/plot_geom/create_example_cone.m @@ -0,0 +1,165 @@ +function [ proj_geom ] = create_example_cone(type) +%% create_example_cone.m +% create an example standard cone beam geometry +% param type type of geometry to create. provided as one of the +% following strings (not case sensitive): +% 'normal' - standard (non vector) geometry +% 'vec' - example vector geometry +% 'helix' - helical trajectory vector geometry +% 'deform_vec' - deformed vector geometry example, +% courtesy of Van Nguyen +% return proj_geom - the geometry that was created +% +% date 21.06.2018 +% author Tim Elberfeld, Alice Presenti, Van Nguyen +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + if(nargin < 1) + type = 'normal'; + end + if strcmpi(type, 'normal') + % first, give measurements in mm + det_spacing = [0.035, 0.035]; + detector_px = [1200, 1200]; + angles = linspace2(0, 2*pi, 100); + source_origin = 30; + origin_det = 200; + phantom_size = 5; + + phantom_px = 150; % voxels for the phantom + vx_size = phantom_size / phantom_px; % voxel size + + % now express all measurements in terms of the voxel size + det_spacing = det_spacing ./ vx_size; + origin_det = origin_det ./ vx_size; + source_origin = source_origin ./ vx_size; + + proj_geom = astra_create_proj_geom('cone', det_spacing(1), ... + det_spacing(2), detector_px(1), detector_px(2), angles,... + source_origin, origin_det); + + elseif strcmpi(type, 'vec') + proj_geom = create_standard_vec_geom(); + + elseif strcmpi(type, 'deform_vec') + proj_geom = create_deform_vec_geom(); + + elseif strcmpi(type, 'helix') + detRows = 220; + detCols = 220; + detPitchX = 10^-3 * 11; % microns to mm + detPitchY = 10^-3 * 11; % microns to mm + objSrcDist = 500; % mm + rotStep = 3.6; % deg + numAngles = 200; + zTranslation = 0.5; % mm + zDist = zTranslation * numAngles; + vectors = zeros(numAngles, 12); + translation = -zDist + (zTranslation * (0:(numAngles-1))); + + minAngle = 0; % just assume we start at 0 + maxAngle = (numAngles * rotStep)/180 * pi; % convert deg to rad + angles = linspace(minAngle, maxAngle, 200); + + % source position per angle + vectors(:, 1) = sin(angles) * objSrcDist; + vectors(:, 2) = -cos(angles) * objSrcDist; + vectors(:, 3) = translation; + + % detector position per angle + vectors(:, 4) = 0; + vectors(:, 5) = 0; + vectors(:, 6) = translation; + + % vector from detector pixel (0,0) to (0,1) + vectors(:, 7) = cos(angles); + vectors(:, 8) = sin(angles); + vectors(:, 9) = zeros(numAngles, 1); + + % vector from detector pixel (0,0) to (1, 0) + vectors(:, 10) = zeros(numAngles, 1); + vectors(:, 11) = zeros(numAngles, 1); + vectors(:, 12) = ones(numAngles, 1); + + proj_geom = astra_create_proj_geom('cone_vec', detCols, detRows, vectors); + + else + proj_geom = create_standard_vec_geom(); + end + + function [proj_geom, z_axis] = create_standard_vec_geom() + % geometry settings taken from code from Alice Presenti + settings = struct; + settings.detectorPixelSize = 0.0748; + % detector size and number of projections + settings.projectionSize = [1536 1944 21]; + settings.SOD = 679.238020; %[mm] + settings.SDD = 791.365618; %[mm] + settings.voxelSize = 1; %[mm] + settings.gamma = linspace(0,300,21)*pi/180; + + S0 = zeros(settings.projectionSize(3), 12); + Sorig = [-settings.SOD, 0, 0,... % the ray origin vector (source) + (settings.SDD-settings.SOD), 0, 0,... % detector center + 0, -settings.detectorPixelSize, 0,... % detector u axis + 0, 0, settings.detectorPixelSize]; % detector v axis + + z_axis = [0, 0, 1]; + for i = 1:settings.projectionSize(3) + S0(i,:) = Sorig(:); + S0(i,1:3) = rotate_around3d(S0(i,1:3),... + z_axis, settings.gamma(i)); + S0(i,4:6) = rotate_around3d(S0(i,4:6), z_axis,... + settings.gamma(i)); + S0(i,7:9) = rotate_around3d(S0(i,7:9), z_axis,... + settings.gamma(i)); + S0(i,10:12) = rotate_around3d(S0(i,10:12),... + z_axis, settings.gamma(i)); + end + proj_geom = astra_create_proj_geom('cone_vec', ... + settings.projectionSize(2), settings.projectionSize(1), S0); + end + + function [proj_geom, z_axis] = create_deform_vec_geom() + settings = struct; + settings.detectorPixelSize = 0.0748; + settings.projectionSize = [1536 1944 21]; + settings.SOD = 679.238020; %[mm] + settings.SDD = 791.365618; %[mm] + settings.voxelSize = 1; %[mm] + settings.gamma = linspace(0,300,21)*pi/180; + + S0 = zeros(settings.projectionSize(3), 12); + Sorig = [-settings.SOD, 0, 0,... % the ray origin vector (source) + (settings.SDD-settings.SOD), 0, 0,... % detector center + 0, -settings.detectorPixelSize, 0,... % detector u axis + 0, 0, settings.detectorPixelSize]; % detector v axis + + z_axis = [0, 0, 1]; + for i = 1:settings.projectionSize(3) + S0(i,:) = Sorig(:); + end + + S0(:, 1:3) = translate_3d(S0(:, 1:3), [100, 150, 0]); + S0(:, 4:6) = translate_3d(S0(:, 4:6), [100, 150, 0]); + + S0 = rotate_detector(S0, [0.48,0.32,0]); + S0 = magnify_proj(S0, 100); + for i = 1:settings.projectionSize(3) + S0(i,1:3) = rotate_around3d(S0(i,1:3), z_axis,... + settings.gamma(i)); + S0(i,4:6) = rotate_around3d(S0(i,4:6), z_axis,... + settings.gamma(i)); + S0(i,7:9) = rotate_around3d(S0(i,7:9), z_axis,... + settings.gamma(i)); + S0(i,10:12) = rotate_around3d(S0(i,10:12), z_axis,... + settings.gamma(i)); + end + + proj_geom = astra_create_proj_geom('cone_vec',... + settings.projectionSize(2), settings.projectionSize(1), S0); + end + +end diff --git a/matlab/algorithms/plot_geom/create_example_fanflat.m b/matlab/algorithms/plot_geom/create_example_fanflat.m new file mode 100644 index 0000000..703a618 --- /dev/null +++ b/matlab/algorithms/plot_geom/create_example_fanflat.m @@ -0,0 +1,50 @@ +function [ geom ] = create_example_fanflat( type ) +%% create_example_fanflat.m +% brief create an example geometry of type 'fanflat' +% param type type of geometry to create. provided as one of the +% following strings (not case sensitive): +% 'normal' - standard fanflat geometry +% 'vec' - example vector geometry +% return proj_geom - the geometry that was created +% date 22.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + if nargin < 1 + type = 'normal'; + end + + if strcmpi(type, 'normal') + geom = make_normal_geometry(); + elseif strcmpi(type, 'vec') + geom = create_example_fanflat('normal'); + geom = fanflat_to_fanflat_vec(geom); + + else + geom = make_normal_geometry(); + end + + function [geom] = make_normal_geometry() + % first, give measurements in mm + det_spacing = 0.035; + detector_px = 1200; + angles = linspace2(0, 2*pi, 100); + source_origin = 30; + origin_det = 200; + phantom_size = 5; + + phantom_px = 150; % voxels for the phantom + vx_size = phantom_size / phantom_px; % voxel size + + % now express all measurements in terms of the voxel size + det_spacing = det_spacing ./ vx_size; + origin_det = origin_det ./ vx_size; + source_origin = source_origin ./ vx_size; + + geom = astra_create_proj_geom('fanflat', det_spacing, ... + detector_px, angles, source_origin, origin_det); + end +end + diff --git a/matlab/algorithms/plot_geom/create_example_parallel3d.m b/matlab/algorithms/plot_geom/create_example_parallel3d.m new file mode 100644 index 0000000..e6fdf8e --- /dev/null +++ b/matlab/algorithms/plot_geom/create_example_parallel3d.m @@ -0,0 +1,30 @@ +function [ proj_geom ] = create_example_parallel3d( type ) +%% create_example_parallel3d.m +% brief create an example geometry of type 'parallel3d' +% param type type of geometry to create. provided as one of the +% following strings (not case sensitive). +% no arguments will create a standard fanflat geometry. +% 'vec' - example vector geometry + +% return proj_geom - the geometry that was created +% date 22.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + if nargin < 1 + type = 'nothing'; + end + + det_spacing = [0.035, 0.035]; + detector_px = [1000, 1000]; + angles = linspace(0, 2*pi, 100); + + proj_geom = astra_create_proj_geom('parallel3d', det_spacing(1),... + det_spacing(2), detector_px(1), detector_px(2), angles); + + if strcmp(type, 'vec') + proj_geom = astra_geom_2vec(proj_geom); + end +end diff --git a/matlab/algorithms/plot_geom/draw/create_gui_figure.m b/matlab/algorithms/plot_geom/draw/create_gui_figure.m new file mode 100644 index 0000000..a9acecf --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/create_gui_figure.m @@ -0,0 +1,58 @@ +function [h_ax, running] = create_gui_figure() +%% create_gui_figure.m +% brief gui for the geometry drawing functions +% return h_ax axis to draw into with draw_*() functions +% running state of the rotation, needs to be passed so that +% the callback will work +% date 20.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + h_figure = figure('name', 'geometry render', 'ButtonDownFcn', @toggle_rotation); + h_ax = axes(h_figure); + + set(h_figure,'CloseRequestFcn', @handle_close_fig) + + xlabel('x axis') + ylabel('y axis') + zlabel('z axis') + + grid on + box off + axis vis3d + axis equal + view(0,0) + + running = false; + do_rotation(); + + function [] = handle_close_fig(h_figure,~) + % this is necessary to stop the rotation before closing the figure + if running + toggle_rotation() + end + + delete(h_figure); + end + + function [] = toggle_rotation(~, ~) + % toggle rotation state + running = ~running; + if running + view(0,0) + do_rotation(); + else + view(45,45); + end + end + + function [] = do_rotation() + % rotate the rendered geometry around the origin + camtarget([0,0,0]); % make origin the camera target and point around which to rotate + while running + camorbit(0.5,0,'camera') + drawnow + end + end +end \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/draw/draw_cad_phantom.m b/matlab/algorithms/plot_geom/draw/draw_cad_phantom.m new file mode 100644 index 0000000..18873a8 --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/draw_cad_phantom.m @@ -0,0 +1,37 @@ +function [] = draw_cad_phantom(filename, magn, h_ax) +%% draw_cad_phantom.m +% brief render an stl model into a 3d axis object +% param vol_geom volume geometry describing the phantom +% param magn magnification multiplier of the phantom. default = 1 +% param h_ax handle to axis to plot into +% +% date 02.07.2018 +% author Alice Presenti +% imec VisionLab +% University of Antwerp +% Modified by Tim Elberfeld +%% + if nargin == 1 + magn = 1; + end + if nargin == 2 + h_ax = axes(gcf); + end + + [v,f,~,~] = stlRead(filename); + m = mean(v); % to center the CAD model! + for i=1:3 + v(:,i) = (v(:,i)- m(i)) .* magn; + end + object.vertices = v; + object.faces = f; + patch(h_ax, object,'FaceColor', [0.8 0.8 1.0], ... + 'EdgeColor', 'none', ... + 'FaceLighting', 'gouraud', ... + 'AmbientStrength', 0.15); + % Add a camera light, and tone down the specular highlighting + camlight('headlight'); + material('dull'); + hold off; + +end \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/draw/draw_cone_geom.m b/matlab/algorithms/plot_geom/draw/draw_cone_geom.m new file mode 100644 index 0000000..ae98294 --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/draw_cone_geom.m @@ -0,0 +1,73 @@ +function [] = draw_cone_geom(h_ax, geom, options) +%% draw_cone_geom.m +% draw an astra cone beam projection geometry +% +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options struct containing the options for this function +% SourceMarker marker to use to mark the source location +% SourceMarkerColor Color of the marker for the source +% DetectorLineColor Color of the lines that draw the detector +% DetectorLineWidth Width of the lines that draw the detector +% OpticalAxisColor color of the lines representing the optical axis +% +% date 21.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + hold on; + % draw origin + h_origin = scatter3(h_ax, 0,0,0, '+k'); + h_origin.SizeData = 120; + h_origin.LineWidth = 2; + + % draw lines between source, origin and detector + line(h_ax, [0, 0], [0, geom.DistanceOriginDetector], [0, 0], 'Color', options.OpticalAxisColor); + line(h_ax, [0, 0], [0, -geom.DistanceOriginSource], [0, 0], 'Color', options.OpticalAxisColor); + + % draw source + scatter3(h_ax, 0, -geom.DistanceOriginSource, 0, options.SourceMarker,... + options.SourceMarkerColor); + + detector = draw_detector(h_ax, geom, options); + + % connect source to detector edges + for idx = 1:4 + line(h_ax,[0, detector.vertices(1, idx)], ... + [-geom.DistanceOriginSource, geom.DistanceOriginDetector],... + [0, detector.vertices(3, idx)],... + 'Color', 'k', 'LineStyle', ':'); + end + + % draw rotation axis + line(h_ax, [0,0],[0,0], 0.6*[-detector.height, detector.height],... + 'LineWidth', options.DetectorLineWidth, 'Color',... + 'k', 'LineStyle', '--'); + + perc = 0.05; + text(h_ax, perc*detector.width, perc*detector.width,... + 0.8*detector.height, 'rotation axis'); + text(h_ax, detector.width*perc, 0, perc*detector.height, 'origin'); + text(h_ax, detector.width*perc, -geom.DistanceOriginSource,... + perc*detector.height, 'x-ray source'); + text(h_ax, 0, geom.DistanceOriginDetector, 0, 'detector'); + hold off; + + function [detector] = draw_detector(h_ax, geom, options) + detector = struct; + detector.height = geom.DetectorRowCount * geom.DetectorSpacingY; + detector.width = geom.DetectorColCount * geom.DetectorSpacingX; + + vertices = zeros(3, 5); + vertices(1, :) = 0.5*[-detector.width, -detector.width,... + detector.width, detector.width, -detector.width]; + vertices(2, :) = repmat([geom.DistanceOriginDetector], 5, 1); + vertices(3, :) = 0.5*[detector.height, -detector.height,... + -detector.height, detector.height, detector.height]; + + detector.vertices = vertices; + plot3(h_ax, detector.vertices(1, :), detector.vertices(2, :),... + detector.vertices(3, :), options.DetectorLineColor); + end +end diff --git a/matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m b/matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m new file mode 100644 index 0000000..c1ed5b0 --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m @@ -0,0 +1,108 @@ +function [] = draw_cone_vec_geom(h_ax, geom, options) +%% draw_cone_vec_geom.m +% draw an astra cone beam vectorized projection geometry +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options struct holding options for drawing +% RotationAxis if specified, will change the rotation axis +% from z-axis to provided axis. +% Must be 3-vector. Default value [0, 0, 1] +% VectorIdx the index of the angle to draw +% Color global color for all lines and markers. +% is overwritten by specialized color options +% SourceMarker Marker to use to mark the source +% SourceMarkerColor Color of the source marker +% DetectorMarker Marker to use to mark the source +% DetectorMarkerColor Color of the source marker +% DetectorLineColor Color of the outline of the detector +% OpticalAxisColor color for drawing the optical axis +% +% date 21.06.2018 +% author Tim Elberfeld, Van Nguyen +% imec VisionLab +% University of Antwerp +% +% - last update 07.11.2018 +%% + vectors = geom.Vectors; + + % source + xray_source = vectors(:, 1:3); + % center of detector + detector_center = vectors(:, 4:6); + + % draw the points and connect with lines + hold on; + num_angles = size(vectors, 1); + for jj = 1:num_angles + s_source = scatter3(h_ax, xray_source(jj, 1), xray_source(jj, 2),... + xray_source(jj, 3)); + s_source.Marker = options.SourceMarker; + s_source.MarkerEdgeColor = options.SourceMarkerColor; + + s_det = scatter3(h_ax, detector_center(jj, 1),... + detector_center(jj, 2), detector_center(jj, 3)); + s_det.MarkerEdgeColor = options.DetectorMarkerColor; + s_det.Marker = options.DetectorMarker; + end + + detector = struct; + detector.u = vectors(options.VectorIdx, 7:9); + detector.v = vectors(options.VectorIdx, 10:12); + detector.height = geom.DetectorColCount; + detector.width = geom.DetectorRowCount; + detector.origin = detector_center(options.VectorIdx, :); + + vertices = draw_detector_vec(h_ax, detector, options); + connect_source_detector(h_ax, vertices, detector_center, ... + xray_source, options); + distances = eucl_dist3d(detector_center, xray_source); + mean_sdd = mean(distances(:)); % mean source detector distance + + draw_rotation_axis(h_ax, mean_sdd, options); + text(h_ax, xray_source(options.VectorIdx, 1),... + xray_source(options.VectorIdx, 2),... + xray_source(options.VectorIdx, 3), 'x-ray source'); + text(h_ax, detector_center(options.VectorIdx, 1),... + detector_center(options.VectorIdx, 2),... + detector_center(options.VectorIdx, 3), 'detector'); + hold off; + + function [] = connect_source_detector(h_ax, vertices,... + detector_center, xray_source, options) + % connect source to detector origin + idx = options.VectorIdx; + line(h_ax, [detector_center(idx, 1), xray_source(idx, 1)],... + [detector_center(idx, 2), xray_source(idx, 2)],... + [detector_center(idx, 3), xray_source(idx, 3)],... + 'Color', options.OpticalAxisColor, 'LineStyle', '--'); + + % connect source to detector edges + for kk = 1:4 + line(h_ax,[xray_source(idx, 1), vertices(1, kk)], ... + [xray_source(idx, 2), vertices(2, kk)],... + [xray_source(idx, 3), vertices(3, kk)],... + 'Color', 'k', 'LineStyle', ':'); + end + end + + function [] = draw_rotation_axis(h_ax, scaling, options) + % draw rotation axis + rot_axis = options.RotationAxis; + if(~isnan(rot_axis(1))) + rot_axis = options.RotationAxis + options.RotationAxisOffset; + origin = options.RotationAxisOffset; + % origin of the geometry is assumed to be [0, 0, 0] always! + line(h_ax, [origin(1), (scaling/2)*rot_axis(1)],... + [origin(2), (scaling/2)*rot_axis(2)],... + [origin(3), (scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + line(h_ax, [origin(1), -(scaling/2)*rot_axis(1)],... + [origin(2), -(scaling/2)*rot_axis(2)],... + [origin(3), -(scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + end + end +end diff --git a/matlab/algorithms/plot_geom/draw/draw_detector_vec.m b/matlab/algorithms/plot_geom/draw/draw_detector_vec.m new file mode 100644 index 0000000..5c293d4 --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/draw_detector_vec.m @@ -0,0 +1,42 @@ +function [ vertices] = draw_detector_vec( h_ax, detector, options) +%% draw_detector_vec.m +% draw a detector for a vector geometry +% param h_ax handle to axis to draw into +% param detector the struct specifying the detector +% .origin 3d coordinates of the detector origin +% .u vector pointing from detector origin to +% pixel (1,0) +% .v vector pointing from detector origin to +% pixel (0,1) +% .width width of the detector (number of px in u +% direction) +% .height height of the detector (number of px in v +% direction) +% param options struct with options +% .Color Color for the line work +% .DetectorLineColor Color of the detector rectangle outline +% return The vertices of the detector rectangle that +% were plotted +% +% date 09.07.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + % draw the detector rectangle + vertices = zeros(3, 5); + vertices(:, 1) = detector.origin - detector.u * detector.width / 2 + ... + detector.v * detector.height / 2; + vertices(:, 2) = detector.origin + detector.u * detector.width / 2 + ... + detector.v * detector.height / 2; + vertices(:, 3) = detector.origin + detector.u * detector.width / 2 - ... + detector.v * detector.height / 2; + vertices(:, 4) = detector.origin - detector.u * detector.width / 2 - ... + detector.v * detector.height / 2; + vertices(:, 5) = vertices(:, 1); + + detector.vertices = vertices; + plot3(h_ax, detector.vertices(1, :), detector.vertices(2, :),... + detector.vertices(3, :), options.DetectorLineColor); + +end diff --git a/matlab/algorithms/plot_geom/draw/draw_fanflat_geom.m b/matlab/algorithms/plot_geom/draw/draw_fanflat_geom.m new file mode 100644 index 0000000..5c97d80 --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/draw_fanflat_geom.m @@ -0,0 +1,25 @@ +function [] = draw_fanflat_geom( h_ax, geom, options) +%% draw_fanflat_geom.m +% draw an astra cone beam projection geometry +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options struct holding options for drawing +% SourceMarker Marker to use to mark the source +% SourceMarkerColor Color of the source marker +% DetectorMarker Marker to use to mark the source +% DetectorMarkerColor Color of the source marker +% DetectorLineColor Color of the outline of the detector +% OpticalAxisColor color for drawing the optical axis +% date 28.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + % convert to faux cone geometry so we don't have to write more code :)! + cone_geom = astra_create_proj_geom('cone', geom.DetectorWidth,... + geom.DetectorWidth, 1, geom.DetectorCount, geom.ProjectionAngles,... + geom.DistanceOriginSource, geom.DistanceOriginDetector); + + draw_cone_geom(h_ax, cone_geom, options); +end + diff --git a/matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m b/matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m new file mode 100644 index 0000000..9f5d620 --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m @@ -0,0 +1,103 @@ +function [ output_args ] = draw_fanflat_vec_geom( h_ax, geom, options) +%% draw_fanflat_vec_geom.m +% draw an astra cone beam projection geometry +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options struct holding options for drawing +% VectorIdx the index of the angle to draw +% SourceMarker Marker to use to mark the source +% SourceMarkerColor Color of the source marker +% DetectorMarker Marker to use to mark the source +% DetectorMarkerColor Color of the source marker +% DetectorLineColor Color of the outline of the detector +% OpticalAxisColor color for drawing the optical axis +% +% date 28.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% +% - last update 09.07.2018 +%% + vectors = geom.Vectors; + + % source + num_angles = size(vectors, 1); + xray_source = [vectors(:, 1:2), zeros(num_angles, 1)]; + % center of detector + detector_center = [vectors(:, 3:4), zeros(num_angles, 1)]; + + % draw the points and connect with lines + hold on; + for jj = 1:num_angles + scatter3(h_ax, xray_source(jj, 1), xray_source(jj, 2),... + xray_source(jj, 3), options.SourceMarker,... + options.SourceMarkerColor); + scatter3(h_ax, detector_center(jj, 1),... + detector_center(jj, 2), detector_center(jj, 3),... + options.DetectorMarker, options.DetectorMarkerColor); + end + + detector = struct; + detector.u = [vectors(options.VectorIdx, 5:6), 0]; + detector.v = fliplr(detector.u); + detector.height = 1; + detector.width = geom.DetectorCount; + detector.origin = detector_center(options.VectorIdx, :); + + vertices = draw_detector_vec(h_ax, detector, options); + connect_source_detector(h_ax, vertices, detector_center,... + xray_source, options); + + distances = eucl_dist3d(detector_center, xray_source); + mean_sdd = mean(distances(:)); % mean source detector distance + draw_rotation_axis(h_ax, mean_sdd, options); + + text(h_ax, xray_source(options.VectorIdx, 1),... + xray_source(options.VectorIdx, 2),... + xray_source(options.VectorIdx, 3), 'x-ray source'); + text(h_ax, detector_center(options.VectorIdx, 1),... + detector_center(options.VectorIdx, 2),... + detector_center(options.VectorIdx, 3), 'detector'); + + hold off; + + function [] = connect_source_detector(h_ax, vertices,... + detector_center, xray_source, options) + idx = options.VectorIdx; + % connect source to detector origin + line(h_ax, [detector_center(idx, 1), xray_source(idx, 1)],... + [detector_center(idx, 2), xray_source(idx, 2)],... + [detector_center(idx, 3), xray_source(idx, 3)],... + 'Color', options.OpticalAxisColor, 'LineStyle', '--'); + + % connect source to detector edges + for kk = 1:4 + line(h_ax,[xray_source(idx, 1), vertices(1, kk)], ... + [xray_source(idx, 2), vertices(2, kk)],... + [xray_source(idx, 3), vertices(3, kk)],... + 'Color', 'k', 'LineStyle', ':'); + end + end + + function [] = draw_rotation_axis(h_ax, scaling, options) + % draw rotation axis + rot_axis = options.RotationAxis; + if(~isnan(rot_axis(1))) + rot_axis = options.RotationAxis + options.RotationAxisOffset; + origin = options.RotationAxisOffset; + % origin of the geometry is assumed to be [0, 0, 0] always! + line(h_ax, [origin(1), (scaling/2)*rot_axis(1)],... + [origin(2), (scaling/2)*rot_axis(2)],... + [origin(3), (scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + line(h_ax, [origin(1), -(scaling/2)*rot_axis(1)],... + [origin(2), -(scaling/2)*rot_axis(2)],... + [origin(3), -(scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + end + end +end + diff --git a/matlab/algorithms/plot_geom/draw/draw_parallel3d_geom.m b/matlab/algorithms/plot_geom/draw/draw_parallel3d_geom.m new file mode 100644 index 0000000..45a8d60 --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/draw_parallel3d_geom.m @@ -0,0 +1,88 @@ +function [ ] = draw_parallel3d_geom( h_ax, geom, options) +%% draw_parallel3d_geom.m +% draw an astra parallel3d projection geometry +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options options struct with additional settings +% .SourceDistance distance of source to origin +% .SourceMarker marker for the source locations +% .SourceMarkerColor color specifier for the source marker +% .DetectorMarker marker for the detector locations. +% Default = '.' +% .DetectorMarkerColor color specifier for the detector marker. +% Default = 'k' +% .DetectorLineColor color for the lines drawing the detector +% outline +% .OpticalAxisColor Color of the line representing the optical +% axis. +% date 22.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% +% - last update 09.07.2018 +%% + dist_origin_detector = options.SourceDistance; + dist_origin_source = options.SourceDistance; + hold on; + + % draw source + scatter3(h_ax, 0, -dist_origin_source, 0, options.SourceMarker,... + options.SourceMarkerColor); + + % draw detector + detector = draw_detector(h_ax, geom, dist_origin_detector, options); + + % draw origin + h_origin = scatter3(h_ax, 0,0,0, '+k'); + h_origin.SizeData = 120; + h_origin.LineWidth = 2; + + % draw lines between source, origin and detector + line(h_ax, [0, 0], [0, dist_origin_detector], [0, 0],... + 'Color', options.OpticalAxisColor); + line(h_ax, [0, 0], [0, -dist_origin_source], [0, 0],... + 'Color', options.OpticalAxisColor); + + % connect source to detector edges + for idx = 1:4 + line(h_ax,[detector.vertices(1, idx),... + detector.vertices(1, idx)],... + [-dist_origin_source, dist_origin_detector],... + [detector.vertices(3, idx), detector.vertices(3, idx)],... + 'Color', 'k', 'LineStyle', ':'); + end + + % draw rotation axis + line(h_ax, [0,0],[0,0], 0.6*[-detector.height, detector.height],... + 'LineWidth', 2, 'Color', 'k', 'LineStyle', '--'); + + perc = 0.05; + text(h_ax, perc*detector.width, perc*detector.width,... + 0.8*detector.height, 'rotation axis'); + text(h_ax, detector.width*perc, 0, perc*detector.height, 'origin'); + text(h_ax, detector.width*perc, -dist_origin_source,... + perc*detector.height, 'x-ray source'); + text(h_ax, 0, dist_origin_detector, 0, 'detector'); + hold off; + + function [detector] = draw_detector(h_ax, geom,... + dist_origin_detector, options) + detector = struct; + detector.height = geom.DetectorRowCount * geom.DetectorSpacingY; + detector.width = geom.DetectorColCount * geom.DetectorSpacingX; + + vertices = zeros(3, 5); + vertices(1, :) = 0.5*[-detector.width, -detector.width,... + detector.width, detector.width, -detector.width]; + vertices(2, :) = repmat(dist_origin_detector, 5, 1); + vertices(3, :) = 0.5*[detector.height, -detector.height,... + -detector.height, detector.height, detector.height]; + + detector.vertices = vertices; + plot3(h_ax, detector.vertices(1, :), detector.vertices(2, :),... + detector.vertices(3, :), options.DetectorLineColor); + end + +end + diff --git a/matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m b/matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m new file mode 100644 index 0000000..351ec42 --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m @@ -0,0 +1,100 @@ +function [ ] = draw_parallel3d_vec_geom( h_ax, geom, options) +%% draw_parallel3d_vec_geom.m +% draw an astra parallel3d projection geometry +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options struct containing the options for this function +% idx index of the vector to draw in more detail +% SourceDistance distance of the source to the origin +% +% date 22.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + vectors = geom.Vectors; + + % source + xray_source = vectors(:, 1:3)*options.SourceDistance; + + % center of detector + detector_center = vectors(:, 4:6); + + % draw the points and connect with lines + hold on; + num_angles = size(vectors, 1); + for jj = 1:num_angles + scatter3(h_ax, xray_source(jj, 1), xray_source(jj, 2), xray_source(jj, 3),... + options.SourceMarkerColor,... + options.SourceMarker); + scatter3(h_ax, detector_center(jj, 1), detector_center(jj, 2),... + detector_center(jj, 3), 'k.'); + end + + detector = struct; + detector.u = vectors(options.VectorIdx, 7:9); + detector.v = vectors(options.VectorIdx, 10:12); + detector.height = geom.DetectorColCount; + detector.width = geom.DetectorRowCount; + detector.origin = detector_center(options.VectorIdx, :); + detector.vertices = draw_detector_vec(h_ax, detector, options); + + connect_source_detector(h_ax, detector, detector_center, xray_source,... + options); + + distances = eucl_dist3d(detector_center, xray_source); + mean_sdd = mean(distances(:)); % mean source detector distance + draw_rotation_axis(h_ax, mean_sdd, options); + text(h_ax, xray_source(options.VectorIdx, 1),... + xray_source(options.VectorIdx, 2), ... + xray_source(options.VectorIdx, 3), 'x-ray source'); + text(h_ax, detector_center(options.VectorIdx, 1),... + detector_center(options.VectorIdx, 2),... + detector_center(options.VectorIdx, 3), 'detector'); + hold off; + + function [] = connect_source_detector(h_ax, detector,... + detector_center, xray_source, options) + % connect source to detector origin + idx = options.VectorIdx; + line(h_ax, [detector_center(idx, 1), xray_source(idx, 1)],... + [detector_center(idx, 2), xray_source(idx, 2)],... + [detector_center(idx, 3), xray_source(idx, 3)],... + 'Color', options.OpticalAxisColor, 'LineStyle', '--'); + + % compute normal of detector plane + n = null([detector.u; detector.v]); + + % connect source to detector edges + for kk = 1:4 + a = detector.vertices(1, kk) - n(1)*xray_source(idx, 1); + b = detector.vertices(2, kk) - n(2)*xray_source(idx, 2); + c = detector.vertices(3, kk) - n(3)*xray_source(idx, 3); + line(h_ax,[a, detector.vertices(1, kk)], ... + [b, detector.vertices(2, kk)],... + [c, detector.vertices(3, kk)],... + 'Color', 'k',... + 'LineStyle', ':'); + end + end + + function [] = draw_rotation_axis(h_ax, scaling, options) + % draw rotation axis + rot_axis = options.RotationAxis; + if(~isnan(rot_axis(1))) + rot_axis = options.RotationAxis + options.RotationAxisOffset; + origin = options.RotationAxisOffset; + % origin of the geometry is assumed to be [0, 0, 0] always! + line(h_ax, [origin(1), (scaling/2)*rot_axis(1)],... + [origin(2), (scaling/2)*rot_axis(2)],... + [origin(3), (scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + line(h_ax, [origin(1), -(scaling/2)*rot_axis(1)],... + [origin(2), -(scaling/2)*rot_axis(2)],... + [origin(3), -(scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + end + end +end diff --git a/matlab/algorithms/plot_geom/draw/draw_proj_geometry.m b/matlab/algorithms/plot_geom/draw/draw_proj_geometry.m new file mode 100644 index 0000000..0d31fa2 --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/draw_proj_geometry.m @@ -0,0 +1,142 @@ +function [] = draw_proj_geometry(geom, h_ax, varargin) +%% draw_proj_geometry.m +% brief rendering function for astra geometries. +% param geom the geometry to plot. If geometry type +% is not supported, throws error +% param h_ax handle to axis to plot into +% ------------------------------ +% optional parameters that can be provided as string value pairs: +% +% param RotationAxis if specified, will change the drawn +% rotation axis to provided axis. +% Must be 3-vector. Default value is +% [NaN, NaN, NaN], (meaning do not draw). +% param RotationAxisOffset if specified, will translate the drawn +% rotation axis by the provided vector. +% Default = [0, 0, 0] +% param VectorIdx index of the vector to visualize if geom +% is a vector geometry type. Default = 1 +% param Color Color for all markers and lines if not +% otherwise specified +% param DetectorMarker marker for the detector locations. +% Default = '.' +% param DetectorMarkerColor color specifier for the detector marker. +% Default = 'k' +% param DetectorLineColor color for the lines drawing the detector +% outline +% param DetectorLineWidth line width of detector rectangle +% param SourceMarker marker for the source locations +% param SourceMarkerColor color specifier for the source marker +% param SourceDistance (only for parallel3d and parallel3d_vec) +% distance of source to origin +% param OpticalAxisColor Color for drawing the optical axis +% +% date 20.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% +% - last update 07.11.2018 +%% + if nargin == 1 + h_ax = axes(gcf); + end + + options = parseoptions(varargin); + + switch geom.type + case 'parallel3d' + disp('type: parallel3d') + disp(['detector spacing: [' num2str(geom.DetectorSpacingX), ', '... + num2str(geom.DetectorSpacingY) ']']); + disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... + num2str(geom.DetectorColCount) ']']); + disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); + disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); + disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); + disp('DistanceOriginDetector inf'); + disp('DistanceOriginSource inf'); + + draw_parallel3d_geom(h_ax, geom, options); + case 'parallel3d_vec' + disp('type: parallel3d_vec') + disp(['detector px: [' num2str(geom.DetectorRowCount), ', '... + num2str(geom.DetectorColCount) ']']); + disp(['# angles: ' num2str(size(geom.Vectors, 1))]); + + draw_parallel3d_vec_geom(h_ax, geom, options); + case 'cone' + disp('type: cone'); + disp(['detector spacing: [' num2str(geom.DetectorSpacingX), ', '... + num2str(geom.DetectorSpacingY) ']']); + disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... + num2str(geom.DetectorColCount) ']']); + disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); + disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); + disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); + disp(['DistanceOriginDetector ' num2str(geom.DistanceOriginDetector)]); + disp(['DistanceOriginSource ' num2str(geom.DistanceOriginSource)]); + + draw_cone_geom(h_ax, geom, options); + case 'cone_vec' + disp('type: cone_vec'); + disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... + num2str(geom.DetectorColCount) ']']); + disp(['# angles: ' num2str(size(geom.Vectors, 1))]); + + draw_cone_vec_geom(h_ax, geom, options); + case 'fanflat' + disp('type: fanflat'); + disp(['detector px: ' num2str(geom.DetectorCount)]); + disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); + disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); + disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); + disp(['DistanceOriginDetector '... + num2str(geom.DistanceOriginDetector)]); + disp(['DistanceOriginSource '... + num2str(geom.DistanceOriginSource)]); + + draw_fanflat_geom(h_ax, geom, options); + case 'fanflat_vec' + disp('type: fanflat_vec'); + disp(['detector px: ' num2str(geom.DetectorCount)]); + disp(['# angles: ' num2str(size(geom.Vectors, 1))]); + + draw_fanflat_vec_geom(h_ax, geom, options); + otherwise + error(['Unknown geometry type ' geom.type]) + end + view(45, 25); % gives nicer default view angle + + function [options] = parseoptions(input_args) + % make an options struct + options = struct; + options.RotationAxis = [NaN, NaN, NaN]; + options.RotationAxisOffset = [0, 0, 0]; + options.VectorIdx = 1; + options.Color = 'k'; + options.DetectorMarker = '.'; + options.DetectorMarkerColor = ''; + options.DetectorLineColor = ''; + options.DetectorLineWidth = 1; + options.SourceMarker = '*'; + options.SourceMarkerColor = ''; + options.SourceDistance = 100; + options.OpticalAxisColor = ''; + options = parseargs(options, input_args{:}); + + % if the color is still empty, replace by global color + if strcmpi(options.DetectorMarkerColor , '') + options.DetectorMarkerColor = options.Color; + end + if strcmpi(options.DetectorLineColor , '') + options.DetectorLineColor = options.Color; + end + if strcmpi(options.SourceMarkerColor , '') + options.SourceMarkerColor = options.Color; + end + if strcmpi(options.OpticalAxisColor , '') + options.OpticalAxisColor = options.Color; + end + end +end diff --git a/matlab/algorithms/plot_geom/draw/draw_vol_geom.m b/matlab/algorithms/plot_geom/draw/draw_vol_geom.m new file mode 100644 index 0000000..e6d550d --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/draw_vol_geom.m @@ -0,0 +1,99 @@ +function [] = draw_vol_geom( vol_geom, vx_size, h_ax, varargin) +%% draw_vol_geom.m +% brief rendering function for astra volume geometries +% describing a phantom. +% param vol_geom volume geometry describing the phantom +% param vx_size voxel size in unit of preference. must be same unit +% that was used to scale the projection geometry +% param h_ax handle to axis to plot into +% ------------------------------ +% optional parameters that can be provided as string value pairs: +% +% param Magnification magnification factor for the phantom. for small +% phantoms it might be necessary to scale the render up +% as otherwise it won't show up in the plot. Default = 1 +% param LineWidth line width for the box wireframe. Default = 2 +% param Color color of the wireframe. Default = 'r' +% +% date 20.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% +% - last update 09.07.2018 +%% + if nargin < 4 + h_ax = axes(gcf); + end + + options = struct; + options.Color = 'r'; + options.LineWidth = 2; + options.Magnification = 1; + options = parseargs(options, varargin{:}); + + hold on; + phantom_height = vol_geom.GridRowCount * vx_size; + phantom_width = vol_geom.GridColCount * vx_size; + phantom_depth = vol_geom.GridSliceCount * vx_size; + + if isfield(vol_geom, 'option') + minx = vol_geom.option.WindowMinX * vx_size; + maxx = vol_geom.option.WindowMaxX * vx_size; + + miny = vol_geom.option.WindowMinY * vx_size; + maxy = vol_geom.option.WindowMaxY * vx_size; + + minz = vol_geom.option.WindowMinZ * vx_size; + maxz = vol_geom.option.WindowMaxZ * vx_size; + else + minx = phantom_width / 2 * vx_size; + maxx = phantom_width / 2 * vx_size; + + miny = phantom_height / 2 * vx_size; + maxy = phantom_height / 2 * vx_size; + + minz = phantom_depth / 2 * vx_size; + maxz = phantom_depth / 2 * vx_size; + end + + xx_phantom = options.Magnification*[minx, minx, minx, minx, maxx, maxx, maxx, maxx]; + yy_phantom = options.Magnification*[miny, miny, maxy, maxy, miny, miny, maxy, maxy]; + zz_phantom = options.Magnification*[minz, maxz, minz, maxz, minz, maxz, minz, maxz]; + + face1 = [xx_phantom(1:4); yy_phantom(1:4); zz_phantom(1:4)]; + face2 = [[xx_phantom(1:2), xx_phantom(5:6)];... + [yy_phantom(1:2), yy_phantom(5:6)];... + [zz_phantom(1:2), zz_phantom(5:6)]]; + face3 = [[xx_phantom(3:4), xx_phantom(7:8)];... + [yy_phantom(3:4), yy_phantom(7:8)];... + [zz_phantom(3:4), zz_phantom(7:8)]]; + face4 = [[xx_phantom(5:6), xx_phantom(7:8)];... + [yy_phantom(5:6), yy_phantom(7:8)];... + [zz_phantom(5:6), zz_phantom(7:8)]]; + + % as we draw only a wire frame, we need only to draw 4 of the faces + draw_face(h_ax, face1, options); + draw_face(h_ax, face2, options); + draw_face(h_ax, face3, options); + draw_face(h_ax, face4, options); + + hold off; + + function [] = draw_face(h_ax, face_coords, options) + line(h_ax, face_coords(1, 1:2), face_coords(2, 1:2),... + face_coords(3, 1:2), 'LineWidth', options.LineWidth,... + 'Color', options.Color); + line(h_ax, face_coords(1, 3:4), face_coords(2, 3:4),... + face_coords(3, 3:4), 'LineWidth', options.LineWidth,... + 'Color', options.Color); + line(h_ax, [face_coords(1, 4),face_coords(1, 2)],... + [face_coords(2, 4),face_coords(2, 2)],... + [face_coords(3, 4),face_coords(3, 2)],... + 'LineWidth', options.LineWidth, 'Color', options.Color); + line(h_ax, [face_coords(1, 1),face_coords(1, 3)],... + [face_coords(2, 1),face_coords(2, 3)],... + [face_coords(3, 1),face_coords(3, 3)],... + 'LineWidth', options.LineWidth, 'Color', options.Color); + end +end diff --git a/matlab/algorithms/plot_geom/stl/bunny.stl b/matlab/algorithms/plot_geom/stl/bunny.stl new file mode 100644 index 0000000..0b7fcaa Binary files /dev/null and b/matlab/algorithms/plot_geom/stl/bunny.stl differ diff --git a/matlab/algorithms/plot_geom/util/cone_to_cone_vec.m b/matlab/algorithms/plot_geom/util/cone_to_cone_vec.m new file mode 100644 index 0000000..0075db9 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/cone_to_cone_vec.m @@ -0,0 +1,41 @@ +function [ cone_vec_geom] = cone_to_cone_vec( cone_geom ) +%% cone_to_cone_vec.m +% brief convert a cone beam projection geometry into a +% cone_vec geometry according to: +% http://www.astra-toolbox.com/docs/geom3d.html#projection-geometries +% +% param cone_geom the cone beam geometry to convert +% return cone_vec_geom the converted geometry +% +% date 21.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + num_angles = numel(cone_geom.ProjectionAngles); + vectors = zeros(num_angles, 12); + + for idx = 1:num_angles + % source + vectors(idx, 1) = sin(cone_geom.ProjectionAngles(idx)) * cone_geom.DistanceOriginSource; + vectors(idx, 2) = -cos(cone_geom.ProjectionAngles(idx)) * cone_geom.DistanceOriginSource; + vectors(idx, 3) = 0; + + % center of detector + vectors(idx, 4) = -sin(cone_geom.ProjectionAngles(idx)) * cone_geom.DistanceOriginDetector; + vectors(idx, 5) = cos(cone_geom.ProjectionAngles(idx)) * cone_geom.DistanceOriginDetector; + vectors(idx, 6) = 0; + + % vector from detector pixel (0,0) to (0,1) + vectors(idx, 7) = cos(cone_geom.ProjectionAngles(idx)) * cone_geom.DetectorSpacingX; + vectors(idx, 8) = sin(cone_geom.ProjectionAngles(idx)) * cone_geom.DetectorSpacingX; + vectors(idx, 9) = 0; + + % vector from detector pixel (0,0) to (1,0) + vectors(idx, 10) = 0; + vectors(idx, 11) = 0; + vectors(idx, 12) = cone_geom.DetectorSpacingY; + end + + cone_vec_geom = astra_create_proj_geom('cone_vec', cone_geom.DetectorRowCount, cone_geom.DetectorColCount, vectors); +end diff --git a/matlab/algorithms/plot_geom/util/eucl_dist3d.m b/matlab/algorithms/plot_geom/util/eucl_dist3d.m new file mode 100644 index 0000000..57d6cb4 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/eucl_dist3d.m @@ -0,0 +1,16 @@ +function [dist] = eucl_dist3d(a, b) +%% eucl_dist3d.m +% 3d euclidean distance for a nx3 matrix holding n 3-vectors +% param a - first vectors +% param b - second vectors +% date 07.11.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last update 07.11.2018 +%% + dist = sqrt((a(:, 1) - b(:, 1)).^2 + ... + (a(:, 2) - b(:, 2)).^2 + ... + (a(:, 3) - b(:, 3)).^2); +end + diff --git a/matlab/algorithms/plot_geom/util/fanflat_to_fanflat_vec.m b/matlab/algorithms/plot_geom/util/fanflat_to_fanflat_vec.m new file mode 100644 index 0000000..9707592 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/fanflat_to_fanflat_vec.m @@ -0,0 +1,4 @@ +function [ vec_geom] = fanflat_to_fanflat_vec( geom ) + vec_geom = astra_geom_2vec(geom); +end + diff --git a/matlab/algorithms/plot_geom/util/magnify_proj.m b/matlab/algorithms/plot_geom/util/magnify_proj.m new file mode 100644 index 0000000..73e892a --- /dev/null +++ b/matlab/algorithms/plot_geom/util/magnify_proj.m @@ -0,0 +1,23 @@ + +function [ magnified_vec_geom ] = magnify_proj( vec_geom, dsdd ) +%% generate magnified vector geometry +% param type vec_geom - example vector geometry +% dsdd - deviation of SDD +% return magnified_vec_geom - the geometry that was created +% +% date 09.07.2018 +% author Van Nguyen +% imec VisionLab +% University of Antwerp +%% + magnified_vec_geom = vec_geom; + vec_sd_direction = vec_geom(:,1:3) - vec_geom(:,4:6); + norm_sd = sqrt(sum(vec_sd_direction.^2,2)); + vec_norm_sd(:,1) = norm_sd; + vec_norm_sd(:,2) = norm_sd; + vec_norm_sd(:,3) = norm_sd; + vec_sd_direction = vec_sd_direction ./ vec_norm_sd; + magnified_vec_geom(:,4:6) = vec_geom(:,4:6) - dsdd * vec_sd_direction; + clearvars -except magnified_vec_geom +end + diff --git a/matlab/algorithms/plot_geom/util/parseargs/license.txt b/matlab/algorithms/plot_geom/util/parseargs/license.txt new file mode 100644 index 0000000..cae4cd5 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/parseargs/license.txt @@ -0,0 +1,27 @@ +Copyright (c) 2016, The MathWorks, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * In all cases, the software is, and all modifications and derivatives + of the software shall be, licensed to you solely for use in conjunction + with MathWorks products and service offerings. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/matlab/algorithms/plot_geom/util/parseargs/parseargs.m b/matlab/algorithms/plot_geom/util/parseargs/parseargs.m new file mode 100644 index 0000000..05ad613 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/parseargs/parseargs.m @@ -0,0 +1,97 @@ +function X = parseargs(X,varargin) +%PARSEARGS - Parses name-value pairs +% +% Behaves like setfield, but accepts multiple name-value pairs and provides +% some additional features: +% 1) If any field of X is an cell-array of strings, it can only be set to +% one of those strings. If no value is specified for that field, the +% first string is selected. +% 2) Where the field is not empty, its data type cannot be changed +% 3) Where the field contains a scalar, its size cannot be changed. +% +% X = parseargs(X,name1,value1,name2,value2,...) +% +% Intended for use as an argument parser for functions which multiple options. +% Example usage: +% +% function my_function(varargin) +% X.StartValue = 0; +% X.StopOnError = false; +% X.SolverType = {'fixedstep','variablestep'}; +% X.OutputFile = 'out.txt'; +% X = parseargs(X,varargin{:}); +% +% Then call (e.g.): +% +% my_function('OutputFile','out2.txt','SolverType','variablestep'); + +% The various #ok comments below are to stop MLint complaining about +% inefficient usage. In all cases, the inefficient usage (of error, getfield, +% setfield and find) is used to ensure compatibility with earlier versions +% of MATLAB. + +% Copyright 2006-2010 The MathWorks, Inc. + +remaining = nargin-1; % number of arguments other than X +count = 1; +fields = fieldnames(X); +modified = zeros(size(fields)); +% Take input arguments two at a time until we run out. +while remaining>=2 + fieldname = varargin{count}; + fieldind = find(strcmp(fieldname,fields)); + if ~isempty(fieldind) + oldvalue = getfield(X,fieldname); %#ok + newvalue = varargin{count+1}; + if iscell(oldvalue) + % Cell arrays must contain strings, and the new value must be + % a string which appears in the list. + if ~iscellstr(oldvalue) + error(sprintf('All allowed values for "%s" must be strings',fieldname)); %#ok + end + if ~ischar(newvalue) + error(sprintf('New value for "%s" must be a string',fieldname)); %#ok + end + if isempty(find(strcmp(oldvalue,newvalue))) %#ok + error(sprintf('"%s" is not allowed for field "%s"',newvalue,fieldname)); %#ok + end + elseif ~isempty(oldvalue) + % The caller isn't allowed to change the data type of a non-empty property, + % and scalars must remain as scalars. + if ~strcmp(class(oldvalue),class(newvalue)) + error(sprintf('Cannot change class of field "%s" from "%s" to "%s"',... + fieldname,class(oldvalue),class(newvalue))); %#ok + elseif numel(oldvalue)==1 & numel(newvalue)~=1 %#ok + error(sprintf('New value for "%s" must be a scalar',fieldname)); %#ok + end + end + X = setfield(X,fieldname,newvalue); %#ok + modified(fieldind) = 1; + else + error(['Not a valid field name: ' fieldname]); + end + remaining = remaining - 2; + count = count + 2; +end +% Check that we had a value for every name. +if remaining~=0 + error('Odd number of arguments supplied. Name-value pairs required'); +end + +% Now find cell arrays which were not modified by the above process, and select +% the first string. +notmodified = find(~modified); +for i=1:length(notmodified) + fieldname = fields{notmodified(i)}; + oldvalue = getfield(X,fieldname); %#ok + if iscell(oldvalue) + if ~iscellstr(oldvalue) + error(sprintf('All allowed values for "%s" must be strings',fieldname)); %#ok + elseif isempty(oldvalue) + error(sprintf('Empty cell array not allowed for field "%s"',fieldname)); %#ok + end + X = setfield(X,fieldname,oldvalue{1}); %#ok + end +end + + diff --git a/matlab/algorithms/plot_geom/util/rotate_around3d.m b/matlab/algorithms/plot_geom/util/rotate_around3d.m new file mode 100644 index 0000000..e9f152b --- /dev/null +++ b/matlab/algorithms/plot_geom/util/rotate_around3d.m @@ -0,0 +1,27 @@ +function [rot_vec] = rotate_around3d(vec, ax, angle) +%% rotate_around.m +% rotate a 3d vector around an axis by an angle +% param vec: 3 x 1 vector to be rotated +% param ax: 3 x 1 vector specifying the axis +% param angle: scalar, angle to rotate by +% return: rotated vector +% +% date: 21.06.2018 +% author: someone at VisionLab, modified by Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + rot_vec = zeros(3, 1); + + rot_vec(1) = (ax(1) * ax(1) * (1-cos(angle)) + cos(angle)) * vec(1) +... + (ax(1) * ax(2) * (1-cos(angle)) - ax(3) * sin(angle)) * vec(2) +... + (ax(1) * ax(3) * (1-cos(angle)) + ax(2) * sin(angle)) * vec(3); + + rot_vec(2) = (ax(1) * ax(2) * (1-cos(angle)) + ax(3) * sin(angle)) * vec(1) +... + (ax(2) * ax(2) * (1-cos(angle)) + cos(angle)) * vec(2) +... + (ax(2) * ax(3) * (1-cos(angle)) - ax(1) * sin(angle)) * vec(3); + + rot_vec(3) = (ax(1) * ax(3) * (1-cos(angle)) - ax(2) * sin(angle)) * vec(1) +... + (ax(2) * ax(3) * (1-cos(angle)) + ax(1) * sin(angle)) * vec(2) +... + (ax(3) * ax(3) * (1-cos(angle)) + cos(angle)) * vec(3); +end diff --git a/matlab/algorithms/plot_geom/util/rotate_detector.m b/matlab/algorithms/plot_geom/util/rotate_detector.m new file mode 100644 index 0000000..019f92a --- /dev/null +++ b/matlab/algorithms/plot_geom/util/rotate_detector.m @@ -0,0 +1,19 @@ +function [ vectors_rot ] = rotate_detector(vectors, rot_angles) +%% rotate the detector part of the vectors of a vector geometry +% param vectors - vectors to transform +% param rot_angles - rotation euler angles +% +% return vectors_rot - copy of input vectors, but rotated +% +% date 09.07.2018 +% author Van Nguyen, Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + vectors_rot = vectors; + vectors_rot(:, 1: 3) = rotate_euler3d(vectors(:, 1: 3), rot_angles); + vectors_rot(:, 4: 6) = rotate_euler3d(vectors(:, 4: 6), rot_angles); + vectors_rot(:, 7: 9) = rotate_euler3d(vectors(:, 7: 9), rot_angles); + vectors_rot(:, 10:12) = rotate_euler3d(vectors(:, 10:12), rot_angles); +end diff --git a/matlab/algorithms/plot_geom/util/rotate_euler3d.m b/matlab/algorithms/plot_geom/util/rotate_euler3d.m new file mode 100644 index 0000000..6fddb57 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/rotate_euler3d.m @@ -0,0 +1,35 @@ +function [ vectors_rot ] = rotate_euler3d(vectors, rot_angles) +%% rotate some vectors by euler angles around an axis +% param vectors - vectors to transform +% param rot_angles - rotation euler angles +% +% return vectors_rot - copy of input vectors, but rotated +% +% date 09.07.2018 +% author Van Nguyen, Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + roll = rot_angles(1); + yaw = rot_angles(2); + pitch = rot_angles(3); + roll_mat = [1 0 0; ... + 0 cos(roll) -sin(roll); ... + 0 sin(roll) cos(roll)]; + + yaw_mat = [cos(yaw) 0 -sin(yaw); ... + 0 1 0; ... + sin(yaw) 0 cos(yaw)]; + + pitch_mat = [cos(pitch) -sin(pitch) 0; ... + sin(pitch) cos(pitch) 0; ... + 0 0 1]; + % simulate rotation and translation of the DETECTOR + rot_mat = roll_mat * yaw_mat * pitch_mat; + vectors_rot = vectors; + + for i = 1:size(vectors, 1) + vectors_rot(i, :) = (rot_mat * vectors(i, :)')'; + end +end diff --git a/matlab/algorithms/plot_geom/util/stlTools/license.txt b/matlab/algorithms/plot_geom/util/stlTools/license.txt new file mode 100644 index 0000000..b2d00b0 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/license.txt @@ -0,0 +1,34 @@ +Copyright (c) 2017, Pau Micó +Copyright (c) 2015, Sven Holcombe +Copyright (c) 2011, Eric Johnson +Copyright (c) 2013, Adam H. Aitkenhead +Copyright (c) 2011, Francis Esmonde-White +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution + * Neither the name of the The MathWorks, Inc. nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + * Neither the name of the The Christie NHS Foundation Trust nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/matlab/algorithms/plot_geom/util/stlTools/readme.txt b/matlab/algorithms/plot_geom/util/stlTools/readme.txt new file mode 100644 index 0000000..b8037d6 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/readme.txt @@ -0,0 +1,16 @@ +The 'stlTools' toolbox is a collection of functions, samples and demos to illustrate how to deal with STL files. Some of them are contributions published in Matlab Central and properly referenced here. +This toolbox contains the following files: + +stlGetFormat: identifies the format of the STL file and returns 'binary' or 'ascii'. This file is inspired in the 'READ-stl' file written and published by Adam H. Aitkenhead (http://www.mathworks.com/matlabcentral/fileexchange/27390-mesh-voxelisation). Copyright (c) 2013, Adam H. Aitkenhead. +stlReadAscii: reads an STL file written in ascii format. This file is inspired in the 'READ-stl' file written and published by Adam H. Aitkenhead (http://www.mathworks.com/matlabcentral/fileexchange/27390-mesh-voxelisation). Copyright (c) 2013, Adam H. Aitkenhead +stlReadBinary: reads an STL file written in binary format. This file is inspired in the 'READ-stl' file written and published by Adam H. Aitkenhead (http://www.mathworks.com/matlabcentral/fileexchange/27390-mesh-voxelisation). Copyright (c) 2013, Adam H. Aitkenhead +stlRead: uses 'stlGetFormat', 'stlReadAscii' and 'stlReadBinary' to make STL reading independent of the format of the file +stlWrite: writes an STL file in 'ascii' or 'binary' formats. This is written and published by Sven Holcombe (http://www.mathworks.com/matlabcentral/fileexchange/20922-stlwrite-filename--varargin-). Copyright (c) 2012, Grant Lohsen. Copyright (c) 2015, Sven Holcombe. +stlSlimVerts: finds and removes duplicated vertices. This function is written and published by Francis Esmonde-White as PATCHSLIM (http://www.mathworks.com/matlabcentral/fileexchange/29986-patch-slim--patchslim-m-). Copyright (c) 2011, Francis Esmonde-White. +stlGetVerts: returns a list of vertices that are 'opened' or 'closed' depending on the 'mode' input parameter. An 'open' vertice is the one that defines an open side. An open side is the one that only takes part of one triangle +stlDelVerts: removes a list of vertices from STL files +stlAddVerts: adds the new vertices from a list (and consequently, new faces) to a STL object +stlPlot: is an easy way to plot an STL object +stlDemo: is a collection of examples about how to use stlTools +femur_binary: is an ascii STL sample used in 'stlDemo'. It is published by Eric Johnson (http://www.mathworks.com/matlabcentral/fileexchange/22409-stl-file-reader). Copyright (c) 2011, Eric Johnson. +sphere_ascii: is a binary STL sample \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlAddVerts.m b/matlab/algorithms/plot_geom/util/stlTools/stlAddVerts.m new file mode 100644 index 0000000..bc4ecbc --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/stlAddVerts.m @@ -0,0 +1,15 @@ +function [vnew, fnew] = stlAddVerts(v, f, list) +%STLADDVERTS adds new vertices (and consequently, new faces) to a STL object +%V is the Nx3 array of vertices +%F is the Mx3 array of faces +%LIST is the list of vertices to be added to the object +%VNEW is the new array of vertices +%FNEW is the new array of faces + +% triangulation just with the slice +faces = delaunay(list(:,1),list(:,2)); % calculate new faces +% update object +nvert = length(v); % number of original vertices +v = [v; list]; % update vertices with the ones in the list +f = [f; faces+nvert]; % update faces with the new ones +[vnew,fnew] = stlSlimVerts(v,f); % clear repeated vertices \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlDelVerts.m b/matlab/algorithms/plot_geom/util/stlTools/stlDelVerts.m new file mode 100644 index 0000000..718ac53 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/stlDelVerts.m @@ -0,0 +1,26 @@ +function [vnew, fnew] = stlDelVerts(v, f, list) +%STLDELVERT removes a list of vertices from STL files +%V is the Nx3 array of vertices +%F is the Mx3 array of faces +%LIST are the vertices (rows) to delete, where length(LIST) < N +%VNEW is the new array of vertices +%FNEW is the new array of faces + +% find (on the global set) the position (rows) of the vertices to be deleted +[~,vdel] = ismember(list,v,'rows'); + +% delete vertices and get new tags +vnew = v; +tags = 1:length(v); +vnew(vdel,:) = []; +tags(vdel) = []; + +% delete faces +fnew = f; +[fdel,~] = find(ismember(f,vdel)); % find the position (rows) of the faces to delete +fnew(fdel,:) = []; + +% rename faces, as some of the vertices have been deleted +flist = reshape(fnew,numel(fnew),1); +[~,ind] = ismember(flist,tags); +fnew = reshape(ind,numel(flist)/3,3); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlDemo.m b/matlab/algorithms/plot_geom/util/stlTools/stlDemo.m new file mode 100644 index 0000000..e82d8db --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/stlDemo.m @@ -0,0 +1,39 @@ +%% STLDEMO shows how to use the functions included in the toolbox STLTOOLS + +%% EXAMPLE 1.- How to cut a sphere and close the base to get a semisphere + +% load an ascii STL sample file (STLGETFORMAT and STLREADASCII) +[vertices,faces,normals,name] = stlRead('sphere300faces.stl'); +stlPlot(vertices,faces,name); + +% the sphere is centered in the origin +% now we get a list of vertices to be deleted if (x,y,z<0) +minZ = 0; +[rows, ~] = find(vertices(:,3) < minZ); +list = vertices(rows,:); + +% if we delete the list of vertices with z<0, we get an opened semisphere +% (as the base is not closed) +[newv,newf] = stlDelVerts(vertices,faces,list); +stlPlot(newv,newf,name); + +% the next step is to identify a new list with the faces that are opened +% (that means all the sides that belong only to a unique triangle) +list = stlGetVerts(newv,newf,'opened'); + +% finally we generate all the new faces that are needed just to close the +% base of the semisphere +[vsemi,fsemi] = stlAddVerts(newv,newf,list); +stlPlot(vsemi,fsemi,'closed semisphere'); + +%% EXAMPLE 2.- How to get a section of a femur + +[vertices,faces,normals,name] = stlRead('femur_binary.stl'); +stlPlot(vertices,faces,name); + +minX = 1.2; +[rows, ~] = find(vertices(:,1) < minX); +list = vertices(rows,:); + +[newv,newf] = stlDelVerts(vertices,faces,list); +stlPlot(newv,newf,'section of the femur'); diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlGetFormat.m b/matlab/algorithms/plot_geom/util/stlTools/stlGetFormat.m new file mode 100644 index 0000000..6901b26 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/stlGetFormat.m @@ -0,0 +1,38 @@ +function format = stlGetFormat(fileName) +%STLGETFORMAT identifies the format of the STL file and returns 'binary' or +%'ascii' + +fid = fopen(fileName); +% Check the file size first, since binary files MUST have a size of 84+(50*n) +fseek(fid,0,1); % Go to the end of the file +fidSIZE = ftell(fid); % Check the size of the file +if rem(fidSIZE-84,50) > 0 + format = 'ascii'; +else + % Files with a size of 84+(50*n), might be either ascii or binary... + % Read first 80 characters of the file. + % For an ASCII file, the data should begin immediately (give or take a few + % blank lines or spaces) and the first word must be 'solid'. + % For a binary file, the first 80 characters contains the header. + % It is bad practice to begin the header of a binary file with the word + % 'solid', so it can be used to identify whether the file is ASCII or + % binary. + fseek(fid,0,-1); % go to the beginning of the file + header = strtrim(char(fread(fid,80,'uchar')')); % trim leading and trailing spaces + isSolid = strcmp(header(1:min(5,length(header))),'solid'); % take first 5 char + fseek(fid,-80,1); % go to the end of the file minus 80 characters + tail = char(fread(fid,80,'uchar')'); + isEndSolid = findstr(tail,'endsolid'); + + % Double check by reading the last 80 characters of the file. + % For an ASCII file, the data should end (give or take a few + % blank lines or spaces) with 'endsolid '. + % If the last 80 characters contains the word 'endsolid' then this + % confirms that the file is indeed ASCII. + if isSolid & isEndSolid + format = 'ascii'; + else + format = 'binary'; + end +end +fclose(fid); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlGetVerts.m b/matlab/algorithms/plot_geom/util/stlTools/stlGetVerts.m new file mode 100644 index 0000000..179eff3 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/stlGetVerts.m @@ -0,0 +1,31 @@ +function list = stlGetVerts(v, f, mode) +%GETVERTS returns the vertices that are 'opened' or 'closed' depending on +%the 'mode'. An 'open' vertice is the one that defines an open side. An +%open side is the one that only takes part of one triangle +%V is the Nx3 array of vertices +%F is the Mx3 array of faces +%MODE can be 'opened' or 'closed' depending of the kind of vertices to list +%LIST is the list of 'opened' or 'closed' vertices + +sides = sort([[f(:,1) f(:,2)]; ... + [f(:,2) f(:,3)]; ... + [f(:,3) f(:,1)]],2); + +[C,ia,ic] = unique(sides,'rows'); +ind_all = sort(ic); % open and closed sides +ind_rep = find(diff(ind_all) == 0); +ind_cls = ind_all(ind_rep); % closed sides +sides_cls = C(ind_cls,:); +ind_rep = [ind_rep; ind_rep+1]; +ind_opn = ind_all; +ind_opn(ind_rep) = []; % open sides +sides_opn = C(ind_opn,:); + +switch mode, + case'opened', + list = v(unique(sides_opn(:)),:); + case 'closed', + list = v(unique(sides_cls(:)),:); + otherwise, + error('getVerts:InvalidMode','The ''mode'' valid values are ''opened'' or ''closed'''); +end \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlPlot.m b/matlab/algorithms/plot_geom/util/stlTools/stlPlot.m new file mode 100644 index 0000000..e9f17c5 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/stlPlot.m @@ -0,0 +1,23 @@ +function stlPlot(v, f, name) +%STLPLOT is an easy way to plot an STL object +%V is the Nx3 array of vertices +%F is the Mx3 array of faces +%NAME is the name of the object, that will be displayed as a title + +figure; +object.vertices = v; +object.faces = f; +patch(object,'FaceColor', [0.8 0.8 1.0], ... + 'EdgeColor', 'none', ... + 'FaceLighting', 'gouraud', ... + 'AmbientStrength', 0.15); + +% Add a camera light, and tone down the specular highlighting +camlight('headlight'); +material('dull'); + +% Fix the axes scaling, and set a nice view angle +axis('image'); +view([-135 35]); +grid on; +title(name); diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlRead.m b/matlab/algorithms/plot_geom/util/stlTools/stlRead.m new file mode 100644 index 0000000..8803516 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/stlRead.m @@ -0,0 +1,13 @@ +function [v, f, n, name] = stlRead(fileName) +%STLREAD reads any STL file not depending on its format +%V are the vertices +%F are the faces +%N are the normals +%NAME is the name of the STL object (NOT the name of the STL file) + +format = stlGetFormat(fileName); +if strcmp(format,'ascii') + [v,f,n,name] = stlReadAscii(fileName); +elseif strcmp(format,'binary') + [v,f,n,name] = stlReadBinary(fileName); +end \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlReadAscii.m b/matlab/algorithms/plot_geom/util/stlTools/stlReadAscii.m new file mode 100644 index 0000000..4490662 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/stlReadAscii.m @@ -0,0 +1,56 @@ +function [v, f, n, name] = stlReadAscii(fileName) +%STLREADASCII reads a STL file written in ASCII format +%V are the vertices +%F are the faces +%N are the normals +%NAME is the name of the STL object (NOT the name of the STL file) + +%====================== +% STL ascii file format +%====================== +% ASCII STL files have the following structure. Technically each facet +% could be any 2D shape, but in practice only triangular facets tend to be +% used. The present code ONLY works for meshes composed of triangular +% facets. +% +% solid object_name +% facet normal x y z +% outer loop +% vertex x y z +% vertex x y z +% vertex x y z +% endloop +% endfacet +% +% +% +% endsolid object_name + +fid = fopen(fileName); +cellcontent = textscan(fid,'%s','delimiter','\n'); % read all the file and put content in cells +content = cellcontent{:}(logical(~strcmp(cellcontent{:},''))); % remove all blank lines +fclose(fid); + +% read the STL name +line1 = char(content(1)); +if (size(line1,2) >= 7) + name = line1(7:end); +else + name = 'Unnamed Object'; +end + +% read the vector normals +normals = char(content(logical(strncmp(content,'facet normal',12)))); +n = str2num(normals(:,13:end)); + +% read the vertex coordinates (vertices) +vertices = char(content(logical(strncmp(content,'vertex',6)))); +v = str2num(vertices(:,7:end)); +nvert = size(vertices,1); % number of vertices +nfaces = sum(strcmp(content,'endfacet')); % number of faces +if (nvert == 3*nfaces) + f = reshape(1:nvert,[3 nfaces])'; % create faces +end + +% slim the file (delete duplicated vertices) +[v,f] = stlSlimVerts(v,f); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlReadBinary.m b/matlab/algorithms/plot_geom/util/stlTools/stlReadBinary.m new file mode 100644 index 0000000..314455d --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/stlReadBinary.m @@ -0,0 +1,60 @@ +function [v, f, n, name] = stlReadBinary(fileName) +%STLREADBINARY reads a STL file written in BINARY format +%V are the vertices +%F are the faces +%N are the normals +%NAME is the name of the STL object (NOT the name of the STL file) + +%======================= +% STL binary file format +%======================= +% Binary STL files have an 84 byte header followed by 50-byte records, each +% describing a single facet of the mesh. Technically each facet could be +% any 2D shape, but that would screw up the 50-byte-per-facet structure, so +% in practice only triangular facets are used. The present code ONLY works +% for meshes composed of triangular facets. +% +% HEADER: +% 80 bytes: Header text +% 4 bytes: (int) The number of facets in the STL mesh +% +% DATA: +% 4 bytes: (float) normal x +% 4 bytes: (float) normal y +% 4 bytes: (float) normal z +% 4 bytes: (float) vertex1 x +% 4 bytes: (float) vertex1 y +% 4 bytes: (float) vertex1 z +% 4 bytes: (float) vertex2 x +% 4 bytes: (float) vertex2 y +% 4 bytes: (float) vertex2 z +% 4 bytes: (float) vertex3 x +% 4 bytes: (float) vertex3 y +% 4 bytes: (float) vertex3 z +% 2 bytes: Padding to make the data for each facet 50-bytes in length +% ...and repeat for next facet... + +fid = fopen(fileName); +header = fread(fid,80,'int8'); % reading header's 80 bytes +name = deblank(native2unicode(header,'ascii')'); +if isempty(name) + name = 'Unnamed Object'; % no object name in binary files! +end +nfaces = fread(fid,1,'int32'); % reading the number of facets in the stl file (next 4 byters) +nvert = 3*nfaces; % number of vertices +% reserve memory for vectors (increase the processing speed) +n = zeros(nfaces,3); +v = zeros(nvert,3); +f = zeros(nfaces,3); +for i = 1 : nfaces % read the data for each facet + tmp = fread(fid,3*4,'float'); % read coordinates + n(i,:) = tmp(1:3); % x,y,z components of the facet's normal vector + v(3*i-2,:) = tmp(4:6); % x,y,z coordinates of vertex 1 + v(3*i-1,:) = tmp(7:9); % x,y,z coordinates of vertex 2 + v(3*i,:) = tmp(10:12); % x,y,z coordinates of vertex 3 + f(i,:) = [3*i-2 3*i-1 3*i]; % face + fread(fid,1,'int16'); % Move to the start of the next facet (2 bytes of padding) +end +fclose(fid); +% slim the file (delete duplicated vertices) +[v,f] = stlSlimVerts(v,f); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlSlimVerts.m b/matlab/algorithms/plot_geom/util/stlTools/stlSlimVerts.m new file mode 100644 index 0000000..2781067 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/stlSlimVerts.m @@ -0,0 +1,29 @@ +function [vnew, fnew]= stlSlimVerts(v, f) +% PATCHSLIM removes duplicate vertices in surface meshes. +% +% This function finds and removes duplicate vertices. +% +% USAGE: [v, f]=patchslim(v, f) +% +% Where v is the vertex list and f is the face list specifying vertex +% connectivity. +% +% v contains the vertices for all triangles [3*n x 3]. +% f contains the vertex lists defining each triangle face [n x 3]. +% +% This will reduce the size of typical v matrix by about a factor of 6. +% +% For more information see: +% http://www.esmonde-white.com/home/diversions/matlab-program-for-loading-stl-files +% +% Francis Esmonde-White, May 2010 + +if ~exist('v','var') + error('The vertex list (v) must be specified.'); +end +if ~exist('f','var') + error('The vertex connectivity of the triangle faces (f) must be specified.'); +end + +[vnew, indexm, indexn] = unique(v, 'rows'); +fnew = indexn(f); diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlWrite.m b/matlab/algorithms/plot_geom/util/stlTools/stlWrite.m new file mode 100644 index 0000000..0ce5d46 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/stlTools/stlWrite.m @@ -0,0 +1,252 @@ +function stlWrite(filename, varargin) +%STLWRITE Write STL file from patch or surface data. +% +% STLWRITE(FILE, FV) writes a stereolithography (STL) file to FILE for a +% triangulated patch defined by FV (a structure with fields 'vertices' +% and 'faces'). +% +% STLWRITE(FILE, FACES, VERTICES) takes faces and vertices separately, +% rather than in an FV struct +% +% STLWRITE(FILE, X, Y, Z) creates an STL file from surface data in X, Y, +% and Z. STLWRITE triangulates this gridded data into a triangulated +% surface using triangulation options specified below. X, Y and Z can be +% two-dimensional arrays with the same size. If X and Y are vectors with +% length equal to SIZE(Z,2) and SIZE(Z,1), respectively, they are passed +% through MESHGRID to create gridded data. If X or Y are scalar values, +% they are used to specify the X and Y spacing between grid points. +% +% STLWRITE(...,'PropertyName',VALUE,'PropertyName',VALUE,...) writes an +% STL file using the following property values: +% +% MODE - File is written using 'binary' (default) or 'ascii'. +% +% TITLE - Header text (max 80 chars) written to the STL file. +% +% TRIANGULATION - When used with gridded data, TRIANGULATION is either: +% 'delaunay' - (default) Delaunay triangulation of X, Y +% 'f' - Forward slash division of grid quads +% 'b' - Back slash division of quadrilaterals +% 'x' - Cross division of quadrilaterals +% Note that 'f', 'b', or 't' triangulations now use an +% inbuilt version of FEX entry 28327, "mesh2tri". +% +% FACECOLOR - Single colour (1-by-3) or one-colour-per-face (N-by-3) +% vector of RGB colours, for face/vertex input. RGB range +% is 5 bits (0:31), stored in VisCAM/SolidView format +% (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL) +% +% Example 1: +% % Write binary STL from face/vertex data +% tmpvol = false(20,20,20); % Empty voxel volume +% tmpvol(8:12,8:12,5:15) = 1; % Turn some voxels on +% fv = isosurface(~tmpvol, 0.5); % Make patch w. faces "out" +% stlwrite('test.stl',fv) % Save to binary .stl +% +% Example 2: +% % Write ascii STL from gridded data +% [X,Y] = deal(1:40); % Create grid reference +% Z = peaks(40); % Create grid height +% stlwrite('test.stl',X,Y,Z,'mode','ascii') +% +% Example 3: +% % Write binary STL with coloured faces +% cVals = fv.vertices(fv.faces(:,1),3); % Colour by Z height. +% cLims = [min(cVals) max(cVals)]; % Transform height values +% nCols = 255; cMap = jet(nCols); % onto an 8-bit colour map +% fColsDbl = interp1(linspace(cLims(1),cLims(2),nCols),cMap,cVals); +% fCols8bit = fColsDbl*255; % Pass cols in 8bit (0-255) RGB triplets +% stlwrite('testCol.stl',fv,'FaceColor',fCols8bit) + +% Original idea adapted from surf2stl by Bill McDonald. Huge speed +% improvements implemented by Oliver Woodford. Non-Delaunay triangulation +% of quadrilateral surface courtesy of Kevin Moerman. FaceColor +% implementation by Grant Lohsen. +% +% Author: Sven Holcombe, 11-24-11 + + +% Check valid filename path +path = fileparts(filename); +if ~isempty(path) && ~exist(path,'dir') + error('Directory "%s" does not exist.',path); +end + +% Get faces, vertices, and user-defined options for writing +[faces, vertices, options] = parseInputs(varargin{:}); +asciiMode = strcmp( options.mode ,'ascii'); + +% Create the facets +facets = single(vertices'); +facets = reshape(facets(:,faces'), 3, 3, []); + +% Compute their normals +V1 = squeeze(facets(:,2,:) - facets(:,1,:)); +V2 = squeeze(facets(:,3,:) - facets(:,1,:)); +normals = V1([2 3 1],:) .* V2([3 1 2],:) - V2([2 3 1],:) .* V1([3 1 2],:); +clear V1 V2 +normals = bsxfun(@times, normals, 1 ./ sqrt(sum(normals .* normals, 1))); +facets = cat(2, reshape(normals, 3, 1, []), facets); +clear normals + +% Open the file for writing +permissions = {'w','wb+'}; +fid = fopen(filename, permissions{asciiMode+1}); +if (fid == -1) + error('stlwrite:cannotWriteFile', 'Unable to write to %s', filename); +end + +% Write the file contents +if asciiMode + % Write HEADER + fprintf(fid,'solid %s\r\n',options.title); + % Write DATA + fprintf(fid,[... + 'facet normal %.7E %.7E %.7E\r\n' ... + 'outer loop\r\n' ... + 'vertex %.7E %.7E %.7E\r\n' ... + 'vertex %.7E %.7E %.7E\r\n' ... + 'vertex %.7E %.7E %.7E\r\n' ... + 'endloop\r\n' ... + 'endfacet\r\n'], facets); + % Write FOOTER + fprintf(fid,'endsolid %s\r\n',options.title); + +else % BINARY + % Write HEADER + fprintf(fid, '%-80s', options.title); % Title + fwrite(fid, size(facets, 3), 'uint32'); % Number of facets + % Write DATA + % Add one uint16(0) to the end of each facet using a typecasting trick + facets = reshape(typecast(facets(:), 'uint16'), 12*2, []); + % Set the last bit to 0 (default) or supplied RGB + facets(end+1,:) = options.facecolor; + fwrite(fid, facets, 'uint16'); +end + +% Close the file +fclose(fid); +%fprintf('Wrote %d facets\n',size(facets, 2)); + + +%% Input handling subfunctions +function [faces, vertices, options] = parseInputs(varargin) +% Determine input type +if isstruct(varargin{1}) % stlwrite('file', FVstruct, ...) + if ~all(isfield(varargin{1},{'vertices','faces'})) + error( 'Variable p must be a faces/vertices structure' ); + end + faces = varargin{1}.faces; + vertices = varargin{1}.vertices; + options = parseOptions(varargin{2:end}); + +elseif isnumeric(varargin{1}) + firstNumInput = cellfun(@isnumeric,varargin); + firstNumInput(find(~firstNumInput,1):end) = 0; % Only consider numerical input PRIOR to the first non-numeric + numericInputCnt = nnz(firstNumInput); + + options = parseOptions(varargin{numericInputCnt+1:end}); + switch numericInputCnt + case 3 % stlwrite('file', X, Y, Z, ...) + % Extract the matrix Z + Z = varargin{3}; + + % Convert scalar XY to vectors + ZsizeXY = fliplr(size(Z)); + for i = 1:2 + if isscalar(varargin{i}) + varargin{i} = (0:ZsizeXY(i)-1) * varargin{i}; + end + end + + % Extract X and Y + if isequal(size(Z), size(varargin{1}), size(varargin{2})) + % X,Y,Z were all provided as matrices + [X,Y] = varargin{1:2}; + elseif numel(varargin{1})==ZsizeXY(1) && numel(varargin{2})==ZsizeXY(2) + % Convert vector XY to meshgrid + [X,Y] = meshgrid(varargin{1}, varargin{2}); + else + error('stlwrite:badinput', 'Unable to resolve X and Y variables'); + end + + % Convert to faces/vertices + if strcmp(options.triangulation,'delaunay') + faces = delaunay(X,Y); + vertices = [X(:) Y(:) Z(:)]; + else + if ~exist('mesh2tri','file') + error('stlwrite:missing', '"mesh2tri" is required to convert X,Y,Z matrices to STL. It can be downloaded from:\n%s\n',... + 'http://www.mathworks.com/matlabcentral/fileexchange/28327') + end + [faces, vertices] = mesh2tri(X, Y, Z, options.triangulation); + end + + case 2 % stlwrite('file', FACES, VERTICES, ...) + faces = varargin{1}; + vertices = varargin{2}; + + otherwise + error('stlwrite:badinput', 'Unable to resolve input types.'); + end +end + +if ~isempty(options.facecolor) % Handle colour preparation + facecolor = uint16(options.facecolor); + %Set the Valid Color bit (bit 15) + c0 = bitshift(ones(size(faces,1),1,'uint16'),15); + %Red color (10:15), Blue color (5:9), Green color (0:4) + c0 = bitor(bitshift(bitand(2^6-1, facecolor(:,1)),10),c0); + c0 = bitor(bitshift(bitand(2^11-1, facecolor(:,2)),5),c0); + c0 = bitor(bitand(2^6-1, facecolor(:,3)),c0); + options.facecolor = c0; +else + options.facecolor = 0; +end + +function options = parseOptions(varargin) +IP = inputParser; +IP.addParamValue('mode', 'binary', @ischar) +IP.addParamValue('title', sprintf('Created by stlwrite.m %s',datestr(now)), @ischar); +IP.addParamValue('triangulation', 'delaunay', @ischar); +IP.addParamValue('facecolor',[], @isnumeric) +IP.addParamValue('facecolour',[], @isnumeric) +IP.parse(varargin{:}); +options = IP.Results; +if ~isempty(options.facecolour) + options.facecolor = options.facecolour; +end + +function [F,V]=mesh2tri(X,Y,Z,tri_type) +% function [F,V]=mesh2tri(X,Y,Z,tri_type) +% +% Available from http://www.mathworks.com/matlabcentral/fileexchange/28327 +% Included here for convenience. Many thanks to Kevin Mattheus Moerman +% kevinmoerman@hotmail.com +% 15/07/2010 +%------------------------------------------------------------------------ + +[J,I]=meshgrid(1:1:size(X,2)-1,1:1:size(X,1)-1); + +switch tri_type + case 'f'%Forward slash + TRI_I=[I(:),I(:)+1,I(:)+1; I(:),I(:),I(:)+1]; + TRI_J=[J(:),J(:)+1,J(:); J(:),J(:)+1,J(:)+1]; + F = sub2ind(size(X),TRI_I,TRI_J); + case 'b'%Back slash + TRI_I=[I(:),I(:)+1,I(:); I(:)+1,I(:)+1,I(:)]; + TRI_J=[J(:)+1,J(:),J(:); J(:)+1,J(:),J(:)+1]; + F = sub2ind(size(X),TRI_I,TRI_J); + case 'x'%Cross + TRI_I=[I(:)+1,I(:); I(:)+1,I(:)+1; I(:),I(:)+1; I(:),I(:)]; + TRI_J=[J(:),J(:); J(:)+1,J(:); J(:)+1,J(:)+1; J(:),J(:)+1]; + IND=((numel(X)+1):numel(X)+prod(size(X)-1))'; + F = sub2ind(size(X),TRI_I,TRI_J); + F(:,3)=repmat(IND,[4,1]); + Fe_I=[I(:),I(:)+1,I(:)+1,I(:)]; Fe_J=[J(:),J(:),J(:)+1,J(:)+1]; + Fe = sub2ind(size(X),Fe_I,Fe_J); + Xe=mean(X(Fe),2); Ye=mean(Y(Fe),2); Ze=mean(Z(Fe),2); + X=[X(:);Xe(:)]; Y=[Y(:);Ye(:)]; Z=[Z(:);Ze(:)]; +end + +V=[X(:),Y(:),Z(:)]; \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/translate_3d.m b/matlab/algorithms/plot_geom/util/translate_3d.m new file mode 100644 index 0000000..bd51485 --- /dev/null +++ b/matlab/algorithms/plot_geom/util/translate_3d.m @@ -0,0 +1,18 @@ +function [ transl_vectors ] = translate_3d( vectors, transl_vec) +%% translate some vectors by a translation vector +% param vectors - the vectors to translate +% param transl_vec - vector geometry translation +% return translated_vec_geom - copy of input geometry with translated +% vectors +% +% date 09.07.2018 +% author Van Nguyen, Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + transl_vectors = vectors; % copy input + transl = repmat(transl_vec, size(vectors, 1), 1); + transl_vectors = transl_vectors + transl; +end + -- cgit v1.2.3 From c19b7e2a4a97ebc3a2c060d67a323e0e6fe66f91 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 15 Nov 2018 17:27:28 +0100 Subject: copy plot_geom files in correct folders when installing --- build/linux/Makefile.in | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/build/linux/Makefile.in b/build/linux/Makefile.in index 2129519..14df491 100644 --- a/build/linux/Makefile.in +++ b/build/linux/Makefile.in @@ -517,8 +517,30 @@ install-matlab: $(MATLAB_MEX) install-matlab-so $(INSTALL_SH) -m 755 -d $(MATLABBASE) $(INSTALL_SH) -m 755 -d $(MATLABBASE)/mex $(INSTALL_SH) -m 755 -d $(MATLABBASE)/tools + $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms $(INSTALL_SH) -m 755 $(MATLAB_MEX) $(MATLABBASE)/mex $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/tools/*.m $(MATLABBASE)/tools + + # TODO: there must be a more efficient way to do this than to create and fill every single folder + # install plot_geom + $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom + $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/*.m $(MATLABBASE)/algorithms/plot_geom + + $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/draw + $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/draw/*.m $(MATLABBASE)/algorithms/plot_geom/draw + + $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/stl + $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/stl/*.stl $(MATLABBASE)/algorithms/plot_geom/stl + + $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/util + $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/util/*.m $(MATLABBASE)/algorithms/plot_geom/util + + $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/util/parseargs + $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/util/parseargs/* $(MATLABBASE)/algorithms/plot_geom/util/parseargs + + $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/util/stlTools + $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/util/stlTools/* $(MATLABBASE)/algorithms/plot_geom/util/stlTools + # TODO: docs else install-matlab: -- cgit v1.2.3 From 40979a6f4ab678a2f57ccaf8aede1156713e3bf8 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 16 Nov 2018 10:14:17 +0100 Subject: add astra_plot_geom command and sample s024 Signed-off-by: Tim --- build/linux/Makefile.in | 3 - matlab/algorithms/plot_geom/__main.m | 44 ------ .../plot_geom/astra_create_example_cone.m | 165 +++++++++++++++++++++ .../plot_geom/astra_create_example_fanflat.m | 50 +++++++ .../plot_geom/astra_create_example_parallel3d.m | 30 ++++ matlab/algorithms/plot_geom/create_example_cone.m | 165 --------------------- .../algorithms/plot_geom/create_example_fanflat.m | 50 ------- .../plot_geom/create_example_parallel3d.m | 30 ---- .../algorithms/plot_geom/draw/create_gui_figure.m | 58 -------- .../algorithms/plot_geom/draw/draw_cad_phantom.m | 8 +- .../algorithms/plot_geom/draw/draw_cone_vec_geom.m | 26 ++-- .../plot_geom/draw/draw_fanflat_vec_geom.m | 17 +-- .../plot_geom/draw/draw_parallel3d_vec_geom.m | 14 +- matlab/algorithms/plot_geom/draw/draw_proj_geom.m | 138 +++++++++++++++++ .../algorithms/plot_geom/draw/draw_proj_geometry.m | 142 ------------------ matlab/algorithms/plot_geom/draw/draw_vol_geom.m | 22 ++- matlab/algorithms/plot_geom/stl/bunny.stl | Bin 47484 -> 0 bytes matlab/tools/astra_plot_geom.m | 91 ++++++++++++ samples/matlab/bunny.stl | Bin 0 -> 47484 bytes samples/matlab/s024_plot_geometry.m | 42 ++++++ 20 files changed, 561 insertions(+), 534 deletions(-) delete mode 100644 matlab/algorithms/plot_geom/__main.m create mode 100644 matlab/algorithms/plot_geom/astra_create_example_cone.m create mode 100644 matlab/algorithms/plot_geom/astra_create_example_fanflat.m create mode 100644 matlab/algorithms/plot_geom/astra_create_example_parallel3d.m delete mode 100644 matlab/algorithms/plot_geom/create_example_cone.m delete mode 100644 matlab/algorithms/plot_geom/create_example_fanflat.m delete mode 100644 matlab/algorithms/plot_geom/create_example_parallel3d.m delete mode 100644 matlab/algorithms/plot_geom/draw/create_gui_figure.m create mode 100644 matlab/algorithms/plot_geom/draw/draw_proj_geom.m delete mode 100644 matlab/algorithms/plot_geom/draw/draw_proj_geometry.m delete mode 100644 matlab/algorithms/plot_geom/stl/bunny.stl create mode 100644 matlab/tools/astra_plot_geom.m create mode 100644 samples/matlab/bunny.stl create mode 100644 samples/matlab/s024_plot_geometry.m diff --git a/build/linux/Makefile.in b/build/linux/Makefile.in index 14df491..73d8279 100644 --- a/build/linux/Makefile.in +++ b/build/linux/Makefile.in @@ -529,9 +529,6 @@ install-matlab: $(MATLAB_MEX) install-matlab-so $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/draw $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/draw/*.m $(MATLABBASE)/algorithms/plot_geom/draw - $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/stl - $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/stl/*.stl $(MATLABBASE)/algorithms/plot_geom/stl - $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/util $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/util/*.m $(MATLABBASE)/algorithms/plot_geom/util diff --git a/matlab/algorithms/plot_geom/__main.m b/matlab/algorithms/plot_geom/__main.m deleted file mode 100644 index 607a242..0000000 --- a/matlab/algorithms/plot_geom/__main.m +++ /dev/null @@ -1,44 +0,0 @@ -%% main.m -% brief small tool to render astra geometries in matlab -% -% date 20.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -% -% - last update 09.07.2018 -%% -% close all; - -[h_gui, is_running] = create_gui_figure(); - -%proj_geom = create_example_cone('vec'); -%proj_geom = create_example_cone('normal'); -%proj_geom = create_example_cone('helix'); -proj_geom = create_example_parallel3d('vec'); -%proj_geom = create_example_fanflat('vec'); -%proj_geom = create_example_fanflat(); -%proj_geom = create_example_parallel3d(); - -draw_proj_geometry(proj_geom, h_gui); -hold on; - -vol_magn = 10; -phantom_size = 5; -phantom_px = 1500; -vx_size = phantom_size / phantom_px; % voxel size -vol_geom = astra_create_vol_geom(phantom_px, phantom_px, phantom_px); -line_width = 1; % line width for phantom -draw_vol_geom(vol_geom, vx_size, h_gui, 'Magnification', vol_magn,... - 'LineWidth', line_width, 'Color', 'r'); - -% this magnification is empirically chosen to fit the stl file -cad_magn = 350; -draw_cad_phantom('stl/bunny.stl', cad_magn, h_gui); - -proj_geom = create_example_cone('deform_vec'); -draw_proj_geometry(proj_geom, h_gui, 'VectorIdx', 3, 'Color', 'b',... - 'RotationAxis', [0,0,1]); - -hold off; -axis equal; diff --git a/matlab/algorithms/plot_geom/astra_create_example_cone.m b/matlab/algorithms/plot_geom/astra_create_example_cone.m new file mode 100644 index 0000000..598899f --- /dev/null +++ b/matlab/algorithms/plot_geom/astra_create_example_cone.m @@ -0,0 +1,165 @@ +function [ proj_geom ] = create_example_cone(type) +%% create_example_cone.m +% create an example standard cone beam geometry +% param type type of geometry to create. provided as one of the +% following strings (not case sensitive): +% 'normal' - standard (non vector) geometry +% 'vec' - example vector geometry +% 'helix' - helical trajectory vector geometry +% 'deform_vec' - deformed vector geometry example, +% courtesy of Van Nguyen +% return proj_geom - the geometry that was created +% +% date 21.06.2018 +% author Tim Elberfeld, Alice Presenti, Van Nguyen +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + if(nargin < 1) + type = 'normal'; + end + if strcmpi(type, 'normal') + % first, give measurements in mm + det_spacing = [0.035, 0.035]; + detector_px = [1200, 1200]; + angles = linspace2(0, 2*pi, 100); + source_origin = 30; + origin_det = 200; + phantom_size = 5; + + phantom_px = 150; % voxels for the phantom + vx_size = phantom_size / phantom_px; % voxel size + + % now express all measurements in terms of the voxel size + det_spacing = det_spacing ./ vx_size; + origin_det = origin_det ./ vx_size; + source_origin = source_origin ./ vx_size; + + proj_geom = astra_create_proj_geom('cone', det_spacing(1), ... + det_spacing(2), detector_px(1), detector_px(2), angles,... + source_origin, origin_det); + + elseif strcmpi(type, 'vec') + proj_geom = create_standard_vec_geom(); + + elseif strcmpi(type, 'deform_vec') + proj_geom = create_deform_vec_geom(); + + elseif strcmpi(type, 'helix') + detRows = 220; + detCols = 220; + detPitchX = 10^-3 * 11; % microns to mm + detPitchY = 10^-3 * 11; % microns to mm + objSrcDist = 500; % mm + rotStep = 3.6; % deg + numAngles = 200; + zTranslation = 0.5; % mm + zDist = zTranslation * numAngles; + vectors = zeros(numAngles, 12); + translation = -zDist + (zTranslation * (0:(numAngles-1))); + + minAngle = 0; % just assume we start at 0 + maxAngle = (numAngles * rotStep)/180 * pi; % convert deg to rad + angles = linspace(minAngle, maxAngle, 200); + + % source position per angle + vectors(:, 1) = sin(angles) * objSrcDist; + vectors(:, 2) = -cos(angles) * objSrcDist; + vectors(:, 3) = translation; + + % detector position per angle + vectors(:, 4) = 0; + vectors(:, 5) = 0; + vectors(:, 6) = translation; + + % vector from detector pixel (0,0) to (0,1) + vectors(:, 7) = cos(angles); + vectors(:, 8) = sin(angles); + vectors(:, 9) = zeros(numAngles, 1); + + % vector from detector pixel (0,0) to (1, 0) + vectors(:, 10) = zeros(numAngles, 1); + vectors(:, 11) = zeros(numAngles, 1); + vectors(:, 12) = ones(numAngles, 1); + + proj_geom = astra_create_proj_geom('cone_vec', detCols, detRows, vectors); + + else + proj_geom = create_standard_vec_geom(); + end + + function [proj_geom, z_axis] = create_standard_vec_geom() + % geometry settings taken from code from Alice Presenti + settings = struct; + settings.detectorPixelSize = 0.0748; + % detector size and number of projections + settings.projectionSize = [1536 1944 21]; + settings.SOD = 679.238020; %[mm] + settings.SDD = 791.365618; %[mm] + settings.voxelSize = 1; %[mm] + settings.gamma = linspace(0,300,21)*pi/180; + + S0 = zeros(settings.projectionSize(3), 12); + Sorig = [-settings.SOD, 0, 0,... % the ray origin vector (source) + (settings.SDD-settings.SOD), 0, 0,... % detector center + 0, -settings.detectorPixelSize, 0,... % detector u axis + 0, 0, settings.detectorPixelSize]; % detector v axis + + z_axis = [0, 0, 1]; + for i = 1:settings.projectionSize(3) + S0(i,:) = Sorig(:); + S0(i,1:3) = rotate_around3d(S0(i,1:3),... + z_axis, settings.gamma(i)); + S0(i,4:6) = rotate_around3d(S0(i,4:6), z_axis,... + settings.gamma(i)); + S0(i,7:9) = rotate_around3d(S0(i,7:9), z_axis,... + settings.gamma(i)); + S0(i,10:12) = rotate_around3d(S0(i,10:12),... + z_axis, settings.gamma(i)); + end + proj_geom = astra_create_proj_geom('cone_vec', ... + settings.projectionSize(2), settings.projectionSize(1), S0); + end + + function [proj_geom, z_axis] = create_deform_vec_geom() + settings = struct; + settings.detectorPixelSize = 0.0748; + settings.projectionSize = [1536 1944 21]; + settings.SOD = 679.238020; %[mm] + settings.SDD = 791.365618; %[mm] + settings.voxelSize = 1; %[mm] + settings.gamma = linspace(0,300,21)*pi/180; + + S0 = zeros(settings.projectionSize(3), 12); + Sorig = [-settings.SOD, 0, 0,... % the ray origin vector (source) + (settings.SDD-settings.SOD), 0, 0,... % detector center + 0, -settings.detectorPixelSize, 0,... % detector u axis + 0, 0, settings.detectorPixelSize]; % detector v axis + + z_axis = [0, 0, 1]; + for i = 1:settings.projectionSize(3) + S0(i,:) = Sorig(:); + end + + S0(:, 1:3) = translate_3d(S0(:, 1:3), [100, 150, 0]); + S0(:, 4:6) = translate_3d(S0(:, 4:6), [100, 150, 0]); + + S0 = rotate_detector(S0, [0.48,0.32,0]); + S0 = magnify_proj(S0, 100); + for i = 1:settings.projectionSize(3) + S0(i,1:3) = rotate_around3d(S0(i,1:3), z_axis,... + settings.gamma(i)); + S0(i,4:6) = rotate_around3d(S0(i,4:6), z_axis,... + settings.gamma(i)); + S0(i,7:9) = rotate_around3d(S0(i,7:9), z_axis,... + settings.gamma(i)); + S0(i,10:12) = rotate_around3d(S0(i,10:12), z_axis,... + settings.gamma(i)); + end + + proj_geom = astra_create_proj_geom('cone_vec',... + settings.projectionSize(2), settings.projectionSize(1), S0); + end + +end diff --git a/matlab/algorithms/plot_geom/astra_create_example_fanflat.m b/matlab/algorithms/plot_geom/astra_create_example_fanflat.m new file mode 100644 index 0000000..703a618 --- /dev/null +++ b/matlab/algorithms/plot_geom/astra_create_example_fanflat.m @@ -0,0 +1,50 @@ +function [ geom ] = create_example_fanflat( type ) +%% create_example_fanflat.m +% brief create an example geometry of type 'fanflat' +% param type type of geometry to create. provided as one of the +% following strings (not case sensitive): +% 'normal' - standard fanflat geometry +% 'vec' - example vector geometry +% return proj_geom - the geometry that was created +% date 22.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + if nargin < 1 + type = 'normal'; + end + + if strcmpi(type, 'normal') + geom = make_normal_geometry(); + elseif strcmpi(type, 'vec') + geom = create_example_fanflat('normal'); + geom = fanflat_to_fanflat_vec(geom); + + else + geom = make_normal_geometry(); + end + + function [geom] = make_normal_geometry() + % first, give measurements in mm + det_spacing = 0.035; + detector_px = 1200; + angles = linspace2(0, 2*pi, 100); + source_origin = 30; + origin_det = 200; + phantom_size = 5; + + phantom_px = 150; % voxels for the phantom + vx_size = phantom_size / phantom_px; % voxel size + + % now express all measurements in terms of the voxel size + det_spacing = det_spacing ./ vx_size; + origin_det = origin_det ./ vx_size; + source_origin = source_origin ./ vx_size; + + geom = astra_create_proj_geom('fanflat', det_spacing, ... + detector_px, angles, source_origin, origin_det); + end +end + diff --git a/matlab/algorithms/plot_geom/astra_create_example_parallel3d.m b/matlab/algorithms/plot_geom/astra_create_example_parallel3d.m new file mode 100644 index 0000000..e6fdf8e --- /dev/null +++ b/matlab/algorithms/plot_geom/astra_create_example_parallel3d.m @@ -0,0 +1,30 @@ +function [ proj_geom ] = create_example_parallel3d( type ) +%% create_example_parallel3d.m +% brief create an example geometry of type 'parallel3d' +% param type type of geometry to create. provided as one of the +% following strings (not case sensitive). +% no arguments will create a standard fanflat geometry. +% 'vec' - example vector geometry + +% return proj_geom - the geometry that was created +% date 22.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + if nargin < 1 + type = 'nothing'; + end + + det_spacing = [0.035, 0.035]; + detector_px = [1000, 1000]; + angles = linspace(0, 2*pi, 100); + + proj_geom = astra_create_proj_geom('parallel3d', det_spacing(1),... + det_spacing(2), detector_px(1), detector_px(2), angles); + + if strcmp(type, 'vec') + proj_geom = astra_geom_2vec(proj_geom); + end +end diff --git a/matlab/algorithms/plot_geom/create_example_cone.m b/matlab/algorithms/plot_geom/create_example_cone.m deleted file mode 100644 index 598899f..0000000 --- a/matlab/algorithms/plot_geom/create_example_cone.m +++ /dev/null @@ -1,165 +0,0 @@ -function [ proj_geom ] = create_example_cone(type) -%% create_example_cone.m -% create an example standard cone beam geometry -% param type type of geometry to create. provided as one of the -% following strings (not case sensitive): -% 'normal' - standard (non vector) geometry -% 'vec' - example vector geometry -% 'helix' - helical trajectory vector geometry -% 'deform_vec' - deformed vector geometry example, -% courtesy of Van Nguyen -% return proj_geom - the geometry that was created -% -% date 21.06.2018 -% author Tim Elberfeld, Alice Presenti, Van Nguyen -% imec VisionLab -% University of Antwerp -% last mod 07.11.2018 -%% - if(nargin < 1) - type = 'normal'; - end - if strcmpi(type, 'normal') - % first, give measurements in mm - det_spacing = [0.035, 0.035]; - detector_px = [1200, 1200]; - angles = linspace2(0, 2*pi, 100); - source_origin = 30; - origin_det = 200; - phantom_size = 5; - - phantom_px = 150; % voxels for the phantom - vx_size = phantom_size / phantom_px; % voxel size - - % now express all measurements in terms of the voxel size - det_spacing = det_spacing ./ vx_size; - origin_det = origin_det ./ vx_size; - source_origin = source_origin ./ vx_size; - - proj_geom = astra_create_proj_geom('cone', det_spacing(1), ... - det_spacing(2), detector_px(1), detector_px(2), angles,... - source_origin, origin_det); - - elseif strcmpi(type, 'vec') - proj_geom = create_standard_vec_geom(); - - elseif strcmpi(type, 'deform_vec') - proj_geom = create_deform_vec_geom(); - - elseif strcmpi(type, 'helix') - detRows = 220; - detCols = 220; - detPitchX = 10^-3 * 11; % microns to mm - detPitchY = 10^-3 * 11; % microns to mm - objSrcDist = 500; % mm - rotStep = 3.6; % deg - numAngles = 200; - zTranslation = 0.5; % mm - zDist = zTranslation * numAngles; - vectors = zeros(numAngles, 12); - translation = -zDist + (zTranslation * (0:(numAngles-1))); - - minAngle = 0; % just assume we start at 0 - maxAngle = (numAngles * rotStep)/180 * pi; % convert deg to rad - angles = linspace(minAngle, maxAngle, 200); - - % source position per angle - vectors(:, 1) = sin(angles) * objSrcDist; - vectors(:, 2) = -cos(angles) * objSrcDist; - vectors(:, 3) = translation; - - % detector position per angle - vectors(:, 4) = 0; - vectors(:, 5) = 0; - vectors(:, 6) = translation; - - % vector from detector pixel (0,0) to (0,1) - vectors(:, 7) = cos(angles); - vectors(:, 8) = sin(angles); - vectors(:, 9) = zeros(numAngles, 1); - - % vector from detector pixel (0,0) to (1, 0) - vectors(:, 10) = zeros(numAngles, 1); - vectors(:, 11) = zeros(numAngles, 1); - vectors(:, 12) = ones(numAngles, 1); - - proj_geom = astra_create_proj_geom('cone_vec', detCols, detRows, vectors); - - else - proj_geom = create_standard_vec_geom(); - end - - function [proj_geom, z_axis] = create_standard_vec_geom() - % geometry settings taken from code from Alice Presenti - settings = struct; - settings.detectorPixelSize = 0.0748; - % detector size and number of projections - settings.projectionSize = [1536 1944 21]; - settings.SOD = 679.238020; %[mm] - settings.SDD = 791.365618; %[mm] - settings.voxelSize = 1; %[mm] - settings.gamma = linspace(0,300,21)*pi/180; - - S0 = zeros(settings.projectionSize(3), 12); - Sorig = [-settings.SOD, 0, 0,... % the ray origin vector (source) - (settings.SDD-settings.SOD), 0, 0,... % detector center - 0, -settings.detectorPixelSize, 0,... % detector u axis - 0, 0, settings.detectorPixelSize]; % detector v axis - - z_axis = [0, 0, 1]; - for i = 1:settings.projectionSize(3) - S0(i,:) = Sorig(:); - S0(i,1:3) = rotate_around3d(S0(i,1:3),... - z_axis, settings.gamma(i)); - S0(i,4:6) = rotate_around3d(S0(i,4:6), z_axis,... - settings.gamma(i)); - S0(i,7:9) = rotate_around3d(S0(i,7:9), z_axis,... - settings.gamma(i)); - S0(i,10:12) = rotate_around3d(S0(i,10:12),... - z_axis, settings.gamma(i)); - end - proj_geom = astra_create_proj_geom('cone_vec', ... - settings.projectionSize(2), settings.projectionSize(1), S0); - end - - function [proj_geom, z_axis] = create_deform_vec_geom() - settings = struct; - settings.detectorPixelSize = 0.0748; - settings.projectionSize = [1536 1944 21]; - settings.SOD = 679.238020; %[mm] - settings.SDD = 791.365618; %[mm] - settings.voxelSize = 1; %[mm] - settings.gamma = linspace(0,300,21)*pi/180; - - S0 = zeros(settings.projectionSize(3), 12); - Sorig = [-settings.SOD, 0, 0,... % the ray origin vector (source) - (settings.SDD-settings.SOD), 0, 0,... % detector center - 0, -settings.detectorPixelSize, 0,... % detector u axis - 0, 0, settings.detectorPixelSize]; % detector v axis - - z_axis = [0, 0, 1]; - for i = 1:settings.projectionSize(3) - S0(i,:) = Sorig(:); - end - - S0(:, 1:3) = translate_3d(S0(:, 1:3), [100, 150, 0]); - S0(:, 4:6) = translate_3d(S0(:, 4:6), [100, 150, 0]); - - S0 = rotate_detector(S0, [0.48,0.32,0]); - S0 = magnify_proj(S0, 100); - for i = 1:settings.projectionSize(3) - S0(i,1:3) = rotate_around3d(S0(i,1:3), z_axis,... - settings.gamma(i)); - S0(i,4:6) = rotate_around3d(S0(i,4:6), z_axis,... - settings.gamma(i)); - S0(i,7:9) = rotate_around3d(S0(i,7:9), z_axis,... - settings.gamma(i)); - S0(i,10:12) = rotate_around3d(S0(i,10:12), z_axis,... - settings.gamma(i)); - end - - proj_geom = astra_create_proj_geom('cone_vec',... - settings.projectionSize(2), settings.projectionSize(1), S0); - end - -end diff --git a/matlab/algorithms/plot_geom/create_example_fanflat.m b/matlab/algorithms/plot_geom/create_example_fanflat.m deleted file mode 100644 index 703a618..0000000 --- a/matlab/algorithms/plot_geom/create_example_fanflat.m +++ /dev/null @@ -1,50 +0,0 @@ -function [ geom ] = create_example_fanflat( type ) -%% create_example_fanflat.m -% brief create an example geometry of type 'fanflat' -% param type type of geometry to create. provided as one of the -% following strings (not case sensitive): -% 'normal' - standard fanflat geometry -% 'vec' - example vector geometry -% return proj_geom - the geometry that was created -% date 22.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -% last mod 07.11.2018 -%% - if nargin < 1 - type = 'normal'; - end - - if strcmpi(type, 'normal') - geom = make_normal_geometry(); - elseif strcmpi(type, 'vec') - geom = create_example_fanflat('normal'); - geom = fanflat_to_fanflat_vec(geom); - - else - geom = make_normal_geometry(); - end - - function [geom] = make_normal_geometry() - % first, give measurements in mm - det_spacing = 0.035; - detector_px = 1200; - angles = linspace2(0, 2*pi, 100); - source_origin = 30; - origin_det = 200; - phantom_size = 5; - - phantom_px = 150; % voxels for the phantom - vx_size = phantom_size / phantom_px; % voxel size - - % now express all measurements in terms of the voxel size - det_spacing = det_spacing ./ vx_size; - origin_det = origin_det ./ vx_size; - source_origin = source_origin ./ vx_size; - - geom = astra_create_proj_geom('fanflat', det_spacing, ... - detector_px, angles, source_origin, origin_det); - end -end - diff --git a/matlab/algorithms/plot_geom/create_example_parallel3d.m b/matlab/algorithms/plot_geom/create_example_parallel3d.m deleted file mode 100644 index e6fdf8e..0000000 --- a/matlab/algorithms/plot_geom/create_example_parallel3d.m +++ /dev/null @@ -1,30 +0,0 @@ -function [ proj_geom ] = create_example_parallel3d( type ) -%% create_example_parallel3d.m -% brief create an example geometry of type 'parallel3d' -% param type type of geometry to create. provided as one of the -% following strings (not case sensitive). -% no arguments will create a standard fanflat geometry. -% 'vec' - example vector geometry - -% return proj_geom - the geometry that was created -% date 22.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -% last mod 07.11.2018 -%% - if nargin < 1 - type = 'nothing'; - end - - det_spacing = [0.035, 0.035]; - detector_px = [1000, 1000]; - angles = linspace(0, 2*pi, 100); - - proj_geom = astra_create_proj_geom('parallel3d', det_spacing(1),... - det_spacing(2), detector_px(1), detector_px(2), angles); - - if strcmp(type, 'vec') - proj_geom = astra_geom_2vec(proj_geom); - end -end diff --git a/matlab/algorithms/plot_geom/draw/create_gui_figure.m b/matlab/algorithms/plot_geom/draw/create_gui_figure.m deleted file mode 100644 index a9acecf..0000000 --- a/matlab/algorithms/plot_geom/draw/create_gui_figure.m +++ /dev/null @@ -1,58 +0,0 @@ -function [h_ax, running] = create_gui_figure() -%% create_gui_figure.m -% brief gui for the geometry drawing functions -% return h_ax axis to draw into with draw_*() functions -% running state of the rotation, needs to be passed so that -% the callback will work -% date 20.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -%% - h_figure = figure('name', 'geometry render', 'ButtonDownFcn', @toggle_rotation); - h_ax = axes(h_figure); - - set(h_figure,'CloseRequestFcn', @handle_close_fig) - - xlabel('x axis') - ylabel('y axis') - zlabel('z axis') - - grid on - box off - axis vis3d - axis equal - view(0,0) - - running = false; - do_rotation(); - - function [] = handle_close_fig(h_figure,~) - % this is necessary to stop the rotation before closing the figure - if running - toggle_rotation() - end - - delete(h_figure); - end - - function [] = toggle_rotation(~, ~) - % toggle rotation state - running = ~running; - if running - view(0,0) - do_rotation(); - else - view(45,45); - end - end - - function [] = do_rotation() - % rotate the rendered geometry around the origin - camtarget([0,0,0]); % make origin the camera target and point around which to rotate - while running - camorbit(0.5,0,'camera') - drawnow - end - end -end \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/draw/draw_cad_phantom.m b/matlab/algorithms/plot_geom/draw/draw_cad_phantom.m index 18873a8..92af844 100644 --- a/matlab/algorithms/plot_geom/draw/draw_cad_phantom.m +++ b/matlab/algorithms/plot_geom/draw/draw_cad_phantom.m @@ -1,9 +1,9 @@ -function [] = draw_cad_phantom(filename, magn, h_ax) +function [] = draw_cad_phantom(filename, magn) %% draw_cad_phantom.m % brief render an stl model into a 3d axis object % param vol_geom volume geometry describing the phantom -% param magn magnification multiplier of the phantom. default = 1 % param h_ax handle to axis to plot into +% param magn magnification multiplier of the phantom. default = 1 % % date 02.07.2018 % author Alice Presenti @@ -11,12 +11,10 @@ function [] = draw_cad_phantom(filename, magn, h_ax) % University of Antwerp % Modified by Tim Elberfeld %% + h_ax = gca; if nargin == 1 magn = 1; end - if nargin == 2 - h_ax = axes(gcf); - end [v,f,~,~] = stlRead(filename); m = mean(v); % to center the CAD model! diff --git a/matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m b/matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m index c1ed5b0..bee83b7 100644 --- a/matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m +++ b/matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m @@ -34,17 +34,15 @@ function [] = draw_cone_vec_geom(h_ax, geom, options) % draw the points and connect with lines hold on; num_angles = size(vectors, 1); - for jj = 1:num_angles - s_source = scatter3(h_ax, xray_source(jj, 1), xray_source(jj, 2),... - xray_source(jj, 3)); - s_source.Marker = options.SourceMarker; - s_source.MarkerEdgeColor = options.SourceMarkerColor; - - s_det = scatter3(h_ax, detector_center(jj, 1),... - detector_center(jj, 2), detector_center(jj, 3)); - s_det.MarkerEdgeColor = options.DetectorMarkerColor; - s_det.Marker = options.DetectorMarker; - end + s_source = scatter3(h_ax, xray_source(:, 1), xray_source(:, 2),... + xray_source(:, 3)); + s_source.Marker = options.SourceMarker; + s_source.MarkerEdgeColor = options.SourceMarkerColor; + + s_det = scatter3(h_ax, detector_center(:, 1),... + detector_center(:, 2), detector_center(:, 3)); + s_det.MarkerEdgeColor = options.DetectorMarkerColor; + s_det.Marker = options.DetectorMarker; detector = struct; detector.u = vectors(options.VectorIdx, 7:9); @@ -56,10 +54,12 @@ function [] = draw_cone_vec_geom(h_ax, geom, options) vertices = draw_detector_vec(h_ax, detector, options); connect_source_detector(h_ax, vertices, detector_center, ... xray_source, options); - distances = eucl_dist3d(detector_center, xray_source); - mean_sdd = mean(distances(:)); % mean source detector distance + % rotation axis will be roughly as long as the source detector distance + distances = eucl_dist3d(detector_center, xray_source); + mean_sdd = mean(distances(:)); % mean source detector distance draw_rotation_axis(h_ax, mean_sdd, options); + text(h_ax, xray_source(options.VectorIdx, 1),... xray_source(options.VectorIdx, 2),... xray_source(options.VectorIdx, 3), 'x-ray source'); diff --git a/matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m b/matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m index 9f5d620..b8261cf 100644 --- a/matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m +++ b/matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m @@ -29,15 +29,13 @@ function [ output_args ] = draw_fanflat_vec_geom( h_ax, geom, options) % draw the points and connect with lines hold on; - for jj = 1:num_angles - scatter3(h_ax, xray_source(jj, 1), xray_source(jj, 2),... - xray_source(jj, 3), options.SourceMarker,... - options.SourceMarkerColor); - scatter3(h_ax, detector_center(jj, 1),... - detector_center(jj, 2), detector_center(jj, 3),... - options.DetectorMarker, options.DetectorMarkerColor); - end - + scatter3(h_ax, xray_source(:, 1), xray_source(:, 2),... + xray_source(:, 3), options.SourceMarker,... + options.SourceMarkerColor); + scatter3(h_ax, detector_center(:, 1),... + detector_center(:, 2), detector_center(:, 3),... + options.DetectorMarker, options.DetectorMarkerColor); + detector = struct; detector.u = [vectors(options.VectorIdx, 5:6), 0]; detector.v = fliplr(detector.u); @@ -49,6 +47,7 @@ function [ output_args ] = draw_fanflat_vec_geom( h_ax, geom, options) connect_source_detector(h_ax, vertices, detector_center,... xray_source, options); + % rotation axis will be roughly as long as the source detector distance distances = eucl_dist3d(detector_center, xray_source); mean_sdd = mean(distances(:)); % mean source detector distance draw_rotation_axis(h_ax, mean_sdd, options); diff --git a/matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m b/matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m index 351ec42..ab63e43 100644 --- a/matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m +++ b/matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m @@ -23,13 +23,11 @@ function [ ] = draw_parallel3d_vec_geom( h_ax, geom, options) % draw the points and connect with lines hold on; num_angles = size(vectors, 1); - for jj = 1:num_angles - scatter3(h_ax, xray_source(jj, 1), xray_source(jj, 2), xray_source(jj, 3),... - options.SourceMarkerColor,... - options.SourceMarker); - scatter3(h_ax, detector_center(jj, 1), detector_center(jj, 2),... - detector_center(jj, 3), 'k.'); - end + scatter3(h_ax, xray_source(:, 1), xray_source(:, 2),... + xray_source(:, 3), options.SourceMarkerColor,... + options.SourceMarker); + scatter3(h_ax, detector_center(:, 1), detector_center(:, 2),... + detector_center(:, 3), 'k.'); detector = struct; detector.u = vectors(options.VectorIdx, 7:9); @@ -42,9 +40,11 @@ function [ ] = draw_parallel3d_vec_geom( h_ax, geom, options) connect_source_detector(h_ax, detector, detector_center, xray_source,... options); + % rotation axis will be roughly as long as the source detector distance distances = eucl_dist3d(detector_center, xray_source); mean_sdd = mean(distances(:)); % mean source detector distance draw_rotation_axis(h_ax, mean_sdd, options); + text(h_ax, xray_source(options.VectorIdx, 1),... xray_source(options.VectorIdx, 2), ... xray_source(options.VectorIdx, 3), 'x-ray source'); diff --git a/matlab/algorithms/plot_geom/draw/draw_proj_geom.m b/matlab/algorithms/plot_geom/draw/draw_proj_geom.m new file mode 100644 index 0000000..c20ddc8 --- /dev/null +++ b/matlab/algorithms/plot_geom/draw/draw_proj_geom.m @@ -0,0 +1,138 @@ +function [] = draw_proj_geom(geom, varargin) +%% draw_proj_geom.m +% brief rendering function for astra geometries. +% param geom the geometry to plot. If geometry type +% is not supported, throws error +% ------------------------------ +% optional parameters that can be provided as string value pairs: +% +% param RotationAxis if specified, will change the drawn +% rotation axis to provided axis. +% Must be 3-vector. Default value is +% [NaN, NaN, NaN], (meaning do not draw). +% param RotationAxisOffset if specified, will translate the drawn +% rotation axis by the provided vector. +% Default = [0, 0, 0] +% param VectorIdx index of the vector to visualize if geom +% is a vector geometry type. Default = 1 +% param Color Color for all markers and lines if not +% otherwise specified +% param DetectorMarker marker for the detector locations. +% Default = '.' +% param DetectorMarkerColor color specifier for the detector marker. +% Default = 'k' +% param DetectorLineColor color for the lines drawing the detector +% outline +% param DetectorLineWidth line width of detector rectangle +% param SourceMarker marker for the source locations +% param SourceMarkerColor color specifier for the source marker +% param SourceDistance (only for parallel3d and parallel3d_vec) +% distance of source to origin +% param OpticalAxisColor Color for drawing the optical axis +% +% date 20.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% +% - last update 07.11.2018 +%% + h_ax = gca; + options = parseoptions(varargin); + + switch geom.type + case 'parallel3d' + disp('type: parallel3d') + disp(['detector spacing: [' num2str(geom.DetectorSpacingX), ', '... + num2str(geom.DetectorSpacingY) ']']); + disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... + num2str(geom.DetectorColCount) ']']); + disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); + disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); + disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); + disp('DistanceOriginDetector inf'); + disp('DistanceOriginSource inf'); + + draw_parallel3d_geom(h_ax, geom, options); + case 'parallel3d_vec' + disp('type: parallel3d_vec') + disp(['detector px: [' num2str(geom.DetectorRowCount), ', '... + num2str(geom.DetectorColCount) ']']); + disp(['# angles: ' num2str(size(geom.Vectors, 1))]); + + draw_parallel3d_vec_geom(h_ax, geom, options); + case 'cone' + disp('type: cone'); + disp(['detector spacing: [' num2str(geom.DetectorSpacingX), ', '... + num2str(geom.DetectorSpacingY) ']']); + disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... + num2str(geom.DetectorColCount) ']']); + disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); + disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); + disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); + disp(['DistanceOriginDetector ' num2str(geom.DistanceOriginDetector)]); + disp(['DistanceOriginSource ' num2str(geom.DistanceOriginSource)]); + + draw_cone_geom(h_ax, geom, options); + case 'cone_vec' + disp('type: cone_vec'); + disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... + num2str(geom.DetectorColCount) ']']); + disp(['# angles: ' num2str(size(geom.Vectors, 1))]); + + draw_cone_vec_geom(h_ax, geom, options); + case 'fanflat' + disp('type: fanflat'); + disp(['detector px: ' num2str(geom.DetectorCount)]); + disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); + disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); + disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); + disp(['DistanceOriginDetector '... + num2str(geom.DistanceOriginDetector)]); + disp(['DistanceOriginSource '... + num2str(geom.DistanceOriginSource)]); + + draw_fanflat_geom(h_ax, geom, options); + case 'fanflat_vec' + disp('type: fanflat_vec'); + disp(['detector px: ' num2str(geom.DetectorCount)]); + disp(['# angles: ' num2str(size(geom.Vectors, 1))]); + + draw_fanflat_vec_geom(h_ax, geom, options); + otherwise + error(['Unknown geometry type ' geom.type]) + end + view(45, 25); % gives nicer default view angle + + function [options] = parseoptions(input_args) + % make an options struct + options = struct; + options.RotationAxis = [NaN, NaN, NaN]; + options.RotationAxisOffset = [0, 0, 0]; + options.VectorIdx = 1; + options.Color = 'k'; + options.DetectorMarker = '.'; + options.DetectorMarkerColor = ''; + options.DetectorLineColor = ''; + options.DetectorLineWidth = 1; + options.SourceMarker = '*'; + options.SourceMarkerColor = ''; + options.SourceDistance = 100; + options.OpticalAxisColor = ''; + options = parseargs(options, input_args{:}); + + % if the color is still empty, replace by global color + if strcmpi(options.DetectorMarkerColor , '') + options.DetectorMarkerColor = options.Color; + end + if strcmpi(options.DetectorLineColor , '') + options.DetectorLineColor = options.Color; + end + if strcmpi(options.SourceMarkerColor , '') + options.SourceMarkerColor = options.Color; + end + if strcmpi(options.OpticalAxisColor , '') + options.OpticalAxisColor = options.Color; + end + end +end diff --git a/matlab/algorithms/plot_geom/draw/draw_proj_geometry.m b/matlab/algorithms/plot_geom/draw/draw_proj_geometry.m deleted file mode 100644 index 0d31fa2..0000000 --- a/matlab/algorithms/plot_geom/draw/draw_proj_geometry.m +++ /dev/null @@ -1,142 +0,0 @@ -function [] = draw_proj_geometry(geom, h_ax, varargin) -%% draw_proj_geometry.m -% brief rendering function for astra geometries. -% param geom the geometry to plot. If geometry type -% is not supported, throws error -% param h_ax handle to axis to plot into -% ------------------------------ -% optional parameters that can be provided as string value pairs: -% -% param RotationAxis if specified, will change the drawn -% rotation axis to provided axis. -% Must be 3-vector. Default value is -% [NaN, NaN, NaN], (meaning do not draw). -% param RotationAxisOffset if specified, will translate the drawn -% rotation axis by the provided vector. -% Default = [0, 0, 0] -% param VectorIdx index of the vector to visualize if geom -% is a vector geometry type. Default = 1 -% param Color Color for all markers and lines if not -% otherwise specified -% param DetectorMarker marker for the detector locations. -% Default = '.' -% param DetectorMarkerColor color specifier for the detector marker. -% Default = 'k' -% param DetectorLineColor color for the lines drawing the detector -% outline -% param DetectorLineWidth line width of detector rectangle -% param SourceMarker marker for the source locations -% param SourceMarkerColor color specifier for the source marker -% param SourceDistance (only for parallel3d and parallel3d_vec) -% distance of source to origin -% param OpticalAxisColor Color for drawing the optical axis -% -% date 20.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -% -% - last update 07.11.2018 -%% - if nargin == 1 - h_ax = axes(gcf); - end - - options = parseoptions(varargin); - - switch geom.type - case 'parallel3d' - disp('type: parallel3d') - disp(['detector spacing: [' num2str(geom.DetectorSpacingX), ', '... - num2str(geom.DetectorSpacingY) ']']); - disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... - num2str(geom.DetectorColCount) ']']); - disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); - disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); - disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); - disp('DistanceOriginDetector inf'); - disp('DistanceOriginSource inf'); - - draw_parallel3d_geom(h_ax, geom, options); - case 'parallel3d_vec' - disp('type: parallel3d_vec') - disp(['detector px: [' num2str(geom.DetectorRowCount), ', '... - num2str(geom.DetectorColCount) ']']); - disp(['# angles: ' num2str(size(geom.Vectors, 1))]); - - draw_parallel3d_vec_geom(h_ax, geom, options); - case 'cone' - disp('type: cone'); - disp(['detector spacing: [' num2str(geom.DetectorSpacingX), ', '... - num2str(geom.DetectorSpacingY) ']']); - disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... - num2str(geom.DetectorColCount) ']']); - disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); - disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); - disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); - disp(['DistanceOriginDetector ' num2str(geom.DistanceOriginDetector)]); - disp(['DistanceOriginSource ' num2str(geom.DistanceOriginSource)]); - - draw_cone_geom(h_ax, geom, options); - case 'cone_vec' - disp('type: cone_vec'); - disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... - num2str(geom.DetectorColCount) ']']); - disp(['# angles: ' num2str(size(geom.Vectors, 1))]); - - draw_cone_vec_geom(h_ax, geom, options); - case 'fanflat' - disp('type: fanflat'); - disp(['detector px: ' num2str(geom.DetectorCount)]); - disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); - disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); - disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); - disp(['DistanceOriginDetector '... - num2str(geom.DistanceOriginDetector)]); - disp(['DistanceOriginSource '... - num2str(geom.DistanceOriginSource)]); - - draw_fanflat_geom(h_ax, geom, options); - case 'fanflat_vec' - disp('type: fanflat_vec'); - disp(['detector px: ' num2str(geom.DetectorCount)]); - disp(['# angles: ' num2str(size(geom.Vectors, 1))]); - - draw_fanflat_vec_geom(h_ax, geom, options); - otherwise - error(['Unknown geometry type ' geom.type]) - end - view(45, 25); % gives nicer default view angle - - function [options] = parseoptions(input_args) - % make an options struct - options = struct; - options.RotationAxis = [NaN, NaN, NaN]; - options.RotationAxisOffset = [0, 0, 0]; - options.VectorIdx = 1; - options.Color = 'k'; - options.DetectorMarker = '.'; - options.DetectorMarkerColor = ''; - options.DetectorLineColor = ''; - options.DetectorLineWidth = 1; - options.SourceMarker = '*'; - options.SourceMarkerColor = ''; - options.SourceDistance = 100; - options.OpticalAxisColor = ''; - options = parseargs(options, input_args{:}); - - % if the color is still empty, replace by global color - if strcmpi(options.DetectorMarkerColor , '') - options.DetectorMarkerColor = options.Color; - end - if strcmpi(options.DetectorLineColor , '') - options.DetectorLineColor = options.Color; - end - if strcmpi(options.SourceMarkerColor , '') - options.SourceMarkerColor = options.Color; - end - if strcmpi(options.OpticalAxisColor , '') - options.OpticalAxisColor = options.Color; - end - end -end diff --git a/matlab/algorithms/plot_geom/draw/draw_vol_geom.m b/matlab/algorithms/plot_geom/draw/draw_vol_geom.m index e6d550d..0b4fe2f 100644 --- a/matlab/algorithms/plot_geom/draw/draw_vol_geom.m +++ b/matlab/algorithms/plot_geom/draw/draw_vol_geom.m @@ -1,17 +1,17 @@ -function [] = draw_vol_geom( vol_geom, vx_size, h_ax, varargin) +function [] = draw_vol_geom( vol_geom, varargin) %% draw_vol_geom.m % brief rendering function for astra volume geometries % describing a phantom. % param vol_geom volume geometry describing the phantom % param vx_size voxel size in unit of preference. must be same unit % that was used to scale the projection geometry -% param h_ax handle to axis to plot into % ------------------------------ % optional parameters that can be provided as string value pairs: % % param Magnification magnification factor for the phantom. for small -% phantoms it might be necessary to scale the render up -% as otherwise it won't show up in the plot. Default = 1 +% phantoms it might be necessary to scale the render +% up as otherwise it won't show up in the plot. +% Default = 1 % param LineWidth line width for the box wireframe. Default = 2 % param Color color of the wireframe. Default = 'r' % @@ -20,12 +20,18 @@ function [] = draw_vol_geom( vol_geom, vx_size, h_ax, varargin) % imec VisionLab % University of Antwerp % -% - last update 09.07.2018 +% - last update 16.11.2018 %% - if nargin < 4 - h_ax = axes(gcf); - end + h_ax = gca; + if mod(size(varargin), 2) ~= 0 + vx_size = varargin{1}; + varargin = varargin(2:end); % consumed vx_size from arg list + else + vx_size = 1; + end + + options = struct; options.Color = 'r'; options.LineWidth = 2; diff --git a/matlab/algorithms/plot_geom/stl/bunny.stl b/matlab/algorithms/plot_geom/stl/bunny.stl deleted file mode 100644 index 0b7fcaa..0000000 Binary files a/matlab/algorithms/plot_geom/stl/bunny.stl and /dev/null differ diff --git a/matlab/tools/astra_plot_geom.m b/matlab/tools/astra_plot_geom.m new file mode 100644 index 0000000..3a654fd --- /dev/null +++ b/matlab/tools/astra_plot_geom.m @@ -0,0 +1,91 @@ +function [] = astra_plot_geom(geometry, varargin) +%-------------------------------------------------------------------------- +% [] = astra_plot_geometry(geometry, varargin) +% +% plot an astra geometry +% +% geometry: any astra geometry, either volume geometry, projection +% geometry or an *.stl file (powered by stlRead). +% varargin: supports a variable number of (ordered and unordered) +% arguments. +% +% the remaining arguments depend on the input: +% if 'geometry' is +% - a volume geometry +% vx_size voxel size in unit of preference. Must +% be same unit that was used to scale the +% projection geometry. +% and as unorderd string-value-pairs +% Magnification magnification factor for the phantom. +% For small phantoms it might be +% necessary to scale the render up as +% otherwise it won't show up in the plot. +% Default = 1 +% LineWidth line width for the box wireframe. +% Default = 2 +% Color color of the wireframe. Default = 'r' +% +% - a projection geometry (as unordered string-value-pairs) +% RotationAxis if specified, will change the drawn +% rotation axis to provided axis. +% Must be 3-vector. Default value is +% [NaN, NaN, NaN], (meaning do not draw). +% RotationAxisOffset if specified, will translate the drawn +% rotation axis by the provided vector. +% Default = [0, 0, 0] +% VectorIdx index of the vector to visualize if +% vector geometry type. Default = 1 +% Color Color for all markers and lines if not +% otherwise specified +% DetectorMarker marker for the detector locations. +% Default = '.' +% DetectorMarkerColor color specifier for the detector marker. +% Default = 'k' +% DetectorLineColor color for the lines drawing the +% detector outline +% DetectorLineWidth line width of detector rectangle +% SourceMarker marker for the source locations +% SourceMarkerColor color specifier for the source marker +% SourceDistance (only for parallel3d and parallel3d_vec) +% distance of source to origin +% OpticalAxisColor Color for drawing the optical axis +% +% - a path to an *.stl file +% magn - magnification factor for vertices in +% CAD file. Default value = 1 +% +%-------------------------------------------------------------------------- +%-------------------------------------------------------------------------- +% This file is part of the ASTRA Toolbox +% +% Copyright: 2010-2018, imec Vision Lab, University of Antwerp +% 2014-2018, CWI, Amsterdam +% License: Open Source under GPLv3 +% Contact: astra@astra-toolbox.com +% Website: http://www.astra-toolbox.com/ +%-------------------------------------------------------------------------- + addpath(genpath('../algorithms/plot_geom')); % add plot_geom tools to matlab path + + if is_vol_geom(geometry) + draw_vol_geom(geometry, varargin{:}); + elseif is_proj_geom(geometry) + draw_proj_geom(geometry, varargin{:}); + elseif ischar(geometry) % assume 'geometry' is a path to a CAD file + draw_cad_phantom(geometry, varargin{:}); + end + + % ---- helper functions ---- + function [ res ] = is_vol_geom(geom) + res = false; + if sum(isfield(geom, {'GridRowCount', 'GridColCount'})) == 2 + res = true; + end + end + + function [ res ] = is_proj_geom(geom) + res = false; + if isfield(geom, 'type') + res = true; + end + end +end diff --git a/samples/matlab/bunny.stl b/samples/matlab/bunny.stl new file mode 100644 index 0000000..0b7fcaa Binary files /dev/null and b/samples/matlab/bunny.stl differ diff --git a/samples/matlab/s024_plot_geometry.m b/samples/matlab/s024_plot_geometry.m new file mode 100644 index 0000000..dd57997 --- /dev/null +++ b/samples/matlab/s024_plot_geometry.m @@ -0,0 +1,42 @@ +%% s024_plot_geometry.m +% brief example of usage for astra_plot_geom command +% - last update 16.11.2018 +% ----------------------------------------------------------------------- +% This file is part of the ASTRA Toolbox +% +% Copyright: 2010-2018, imec Vision Lab, University of Antwerp +% 2014-2018, CWI, Amsterdam +% License: Open Source under GPLv3 +% Contact: astra@astra-toolbox.com +% Website: http://www.astra-toolbox.com/ +% ----------------------------------------------------------------------- +%% +close all; + +% proj_geom = astra_create_example_cone('vec'); +% proj_geom = astra_create_example_cone('normal'); +proj_geom = astra_create_example_cone('helix'); +% proj_geom = astra_create_example_parallel3d('vec'); +% proj_geom = astra_create_example_fanflat('vec'); +% proj_geom = astra_create_example_fanflat(); +% proj_geom = astra_create_example_parallel3d(); +% proj_geom = create_example_cone('deform_vec'); + +astra_plot_geom(proj_geom); +hold on; + +vol_magn = 20; +phantom_size = 5; +phantom_px = 1500; +vx_size = phantom_size / phantom_px; % voxel size +vol_geom = astra_create_vol_geom(phantom_px, phantom_px, phantom_px); +line_width = 1; % line width for phantom +astra_plot_geom(vol_geom, vx_size, 'Magnification', vol_magn,... + 'LineWidth', line_width, 'Color', 'r'); + +% this magnification is empirically chosen to fit the stl file +cad_magn = 900; +astra_plot_geom('bunny.stl', cad_magn); + +hold off; +axis equal; -- cgit v1.2.3 From 3276485c96636cd38248908ff3575282654ff335 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Wed, 12 Dec 2018 14:45:38 +0100 Subject: Reorganize functions into packages/private functions This also replaces modifying the path with a request to the user to modify the path. --- build/linux/Makefile.in | 20 +- .../algorithms/plot_geom/+draw/draw_cad_phantom.m | 35 +++ matlab/algorithms/plot_geom/+draw/draw_cone_geom.m | 73 ++++++ .../plot_geom/+draw/draw_cone_vec_geom.m | 108 +++++++++ .../algorithms/plot_geom/+draw/draw_detector_vec.m | 42 ++++ .../algorithms/plot_geom/+draw/draw_fanflat_geom.m | 25 ++ .../plot_geom/+draw/draw_fanflat_vec_geom.m | 102 +++++++++ .../plot_geom/+draw/draw_parallel3d_geom.m | 88 +++++++ .../plot_geom/+draw/draw_parallel3d_vec_geom.m | 100 ++++++++ matlab/algorithms/plot_geom/+draw/draw_proj_geom.m | 138 +++++++++++ matlab/algorithms/plot_geom/+draw/draw_vol_geom.m | 105 +++++++++ .../plot_geom/+draw/private/eucl_dist3d.m | 16 ++ matlab/algorithms/plot_geom/+parseargs/license.txt | 27 +++ matlab/algorithms/plot_geom/+parseargs/parseargs.m | 97 ++++++++ matlab/algorithms/plot_geom/+stlTools/license.txt | 34 +++ matlab/algorithms/plot_geom/+stlTools/readme.txt | 16 ++ .../algorithms/plot_geom/+stlTools/stlAddVerts.m | 17 ++ .../algorithms/plot_geom/+stlTools/stlDelVerts.m | 26 +++ matlab/algorithms/plot_geom/+stlTools/stlDemo.m | 41 ++++ .../algorithms/plot_geom/+stlTools/stlGetFormat.m | 38 ++++ .../algorithms/plot_geom/+stlTools/stlGetVerts.m | 31 +++ matlab/algorithms/plot_geom/+stlTools/stlPlot.m | 23 ++ matlab/algorithms/plot_geom/+stlTools/stlRead.m | 15 ++ .../algorithms/plot_geom/+stlTools/stlReadAscii.m | 58 +++++ .../algorithms/plot_geom/+stlTools/stlReadBinary.m | 62 +++++ .../algorithms/plot_geom/+stlTools/stlSlimVerts.m | 29 +++ matlab/algorithms/plot_geom/+stlTools/stlWrite.m | 252 +++++++++++++++++++++ .../plot_geom/astra_create_example_fanflat.m | 4 +- .../algorithms/plot_geom/draw/draw_cad_phantom.m | 35 --- matlab/algorithms/plot_geom/draw/draw_cone_geom.m | 73 ------ .../algorithms/plot_geom/draw/draw_cone_vec_geom.m | 108 --------- .../algorithms/plot_geom/draw/draw_detector_vec.m | 42 ---- .../algorithms/plot_geom/draw/draw_fanflat_geom.m | 25 -- .../plot_geom/draw/draw_fanflat_vec_geom.m | 102 --------- .../plot_geom/draw/draw_parallel3d_geom.m | 88 ------- .../plot_geom/draw/draw_parallel3d_vec_geom.m | 100 -------- matlab/algorithms/plot_geom/draw/draw_proj_geom.m | 138 ----------- matlab/algorithms/plot_geom/draw/draw_vol_geom.m | 105 --------- matlab/algorithms/plot_geom/private/magnify_proj.m | 23 ++ .../algorithms/plot_geom/private/rotate_around3d.m | 27 +++ .../algorithms/plot_geom/private/rotate_detector.m | 19 ++ .../algorithms/plot_geom/private/rotate_euler3d.m | 35 +++ matlab/algorithms/plot_geom/private/translate_3d.m | 18 ++ .../algorithms/plot_geom/util/cone_to_cone_vec.m | 41 ---- matlab/algorithms/plot_geom/util/eucl_dist3d.m | 16 -- .../plot_geom/util/fanflat_to_fanflat_vec.m | 4 - matlab/algorithms/plot_geom/util/magnify_proj.m | 23 -- .../plot_geom/util/parseargs/license.txt | 27 --- .../plot_geom/util/parseargs/parseargs.m | 97 -------- matlab/algorithms/plot_geom/util/rotate_around3d.m | 27 --- matlab/algorithms/plot_geom/util/rotate_detector.m | 19 -- matlab/algorithms/plot_geom/util/rotate_euler3d.m | 35 --- .../algorithms/plot_geom/util/stlTools/license.txt | 34 --- .../algorithms/plot_geom/util/stlTools/readme.txt | 16 -- .../plot_geom/util/stlTools/stlAddVerts.m | 15 -- .../plot_geom/util/stlTools/stlDelVerts.m | 26 --- .../algorithms/plot_geom/util/stlTools/stlDemo.m | 39 ---- .../plot_geom/util/stlTools/stlGetFormat.m | 38 ---- .../plot_geom/util/stlTools/stlGetVerts.m | 31 --- .../algorithms/plot_geom/util/stlTools/stlPlot.m | 23 -- .../algorithms/plot_geom/util/stlTools/stlRead.m | 13 -- .../plot_geom/util/stlTools/stlReadAscii.m | 56 ----- .../plot_geom/util/stlTools/stlReadBinary.m | 60 ----- .../plot_geom/util/stlTools/stlSlimVerts.m | 29 --- .../algorithms/plot_geom/util/stlTools/stlWrite.m | 252 --------------------- matlab/algorithms/plot_geom/util/translate_3d.m | 18 -- matlab/tools/astra_plot_geom.m | 10 +- samples/matlab/s024_plot_geometry.m | 7 +- 68 files changed, 1738 insertions(+), 1778 deletions(-) create mode 100644 matlab/algorithms/plot_geom/+draw/draw_cad_phantom.m create mode 100644 matlab/algorithms/plot_geom/+draw/draw_cone_geom.m create mode 100644 matlab/algorithms/plot_geom/+draw/draw_cone_vec_geom.m create mode 100644 matlab/algorithms/plot_geom/+draw/draw_detector_vec.m create mode 100644 matlab/algorithms/plot_geom/+draw/draw_fanflat_geom.m create mode 100644 matlab/algorithms/plot_geom/+draw/draw_fanflat_vec_geom.m create mode 100644 matlab/algorithms/plot_geom/+draw/draw_parallel3d_geom.m create mode 100644 matlab/algorithms/plot_geom/+draw/draw_parallel3d_vec_geom.m create mode 100644 matlab/algorithms/plot_geom/+draw/draw_proj_geom.m create mode 100644 matlab/algorithms/plot_geom/+draw/draw_vol_geom.m create mode 100644 matlab/algorithms/plot_geom/+draw/private/eucl_dist3d.m create mode 100644 matlab/algorithms/plot_geom/+parseargs/license.txt create mode 100644 matlab/algorithms/plot_geom/+parseargs/parseargs.m create mode 100644 matlab/algorithms/plot_geom/+stlTools/license.txt create mode 100644 matlab/algorithms/plot_geom/+stlTools/readme.txt create mode 100644 matlab/algorithms/plot_geom/+stlTools/stlAddVerts.m create mode 100644 matlab/algorithms/plot_geom/+stlTools/stlDelVerts.m create mode 100644 matlab/algorithms/plot_geom/+stlTools/stlDemo.m create mode 100644 matlab/algorithms/plot_geom/+stlTools/stlGetFormat.m create mode 100644 matlab/algorithms/plot_geom/+stlTools/stlGetVerts.m create mode 100644 matlab/algorithms/plot_geom/+stlTools/stlPlot.m create mode 100644 matlab/algorithms/plot_geom/+stlTools/stlRead.m create mode 100644 matlab/algorithms/plot_geom/+stlTools/stlReadAscii.m create mode 100644 matlab/algorithms/plot_geom/+stlTools/stlReadBinary.m create mode 100644 matlab/algorithms/plot_geom/+stlTools/stlSlimVerts.m create mode 100644 matlab/algorithms/plot_geom/+stlTools/stlWrite.m delete mode 100644 matlab/algorithms/plot_geom/draw/draw_cad_phantom.m delete mode 100644 matlab/algorithms/plot_geom/draw/draw_cone_geom.m delete mode 100644 matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m delete mode 100644 matlab/algorithms/plot_geom/draw/draw_detector_vec.m delete mode 100644 matlab/algorithms/plot_geom/draw/draw_fanflat_geom.m delete mode 100644 matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m delete mode 100644 matlab/algorithms/plot_geom/draw/draw_parallel3d_geom.m delete mode 100644 matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m delete mode 100644 matlab/algorithms/plot_geom/draw/draw_proj_geom.m delete mode 100644 matlab/algorithms/plot_geom/draw/draw_vol_geom.m create mode 100644 matlab/algorithms/plot_geom/private/magnify_proj.m create mode 100644 matlab/algorithms/plot_geom/private/rotate_around3d.m create mode 100644 matlab/algorithms/plot_geom/private/rotate_detector.m create mode 100644 matlab/algorithms/plot_geom/private/rotate_euler3d.m create mode 100644 matlab/algorithms/plot_geom/private/translate_3d.m delete mode 100644 matlab/algorithms/plot_geom/util/cone_to_cone_vec.m delete mode 100644 matlab/algorithms/plot_geom/util/eucl_dist3d.m delete mode 100644 matlab/algorithms/plot_geom/util/fanflat_to_fanflat_vec.m delete mode 100644 matlab/algorithms/plot_geom/util/magnify_proj.m delete mode 100644 matlab/algorithms/plot_geom/util/parseargs/license.txt delete mode 100644 matlab/algorithms/plot_geom/util/parseargs/parseargs.m delete mode 100644 matlab/algorithms/plot_geom/util/rotate_around3d.m delete mode 100644 matlab/algorithms/plot_geom/util/rotate_detector.m delete mode 100644 matlab/algorithms/plot_geom/util/rotate_euler3d.m delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/license.txt delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/readme.txt delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlAddVerts.m delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlDelVerts.m delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlDemo.m delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlGetFormat.m delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlGetVerts.m delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlPlot.m delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlRead.m delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlReadAscii.m delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlReadBinary.m delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlSlimVerts.m delete mode 100644 matlab/algorithms/plot_geom/util/stlTools/stlWrite.m delete mode 100644 matlab/algorithms/plot_geom/util/translate_3d.m diff --git a/build/linux/Makefile.in b/build/linux/Makefile.in index 73d8279..a294578 100644 --- a/build/linux/Makefile.in +++ b/build/linux/Makefile.in @@ -521,22 +521,10 @@ install-matlab: $(MATLAB_MEX) install-matlab-so $(INSTALL_SH) -m 755 $(MATLAB_MEX) $(MATLABBASE)/mex $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/tools/*.m $(MATLABBASE)/tools - # TODO: there must be a more efficient way to do this than to create and fill every single folder - # install plot_geom - $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom - $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/*.m $(MATLABBASE)/algorithms/plot_geom - - $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/draw - $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/draw/*.m $(MATLABBASE)/algorithms/plot_geom/draw - - $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/util - $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/util/*.m $(MATLABBASE)/algorithms/plot_geom/util - - $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/util/parseargs - $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/util/parseargs/* $(MATLABBASE)/algorithms/plot_geom/util/parseargs - - $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/plot_geom/util/stlTools - $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/plot_geom/util/stlTools/* $(MATLABBASE)/algorithms/plot_geom/util/stlTools + for D in plot_geom plot_geom/private plot_geom/+draw plot_geom/+draw/private plot_geom/+parseargs plot_geom/+stlTools; do \ + $(INSTALL_SH) -m 755 -d $(MATLABBASE)/algorithms/$$D; \ + $(INSTALL_SH) -m 644 $(srcdir)/../../matlab/algorithms/$$D/*.m $(MATLABBASE)/algorithms/$$D; \ + done # TODO: docs else diff --git a/matlab/algorithms/plot_geom/+draw/draw_cad_phantom.m b/matlab/algorithms/plot_geom/+draw/draw_cad_phantom.m new file mode 100644 index 0000000..55dedc4 --- /dev/null +++ b/matlab/algorithms/plot_geom/+draw/draw_cad_phantom.m @@ -0,0 +1,35 @@ +function [] = draw_cad_phantom(filename, magn) +%% draw_cad_phantom.m +% brief render an stl model into a 3d axis object +% param vol_geom volume geometry describing the phantom +% param h_ax handle to axis to plot into +% param magn magnification multiplier of the phantom. default = 1 +% +% date 02.07.2018 +% author Alice Presenti +% imec VisionLab +% University of Antwerp +% Modified by Tim Elberfeld +%% + h_ax = gca; + if nargin == 1 + magn = 1; + end + + [v,f,~,~] = stlTools.stlRead(filename); + m = mean(v); % to center the CAD model! + for i=1:3 + v(:,i) = (v(:,i)- m(i)) .* magn; + end + object.vertices = v; + object.faces = f; + patch(h_ax, object,'FaceColor', [0.8 0.8 1.0], ... + 'EdgeColor', 'none', ... + 'FaceLighting', 'gouraud', ... + 'AmbientStrength', 0.15); + % Add a camera light, and tone down the specular highlighting + camlight('headlight'); + material('dull'); + hold off; + +end \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/+draw/draw_cone_geom.m b/matlab/algorithms/plot_geom/+draw/draw_cone_geom.m new file mode 100644 index 0000000..ae98294 --- /dev/null +++ b/matlab/algorithms/plot_geom/+draw/draw_cone_geom.m @@ -0,0 +1,73 @@ +function [] = draw_cone_geom(h_ax, geom, options) +%% draw_cone_geom.m +% draw an astra cone beam projection geometry +% +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options struct containing the options for this function +% SourceMarker marker to use to mark the source location +% SourceMarkerColor Color of the marker for the source +% DetectorLineColor Color of the lines that draw the detector +% DetectorLineWidth Width of the lines that draw the detector +% OpticalAxisColor color of the lines representing the optical axis +% +% date 21.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + hold on; + % draw origin + h_origin = scatter3(h_ax, 0,0,0, '+k'); + h_origin.SizeData = 120; + h_origin.LineWidth = 2; + + % draw lines between source, origin and detector + line(h_ax, [0, 0], [0, geom.DistanceOriginDetector], [0, 0], 'Color', options.OpticalAxisColor); + line(h_ax, [0, 0], [0, -geom.DistanceOriginSource], [0, 0], 'Color', options.OpticalAxisColor); + + % draw source + scatter3(h_ax, 0, -geom.DistanceOriginSource, 0, options.SourceMarker,... + options.SourceMarkerColor); + + detector = draw_detector(h_ax, geom, options); + + % connect source to detector edges + for idx = 1:4 + line(h_ax,[0, detector.vertices(1, idx)], ... + [-geom.DistanceOriginSource, geom.DistanceOriginDetector],... + [0, detector.vertices(3, idx)],... + 'Color', 'k', 'LineStyle', ':'); + end + + % draw rotation axis + line(h_ax, [0,0],[0,0], 0.6*[-detector.height, detector.height],... + 'LineWidth', options.DetectorLineWidth, 'Color',... + 'k', 'LineStyle', '--'); + + perc = 0.05; + text(h_ax, perc*detector.width, perc*detector.width,... + 0.8*detector.height, 'rotation axis'); + text(h_ax, detector.width*perc, 0, perc*detector.height, 'origin'); + text(h_ax, detector.width*perc, -geom.DistanceOriginSource,... + perc*detector.height, 'x-ray source'); + text(h_ax, 0, geom.DistanceOriginDetector, 0, 'detector'); + hold off; + + function [detector] = draw_detector(h_ax, geom, options) + detector = struct; + detector.height = geom.DetectorRowCount * geom.DetectorSpacingY; + detector.width = geom.DetectorColCount * geom.DetectorSpacingX; + + vertices = zeros(3, 5); + vertices(1, :) = 0.5*[-detector.width, -detector.width,... + detector.width, detector.width, -detector.width]; + vertices(2, :) = repmat([geom.DistanceOriginDetector], 5, 1); + vertices(3, :) = 0.5*[detector.height, -detector.height,... + -detector.height, detector.height, detector.height]; + + detector.vertices = vertices; + plot3(h_ax, detector.vertices(1, :), detector.vertices(2, :),... + detector.vertices(3, :), options.DetectorLineColor); + end +end diff --git a/matlab/algorithms/plot_geom/+draw/draw_cone_vec_geom.m b/matlab/algorithms/plot_geom/+draw/draw_cone_vec_geom.m new file mode 100644 index 0000000..dac7410 --- /dev/null +++ b/matlab/algorithms/plot_geom/+draw/draw_cone_vec_geom.m @@ -0,0 +1,108 @@ +function [] = draw_cone_vec_geom(h_ax, geom, options) +%% draw_cone_vec_geom.m +% draw an astra cone beam vectorized projection geometry +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options struct holding options for drawing +% RotationAxis if specified, will change the rotation axis +% from z-axis to provided axis. +% Must be 3-vector. Default value [0, 0, 1] +% VectorIdx the index of the angle to draw +% Color global color for all lines and markers. +% is overwritten by specialized color options +% SourceMarker Marker to use to mark the source +% SourceMarkerColor Color of the source marker +% DetectorMarker Marker to use to mark the source +% DetectorMarkerColor Color of the source marker +% DetectorLineColor Color of the outline of the detector +% OpticalAxisColor color for drawing the optical axis +% +% date 21.06.2018 +% author Tim Elberfeld, Van Nguyen +% imec VisionLab +% University of Antwerp +% +% - last update 07.11.2018 +%% + vectors = geom.Vectors; + + % source + xray_source = vectors(:, 1:3); + % center of detector + detector_center = vectors(:, 4:6); + + % draw the points and connect with lines + hold on; + num_angles = size(vectors, 1); + s_source = scatter3(h_ax, xray_source(:, 1), xray_source(:, 2),... + xray_source(:, 3)); + s_source.Marker = options.SourceMarker; + s_source.MarkerEdgeColor = options.SourceMarkerColor; + + s_det = scatter3(h_ax, detector_center(:, 1),... + detector_center(:, 2), detector_center(:, 3)); + s_det.MarkerEdgeColor = options.DetectorMarkerColor; + s_det.Marker = options.DetectorMarker; + + detector = struct; + detector.u = vectors(options.VectorIdx, 7:9); + detector.v = vectors(options.VectorIdx, 10:12); + detector.height = geom.DetectorColCount; + detector.width = geom.DetectorRowCount; + detector.origin = detector_center(options.VectorIdx, :); + + vertices = draw.draw_detector_vec(h_ax, detector, options); + connect_source_detector(h_ax, vertices, detector_center, ... + xray_source, options); + + % rotation axis will be roughly as long as the source detector distance + distances = eucl_dist3d(detector_center, xray_source); + mean_sdd = mean(distances(:)); % mean source detector distance + draw_rotation_axis(h_ax, mean_sdd, options); + + text(h_ax, xray_source(options.VectorIdx, 1),... + xray_source(options.VectorIdx, 2),... + xray_source(options.VectorIdx, 3), 'x-ray source'); + text(h_ax, detector_center(options.VectorIdx, 1),... + detector_center(options.VectorIdx, 2),... + detector_center(options.VectorIdx, 3), 'detector'); + hold off; + + function [] = connect_source_detector(h_ax, vertices,... + detector_center, xray_source, options) + % connect source to detector origin + idx = options.VectorIdx; + line(h_ax, [detector_center(idx, 1), xray_source(idx, 1)],... + [detector_center(idx, 2), xray_source(idx, 2)],... + [detector_center(idx, 3), xray_source(idx, 3)],... + 'Color', options.OpticalAxisColor, 'LineStyle', '--'); + + % connect source to detector edges + for kk = 1:4 + line(h_ax,[xray_source(idx, 1), vertices(1, kk)], ... + [xray_source(idx, 2), vertices(2, kk)],... + [xray_source(idx, 3), vertices(3, kk)],... + 'Color', 'k', 'LineStyle', ':'); + end + end + + function [] = draw_rotation_axis(h_ax, scaling, options) + % draw rotation axis + rot_axis = options.RotationAxis; + if(~isnan(rot_axis(1))) + rot_axis = options.RotationAxis + options.RotationAxisOffset; + origin = options.RotationAxisOffset; + % origin of the geometry is assumed to be [0, 0, 0] always! + line(h_ax, [origin(1), (scaling/2)*rot_axis(1)],... + [origin(2), (scaling/2)*rot_axis(2)],... + [origin(3), (scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + line(h_ax, [origin(1), -(scaling/2)*rot_axis(1)],... + [origin(2), -(scaling/2)*rot_axis(2)],... + [origin(3), -(scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + end + end +end diff --git a/matlab/algorithms/plot_geom/+draw/draw_detector_vec.m b/matlab/algorithms/plot_geom/+draw/draw_detector_vec.m new file mode 100644 index 0000000..5c293d4 --- /dev/null +++ b/matlab/algorithms/plot_geom/+draw/draw_detector_vec.m @@ -0,0 +1,42 @@ +function [ vertices] = draw_detector_vec( h_ax, detector, options) +%% draw_detector_vec.m +% draw a detector for a vector geometry +% param h_ax handle to axis to draw into +% param detector the struct specifying the detector +% .origin 3d coordinates of the detector origin +% .u vector pointing from detector origin to +% pixel (1,0) +% .v vector pointing from detector origin to +% pixel (0,1) +% .width width of the detector (number of px in u +% direction) +% .height height of the detector (number of px in v +% direction) +% param options struct with options +% .Color Color for the line work +% .DetectorLineColor Color of the detector rectangle outline +% return The vertices of the detector rectangle that +% were plotted +% +% date 09.07.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + % draw the detector rectangle + vertices = zeros(3, 5); + vertices(:, 1) = detector.origin - detector.u * detector.width / 2 + ... + detector.v * detector.height / 2; + vertices(:, 2) = detector.origin + detector.u * detector.width / 2 + ... + detector.v * detector.height / 2; + vertices(:, 3) = detector.origin + detector.u * detector.width / 2 - ... + detector.v * detector.height / 2; + vertices(:, 4) = detector.origin - detector.u * detector.width / 2 - ... + detector.v * detector.height / 2; + vertices(:, 5) = vertices(:, 1); + + detector.vertices = vertices; + plot3(h_ax, detector.vertices(1, :), detector.vertices(2, :),... + detector.vertices(3, :), options.DetectorLineColor); + +end diff --git a/matlab/algorithms/plot_geom/+draw/draw_fanflat_geom.m b/matlab/algorithms/plot_geom/+draw/draw_fanflat_geom.m new file mode 100644 index 0000000..a5f28ea --- /dev/null +++ b/matlab/algorithms/plot_geom/+draw/draw_fanflat_geom.m @@ -0,0 +1,25 @@ +function [] = draw_fanflat_geom( h_ax, geom, options) +%% draw_fanflat_geom.m +% draw an astra cone beam projection geometry +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options struct holding options for drawing +% SourceMarker Marker to use to mark the source +% SourceMarkerColor Color of the source marker +% DetectorMarker Marker to use to mark the source +% DetectorMarkerColor Color of the source marker +% DetectorLineColor Color of the outline of the detector +% OpticalAxisColor color for drawing the optical axis +% date 28.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + % convert to faux cone geometry so we don't have to write more code :)! + cone_geom = astra_create_proj_geom('cone', geom.DetectorWidth,... + geom.DetectorWidth, 1, geom.DetectorCount, geom.ProjectionAngles,... + geom.DistanceOriginSource, geom.DistanceOriginDetector); + + draw.draw_cone_geom(h_ax, cone_geom, options); +end + diff --git a/matlab/algorithms/plot_geom/+draw/draw_fanflat_vec_geom.m b/matlab/algorithms/plot_geom/+draw/draw_fanflat_vec_geom.m new file mode 100644 index 0000000..761d96a --- /dev/null +++ b/matlab/algorithms/plot_geom/+draw/draw_fanflat_vec_geom.m @@ -0,0 +1,102 @@ +function [ output_args ] = draw_fanflat_vec_geom( h_ax, geom, options) +%% draw_fanflat_vec_geom.m +% draw an astra cone beam projection geometry +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options struct holding options for drawing +% VectorIdx the index of the angle to draw +% SourceMarker Marker to use to mark the source +% SourceMarkerColor Color of the source marker +% DetectorMarker Marker to use to mark the source +% DetectorMarkerColor Color of the source marker +% DetectorLineColor Color of the outline of the detector +% OpticalAxisColor color for drawing the optical axis +% +% date 28.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% +% - last update 09.07.2018 +%% + vectors = geom.Vectors; + + % source + num_angles = size(vectors, 1); + xray_source = [vectors(:, 1:2), zeros(num_angles, 1)]; + % center of detector + detector_center = [vectors(:, 3:4), zeros(num_angles, 1)]; + + % draw the points and connect with lines + hold on; + scatter3(h_ax, xray_source(:, 1), xray_source(:, 2),... + xray_source(:, 3), options.SourceMarker,... + options.SourceMarkerColor); + scatter3(h_ax, detector_center(:, 1),... + detector_center(:, 2), detector_center(:, 3),... + options.DetectorMarker, options.DetectorMarkerColor); + + detector = struct; + detector.u = [vectors(options.VectorIdx, 5:6), 0]; + detector.v = fliplr(detector.u); + detector.height = 1; + detector.width = geom.DetectorCount; + detector.origin = detector_center(options.VectorIdx, :); + + vertices = draw.draw_detector_vec(h_ax, detector, options); + connect_source_detector(h_ax, vertices, detector_center,... + xray_source, options); + + % rotation axis will be roughly as long as the source detector distance + distances = eucl_dist3d(detector_center, xray_source); + mean_sdd = mean(distances(:)); % mean source detector distance + draw_rotation_axis(h_ax, mean_sdd, options); + + text(h_ax, xray_source(options.VectorIdx, 1),... + xray_source(options.VectorIdx, 2),... + xray_source(options.VectorIdx, 3), 'x-ray source'); + text(h_ax, detector_center(options.VectorIdx, 1),... + detector_center(options.VectorIdx, 2),... + detector_center(options.VectorIdx, 3), 'detector'); + + hold off; + + function [] = connect_source_detector(h_ax, vertices,... + detector_center, xray_source, options) + idx = options.VectorIdx; + % connect source to detector origin + line(h_ax, [detector_center(idx, 1), xray_source(idx, 1)],... + [detector_center(idx, 2), xray_source(idx, 2)],... + [detector_center(idx, 3), xray_source(idx, 3)],... + 'Color', options.OpticalAxisColor, 'LineStyle', '--'); + + % connect source to detector edges + for kk = 1:4 + line(h_ax,[xray_source(idx, 1), vertices(1, kk)], ... + [xray_source(idx, 2), vertices(2, kk)],... + [xray_source(idx, 3), vertices(3, kk)],... + 'Color', 'k', 'LineStyle', ':'); + end + end + + function [] = draw_rotation_axis(h_ax, scaling, options) + % draw rotation axis + rot_axis = options.RotationAxis; + if(~isnan(rot_axis(1))) + rot_axis = options.RotationAxis + options.RotationAxisOffset; + origin = options.RotationAxisOffset; + % origin of the geometry is assumed to be [0, 0, 0] always! + line(h_ax, [origin(1), (scaling/2)*rot_axis(1)],... + [origin(2), (scaling/2)*rot_axis(2)],... + [origin(3), (scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + line(h_ax, [origin(1), -(scaling/2)*rot_axis(1)],... + [origin(2), -(scaling/2)*rot_axis(2)],... + [origin(3), -(scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + end + end +end + diff --git a/matlab/algorithms/plot_geom/+draw/draw_parallel3d_geom.m b/matlab/algorithms/plot_geom/+draw/draw_parallel3d_geom.m new file mode 100644 index 0000000..45a8d60 --- /dev/null +++ b/matlab/algorithms/plot_geom/+draw/draw_parallel3d_geom.m @@ -0,0 +1,88 @@ +function [ ] = draw_parallel3d_geom( h_ax, geom, options) +%% draw_parallel3d_geom.m +% draw an astra parallel3d projection geometry +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options options struct with additional settings +% .SourceDistance distance of source to origin +% .SourceMarker marker for the source locations +% .SourceMarkerColor color specifier for the source marker +% .DetectorMarker marker for the detector locations. +% Default = '.' +% .DetectorMarkerColor color specifier for the detector marker. +% Default = 'k' +% .DetectorLineColor color for the lines drawing the detector +% outline +% .OpticalAxisColor Color of the line representing the optical +% axis. +% date 22.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% +% - last update 09.07.2018 +%% + dist_origin_detector = options.SourceDistance; + dist_origin_source = options.SourceDistance; + hold on; + + % draw source + scatter3(h_ax, 0, -dist_origin_source, 0, options.SourceMarker,... + options.SourceMarkerColor); + + % draw detector + detector = draw_detector(h_ax, geom, dist_origin_detector, options); + + % draw origin + h_origin = scatter3(h_ax, 0,0,0, '+k'); + h_origin.SizeData = 120; + h_origin.LineWidth = 2; + + % draw lines between source, origin and detector + line(h_ax, [0, 0], [0, dist_origin_detector], [0, 0],... + 'Color', options.OpticalAxisColor); + line(h_ax, [0, 0], [0, -dist_origin_source], [0, 0],... + 'Color', options.OpticalAxisColor); + + % connect source to detector edges + for idx = 1:4 + line(h_ax,[detector.vertices(1, idx),... + detector.vertices(1, idx)],... + [-dist_origin_source, dist_origin_detector],... + [detector.vertices(3, idx), detector.vertices(3, idx)],... + 'Color', 'k', 'LineStyle', ':'); + end + + % draw rotation axis + line(h_ax, [0,0],[0,0], 0.6*[-detector.height, detector.height],... + 'LineWidth', 2, 'Color', 'k', 'LineStyle', '--'); + + perc = 0.05; + text(h_ax, perc*detector.width, perc*detector.width,... + 0.8*detector.height, 'rotation axis'); + text(h_ax, detector.width*perc, 0, perc*detector.height, 'origin'); + text(h_ax, detector.width*perc, -dist_origin_source,... + perc*detector.height, 'x-ray source'); + text(h_ax, 0, dist_origin_detector, 0, 'detector'); + hold off; + + function [detector] = draw_detector(h_ax, geom,... + dist_origin_detector, options) + detector = struct; + detector.height = geom.DetectorRowCount * geom.DetectorSpacingY; + detector.width = geom.DetectorColCount * geom.DetectorSpacingX; + + vertices = zeros(3, 5); + vertices(1, :) = 0.5*[-detector.width, -detector.width,... + detector.width, detector.width, -detector.width]; + vertices(2, :) = repmat(dist_origin_detector, 5, 1); + vertices(3, :) = 0.5*[detector.height, -detector.height,... + -detector.height, detector.height, detector.height]; + + detector.vertices = vertices; + plot3(h_ax, detector.vertices(1, :), detector.vertices(2, :),... + detector.vertices(3, :), options.DetectorLineColor); + end + +end + diff --git a/matlab/algorithms/plot_geom/+draw/draw_parallel3d_vec_geom.m b/matlab/algorithms/plot_geom/+draw/draw_parallel3d_vec_geom.m new file mode 100644 index 0000000..e59fa91 --- /dev/null +++ b/matlab/algorithms/plot_geom/+draw/draw_parallel3d_vec_geom.m @@ -0,0 +1,100 @@ +function [ ] = draw_parallel3d_vec_geom( h_ax, geom, options) +%% draw_parallel3d_vec_geom.m +% draw an astra parallel3d projection geometry +% param h_ax handle to axis to draw into +% param geom the geometry to draw +% param options struct containing the options for this function +% idx index of the vector to draw in more detail +% SourceDistance distance of the source to the origin +% +% date 22.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + vectors = geom.Vectors; + + % source + xray_source = vectors(:, 1:3)*options.SourceDistance; + + % center of detector + detector_center = vectors(:, 4:6); + + % draw the points and connect with lines + hold on; + num_angles = size(vectors, 1); + scatter3(h_ax, xray_source(:, 1), xray_source(:, 2),... + xray_source(:, 3), options.SourceMarkerColor,... + options.SourceMarker); + scatter3(h_ax, detector_center(:, 1), detector_center(:, 2),... + detector_center(:, 3), 'k.'); + + detector = struct; + detector.u = vectors(options.VectorIdx, 7:9); + detector.v = vectors(options.VectorIdx, 10:12); + detector.height = geom.DetectorColCount; + detector.width = geom.DetectorRowCount; + detector.origin = detector_center(options.VectorIdx, :); + detector.vertices = draw.draw_detector_vec(h_ax, detector, options); + + connect_source_detector(h_ax, detector, detector_center, xray_source,... + options); + + % rotation axis will be roughly as long as the source detector distance + distances = eucl_dist3d(detector_center, xray_source); + mean_sdd = mean(distances(:)); % mean source detector distance + draw_rotation_axis(h_ax, mean_sdd, options); + + text(h_ax, xray_source(options.VectorIdx, 1),... + xray_source(options.VectorIdx, 2), ... + xray_source(options.VectorIdx, 3), 'x-ray source'); + text(h_ax, detector_center(options.VectorIdx, 1),... + detector_center(options.VectorIdx, 2),... + detector_center(options.VectorIdx, 3), 'detector'); + hold off; + + function [] = connect_source_detector(h_ax, detector,... + detector_center, xray_source, options) + % connect source to detector origin + idx = options.VectorIdx; + line(h_ax, [detector_center(idx, 1), xray_source(idx, 1)],... + [detector_center(idx, 2), xray_source(idx, 2)],... + [detector_center(idx, 3), xray_source(idx, 3)],... + 'Color', options.OpticalAxisColor, 'LineStyle', '--'); + + % compute normal of detector plane + n = null([detector.u; detector.v]); + + % connect source to detector edges + for kk = 1:4 + a = detector.vertices(1, kk) - n(1)*xray_source(idx, 1); + b = detector.vertices(2, kk) - n(2)*xray_source(idx, 2); + c = detector.vertices(3, kk) - n(3)*xray_source(idx, 3); + line(h_ax,[a, detector.vertices(1, kk)], ... + [b, detector.vertices(2, kk)],... + [c, detector.vertices(3, kk)],... + 'Color', 'k',... + 'LineStyle', ':'); + end + end + + function [] = draw_rotation_axis(h_ax, scaling, options) + % draw rotation axis + rot_axis = options.RotationAxis; + if(~isnan(rot_axis(1))) + rot_axis = options.RotationAxis + options.RotationAxisOffset; + origin = options.RotationAxisOffset; + % origin of the geometry is assumed to be [0, 0, 0] always! + line(h_ax, [origin(1), (scaling/2)*rot_axis(1)],... + [origin(2), (scaling/2)*rot_axis(2)],... + [origin(3), (scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + line(h_ax, [origin(1), -(scaling/2)*rot_axis(1)],... + [origin(2), -(scaling/2)*rot_axis(2)],... + [origin(3), -(scaling/2)*rot_axis(3)],... + 'Color', options.OpticalAxisColor,... + 'LineStyle', '-.'); + end + end +end diff --git a/matlab/algorithms/plot_geom/+draw/draw_proj_geom.m b/matlab/algorithms/plot_geom/+draw/draw_proj_geom.m new file mode 100644 index 0000000..9691448 --- /dev/null +++ b/matlab/algorithms/plot_geom/+draw/draw_proj_geom.m @@ -0,0 +1,138 @@ +function [] = draw_proj_geom(geom, varargin) +%% draw_proj_geom.m +% brief rendering function for astra geometries. +% param geom the geometry to plot. If geometry type +% is not supported, throws error +% ------------------------------ +% optional parameters that can be provided as string value pairs: +% +% param RotationAxis if specified, will change the drawn +% rotation axis to provided axis. +% Must be 3-vector. Default value is +% [NaN, NaN, NaN], (meaning do not draw). +% param RotationAxisOffset if specified, will translate the drawn +% rotation axis by the provided vector. +% Default = [0, 0, 0] +% param VectorIdx index of the vector to visualize if geom +% is a vector geometry type. Default = 1 +% param Color Color for all markers and lines if not +% otherwise specified +% param DetectorMarker marker for the detector locations. +% Default = '.' +% param DetectorMarkerColor color specifier for the detector marker. +% Default = 'k' +% param DetectorLineColor color for the lines drawing the detector +% outline +% param DetectorLineWidth line width of detector rectangle +% param SourceMarker marker for the source locations +% param SourceMarkerColor color specifier for the source marker +% param SourceDistance (only for parallel3d and parallel3d_vec) +% distance of source to origin +% param OpticalAxisColor Color for drawing the optical axis +% +% date 20.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% +% - last update 07.11.2018 +%% + h_ax = gca; + options = parseoptions(varargin); + + switch geom.type + case 'parallel3d' + disp('type: parallel3d') + disp(['detector spacing: [' num2str(geom.DetectorSpacingX), ', '... + num2str(geom.DetectorSpacingY) ']']); + disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... + num2str(geom.DetectorColCount) ']']); + disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); + disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); + disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); + disp('DistanceOriginDetector inf'); + disp('DistanceOriginSource inf'); + + draw.draw_parallel3d_geom(h_ax, geom, options); + case 'parallel3d_vec' + disp('type: parallel3d_vec') + disp(['detector px: [' num2str(geom.DetectorRowCount), ', '... + num2str(geom.DetectorColCount) ']']); + disp(['# angles: ' num2str(size(geom.Vectors, 1))]); + + draw.draw_parallel3d_vec_geom(h_ax, geom, options); + case 'cone' + disp('type: cone'); + disp(['detector spacing: [' num2str(geom.DetectorSpacingX), ', '... + num2str(geom.DetectorSpacingY) ']']); + disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... + num2str(geom.DetectorColCount) ']']); + disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); + disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); + disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); + disp(['DistanceOriginDetector ' num2str(geom.DistanceOriginDetector)]); + disp(['DistanceOriginSource ' num2str(geom.DistanceOriginSource)]); + + draw.draw_cone_geom(h_ax, geom, options); + case 'cone_vec' + disp('type: cone_vec'); + disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... + num2str(geom.DetectorColCount) ']']); + disp(['# angles: ' num2str(size(geom.Vectors, 1))]); + + draw.draw_cone_vec_geom(h_ax, geom, options); + case 'fanflat' + disp('type: fanflat'); + disp(['detector px: ' num2str(geom.DetectorCount)]); + disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); + disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); + disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); + disp(['DistanceOriginDetector '... + num2str(geom.DistanceOriginDetector)]); + disp(['DistanceOriginSource '... + num2str(geom.DistanceOriginSource)]); + + draw.draw_fanflat_geom(h_ax, geom, options); + case 'fanflat_vec' + disp('type: fanflat_vec'); + disp(['detector px: ' num2str(geom.DetectorCount)]); + disp(['# angles: ' num2str(size(geom.Vectors, 1))]); + + draw.draw_fanflat_vec_geom(h_ax, geom, options); + otherwise + error(['Unknown geometry type ' geom.type]) + end + view(45, 25); % gives nicer default view angle + + function [options] = parseoptions(input_args) + % make an options struct + options = struct; + options.RotationAxis = [NaN, NaN, NaN]; + options.RotationAxisOffset = [0, 0, 0]; + options.VectorIdx = 1; + options.Color = 'k'; + options.DetectorMarker = '.'; + options.DetectorMarkerColor = ''; + options.DetectorLineColor = ''; + options.DetectorLineWidth = 1; + options.SourceMarker = '*'; + options.SourceMarkerColor = ''; + options.SourceDistance = 100; + options.OpticalAxisColor = ''; + options = parseargs.parseargs(options, input_args{:}); + + % if the color is still empty, replace by global color + if strcmpi(options.DetectorMarkerColor , '') + options.DetectorMarkerColor = options.Color; + end + if strcmpi(options.DetectorLineColor , '') + options.DetectorLineColor = options.Color; + end + if strcmpi(options.SourceMarkerColor , '') + options.SourceMarkerColor = options.Color; + end + if strcmpi(options.OpticalAxisColor , '') + options.OpticalAxisColor = options.Color; + end + end +end diff --git a/matlab/algorithms/plot_geom/+draw/draw_vol_geom.m b/matlab/algorithms/plot_geom/+draw/draw_vol_geom.m new file mode 100644 index 0000000..65126c2 --- /dev/null +++ b/matlab/algorithms/plot_geom/+draw/draw_vol_geom.m @@ -0,0 +1,105 @@ +function [] = draw_vol_geom( vol_geom, varargin) +%% draw_vol_geom.m +% brief rendering function for astra volume geometries +% describing a phantom. +% param vol_geom volume geometry describing the phantom +% param vx_size voxel size in unit of preference. must be same unit +% that was used to scale the projection geometry +% ------------------------------ +% optional parameters that can be provided as string value pairs: +% +% param Magnification magnification factor for the phantom. for small +% phantoms it might be necessary to scale the render +% up as otherwise it won't show up in the plot. +% Default = 1 +% param LineWidth line width for the box wireframe. Default = 2 +% param Color color of the wireframe. Default = 'r' +% +% date 20.06.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% +% - last update 16.11.2018 +%% + h_ax = gca; + + if mod(size(varargin), 2) ~= 0 + vx_size = varargin{1}; + varargin = varargin(2:end); % consumed vx_size from arg list + else + vx_size = 1; + end + + + options = struct; + options.Color = 'r'; + options.LineWidth = 2; + options.Magnification = 1; + options = parseargs.parseargs(options, varargin{:}); + + hold on; + phantom_height = vol_geom.GridRowCount * vx_size; + phantom_width = vol_geom.GridColCount * vx_size; + phantom_depth = vol_geom.GridSliceCount * vx_size; + + if isfield(vol_geom, 'option') + minx = vol_geom.option.WindowMinX * vx_size; + maxx = vol_geom.option.WindowMaxX * vx_size; + + miny = vol_geom.option.WindowMinY * vx_size; + maxy = vol_geom.option.WindowMaxY * vx_size; + + minz = vol_geom.option.WindowMinZ * vx_size; + maxz = vol_geom.option.WindowMaxZ * vx_size; + else + minx = phantom_width / 2 * vx_size; + maxx = phantom_width / 2 * vx_size; + + miny = phantom_height / 2 * vx_size; + maxy = phantom_height / 2 * vx_size; + + minz = phantom_depth / 2 * vx_size; + maxz = phantom_depth / 2 * vx_size; + end + + xx_phantom = options.Magnification*[minx, minx, minx, minx, maxx, maxx, maxx, maxx]; + yy_phantom = options.Magnification*[miny, miny, maxy, maxy, miny, miny, maxy, maxy]; + zz_phantom = options.Magnification*[minz, maxz, minz, maxz, minz, maxz, minz, maxz]; + + face1 = [xx_phantom(1:4); yy_phantom(1:4); zz_phantom(1:4)]; + face2 = [[xx_phantom(1:2), xx_phantom(5:6)];... + [yy_phantom(1:2), yy_phantom(5:6)];... + [zz_phantom(1:2), zz_phantom(5:6)]]; + face3 = [[xx_phantom(3:4), xx_phantom(7:8)];... + [yy_phantom(3:4), yy_phantom(7:8)];... + [zz_phantom(3:4), zz_phantom(7:8)]]; + face4 = [[xx_phantom(5:6), xx_phantom(7:8)];... + [yy_phantom(5:6), yy_phantom(7:8)];... + [zz_phantom(5:6), zz_phantom(7:8)]]; + + % as we draw only a wire frame, we need only to draw 4 of the faces + draw_face(h_ax, face1, options); + draw_face(h_ax, face2, options); + draw_face(h_ax, face3, options); + draw_face(h_ax, face4, options); + + hold off; + + function [] = draw_face(h_ax, face_coords, options) + line(h_ax, face_coords(1, 1:2), face_coords(2, 1:2),... + face_coords(3, 1:2), 'LineWidth', options.LineWidth,... + 'Color', options.Color); + line(h_ax, face_coords(1, 3:4), face_coords(2, 3:4),... + face_coords(3, 3:4), 'LineWidth', options.LineWidth,... + 'Color', options.Color); + line(h_ax, [face_coords(1, 4),face_coords(1, 2)],... + [face_coords(2, 4),face_coords(2, 2)],... + [face_coords(3, 4),face_coords(3, 2)],... + 'LineWidth', options.LineWidth, 'Color', options.Color); + line(h_ax, [face_coords(1, 1),face_coords(1, 3)],... + [face_coords(2, 1),face_coords(2, 3)],... + [face_coords(3, 1),face_coords(3, 3)],... + 'LineWidth', options.LineWidth, 'Color', options.Color); + end +end diff --git a/matlab/algorithms/plot_geom/+draw/private/eucl_dist3d.m b/matlab/algorithms/plot_geom/+draw/private/eucl_dist3d.m new file mode 100644 index 0000000..57d6cb4 --- /dev/null +++ b/matlab/algorithms/plot_geom/+draw/private/eucl_dist3d.m @@ -0,0 +1,16 @@ +function [dist] = eucl_dist3d(a, b) +%% eucl_dist3d.m +% 3d euclidean distance for a nx3 matrix holding n 3-vectors +% param a - first vectors +% param b - second vectors +% date 07.11.2018 +% author Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last update 07.11.2018 +%% + dist = sqrt((a(:, 1) - b(:, 1)).^2 + ... + (a(:, 2) - b(:, 2)).^2 + ... + (a(:, 3) - b(:, 3)).^2); +end + diff --git a/matlab/algorithms/plot_geom/+parseargs/license.txt b/matlab/algorithms/plot_geom/+parseargs/license.txt new file mode 100644 index 0000000..cae4cd5 --- /dev/null +++ b/matlab/algorithms/plot_geom/+parseargs/license.txt @@ -0,0 +1,27 @@ +Copyright (c) 2016, The MathWorks, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * In all cases, the software is, and all modifications and derivatives + of the software shall be, licensed to you solely for use in conjunction + with MathWorks products and service offerings. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/matlab/algorithms/plot_geom/+parseargs/parseargs.m b/matlab/algorithms/plot_geom/+parseargs/parseargs.m new file mode 100644 index 0000000..05ad613 --- /dev/null +++ b/matlab/algorithms/plot_geom/+parseargs/parseargs.m @@ -0,0 +1,97 @@ +function X = parseargs(X,varargin) +%PARSEARGS - Parses name-value pairs +% +% Behaves like setfield, but accepts multiple name-value pairs and provides +% some additional features: +% 1) If any field of X is an cell-array of strings, it can only be set to +% one of those strings. If no value is specified for that field, the +% first string is selected. +% 2) Where the field is not empty, its data type cannot be changed +% 3) Where the field contains a scalar, its size cannot be changed. +% +% X = parseargs(X,name1,value1,name2,value2,...) +% +% Intended for use as an argument parser for functions which multiple options. +% Example usage: +% +% function my_function(varargin) +% X.StartValue = 0; +% X.StopOnError = false; +% X.SolverType = {'fixedstep','variablestep'}; +% X.OutputFile = 'out.txt'; +% X = parseargs(X,varargin{:}); +% +% Then call (e.g.): +% +% my_function('OutputFile','out2.txt','SolverType','variablestep'); + +% The various #ok comments below are to stop MLint complaining about +% inefficient usage. In all cases, the inefficient usage (of error, getfield, +% setfield and find) is used to ensure compatibility with earlier versions +% of MATLAB. + +% Copyright 2006-2010 The MathWorks, Inc. + +remaining = nargin-1; % number of arguments other than X +count = 1; +fields = fieldnames(X); +modified = zeros(size(fields)); +% Take input arguments two at a time until we run out. +while remaining>=2 + fieldname = varargin{count}; + fieldind = find(strcmp(fieldname,fields)); + if ~isempty(fieldind) + oldvalue = getfield(X,fieldname); %#ok + newvalue = varargin{count+1}; + if iscell(oldvalue) + % Cell arrays must contain strings, and the new value must be + % a string which appears in the list. + if ~iscellstr(oldvalue) + error(sprintf('All allowed values for "%s" must be strings',fieldname)); %#ok + end + if ~ischar(newvalue) + error(sprintf('New value for "%s" must be a string',fieldname)); %#ok + end + if isempty(find(strcmp(oldvalue,newvalue))) %#ok + error(sprintf('"%s" is not allowed for field "%s"',newvalue,fieldname)); %#ok + end + elseif ~isempty(oldvalue) + % The caller isn't allowed to change the data type of a non-empty property, + % and scalars must remain as scalars. + if ~strcmp(class(oldvalue),class(newvalue)) + error(sprintf('Cannot change class of field "%s" from "%s" to "%s"',... + fieldname,class(oldvalue),class(newvalue))); %#ok + elseif numel(oldvalue)==1 & numel(newvalue)~=1 %#ok + error(sprintf('New value for "%s" must be a scalar',fieldname)); %#ok + end + end + X = setfield(X,fieldname,newvalue); %#ok + modified(fieldind) = 1; + else + error(['Not a valid field name: ' fieldname]); + end + remaining = remaining - 2; + count = count + 2; +end +% Check that we had a value for every name. +if remaining~=0 + error('Odd number of arguments supplied. Name-value pairs required'); +end + +% Now find cell arrays which were not modified by the above process, and select +% the first string. +notmodified = find(~modified); +for i=1:length(notmodified) + fieldname = fields{notmodified(i)}; + oldvalue = getfield(X,fieldname); %#ok + if iscell(oldvalue) + if ~iscellstr(oldvalue) + error(sprintf('All allowed values for "%s" must be strings',fieldname)); %#ok + elseif isempty(oldvalue) + error(sprintf('Empty cell array not allowed for field "%s"',fieldname)); %#ok + end + X = setfield(X,fieldname,oldvalue{1}); %#ok + end +end + + diff --git a/matlab/algorithms/plot_geom/+stlTools/license.txt b/matlab/algorithms/plot_geom/+stlTools/license.txt new file mode 100644 index 0000000..b2d00b0 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/license.txt @@ -0,0 +1,34 @@ +Copyright (c) 2017, Pau Micó +Copyright (c) 2015, Sven Holcombe +Copyright (c) 2011, Eric Johnson +Copyright (c) 2013, Adam H. Aitkenhead +Copyright (c) 2011, Francis Esmonde-White +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution + * Neither the name of the The MathWorks, Inc. nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + * Neither the name of the The Christie NHS Foundation Trust nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/matlab/algorithms/plot_geom/+stlTools/readme.txt b/matlab/algorithms/plot_geom/+stlTools/readme.txt new file mode 100644 index 0000000..b8037d6 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/readme.txt @@ -0,0 +1,16 @@ +The 'stlTools' toolbox is a collection of functions, samples and demos to illustrate how to deal with STL files. Some of them are contributions published in Matlab Central and properly referenced here. +This toolbox contains the following files: + +stlGetFormat: identifies the format of the STL file and returns 'binary' or 'ascii'. This file is inspired in the 'READ-stl' file written and published by Adam H. Aitkenhead (http://www.mathworks.com/matlabcentral/fileexchange/27390-mesh-voxelisation). Copyright (c) 2013, Adam H. Aitkenhead. +stlReadAscii: reads an STL file written in ascii format. This file is inspired in the 'READ-stl' file written and published by Adam H. Aitkenhead (http://www.mathworks.com/matlabcentral/fileexchange/27390-mesh-voxelisation). Copyright (c) 2013, Adam H. Aitkenhead +stlReadBinary: reads an STL file written in binary format. This file is inspired in the 'READ-stl' file written and published by Adam H. Aitkenhead (http://www.mathworks.com/matlabcentral/fileexchange/27390-mesh-voxelisation). Copyright (c) 2013, Adam H. Aitkenhead +stlRead: uses 'stlGetFormat', 'stlReadAscii' and 'stlReadBinary' to make STL reading independent of the format of the file +stlWrite: writes an STL file in 'ascii' or 'binary' formats. This is written and published by Sven Holcombe (http://www.mathworks.com/matlabcentral/fileexchange/20922-stlwrite-filename--varargin-). Copyright (c) 2012, Grant Lohsen. Copyright (c) 2015, Sven Holcombe. +stlSlimVerts: finds and removes duplicated vertices. This function is written and published by Francis Esmonde-White as PATCHSLIM (http://www.mathworks.com/matlabcentral/fileexchange/29986-patch-slim--patchslim-m-). Copyright (c) 2011, Francis Esmonde-White. +stlGetVerts: returns a list of vertices that are 'opened' or 'closed' depending on the 'mode' input parameter. An 'open' vertice is the one that defines an open side. An open side is the one that only takes part of one triangle +stlDelVerts: removes a list of vertices from STL files +stlAddVerts: adds the new vertices from a list (and consequently, new faces) to a STL object +stlPlot: is an easy way to plot an STL object +stlDemo: is a collection of examples about how to use stlTools +femur_binary: is an ascii STL sample used in 'stlDemo'. It is published by Eric Johnson (http://www.mathworks.com/matlabcentral/fileexchange/22409-stl-file-reader). Copyright (c) 2011, Eric Johnson. +sphere_ascii: is a binary STL sample \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/+stlTools/stlAddVerts.m b/matlab/algorithms/plot_geom/+stlTools/stlAddVerts.m new file mode 100644 index 0000000..1894cd7 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/stlAddVerts.m @@ -0,0 +1,17 @@ +function [vnew, fnew] = stlAddVerts(v, f, list) +%STLADDVERTS adds new vertices (and consequently, new faces) to a STL object +%V is the Nx3 array of vertices +%F is the Mx3 array of faces +%LIST is the list of vertices to be added to the object +%VNEW is the new array of vertices +%FNEW is the new array of faces + +import stlTools.* + +% triangulation just with the slice +faces = delaunay(list(:,1),list(:,2)); % calculate new faces +% update object +nvert = length(v); % number of original vertices +v = [v; list]; % update vertices with the ones in the list +f = [f; faces+nvert]; % update faces with the new ones +[vnew,fnew] = stlSlimVerts(v,f); % clear repeated vertices \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/+stlTools/stlDelVerts.m b/matlab/algorithms/plot_geom/+stlTools/stlDelVerts.m new file mode 100644 index 0000000..718ac53 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/stlDelVerts.m @@ -0,0 +1,26 @@ +function [vnew, fnew] = stlDelVerts(v, f, list) +%STLDELVERT removes a list of vertices from STL files +%V is the Nx3 array of vertices +%F is the Mx3 array of faces +%LIST are the vertices (rows) to delete, where length(LIST) < N +%VNEW is the new array of vertices +%FNEW is the new array of faces + +% find (on the global set) the position (rows) of the vertices to be deleted +[~,vdel] = ismember(list,v,'rows'); + +% delete vertices and get new tags +vnew = v; +tags = 1:length(v); +vnew(vdel,:) = []; +tags(vdel) = []; + +% delete faces +fnew = f; +[fdel,~] = find(ismember(f,vdel)); % find the position (rows) of the faces to delete +fnew(fdel,:) = []; + +% rename faces, as some of the vertices have been deleted +flist = reshape(fnew,numel(fnew),1); +[~,ind] = ismember(flist,tags); +fnew = reshape(ind,numel(flist)/3,3); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/+stlTools/stlDemo.m b/matlab/algorithms/plot_geom/+stlTools/stlDemo.m new file mode 100644 index 0000000..af46315 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/stlDemo.m @@ -0,0 +1,41 @@ +%% STLDEMO shows how to use the functions included in the toolbox STLTOOLS + +import stlTools.* + +%% EXAMPLE 1.- How to cut a sphere and close the base to get a semisphere + +% load an ascii STL sample file (STLGETFORMAT and STLREADASCII) +[vertices,faces,normals,name] = stlRead('sphere300faces.stl'); +stlPlot(vertices,faces,name); + +% the sphere is centered in the origin +% now we get a list of vertices to be deleted if (x,y,z<0) +minZ = 0; +[rows, ~] = find(vertices(:,3) < minZ); +list = vertices(rows,:); + +% if we delete the list of vertices with z<0, we get an opened semisphere +% (as the base is not closed) +[newv,newf] = stlDelVerts(vertices,faces,list); +stlPlot(newv,newf,name); + +% the next step is to identify a new list with the faces that are opened +% (that means all the sides that belong only to a unique triangle) +list = stlGetVerts(newv,newf,'opened'); + +% finally we generate all the new faces that are needed just to close the +% base of the semisphere +[vsemi,fsemi] = stlAddVerts(newv,newf,list); +stlPlot(vsemi,fsemi,'closed semisphere'); + +%% EXAMPLE 2.- How to get a section of a femur + +[vertices,faces,normals,name] = stlRead('femur_binary.stl'); +stlPlot(vertices,faces,name); + +minX = 1.2; +[rows, ~] = find(vertices(:,1) < minX); +list = vertices(rows,:); + +[newv,newf] = stlDelVerts(vertices,faces,list); +stlPlot(newv,newf,'section of the femur'); diff --git a/matlab/algorithms/plot_geom/+stlTools/stlGetFormat.m b/matlab/algorithms/plot_geom/+stlTools/stlGetFormat.m new file mode 100644 index 0000000..6901b26 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/stlGetFormat.m @@ -0,0 +1,38 @@ +function format = stlGetFormat(fileName) +%STLGETFORMAT identifies the format of the STL file and returns 'binary' or +%'ascii' + +fid = fopen(fileName); +% Check the file size first, since binary files MUST have a size of 84+(50*n) +fseek(fid,0,1); % Go to the end of the file +fidSIZE = ftell(fid); % Check the size of the file +if rem(fidSIZE-84,50) > 0 + format = 'ascii'; +else + % Files with a size of 84+(50*n), might be either ascii or binary... + % Read first 80 characters of the file. + % For an ASCII file, the data should begin immediately (give or take a few + % blank lines or spaces) and the first word must be 'solid'. + % For a binary file, the first 80 characters contains the header. + % It is bad practice to begin the header of a binary file with the word + % 'solid', so it can be used to identify whether the file is ASCII or + % binary. + fseek(fid,0,-1); % go to the beginning of the file + header = strtrim(char(fread(fid,80,'uchar')')); % trim leading and trailing spaces + isSolid = strcmp(header(1:min(5,length(header))),'solid'); % take first 5 char + fseek(fid,-80,1); % go to the end of the file minus 80 characters + tail = char(fread(fid,80,'uchar')'); + isEndSolid = findstr(tail,'endsolid'); + + % Double check by reading the last 80 characters of the file. + % For an ASCII file, the data should end (give or take a few + % blank lines or spaces) with 'endsolid '. + % If the last 80 characters contains the word 'endsolid' then this + % confirms that the file is indeed ASCII. + if isSolid & isEndSolid + format = 'ascii'; + else + format = 'binary'; + end +end +fclose(fid); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/+stlTools/stlGetVerts.m b/matlab/algorithms/plot_geom/+stlTools/stlGetVerts.m new file mode 100644 index 0000000..179eff3 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/stlGetVerts.m @@ -0,0 +1,31 @@ +function list = stlGetVerts(v, f, mode) +%GETVERTS returns the vertices that are 'opened' or 'closed' depending on +%the 'mode'. An 'open' vertice is the one that defines an open side. An +%open side is the one that only takes part of one triangle +%V is the Nx3 array of vertices +%F is the Mx3 array of faces +%MODE can be 'opened' or 'closed' depending of the kind of vertices to list +%LIST is the list of 'opened' or 'closed' vertices + +sides = sort([[f(:,1) f(:,2)]; ... + [f(:,2) f(:,3)]; ... + [f(:,3) f(:,1)]],2); + +[C,ia,ic] = unique(sides,'rows'); +ind_all = sort(ic); % open and closed sides +ind_rep = find(diff(ind_all) == 0); +ind_cls = ind_all(ind_rep); % closed sides +sides_cls = C(ind_cls,:); +ind_rep = [ind_rep; ind_rep+1]; +ind_opn = ind_all; +ind_opn(ind_rep) = []; % open sides +sides_opn = C(ind_opn,:); + +switch mode, + case'opened', + list = v(unique(sides_opn(:)),:); + case 'closed', + list = v(unique(sides_cls(:)),:); + otherwise, + error('getVerts:InvalidMode','The ''mode'' valid values are ''opened'' or ''closed'''); +end \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/+stlTools/stlPlot.m b/matlab/algorithms/plot_geom/+stlTools/stlPlot.m new file mode 100644 index 0000000..e9f17c5 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/stlPlot.m @@ -0,0 +1,23 @@ +function stlPlot(v, f, name) +%STLPLOT is an easy way to plot an STL object +%V is the Nx3 array of vertices +%F is the Mx3 array of faces +%NAME is the name of the object, that will be displayed as a title + +figure; +object.vertices = v; +object.faces = f; +patch(object,'FaceColor', [0.8 0.8 1.0], ... + 'EdgeColor', 'none', ... + 'FaceLighting', 'gouraud', ... + 'AmbientStrength', 0.15); + +% Add a camera light, and tone down the specular highlighting +camlight('headlight'); +material('dull'); + +% Fix the axes scaling, and set a nice view angle +axis('image'); +view([-135 35]); +grid on; +title(name); diff --git a/matlab/algorithms/plot_geom/+stlTools/stlRead.m b/matlab/algorithms/plot_geom/+stlTools/stlRead.m new file mode 100644 index 0000000..5775e50 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/stlRead.m @@ -0,0 +1,15 @@ +function [v, f, n, name] = stlRead(fileName) +%STLREAD reads any STL file not depending on its format +%V are the vertices +%F are the faces +%N are the normals +%NAME is the name of the STL object (NOT the name of the STL file) + +import stlTools.* + +format = stlGetFormat(fileName); +if strcmp(format,'ascii') + [v,f,n,name] = stlReadAscii(fileName); +elseif strcmp(format,'binary') + [v,f,n,name] = stlReadBinary(fileName); +end \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/+stlTools/stlReadAscii.m b/matlab/algorithms/plot_geom/+stlTools/stlReadAscii.m new file mode 100644 index 0000000..b035aa8 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/stlReadAscii.m @@ -0,0 +1,58 @@ +function [v, f, n, name] = stlReadAscii(fileName) +%STLREADASCII reads a STL file written in ASCII format +%V are the vertices +%F are the faces +%N are the normals +%NAME is the name of the STL object (NOT the name of the STL file) + +import stlTools.* + +%====================== +% STL ascii file format +%====================== +% ASCII STL files have the following structure. Technically each facet +% could be any 2D shape, but in practice only triangular facets tend to be +% used. The present code ONLY works for meshes composed of triangular +% facets. +% +% solid object_name +% facet normal x y z +% outer loop +% vertex x y z +% vertex x y z +% vertex x y z +% endloop +% endfacet +% +% +% +% endsolid object_name + +fid = fopen(fileName); +cellcontent = textscan(fid,'%s','delimiter','\n'); % read all the file and put content in cells +content = cellcontent{:}(logical(~strcmp(cellcontent{:},''))); % remove all blank lines +fclose(fid); + +% read the STL name +line1 = char(content(1)); +if (size(line1,2) >= 7) + name = line1(7:end); +else + name = 'Unnamed Object'; +end + +% read the vector normals +normals = char(content(logical(strncmp(content,'facet normal',12)))); +n = str2num(normals(:,13:end)); + +% read the vertex coordinates (vertices) +vertices = char(content(logical(strncmp(content,'vertex',6)))); +v = str2num(vertices(:,7:end)); +nvert = size(vertices,1); % number of vertices +nfaces = sum(strcmp(content,'endfacet')); % number of faces +if (nvert == 3*nfaces) + f = reshape(1:nvert,[3 nfaces])'; % create faces +end + +% slim the file (delete duplicated vertices) +[v,f] = stlSlimVerts(v,f); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/+stlTools/stlReadBinary.m b/matlab/algorithms/plot_geom/+stlTools/stlReadBinary.m new file mode 100644 index 0000000..3e04f7a --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/stlReadBinary.m @@ -0,0 +1,62 @@ +function [v, f, n, name] = stlReadBinary(fileName) +%STLREADBINARY reads a STL file written in BINARY format +%V are the vertices +%F are the faces +%N are the normals +%NAME is the name of the STL object (NOT the name of the STL file) + +import stlTools.* + +%======================= +% STL binary file format +%======================= +% Binary STL files have an 84 byte header followed by 50-byte records, each +% describing a single facet of the mesh. Technically each facet could be +% any 2D shape, but that would screw up the 50-byte-per-facet structure, so +% in practice only triangular facets are used. The present code ONLY works +% for meshes composed of triangular facets. +% +% HEADER: +% 80 bytes: Header text +% 4 bytes: (int) The number of facets in the STL mesh +% +% DATA: +% 4 bytes: (float) normal x +% 4 bytes: (float) normal y +% 4 bytes: (float) normal z +% 4 bytes: (float) vertex1 x +% 4 bytes: (float) vertex1 y +% 4 bytes: (float) vertex1 z +% 4 bytes: (float) vertex2 x +% 4 bytes: (float) vertex2 y +% 4 bytes: (float) vertex2 z +% 4 bytes: (float) vertex3 x +% 4 bytes: (float) vertex3 y +% 4 bytes: (float) vertex3 z +% 2 bytes: Padding to make the data for each facet 50-bytes in length +% ...and repeat for next facet... + +fid = fopen(fileName); +header = fread(fid,80,'int8'); % reading header's 80 bytes +name = deblank(native2unicode(header,'ascii')'); +if isempty(name) + name = 'Unnamed Object'; % no object name in binary files! +end +nfaces = fread(fid,1,'int32'); % reading the number of facets in the stl file (next 4 byters) +nvert = 3*nfaces; % number of vertices +% reserve memory for vectors (increase the processing speed) +n = zeros(nfaces,3); +v = zeros(nvert,3); +f = zeros(nfaces,3); +for i = 1 : nfaces % read the data for each facet + tmp = fread(fid,3*4,'float'); % read coordinates + n(i,:) = tmp(1:3); % x,y,z components of the facet's normal vector + v(3*i-2,:) = tmp(4:6); % x,y,z coordinates of vertex 1 + v(3*i-1,:) = tmp(7:9); % x,y,z coordinates of vertex 2 + v(3*i,:) = tmp(10:12); % x,y,z coordinates of vertex 3 + f(i,:) = [3*i-2 3*i-1 3*i]; % face + fread(fid,1,'int16'); % Move to the start of the next facet (2 bytes of padding) +end +fclose(fid); +% slim the file (delete duplicated vertices) +[v,f] = stlSlimVerts(v,f); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/+stlTools/stlSlimVerts.m b/matlab/algorithms/plot_geom/+stlTools/stlSlimVerts.m new file mode 100644 index 0000000..2781067 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/stlSlimVerts.m @@ -0,0 +1,29 @@ +function [vnew, fnew]= stlSlimVerts(v, f) +% PATCHSLIM removes duplicate vertices in surface meshes. +% +% This function finds and removes duplicate vertices. +% +% USAGE: [v, f]=patchslim(v, f) +% +% Where v is the vertex list and f is the face list specifying vertex +% connectivity. +% +% v contains the vertices for all triangles [3*n x 3]. +% f contains the vertex lists defining each triangle face [n x 3]. +% +% This will reduce the size of typical v matrix by about a factor of 6. +% +% For more information see: +% http://www.esmonde-white.com/home/diversions/matlab-program-for-loading-stl-files +% +% Francis Esmonde-White, May 2010 + +if ~exist('v','var') + error('The vertex list (v) must be specified.'); +end +if ~exist('f','var') + error('The vertex connectivity of the triangle faces (f) must be specified.'); +end + +[vnew, indexm, indexn] = unique(v, 'rows'); +fnew = indexn(f); diff --git a/matlab/algorithms/plot_geom/+stlTools/stlWrite.m b/matlab/algorithms/plot_geom/+stlTools/stlWrite.m new file mode 100644 index 0000000..0ce5d46 --- /dev/null +++ b/matlab/algorithms/plot_geom/+stlTools/stlWrite.m @@ -0,0 +1,252 @@ +function stlWrite(filename, varargin) +%STLWRITE Write STL file from patch or surface data. +% +% STLWRITE(FILE, FV) writes a stereolithography (STL) file to FILE for a +% triangulated patch defined by FV (a structure with fields 'vertices' +% and 'faces'). +% +% STLWRITE(FILE, FACES, VERTICES) takes faces and vertices separately, +% rather than in an FV struct +% +% STLWRITE(FILE, X, Y, Z) creates an STL file from surface data in X, Y, +% and Z. STLWRITE triangulates this gridded data into a triangulated +% surface using triangulation options specified below. X, Y and Z can be +% two-dimensional arrays with the same size. If X and Y are vectors with +% length equal to SIZE(Z,2) and SIZE(Z,1), respectively, they are passed +% through MESHGRID to create gridded data. If X or Y are scalar values, +% they are used to specify the X and Y spacing between grid points. +% +% STLWRITE(...,'PropertyName',VALUE,'PropertyName',VALUE,...) writes an +% STL file using the following property values: +% +% MODE - File is written using 'binary' (default) or 'ascii'. +% +% TITLE - Header text (max 80 chars) written to the STL file. +% +% TRIANGULATION - When used with gridded data, TRIANGULATION is either: +% 'delaunay' - (default) Delaunay triangulation of X, Y +% 'f' - Forward slash division of grid quads +% 'b' - Back slash division of quadrilaterals +% 'x' - Cross division of quadrilaterals +% Note that 'f', 'b', or 't' triangulations now use an +% inbuilt version of FEX entry 28327, "mesh2tri". +% +% FACECOLOR - Single colour (1-by-3) or one-colour-per-face (N-by-3) +% vector of RGB colours, for face/vertex input. RGB range +% is 5 bits (0:31), stored in VisCAM/SolidView format +% (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL) +% +% Example 1: +% % Write binary STL from face/vertex data +% tmpvol = false(20,20,20); % Empty voxel volume +% tmpvol(8:12,8:12,5:15) = 1; % Turn some voxels on +% fv = isosurface(~tmpvol, 0.5); % Make patch w. faces "out" +% stlwrite('test.stl',fv) % Save to binary .stl +% +% Example 2: +% % Write ascii STL from gridded data +% [X,Y] = deal(1:40); % Create grid reference +% Z = peaks(40); % Create grid height +% stlwrite('test.stl',X,Y,Z,'mode','ascii') +% +% Example 3: +% % Write binary STL with coloured faces +% cVals = fv.vertices(fv.faces(:,1),3); % Colour by Z height. +% cLims = [min(cVals) max(cVals)]; % Transform height values +% nCols = 255; cMap = jet(nCols); % onto an 8-bit colour map +% fColsDbl = interp1(linspace(cLims(1),cLims(2),nCols),cMap,cVals); +% fCols8bit = fColsDbl*255; % Pass cols in 8bit (0-255) RGB triplets +% stlwrite('testCol.stl',fv,'FaceColor',fCols8bit) + +% Original idea adapted from surf2stl by Bill McDonald. Huge speed +% improvements implemented by Oliver Woodford. Non-Delaunay triangulation +% of quadrilateral surface courtesy of Kevin Moerman. FaceColor +% implementation by Grant Lohsen. +% +% Author: Sven Holcombe, 11-24-11 + + +% Check valid filename path +path = fileparts(filename); +if ~isempty(path) && ~exist(path,'dir') + error('Directory "%s" does not exist.',path); +end + +% Get faces, vertices, and user-defined options for writing +[faces, vertices, options] = parseInputs(varargin{:}); +asciiMode = strcmp( options.mode ,'ascii'); + +% Create the facets +facets = single(vertices'); +facets = reshape(facets(:,faces'), 3, 3, []); + +% Compute their normals +V1 = squeeze(facets(:,2,:) - facets(:,1,:)); +V2 = squeeze(facets(:,3,:) - facets(:,1,:)); +normals = V1([2 3 1],:) .* V2([3 1 2],:) - V2([2 3 1],:) .* V1([3 1 2],:); +clear V1 V2 +normals = bsxfun(@times, normals, 1 ./ sqrt(sum(normals .* normals, 1))); +facets = cat(2, reshape(normals, 3, 1, []), facets); +clear normals + +% Open the file for writing +permissions = {'w','wb+'}; +fid = fopen(filename, permissions{asciiMode+1}); +if (fid == -1) + error('stlwrite:cannotWriteFile', 'Unable to write to %s', filename); +end + +% Write the file contents +if asciiMode + % Write HEADER + fprintf(fid,'solid %s\r\n',options.title); + % Write DATA + fprintf(fid,[... + 'facet normal %.7E %.7E %.7E\r\n' ... + 'outer loop\r\n' ... + 'vertex %.7E %.7E %.7E\r\n' ... + 'vertex %.7E %.7E %.7E\r\n' ... + 'vertex %.7E %.7E %.7E\r\n' ... + 'endloop\r\n' ... + 'endfacet\r\n'], facets); + % Write FOOTER + fprintf(fid,'endsolid %s\r\n',options.title); + +else % BINARY + % Write HEADER + fprintf(fid, '%-80s', options.title); % Title + fwrite(fid, size(facets, 3), 'uint32'); % Number of facets + % Write DATA + % Add one uint16(0) to the end of each facet using a typecasting trick + facets = reshape(typecast(facets(:), 'uint16'), 12*2, []); + % Set the last bit to 0 (default) or supplied RGB + facets(end+1,:) = options.facecolor; + fwrite(fid, facets, 'uint16'); +end + +% Close the file +fclose(fid); +%fprintf('Wrote %d facets\n',size(facets, 2)); + + +%% Input handling subfunctions +function [faces, vertices, options] = parseInputs(varargin) +% Determine input type +if isstruct(varargin{1}) % stlwrite('file', FVstruct, ...) + if ~all(isfield(varargin{1},{'vertices','faces'})) + error( 'Variable p must be a faces/vertices structure' ); + end + faces = varargin{1}.faces; + vertices = varargin{1}.vertices; + options = parseOptions(varargin{2:end}); + +elseif isnumeric(varargin{1}) + firstNumInput = cellfun(@isnumeric,varargin); + firstNumInput(find(~firstNumInput,1):end) = 0; % Only consider numerical input PRIOR to the first non-numeric + numericInputCnt = nnz(firstNumInput); + + options = parseOptions(varargin{numericInputCnt+1:end}); + switch numericInputCnt + case 3 % stlwrite('file', X, Y, Z, ...) + % Extract the matrix Z + Z = varargin{3}; + + % Convert scalar XY to vectors + ZsizeXY = fliplr(size(Z)); + for i = 1:2 + if isscalar(varargin{i}) + varargin{i} = (0:ZsizeXY(i)-1) * varargin{i}; + end + end + + % Extract X and Y + if isequal(size(Z), size(varargin{1}), size(varargin{2})) + % X,Y,Z were all provided as matrices + [X,Y] = varargin{1:2}; + elseif numel(varargin{1})==ZsizeXY(1) && numel(varargin{2})==ZsizeXY(2) + % Convert vector XY to meshgrid + [X,Y] = meshgrid(varargin{1}, varargin{2}); + else + error('stlwrite:badinput', 'Unable to resolve X and Y variables'); + end + + % Convert to faces/vertices + if strcmp(options.triangulation,'delaunay') + faces = delaunay(X,Y); + vertices = [X(:) Y(:) Z(:)]; + else + if ~exist('mesh2tri','file') + error('stlwrite:missing', '"mesh2tri" is required to convert X,Y,Z matrices to STL. It can be downloaded from:\n%s\n',... + 'http://www.mathworks.com/matlabcentral/fileexchange/28327') + end + [faces, vertices] = mesh2tri(X, Y, Z, options.triangulation); + end + + case 2 % stlwrite('file', FACES, VERTICES, ...) + faces = varargin{1}; + vertices = varargin{2}; + + otherwise + error('stlwrite:badinput', 'Unable to resolve input types.'); + end +end + +if ~isempty(options.facecolor) % Handle colour preparation + facecolor = uint16(options.facecolor); + %Set the Valid Color bit (bit 15) + c0 = bitshift(ones(size(faces,1),1,'uint16'),15); + %Red color (10:15), Blue color (5:9), Green color (0:4) + c0 = bitor(bitshift(bitand(2^6-1, facecolor(:,1)),10),c0); + c0 = bitor(bitshift(bitand(2^11-1, facecolor(:,2)),5),c0); + c0 = bitor(bitand(2^6-1, facecolor(:,3)),c0); + options.facecolor = c0; +else + options.facecolor = 0; +end + +function options = parseOptions(varargin) +IP = inputParser; +IP.addParamValue('mode', 'binary', @ischar) +IP.addParamValue('title', sprintf('Created by stlwrite.m %s',datestr(now)), @ischar); +IP.addParamValue('triangulation', 'delaunay', @ischar); +IP.addParamValue('facecolor',[], @isnumeric) +IP.addParamValue('facecolour',[], @isnumeric) +IP.parse(varargin{:}); +options = IP.Results; +if ~isempty(options.facecolour) + options.facecolor = options.facecolour; +end + +function [F,V]=mesh2tri(X,Y,Z,tri_type) +% function [F,V]=mesh2tri(X,Y,Z,tri_type) +% +% Available from http://www.mathworks.com/matlabcentral/fileexchange/28327 +% Included here for convenience. Many thanks to Kevin Mattheus Moerman +% kevinmoerman@hotmail.com +% 15/07/2010 +%------------------------------------------------------------------------ + +[J,I]=meshgrid(1:1:size(X,2)-1,1:1:size(X,1)-1); + +switch tri_type + case 'f'%Forward slash + TRI_I=[I(:),I(:)+1,I(:)+1; I(:),I(:),I(:)+1]; + TRI_J=[J(:),J(:)+1,J(:); J(:),J(:)+1,J(:)+1]; + F = sub2ind(size(X),TRI_I,TRI_J); + case 'b'%Back slash + TRI_I=[I(:),I(:)+1,I(:); I(:)+1,I(:)+1,I(:)]; + TRI_J=[J(:)+1,J(:),J(:); J(:)+1,J(:),J(:)+1]; + F = sub2ind(size(X),TRI_I,TRI_J); + case 'x'%Cross + TRI_I=[I(:)+1,I(:); I(:)+1,I(:)+1; I(:),I(:)+1; I(:),I(:)]; + TRI_J=[J(:),J(:); J(:)+1,J(:); J(:)+1,J(:)+1; J(:),J(:)+1]; + IND=((numel(X)+1):numel(X)+prod(size(X)-1))'; + F = sub2ind(size(X),TRI_I,TRI_J); + F(:,3)=repmat(IND,[4,1]); + Fe_I=[I(:),I(:)+1,I(:)+1,I(:)]; Fe_J=[J(:),J(:),J(:)+1,J(:)+1]; + Fe = sub2ind(size(X),Fe_I,Fe_J); + Xe=mean(X(Fe),2); Ye=mean(Y(Fe),2); Ze=mean(Z(Fe),2); + X=[X(:);Xe(:)]; Y=[Y(:);Ye(:)]; Z=[Z(:);Ze(:)]; +end + +V=[X(:),Y(:),Z(:)]; \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/astra_create_example_fanflat.m b/matlab/algorithms/plot_geom/astra_create_example_fanflat.m index 703a618..251cb47 100644 --- a/matlab/algorithms/plot_geom/astra_create_example_fanflat.m +++ b/matlab/algorithms/plot_geom/astra_create_example_fanflat.m @@ -19,8 +19,8 @@ function [ geom ] = create_example_fanflat( type ) if strcmpi(type, 'normal') geom = make_normal_geometry(); elseif strcmpi(type, 'vec') - geom = create_example_fanflat('normal'); - geom = fanflat_to_fanflat_vec(geom); + geom = astra_create_example_fanflat('normal'); + geom = astra_geom_2vec(geom); else geom = make_normal_geometry(); diff --git a/matlab/algorithms/plot_geom/draw/draw_cad_phantom.m b/matlab/algorithms/plot_geom/draw/draw_cad_phantom.m deleted file mode 100644 index 92af844..0000000 --- a/matlab/algorithms/plot_geom/draw/draw_cad_phantom.m +++ /dev/null @@ -1,35 +0,0 @@ -function [] = draw_cad_phantom(filename, magn) -%% draw_cad_phantom.m -% brief render an stl model into a 3d axis object -% param vol_geom volume geometry describing the phantom -% param h_ax handle to axis to plot into -% param magn magnification multiplier of the phantom. default = 1 -% -% date 02.07.2018 -% author Alice Presenti -% imec VisionLab -% University of Antwerp -% Modified by Tim Elberfeld -%% - h_ax = gca; - if nargin == 1 - magn = 1; - end - - [v,f,~,~] = stlRead(filename); - m = mean(v); % to center the CAD model! - for i=1:3 - v(:,i) = (v(:,i)- m(i)) .* magn; - end - object.vertices = v; - object.faces = f; - patch(h_ax, object,'FaceColor', [0.8 0.8 1.0], ... - 'EdgeColor', 'none', ... - 'FaceLighting', 'gouraud', ... - 'AmbientStrength', 0.15); - % Add a camera light, and tone down the specular highlighting - camlight('headlight'); - material('dull'); - hold off; - -end \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/draw/draw_cone_geom.m b/matlab/algorithms/plot_geom/draw/draw_cone_geom.m deleted file mode 100644 index ae98294..0000000 --- a/matlab/algorithms/plot_geom/draw/draw_cone_geom.m +++ /dev/null @@ -1,73 +0,0 @@ -function [] = draw_cone_geom(h_ax, geom, options) -%% draw_cone_geom.m -% draw an astra cone beam projection geometry -% -% param h_ax handle to axis to draw into -% param geom the geometry to draw -% param options struct containing the options for this function -% SourceMarker marker to use to mark the source location -% SourceMarkerColor Color of the marker for the source -% DetectorLineColor Color of the lines that draw the detector -% DetectorLineWidth Width of the lines that draw the detector -% OpticalAxisColor color of the lines representing the optical axis -% -% date 21.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -%% - hold on; - % draw origin - h_origin = scatter3(h_ax, 0,0,0, '+k'); - h_origin.SizeData = 120; - h_origin.LineWidth = 2; - - % draw lines between source, origin and detector - line(h_ax, [0, 0], [0, geom.DistanceOriginDetector], [0, 0], 'Color', options.OpticalAxisColor); - line(h_ax, [0, 0], [0, -geom.DistanceOriginSource], [0, 0], 'Color', options.OpticalAxisColor); - - % draw source - scatter3(h_ax, 0, -geom.DistanceOriginSource, 0, options.SourceMarker,... - options.SourceMarkerColor); - - detector = draw_detector(h_ax, geom, options); - - % connect source to detector edges - for idx = 1:4 - line(h_ax,[0, detector.vertices(1, idx)], ... - [-geom.DistanceOriginSource, geom.DistanceOriginDetector],... - [0, detector.vertices(3, idx)],... - 'Color', 'k', 'LineStyle', ':'); - end - - % draw rotation axis - line(h_ax, [0,0],[0,0], 0.6*[-detector.height, detector.height],... - 'LineWidth', options.DetectorLineWidth, 'Color',... - 'k', 'LineStyle', '--'); - - perc = 0.05; - text(h_ax, perc*detector.width, perc*detector.width,... - 0.8*detector.height, 'rotation axis'); - text(h_ax, detector.width*perc, 0, perc*detector.height, 'origin'); - text(h_ax, detector.width*perc, -geom.DistanceOriginSource,... - perc*detector.height, 'x-ray source'); - text(h_ax, 0, geom.DistanceOriginDetector, 0, 'detector'); - hold off; - - function [detector] = draw_detector(h_ax, geom, options) - detector = struct; - detector.height = geom.DetectorRowCount * geom.DetectorSpacingY; - detector.width = geom.DetectorColCount * geom.DetectorSpacingX; - - vertices = zeros(3, 5); - vertices(1, :) = 0.5*[-detector.width, -detector.width,... - detector.width, detector.width, -detector.width]; - vertices(2, :) = repmat([geom.DistanceOriginDetector], 5, 1); - vertices(3, :) = 0.5*[detector.height, -detector.height,... - -detector.height, detector.height, detector.height]; - - detector.vertices = vertices; - plot3(h_ax, detector.vertices(1, :), detector.vertices(2, :),... - detector.vertices(3, :), options.DetectorLineColor); - end -end diff --git a/matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m b/matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m deleted file mode 100644 index bee83b7..0000000 --- a/matlab/algorithms/plot_geom/draw/draw_cone_vec_geom.m +++ /dev/null @@ -1,108 +0,0 @@ -function [] = draw_cone_vec_geom(h_ax, geom, options) -%% draw_cone_vec_geom.m -% draw an astra cone beam vectorized projection geometry -% param h_ax handle to axis to draw into -% param geom the geometry to draw -% param options struct holding options for drawing -% RotationAxis if specified, will change the rotation axis -% from z-axis to provided axis. -% Must be 3-vector. Default value [0, 0, 1] -% VectorIdx the index of the angle to draw -% Color global color for all lines and markers. -% is overwritten by specialized color options -% SourceMarker Marker to use to mark the source -% SourceMarkerColor Color of the source marker -% DetectorMarker Marker to use to mark the source -% DetectorMarkerColor Color of the source marker -% DetectorLineColor Color of the outline of the detector -% OpticalAxisColor color for drawing the optical axis -% -% date 21.06.2018 -% author Tim Elberfeld, Van Nguyen -% imec VisionLab -% University of Antwerp -% -% - last update 07.11.2018 -%% - vectors = geom.Vectors; - - % source - xray_source = vectors(:, 1:3); - % center of detector - detector_center = vectors(:, 4:6); - - % draw the points and connect with lines - hold on; - num_angles = size(vectors, 1); - s_source = scatter3(h_ax, xray_source(:, 1), xray_source(:, 2),... - xray_source(:, 3)); - s_source.Marker = options.SourceMarker; - s_source.MarkerEdgeColor = options.SourceMarkerColor; - - s_det = scatter3(h_ax, detector_center(:, 1),... - detector_center(:, 2), detector_center(:, 3)); - s_det.MarkerEdgeColor = options.DetectorMarkerColor; - s_det.Marker = options.DetectorMarker; - - detector = struct; - detector.u = vectors(options.VectorIdx, 7:9); - detector.v = vectors(options.VectorIdx, 10:12); - detector.height = geom.DetectorColCount; - detector.width = geom.DetectorRowCount; - detector.origin = detector_center(options.VectorIdx, :); - - vertices = draw_detector_vec(h_ax, detector, options); - connect_source_detector(h_ax, vertices, detector_center, ... - xray_source, options); - - % rotation axis will be roughly as long as the source detector distance - distances = eucl_dist3d(detector_center, xray_source); - mean_sdd = mean(distances(:)); % mean source detector distance - draw_rotation_axis(h_ax, mean_sdd, options); - - text(h_ax, xray_source(options.VectorIdx, 1),... - xray_source(options.VectorIdx, 2),... - xray_source(options.VectorIdx, 3), 'x-ray source'); - text(h_ax, detector_center(options.VectorIdx, 1),... - detector_center(options.VectorIdx, 2),... - detector_center(options.VectorIdx, 3), 'detector'); - hold off; - - function [] = connect_source_detector(h_ax, vertices,... - detector_center, xray_source, options) - % connect source to detector origin - idx = options.VectorIdx; - line(h_ax, [detector_center(idx, 1), xray_source(idx, 1)],... - [detector_center(idx, 2), xray_source(idx, 2)],... - [detector_center(idx, 3), xray_source(idx, 3)],... - 'Color', options.OpticalAxisColor, 'LineStyle', '--'); - - % connect source to detector edges - for kk = 1:4 - line(h_ax,[xray_source(idx, 1), vertices(1, kk)], ... - [xray_source(idx, 2), vertices(2, kk)],... - [xray_source(idx, 3), vertices(3, kk)],... - 'Color', 'k', 'LineStyle', ':'); - end - end - - function [] = draw_rotation_axis(h_ax, scaling, options) - % draw rotation axis - rot_axis = options.RotationAxis; - if(~isnan(rot_axis(1))) - rot_axis = options.RotationAxis + options.RotationAxisOffset; - origin = options.RotationAxisOffset; - % origin of the geometry is assumed to be [0, 0, 0] always! - line(h_ax, [origin(1), (scaling/2)*rot_axis(1)],... - [origin(2), (scaling/2)*rot_axis(2)],... - [origin(3), (scaling/2)*rot_axis(3)],... - 'Color', options.OpticalAxisColor,... - 'LineStyle', '-.'); - line(h_ax, [origin(1), -(scaling/2)*rot_axis(1)],... - [origin(2), -(scaling/2)*rot_axis(2)],... - [origin(3), -(scaling/2)*rot_axis(3)],... - 'Color', options.OpticalAxisColor,... - 'LineStyle', '-.'); - end - end -end diff --git a/matlab/algorithms/plot_geom/draw/draw_detector_vec.m b/matlab/algorithms/plot_geom/draw/draw_detector_vec.m deleted file mode 100644 index 5c293d4..0000000 --- a/matlab/algorithms/plot_geom/draw/draw_detector_vec.m +++ /dev/null @@ -1,42 +0,0 @@ -function [ vertices] = draw_detector_vec( h_ax, detector, options) -%% draw_detector_vec.m -% draw a detector for a vector geometry -% param h_ax handle to axis to draw into -% param detector the struct specifying the detector -% .origin 3d coordinates of the detector origin -% .u vector pointing from detector origin to -% pixel (1,0) -% .v vector pointing from detector origin to -% pixel (0,1) -% .width width of the detector (number of px in u -% direction) -% .height height of the detector (number of px in v -% direction) -% param options struct with options -% .Color Color for the line work -% .DetectorLineColor Color of the detector rectangle outline -% return The vertices of the detector rectangle that -% were plotted -% -% date 09.07.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -%% - % draw the detector rectangle - vertices = zeros(3, 5); - vertices(:, 1) = detector.origin - detector.u * detector.width / 2 + ... - detector.v * detector.height / 2; - vertices(:, 2) = detector.origin + detector.u * detector.width / 2 + ... - detector.v * detector.height / 2; - vertices(:, 3) = detector.origin + detector.u * detector.width / 2 - ... - detector.v * detector.height / 2; - vertices(:, 4) = detector.origin - detector.u * detector.width / 2 - ... - detector.v * detector.height / 2; - vertices(:, 5) = vertices(:, 1); - - detector.vertices = vertices; - plot3(h_ax, detector.vertices(1, :), detector.vertices(2, :),... - detector.vertices(3, :), options.DetectorLineColor); - -end diff --git a/matlab/algorithms/plot_geom/draw/draw_fanflat_geom.m b/matlab/algorithms/plot_geom/draw/draw_fanflat_geom.m deleted file mode 100644 index 5c97d80..0000000 --- a/matlab/algorithms/plot_geom/draw/draw_fanflat_geom.m +++ /dev/null @@ -1,25 +0,0 @@ -function [] = draw_fanflat_geom( h_ax, geom, options) -%% draw_fanflat_geom.m -% draw an astra cone beam projection geometry -% param h_ax handle to axis to draw into -% param geom the geometry to draw -% param options struct holding options for drawing -% SourceMarker Marker to use to mark the source -% SourceMarkerColor Color of the source marker -% DetectorMarker Marker to use to mark the source -% DetectorMarkerColor Color of the source marker -% DetectorLineColor Color of the outline of the detector -% OpticalAxisColor color for drawing the optical axis -% date 28.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -%% - % convert to faux cone geometry so we don't have to write more code :)! - cone_geom = astra_create_proj_geom('cone', geom.DetectorWidth,... - geom.DetectorWidth, 1, geom.DetectorCount, geom.ProjectionAngles,... - geom.DistanceOriginSource, geom.DistanceOriginDetector); - - draw_cone_geom(h_ax, cone_geom, options); -end - diff --git a/matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m b/matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m deleted file mode 100644 index b8261cf..0000000 --- a/matlab/algorithms/plot_geom/draw/draw_fanflat_vec_geom.m +++ /dev/null @@ -1,102 +0,0 @@ -function [ output_args ] = draw_fanflat_vec_geom( h_ax, geom, options) -%% draw_fanflat_vec_geom.m -% draw an astra cone beam projection geometry -% param h_ax handle to axis to draw into -% param geom the geometry to draw -% param options struct holding options for drawing -% VectorIdx the index of the angle to draw -% SourceMarker Marker to use to mark the source -% SourceMarkerColor Color of the source marker -% DetectorMarker Marker to use to mark the source -% DetectorMarkerColor Color of the source marker -% DetectorLineColor Color of the outline of the detector -% OpticalAxisColor color for drawing the optical axis -% -% date 28.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -% -% - last update 09.07.2018 -%% - vectors = geom.Vectors; - - % source - num_angles = size(vectors, 1); - xray_source = [vectors(:, 1:2), zeros(num_angles, 1)]; - % center of detector - detector_center = [vectors(:, 3:4), zeros(num_angles, 1)]; - - % draw the points and connect with lines - hold on; - scatter3(h_ax, xray_source(:, 1), xray_source(:, 2),... - xray_source(:, 3), options.SourceMarker,... - options.SourceMarkerColor); - scatter3(h_ax, detector_center(:, 1),... - detector_center(:, 2), detector_center(:, 3),... - options.DetectorMarker, options.DetectorMarkerColor); - - detector = struct; - detector.u = [vectors(options.VectorIdx, 5:6), 0]; - detector.v = fliplr(detector.u); - detector.height = 1; - detector.width = geom.DetectorCount; - detector.origin = detector_center(options.VectorIdx, :); - - vertices = draw_detector_vec(h_ax, detector, options); - connect_source_detector(h_ax, vertices, detector_center,... - xray_source, options); - - % rotation axis will be roughly as long as the source detector distance - distances = eucl_dist3d(detector_center, xray_source); - mean_sdd = mean(distances(:)); % mean source detector distance - draw_rotation_axis(h_ax, mean_sdd, options); - - text(h_ax, xray_source(options.VectorIdx, 1),... - xray_source(options.VectorIdx, 2),... - xray_source(options.VectorIdx, 3), 'x-ray source'); - text(h_ax, detector_center(options.VectorIdx, 1),... - detector_center(options.VectorIdx, 2),... - detector_center(options.VectorIdx, 3), 'detector'); - - hold off; - - function [] = connect_source_detector(h_ax, vertices,... - detector_center, xray_source, options) - idx = options.VectorIdx; - % connect source to detector origin - line(h_ax, [detector_center(idx, 1), xray_source(idx, 1)],... - [detector_center(idx, 2), xray_source(idx, 2)],... - [detector_center(idx, 3), xray_source(idx, 3)],... - 'Color', options.OpticalAxisColor, 'LineStyle', '--'); - - % connect source to detector edges - for kk = 1:4 - line(h_ax,[xray_source(idx, 1), vertices(1, kk)], ... - [xray_source(idx, 2), vertices(2, kk)],... - [xray_source(idx, 3), vertices(3, kk)],... - 'Color', 'k', 'LineStyle', ':'); - end - end - - function [] = draw_rotation_axis(h_ax, scaling, options) - % draw rotation axis - rot_axis = options.RotationAxis; - if(~isnan(rot_axis(1))) - rot_axis = options.RotationAxis + options.RotationAxisOffset; - origin = options.RotationAxisOffset; - % origin of the geometry is assumed to be [0, 0, 0] always! - line(h_ax, [origin(1), (scaling/2)*rot_axis(1)],... - [origin(2), (scaling/2)*rot_axis(2)],... - [origin(3), (scaling/2)*rot_axis(3)],... - 'Color', options.OpticalAxisColor,... - 'LineStyle', '-.'); - line(h_ax, [origin(1), -(scaling/2)*rot_axis(1)],... - [origin(2), -(scaling/2)*rot_axis(2)],... - [origin(3), -(scaling/2)*rot_axis(3)],... - 'Color', options.OpticalAxisColor,... - 'LineStyle', '-.'); - end - end -end - diff --git a/matlab/algorithms/plot_geom/draw/draw_parallel3d_geom.m b/matlab/algorithms/plot_geom/draw/draw_parallel3d_geom.m deleted file mode 100644 index 45a8d60..0000000 --- a/matlab/algorithms/plot_geom/draw/draw_parallel3d_geom.m +++ /dev/null @@ -1,88 +0,0 @@ -function [ ] = draw_parallel3d_geom( h_ax, geom, options) -%% draw_parallel3d_geom.m -% draw an astra parallel3d projection geometry -% param h_ax handle to axis to draw into -% param geom the geometry to draw -% param options options struct with additional settings -% .SourceDistance distance of source to origin -% .SourceMarker marker for the source locations -% .SourceMarkerColor color specifier for the source marker -% .DetectorMarker marker for the detector locations. -% Default = '.' -% .DetectorMarkerColor color specifier for the detector marker. -% Default = 'k' -% .DetectorLineColor color for the lines drawing the detector -% outline -% .OpticalAxisColor Color of the line representing the optical -% axis. -% date 22.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -% -% - last update 09.07.2018 -%% - dist_origin_detector = options.SourceDistance; - dist_origin_source = options.SourceDistance; - hold on; - - % draw source - scatter3(h_ax, 0, -dist_origin_source, 0, options.SourceMarker,... - options.SourceMarkerColor); - - % draw detector - detector = draw_detector(h_ax, geom, dist_origin_detector, options); - - % draw origin - h_origin = scatter3(h_ax, 0,0,0, '+k'); - h_origin.SizeData = 120; - h_origin.LineWidth = 2; - - % draw lines between source, origin and detector - line(h_ax, [0, 0], [0, dist_origin_detector], [0, 0],... - 'Color', options.OpticalAxisColor); - line(h_ax, [0, 0], [0, -dist_origin_source], [0, 0],... - 'Color', options.OpticalAxisColor); - - % connect source to detector edges - for idx = 1:4 - line(h_ax,[detector.vertices(1, idx),... - detector.vertices(1, idx)],... - [-dist_origin_source, dist_origin_detector],... - [detector.vertices(3, idx), detector.vertices(3, idx)],... - 'Color', 'k', 'LineStyle', ':'); - end - - % draw rotation axis - line(h_ax, [0,0],[0,0], 0.6*[-detector.height, detector.height],... - 'LineWidth', 2, 'Color', 'k', 'LineStyle', '--'); - - perc = 0.05; - text(h_ax, perc*detector.width, perc*detector.width,... - 0.8*detector.height, 'rotation axis'); - text(h_ax, detector.width*perc, 0, perc*detector.height, 'origin'); - text(h_ax, detector.width*perc, -dist_origin_source,... - perc*detector.height, 'x-ray source'); - text(h_ax, 0, dist_origin_detector, 0, 'detector'); - hold off; - - function [detector] = draw_detector(h_ax, geom,... - dist_origin_detector, options) - detector = struct; - detector.height = geom.DetectorRowCount * geom.DetectorSpacingY; - detector.width = geom.DetectorColCount * geom.DetectorSpacingX; - - vertices = zeros(3, 5); - vertices(1, :) = 0.5*[-detector.width, -detector.width,... - detector.width, detector.width, -detector.width]; - vertices(2, :) = repmat(dist_origin_detector, 5, 1); - vertices(3, :) = 0.5*[detector.height, -detector.height,... - -detector.height, detector.height, detector.height]; - - detector.vertices = vertices; - plot3(h_ax, detector.vertices(1, :), detector.vertices(2, :),... - detector.vertices(3, :), options.DetectorLineColor); - end - -end - diff --git a/matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m b/matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m deleted file mode 100644 index ab63e43..0000000 --- a/matlab/algorithms/plot_geom/draw/draw_parallel3d_vec_geom.m +++ /dev/null @@ -1,100 +0,0 @@ -function [ ] = draw_parallel3d_vec_geom( h_ax, geom, options) -%% draw_parallel3d_vec_geom.m -% draw an astra parallel3d projection geometry -% param h_ax handle to axis to draw into -% param geom the geometry to draw -% param options struct containing the options for this function -% idx index of the vector to draw in more detail -% SourceDistance distance of the source to the origin -% -% date 22.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -%% - vectors = geom.Vectors; - - % source - xray_source = vectors(:, 1:3)*options.SourceDistance; - - % center of detector - detector_center = vectors(:, 4:6); - - % draw the points and connect with lines - hold on; - num_angles = size(vectors, 1); - scatter3(h_ax, xray_source(:, 1), xray_source(:, 2),... - xray_source(:, 3), options.SourceMarkerColor,... - options.SourceMarker); - scatter3(h_ax, detector_center(:, 1), detector_center(:, 2),... - detector_center(:, 3), 'k.'); - - detector = struct; - detector.u = vectors(options.VectorIdx, 7:9); - detector.v = vectors(options.VectorIdx, 10:12); - detector.height = geom.DetectorColCount; - detector.width = geom.DetectorRowCount; - detector.origin = detector_center(options.VectorIdx, :); - detector.vertices = draw_detector_vec(h_ax, detector, options); - - connect_source_detector(h_ax, detector, detector_center, xray_source,... - options); - - % rotation axis will be roughly as long as the source detector distance - distances = eucl_dist3d(detector_center, xray_source); - mean_sdd = mean(distances(:)); % mean source detector distance - draw_rotation_axis(h_ax, mean_sdd, options); - - text(h_ax, xray_source(options.VectorIdx, 1),... - xray_source(options.VectorIdx, 2), ... - xray_source(options.VectorIdx, 3), 'x-ray source'); - text(h_ax, detector_center(options.VectorIdx, 1),... - detector_center(options.VectorIdx, 2),... - detector_center(options.VectorIdx, 3), 'detector'); - hold off; - - function [] = connect_source_detector(h_ax, detector,... - detector_center, xray_source, options) - % connect source to detector origin - idx = options.VectorIdx; - line(h_ax, [detector_center(idx, 1), xray_source(idx, 1)],... - [detector_center(idx, 2), xray_source(idx, 2)],... - [detector_center(idx, 3), xray_source(idx, 3)],... - 'Color', options.OpticalAxisColor, 'LineStyle', '--'); - - % compute normal of detector plane - n = null([detector.u; detector.v]); - - % connect source to detector edges - for kk = 1:4 - a = detector.vertices(1, kk) - n(1)*xray_source(idx, 1); - b = detector.vertices(2, kk) - n(2)*xray_source(idx, 2); - c = detector.vertices(3, kk) - n(3)*xray_source(idx, 3); - line(h_ax,[a, detector.vertices(1, kk)], ... - [b, detector.vertices(2, kk)],... - [c, detector.vertices(3, kk)],... - 'Color', 'k',... - 'LineStyle', ':'); - end - end - - function [] = draw_rotation_axis(h_ax, scaling, options) - % draw rotation axis - rot_axis = options.RotationAxis; - if(~isnan(rot_axis(1))) - rot_axis = options.RotationAxis + options.RotationAxisOffset; - origin = options.RotationAxisOffset; - % origin of the geometry is assumed to be [0, 0, 0] always! - line(h_ax, [origin(1), (scaling/2)*rot_axis(1)],... - [origin(2), (scaling/2)*rot_axis(2)],... - [origin(3), (scaling/2)*rot_axis(3)],... - 'Color', options.OpticalAxisColor,... - 'LineStyle', '-.'); - line(h_ax, [origin(1), -(scaling/2)*rot_axis(1)],... - [origin(2), -(scaling/2)*rot_axis(2)],... - [origin(3), -(scaling/2)*rot_axis(3)],... - 'Color', options.OpticalAxisColor,... - 'LineStyle', '-.'); - end - end -end diff --git a/matlab/algorithms/plot_geom/draw/draw_proj_geom.m b/matlab/algorithms/plot_geom/draw/draw_proj_geom.m deleted file mode 100644 index c20ddc8..0000000 --- a/matlab/algorithms/plot_geom/draw/draw_proj_geom.m +++ /dev/null @@ -1,138 +0,0 @@ -function [] = draw_proj_geom(geom, varargin) -%% draw_proj_geom.m -% brief rendering function for astra geometries. -% param geom the geometry to plot. If geometry type -% is not supported, throws error -% ------------------------------ -% optional parameters that can be provided as string value pairs: -% -% param RotationAxis if specified, will change the drawn -% rotation axis to provided axis. -% Must be 3-vector. Default value is -% [NaN, NaN, NaN], (meaning do not draw). -% param RotationAxisOffset if specified, will translate the drawn -% rotation axis by the provided vector. -% Default = [0, 0, 0] -% param VectorIdx index of the vector to visualize if geom -% is a vector geometry type. Default = 1 -% param Color Color for all markers and lines if not -% otherwise specified -% param DetectorMarker marker for the detector locations. -% Default = '.' -% param DetectorMarkerColor color specifier for the detector marker. -% Default = 'k' -% param DetectorLineColor color for the lines drawing the detector -% outline -% param DetectorLineWidth line width of detector rectangle -% param SourceMarker marker for the source locations -% param SourceMarkerColor color specifier for the source marker -% param SourceDistance (only for parallel3d and parallel3d_vec) -% distance of source to origin -% param OpticalAxisColor Color for drawing the optical axis -% -% date 20.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -% -% - last update 07.11.2018 -%% - h_ax = gca; - options = parseoptions(varargin); - - switch geom.type - case 'parallel3d' - disp('type: parallel3d') - disp(['detector spacing: [' num2str(geom.DetectorSpacingX), ', '... - num2str(geom.DetectorSpacingY) ']']); - disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... - num2str(geom.DetectorColCount) ']']); - disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); - disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); - disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); - disp('DistanceOriginDetector inf'); - disp('DistanceOriginSource inf'); - - draw_parallel3d_geom(h_ax, geom, options); - case 'parallel3d_vec' - disp('type: parallel3d_vec') - disp(['detector px: [' num2str(geom.DetectorRowCount), ', '... - num2str(geom.DetectorColCount) ']']); - disp(['# angles: ' num2str(size(geom.Vectors, 1))]); - - draw_parallel3d_vec_geom(h_ax, geom, options); - case 'cone' - disp('type: cone'); - disp(['detector spacing: [' num2str(geom.DetectorSpacingX), ', '... - num2str(geom.DetectorSpacingY) ']']); - disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... - num2str(geom.DetectorColCount) ']']); - disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); - disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); - disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); - disp(['DistanceOriginDetector ' num2str(geom.DistanceOriginDetector)]); - disp(['DistanceOriginSource ' num2str(geom.DistanceOriginSource)]); - - draw_cone_geom(h_ax, geom, options); - case 'cone_vec' - disp('type: cone_vec'); - disp(['detector px: [' num2str(geom.DetectorRowCount), ', ' ... - num2str(geom.DetectorColCount) ']']); - disp(['# angles: ' num2str(size(geom.Vectors, 1))]); - - draw_cone_vec_geom(h_ax, geom, options); - case 'fanflat' - disp('type: fanflat'); - disp(['detector px: ' num2str(geom.DetectorCount)]); - disp(['angle lo: ' num2str(geom.ProjectionAngles(1))]); - disp(['angle hi: ' num2str(geom.ProjectionAngles(end))]); - disp(['# angles: ' num2str(numel(geom.ProjectionAngles))]); - disp(['DistanceOriginDetector '... - num2str(geom.DistanceOriginDetector)]); - disp(['DistanceOriginSource '... - num2str(geom.DistanceOriginSource)]); - - draw_fanflat_geom(h_ax, geom, options); - case 'fanflat_vec' - disp('type: fanflat_vec'); - disp(['detector px: ' num2str(geom.DetectorCount)]); - disp(['# angles: ' num2str(size(geom.Vectors, 1))]); - - draw_fanflat_vec_geom(h_ax, geom, options); - otherwise - error(['Unknown geometry type ' geom.type]) - end - view(45, 25); % gives nicer default view angle - - function [options] = parseoptions(input_args) - % make an options struct - options = struct; - options.RotationAxis = [NaN, NaN, NaN]; - options.RotationAxisOffset = [0, 0, 0]; - options.VectorIdx = 1; - options.Color = 'k'; - options.DetectorMarker = '.'; - options.DetectorMarkerColor = ''; - options.DetectorLineColor = ''; - options.DetectorLineWidth = 1; - options.SourceMarker = '*'; - options.SourceMarkerColor = ''; - options.SourceDistance = 100; - options.OpticalAxisColor = ''; - options = parseargs(options, input_args{:}); - - % if the color is still empty, replace by global color - if strcmpi(options.DetectorMarkerColor , '') - options.DetectorMarkerColor = options.Color; - end - if strcmpi(options.DetectorLineColor , '') - options.DetectorLineColor = options.Color; - end - if strcmpi(options.SourceMarkerColor , '') - options.SourceMarkerColor = options.Color; - end - if strcmpi(options.OpticalAxisColor , '') - options.OpticalAxisColor = options.Color; - end - end -end diff --git a/matlab/algorithms/plot_geom/draw/draw_vol_geom.m b/matlab/algorithms/plot_geom/draw/draw_vol_geom.m deleted file mode 100644 index 0b4fe2f..0000000 --- a/matlab/algorithms/plot_geom/draw/draw_vol_geom.m +++ /dev/null @@ -1,105 +0,0 @@ -function [] = draw_vol_geom( vol_geom, varargin) -%% draw_vol_geom.m -% brief rendering function for astra volume geometries -% describing a phantom. -% param vol_geom volume geometry describing the phantom -% param vx_size voxel size in unit of preference. must be same unit -% that was used to scale the projection geometry -% ------------------------------ -% optional parameters that can be provided as string value pairs: -% -% param Magnification magnification factor for the phantom. for small -% phantoms it might be necessary to scale the render -% up as otherwise it won't show up in the plot. -% Default = 1 -% param LineWidth line width for the box wireframe. Default = 2 -% param Color color of the wireframe. Default = 'r' -% -% date 20.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -% -% - last update 16.11.2018 -%% - h_ax = gca; - - if mod(size(varargin), 2) ~= 0 - vx_size = varargin{1}; - varargin = varargin(2:end); % consumed vx_size from arg list - else - vx_size = 1; - end - - - options = struct; - options.Color = 'r'; - options.LineWidth = 2; - options.Magnification = 1; - options = parseargs(options, varargin{:}); - - hold on; - phantom_height = vol_geom.GridRowCount * vx_size; - phantom_width = vol_geom.GridColCount * vx_size; - phantom_depth = vol_geom.GridSliceCount * vx_size; - - if isfield(vol_geom, 'option') - minx = vol_geom.option.WindowMinX * vx_size; - maxx = vol_geom.option.WindowMaxX * vx_size; - - miny = vol_geom.option.WindowMinY * vx_size; - maxy = vol_geom.option.WindowMaxY * vx_size; - - minz = vol_geom.option.WindowMinZ * vx_size; - maxz = vol_geom.option.WindowMaxZ * vx_size; - else - minx = phantom_width / 2 * vx_size; - maxx = phantom_width / 2 * vx_size; - - miny = phantom_height / 2 * vx_size; - maxy = phantom_height / 2 * vx_size; - - minz = phantom_depth / 2 * vx_size; - maxz = phantom_depth / 2 * vx_size; - end - - xx_phantom = options.Magnification*[minx, minx, minx, minx, maxx, maxx, maxx, maxx]; - yy_phantom = options.Magnification*[miny, miny, maxy, maxy, miny, miny, maxy, maxy]; - zz_phantom = options.Magnification*[minz, maxz, minz, maxz, minz, maxz, minz, maxz]; - - face1 = [xx_phantom(1:4); yy_phantom(1:4); zz_phantom(1:4)]; - face2 = [[xx_phantom(1:2), xx_phantom(5:6)];... - [yy_phantom(1:2), yy_phantom(5:6)];... - [zz_phantom(1:2), zz_phantom(5:6)]]; - face3 = [[xx_phantom(3:4), xx_phantom(7:8)];... - [yy_phantom(3:4), yy_phantom(7:8)];... - [zz_phantom(3:4), zz_phantom(7:8)]]; - face4 = [[xx_phantom(5:6), xx_phantom(7:8)];... - [yy_phantom(5:6), yy_phantom(7:8)];... - [zz_phantom(5:6), zz_phantom(7:8)]]; - - % as we draw only a wire frame, we need only to draw 4 of the faces - draw_face(h_ax, face1, options); - draw_face(h_ax, face2, options); - draw_face(h_ax, face3, options); - draw_face(h_ax, face4, options); - - hold off; - - function [] = draw_face(h_ax, face_coords, options) - line(h_ax, face_coords(1, 1:2), face_coords(2, 1:2),... - face_coords(3, 1:2), 'LineWidth', options.LineWidth,... - 'Color', options.Color); - line(h_ax, face_coords(1, 3:4), face_coords(2, 3:4),... - face_coords(3, 3:4), 'LineWidth', options.LineWidth,... - 'Color', options.Color); - line(h_ax, [face_coords(1, 4),face_coords(1, 2)],... - [face_coords(2, 4),face_coords(2, 2)],... - [face_coords(3, 4),face_coords(3, 2)],... - 'LineWidth', options.LineWidth, 'Color', options.Color); - line(h_ax, [face_coords(1, 1),face_coords(1, 3)],... - [face_coords(2, 1),face_coords(2, 3)],... - [face_coords(3, 1),face_coords(3, 3)],... - 'LineWidth', options.LineWidth, 'Color', options.Color); - end -end diff --git a/matlab/algorithms/plot_geom/private/magnify_proj.m b/matlab/algorithms/plot_geom/private/magnify_proj.m new file mode 100644 index 0000000..73e892a --- /dev/null +++ b/matlab/algorithms/plot_geom/private/magnify_proj.m @@ -0,0 +1,23 @@ + +function [ magnified_vec_geom ] = magnify_proj( vec_geom, dsdd ) +%% generate magnified vector geometry +% param type vec_geom - example vector geometry +% dsdd - deviation of SDD +% return magnified_vec_geom - the geometry that was created +% +% date 09.07.2018 +% author Van Nguyen +% imec VisionLab +% University of Antwerp +%% + magnified_vec_geom = vec_geom; + vec_sd_direction = vec_geom(:,1:3) - vec_geom(:,4:6); + norm_sd = sqrt(sum(vec_sd_direction.^2,2)); + vec_norm_sd(:,1) = norm_sd; + vec_norm_sd(:,2) = norm_sd; + vec_norm_sd(:,3) = norm_sd; + vec_sd_direction = vec_sd_direction ./ vec_norm_sd; + magnified_vec_geom(:,4:6) = vec_geom(:,4:6) - dsdd * vec_sd_direction; + clearvars -except magnified_vec_geom +end + diff --git a/matlab/algorithms/plot_geom/private/rotate_around3d.m b/matlab/algorithms/plot_geom/private/rotate_around3d.m new file mode 100644 index 0000000..e9f152b --- /dev/null +++ b/matlab/algorithms/plot_geom/private/rotate_around3d.m @@ -0,0 +1,27 @@ +function [rot_vec] = rotate_around3d(vec, ax, angle) +%% rotate_around.m +% rotate a 3d vector around an axis by an angle +% param vec: 3 x 1 vector to be rotated +% param ax: 3 x 1 vector specifying the axis +% param angle: scalar, angle to rotate by +% return: rotated vector +% +% date: 21.06.2018 +% author: someone at VisionLab, modified by Tim Elberfeld +% imec VisionLab +% University of Antwerp +%% + rot_vec = zeros(3, 1); + + rot_vec(1) = (ax(1) * ax(1) * (1-cos(angle)) + cos(angle)) * vec(1) +... + (ax(1) * ax(2) * (1-cos(angle)) - ax(3) * sin(angle)) * vec(2) +... + (ax(1) * ax(3) * (1-cos(angle)) + ax(2) * sin(angle)) * vec(3); + + rot_vec(2) = (ax(1) * ax(2) * (1-cos(angle)) + ax(3) * sin(angle)) * vec(1) +... + (ax(2) * ax(2) * (1-cos(angle)) + cos(angle)) * vec(2) +... + (ax(2) * ax(3) * (1-cos(angle)) - ax(1) * sin(angle)) * vec(3); + + rot_vec(3) = (ax(1) * ax(3) * (1-cos(angle)) - ax(2) * sin(angle)) * vec(1) +... + (ax(2) * ax(3) * (1-cos(angle)) + ax(1) * sin(angle)) * vec(2) +... + (ax(3) * ax(3) * (1-cos(angle)) + cos(angle)) * vec(3); +end diff --git a/matlab/algorithms/plot_geom/private/rotate_detector.m b/matlab/algorithms/plot_geom/private/rotate_detector.m new file mode 100644 index 0000000..019f92a --- /dev/null +++ b/matlab/algorithms/plot_geom/private/rotate_detector.m @@ -0,0 +1,19 @@ +function [ vectors_rot ] = rotate_detector(vectors, rot_angles) +%% rotate the detector part of the vectors of a vector geometry +% param vectors - vectors to transform +% param rot_angles - rotation euler angles +% +% return vectors_rot - copy of input vectors, but rotated +% +% date 09.07.2018 +% author Van Nguyen, Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + vectors_rot = vectors; + vectors_rot(:, 1: 3) = rotate_euler3d(vectors(:, 1: 3), rot_angles); + vectors_rot(:, 4: 6) = rotate_euler3d(vectors(:, 4: 6), rot_angles); + vectors_rot(:, 7: 9) = rotate_euler3d(vectors(:, 7: 9), rot_angles); + vectors_rot(:, 10:12) = rotate_euler3d(vectors(:, 10:12), rot_angles); +end diff --git a/matlab/algorithms/plot_geom/private/rotate_euler3d.m b/matlab/algorithms/plot_geom/private/rotate_euler3d.m new file mode 100644 index 0000000..6fddb57 --- /dev/null +++ b/matlab/algorithms/plot_geom/private/rotate_euler3d.m @@ -0,0 +1,35 @@ +function [ vectors_rot ] = rotate_euler3d(vectors, rot_angles) +%% rotate some vectors by euler angles around an axis +% param vectors - vectors to transform +% param rot_angles - rotation euler angles +% +% return vectors_rot - copy of input vectors, but rotated +% +% date 09.07.2018 +% author Van Nguyen, Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + roll = rot_angles(1); + yaw = rot_angles(2); + pitch = rot_angles(3); + roll_mat = [1 0 0; ... + 0 cos(roll) -sin(roll); ... + 0 sin(roll) cos(roll)]; + + yaw_mat = [cos(yaw) 0 -sin(yaw); ... + 0 1 0; ... + sin(yaw) 0 cos(yaw)]; + + pitch_mat = [cos(pitch) -sin(pitch) 0; ... + sin(pitch) cos(pitch) 0; ... + 0 0 1]; + % simulate rotation and translation of the DETECTOR + rot_mat = roll_mat * yaw_mat * pitch_mat; + vectors_rot = vectors; + + for i = 1:size(vectors, 1) + vectors_rot(i, :) = (rot_mat * vectors(i, :)')'; + end +end diff --git a/matlab/algorithms/plot_geom/private/translate_3d.m b/matlab/algorithms/plot_geom/private/translate_3d.m new file mode 100644 index 0000000..bd51485 --- /dev/null +++ b/matlab/algorithms/plot_geom/private/translate_3d.m @@ -0,0 +1,18 @@ +function [ transl_vectors ] = translate_3d( vectors, transl_vec) +%% translate some vectors by a translation vector +% param vectors - the vectors to translate +% param transl_vec - vector geometry translation +% return translated_vec_geom - copy of input geometry with translated +% vectors +% +% date 09.07.2018 +% author Van Nguyen, Tim Elberfeld +% imec VisionLab +% University of Antwerp +% last mod 07.11.2018 +%% + transl_vectors = vectors; % copy input + transl = repmat(transl_vec, size(vectors, 1), 1); + transl_vectors = transl_vectors + transl; +end + diff --git a/matlab/algorithms/plot_geom/util/cone_to_cone_vec.m b/matlab/algorithms/plot_geom/util/cone_to_cone_vec.m deleted file mode 100644 index 0075db9..0000000 --- a/matlab/algorithms/plot_geom/util/cone_to_cone_vec.m +++ /dev/null @@ -1,41 +0,0 @@ -function [ cone_vec_geom] = cone_to_cone_vec( cone_geom ) -%% cone_to_cone_vec.m -% brief convert a cone beam projection geometry into a -% cone_vec geometry according to: -% http://www.astra-toolbox.com/docs/geom3d.html#projection-geometries -% -% param cone_geom the cone beam geometry to convert -% return cone_vec_geom the converted geometry -% -% date 21.06.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -%% - num_angles = numel(cone_geom.ProjectionAngles); - vectors = zeros(num_angles, 12); - - for idx = 1:num_angles - % source - vectors(idx, 1) = sin(cone_geom.ProjectionAngles(idx)) * cone_geom.DistanceOriginSource; - vectors(idx, 2) = -cos(cone_geom.ProjectionAngles(idx)) * cone_geom.DistanceOriginSource; - vectors(idx, 3) = 0; - - % center of detector - vectors(idx, 4) = -sin(cone_geom.ProjectionAngles(idx)) * cone_geom.DistanceOriginDetector; - vectors(idx, 5) = cos(cone_geom.ProjectionAngles(idx)) * cone_geom.DistanceOriginDetector; - vectors(idx, 6) = 0; - - % vector from detector pixel (0,0) to (0,1) - vectors(idx, 7) = cos(cone_geom.ProjectionAngles(idx)) * cone_geom.DetectorSpacingX; - vectors(idx, 8) = sin(cone_geom.ProjectionAngles(idx)) * cone_geom.DetectorSpacingX; - vectors(idx, 9) = 0; - - % vector from detector pixel (0,0) to (1,0) - vectors(idx, 10) = 0; - vectors(idx, 11) = 0; - vectors(idx, 12) = cone_geom.DetectorSpacingY; - end - - cone_vec_geom = astra_create_proj_geom('cone_vec', cone_geom.DetectorRowCount, cone_geom.DetectorColCount, vectors); -end diff --git a/matlab/algorithms/plot_geom/util/eucl_dist3d.m b/matlab/algorithms/plot_geom/util/eucl_dist3d.m deleted file mode 100644 index 57d6cb4..0000000 --- a/matlab/algorithms/plot_geom/util/eucl_dist3d.m +++ /dev/null @@ -1,16 +0,0 @@ -function [dist] = eucl_dist3d(a, b) -%% eucl_dist3d.m -% 3d euclidean distance for a nx3 matrix holding n 3-vectors -% param a - first vectors -% param b - second vectors -% date 07.11.2018 -% author Tim Elberfeld -% imec VisionLab -% University of Antwerp -% last update 07.11.2018 -%% - dist = sqrt((a(:, 1) - b(:, 1)).^2 + ... - (a(:, 2) - b(:, 2)).^2 + ... - (a(:, 3) - b(:, 3)).^2); -end - diff --git a/matlab/algorithms/plot_geom/util/fanflat_to_fanflat_vec.m b/matlab/algorithms/plot_geom/util/fanflat_to_fanflat_vec.m deleted file mode 100644 index 9707592..0000000 --- a/matlab/algorithms/plot_geom/util/fanflat_to_fanflat_vec.m +++ /dev/null @@ -1,4 +0,0 @@ -function [ vec_geom] = fanflat_to_fanflat_vec( geom ) - vec_geom = astra_geom_2vec(geom); -end - diff --git a/matlab/algorithms/plot_geom/util/magnify_proj.m b/matlab/algorithms/plot_geom/util/magnify_proj.m deleted file mode 100644 index 73e892a..0000000 --- a/matlab/algorithms/plot_geom/util/magnify_proj.m +++ /dev/null @@ -1,23 +0,0 @@ - -function [ magnified_vec_geom ] = magnify_proj( vec_geom, dsdd ) -%% generate magnified vector geometry -% param type vec_geom - example vector geometry -% dsdd - deviation of SDD -% return magnified_vec_geom - the geometry that was created -% -% date 09.07.2018 -% author Van Nguyen -% imec VisionLab -% University of Antwerp -%% - magnified_vec_geom = vec_geom; - vec_sd_direction = vec_geom(:,1:3) - vec_geom(:,4:6); - norm_sd = sqrt(sum(vec_sd_direction.^2,2)); - vec_norm_sd(:,1) = norm_sd; - vec_norm_sd(:,2) = norm_sd; - vec_norm_sd(:,3) = norm_sd; - vec_sd_direction = vec_sd_direction ./ vec_norm_sd; - magnified_vec_geom(:,4:6) = vec_geom(:,4:6) - dsdd * vec_sd_direction; - clearvars -except magnified_vec_geom -end - diff --git a/matlab/algorithms/plot_geom/util/parseargs/license.txt b/matlab/algorithms/plot_geom/util/parseargs/license.txt deleted file mode 100644 index cae4cd5..0000000 --- a/matlab/algorithms/plot_geom/util/parseargs/license.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2016, The MathWorks, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - * In all cases, the software is, and all modifications and derivatives - of the software shall be, licensed to you solely for use in conjunction - with MathWorks products and service offerings. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/matlab/algorithms/plot_geom/util/parseargs/parseargs.m b/matlab/algorithms/plot_geom/util/parseargs/parseargs.m deleted file mode 100644 index 05ad613..0000000 --- a/matlab/algorithms/plot_geom/util/parseargs/parseargs.m +++ /dev/null @@ -1,97 +0,0 @@ -function X = parseargs(X,varargin) -%PARSEARGS - Parses name-value pairs -% -% Behaves like setfield, but accepts multiple name-value pairs and provides -% some additional features: -% 1) If any field of X is an cell-array of strings, it can only be set to -% one of those strings. If no value is specified for that field, the -% first string is selected. -% 2) Where the field is not empty, its data type cannot be changed -% 3) Where the field contains a scalar, its size cannot be changed. -% -% X = parseargs(X,name1,value1,name2,value2,...) -% -% Intended for use as an argument parser for functions which multiple options. -% Example usage: -% -% function my_function(varargin) -% X.StartValue = 0; -% X.StopOnError = false; -% X.SolverType = {'fixedstep','variablestep'}; -% X.OutputFile = 'out.txt'; -% X = parseargs(X,varargin{:}); -% -% Then call (e.g.): -% -% my_function('OutputFile','out2.txt','SolverType','variablestep'); - -% The various #ok comments below are to stop MLint complaining about -% inefficient usage. In all cases, the inefficient usage (of error, getfield, -% setfield and find) is used to ensure compatibility with earlier versions -% of MATLAB. - -% Copyright 2006-2010 The MathWorks, Inc. - -remaining = nargin-1; % number of arguments other than X -count = 1; -fields = fieldnames(X); -modified = zeros(size(fields)); -% Take input arguments two at a time until we run out. -while remaining>=2 - fieldname = varargin{count}; - fieldind = find(strcmp(fieldname,fields)); - if ~isempty(fieldind) - oldvalue = getfield(X,fieldname); %#ok - newvalue = varargin{count+1}; - if iscell(oldvalue) - % Cell arrays must contain strings, and the new value must be - % a string which appears in the list. - if ~iscellstr(oldvalue) - error(sprintf('All allowed values for "%s" must be strings',fieldname)); %#ok - end - if ~ischar(newvalue) - error(sprintf('New value for "%s" must be a string',fieldname)); %#ok - end - if isempty(find(strcmp(oldvalue,newvalue))) %#ok - error(sprintf('"%s" is not allowed for field "%s"',newvalue,fieldname)); %#ok - end - elseif ~isempty(oldvalue) - % The caller isn't allowed to change the data type of a non-empty property, - % and scalars must remain as scalars. - if ~strcmp(class(oldvalue),class(newvalue)) - error(sprintf('Cannot change class of field "%s" from "%s" to "%s"',... - fieldname,class(oldvalue),class(newvalue))); %#ok - elseif numel(oldvalue)==1 & numel(newvalue)~=1 %#ok - error(sprintf('New value for "%s" must be a scalar',fieldname)); %#ok - end - end - X = setfield(X,fieldname,newvalue); %#ok - modified(fieldind) = 1; - else - error(['Not a valid field name: ' fieldname]); - end - remaining = remaining - 2; - count = count + 2; -end -% Check that we had a value for every name. -if remaining~=0 - error('Odd number of arguments supplied. Name-value pairs required'); -end - -% Now find cell arrays which were not modified by the above process, and select -% the first string. -notmodified = find(~modified); -for i=1:length(notmodified) - fieldname = fields{notmodified(i)}; - oldvalue = getfield(X,fieldname); %#ok - if iscell(oldvalue) - if ~iscellstr(oldvalue) - error(sprintf('All allowed values for "%s" must be strings',fieldname)); %#ok - elseif isempty(oldvalue) - error(sprintf('Empty cell array not allowed for field "%s"',fieldname)); %#ok - end - X = setfield(X,fieldname,oldvalue{1}); %#ok - end -end - - diff --git a/matlab/algorithms/plot_geom/util/rotate_around3d.m b/matlab/algorithms/plot_geom/util/rotate_around3d.m deleted file mode 100644 index e9f152b..0000000 --- a/matlab/algorithms/plot_geom/util/rotate_around3d.m +++ /dev/null @@ -1,27 +0,0 @@ -function [rot_vec] = rotate_around3d(vec, ax, angle) -%% rotate_around.m -% rotate a 3d vector around an axis by an angle -% param vec: 3 x 1 vector to be rotated -% param ax: 3 x 1 vector specifying the axis -% param angle: scalar, angle to rotate by -% return: rotated vector -% -% date: 21.06.2018 -% author: someone at VisionLab, modified by Tim Elberfeld -% imec VisionLab -% University of Antwerp -%% - rot_vec = zeros(3, 1); - - rot_vec(1) = (ax(1) * ax(1) * (1-cos(angle)) + cos(angle)) * vec(1) +... - (ax(1) * ax(2) * (1-cos(angle)) - ax(3) * sin(angle)) * vec(2) +... - (ax(1) * ax(3) * (1-cos(angle)) + ax(2) * sin(angle)) * vec(3); - - rot_vec(2) = (ax(1) * ax(2) * (1-cos(angle)) + ax(3) * sin(angle)) * vec(1) +... - (ax(2) * ax(2) * (1-cos(angle)) + cos(angle)) * vec(2) +... - (ax(2) * ax(3) * (1-cos(angle)) - ax(1) * sin(angle)) * vec(3); - - rot_vec(3) = (ax(1) * ax(3) * (1-cos(angle)) - ax(2) * sin(angle)) * vec(1) +... - (ax(2) * ax(3) * (1-cos(angle)) + ax(1) * sin(angle)) * vec(2) +... - (ax(3) * ax(3) * (1-cos(angle)) + cos(angle)) * vec(3); -end diff --git a/matlab/algorithms/plot_geom/util/rotate_detector.m b/matlab/algorithms/plot_geom/util/rotate_detector.m deleted file mode 100644 index 019f92a..0000000 --- a/matlab/algorithms/plot_geom/util/rotate_detector.m +++ /dev/null @@ -1,19 +0,0 @@ -function [ vectors_rot ] = rotate_detector(vectors, rot_angles) -%% rotate the detector part of the vectors of a vector geometry -% param vectors - vectors to transform -% param rot_angles - rotation euler angles -% -% return vectors_rot - copy of input vectors, but rotated -% -% date 09.07.2018 -% author Van Nguyen, Tim Elberfeld -% imec VisionLab -% University of Antwerp -% last mod 07.11.2018 -%% - vectors_rot = vectors; - vectors_rot(:, 1: 3) = rotate_euler3d(vectors(:, 1: 3), rot_angles); - vectors_rot(:, 4: 6) = rotate_euler3d(vectors(:, 4: 6), rot_angles); - vectors_rot(:, 7: 9) = rotate_euler3d(vectors(:, 7: 9), rot_angles); - vectors_rot(:, 10:12) = rotate_euler3d(vectors(:, 10:12), rot_angles); -end diff --git a/matlab/algorithms/plot_geom/util/rotate_euler3d.m b/matlab/algorithms/plot_geom/util/rotate_euler3d.m deleted file mode 100644 index 6fddb57..0000000 --- a/matlab/algorithms/plot_geom/util/rotate_euler3d.m +++ /dev/null @@ -1,35 +0,0 @@ -function [ vectors_rot ] = rotate_euler3d(vectors, rot_angles) -%% rotate some vectors by euler angles around an axis -% param vectors - vectors to transform -% param rot_angles - rotation euler angles -% -% return vectors_rot - copy of input vectors, but rotated -% -% date 09.07.2018 -% author Van Nguyen, Tim Elberfeld -% imec VisionLab -% University of Antwerp -% last mod 07.11.2018 -%% - roll = rot_angles(1); - yaw = rot_angles(2); - pitch = rot_angles(3); - roll_mat = [1 0 0; ... - 0 cos(roll) -sin(roll); ... - 0 sin(roll) cos(roll)]; - - yaw_mat = [cos(yaw) 0 -sin(yaw); ... - 0 1 0; ... - sin(yaw) 0 cos(yaw)]; - - pitch_mat = [cos(pitch) -sin(pitch) 0; ... - sin(pitch) cos(pitch) 0; ... - 0 0 1]; - % simulate rotation and translation of the DETECTOR - rot_mat = roll_mat * yaw_mat * pitch_mat; - vectors_rot = vectors; - - for i = 1:size(vectors, 1) - vectors_rot(i, :) = (rot_mat * vectors(i, :)')'; - end -end diff --git a/matlab/algorithms/plot_geom/util/stlTools/license.txt b/matlab/algorithms/plot_geom/util/stlTools/license.txt deleted file mode 100644 index b2d00b0..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/license.txt +++ /dev/null @@ -1,34 +0,0 @@ -Copyright (c) 2017, Pau Micó -Copyright (c) 2015, Sven Holcombe -Copyright (c) 2011, Eric Johnson -Copyright (c) 2013, Adam H. Aitkenhead -Copyright (c) 2011, Francis Esmonde-White -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution - * Neither the name of the The MathWorks, Inc. nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - * Neither the name of the The Christie NHS Foundation Trust nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/matlab/algorithms/plot_geom/util/stlTools/readme.txt b/matlab/algorithms/plot_geom/util/stlTools/readme.txt deleted file mode 100644 index b8037d6..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/readme.txt +++ /dev/null @@ -1,16 +0,0 @@ -The 'stlTools' toolbox is a collection of functions, samples and demos to illustrate how to deal with STL files. Some of them are contributions published in Matlab Central and properly referenced here. -This toolbox contains the following files: - -stlGetFormat: identifies the format of the STL file and returns 'binary' or 'ascii'. This file is inspired in the 'READ-stl' file written and published by Adam H. Aitkenhead (http://www.mathworks.com/matlabcentral/fileexchange/27390-mesh-voxelisation). Copyright (c) 2013, Adam H. Aitkenhead. -stlReadAscii: reads an STL file written in ascii format. This file is inspired in the 'READ-stl' file written and published by Adam H. Aitkenhead (http://www.mathworks.com/matlabcentral/fileexchange/27390-mesh-voxelisation). Copyright (c) 2013, Adam H. Aitkenhead -stlReadBinary: reads an STL file written in binary format. This file is inspired in the 'READ-stl' file written and published by Adam H. Aitkenhead (http://www.mathworks.com/matlabcentral/fileexchange/27390-mesh-voxelisation). Copyright (c) 2013, Adam H. Aitkenhead -stlRead: uses 'stlGetFormat', 'stlReadAscii' and 'stlReadBinary' to make STL reading independent of the format of the file -stlWrite: writes an STL file in 'ascii' or 'binary' formats. This is written and published by Sven Holcombe (http://www.mathworks.com/matlabcentral/fileexchange/20922-stlwrite-filename--varargin-). Copyright (c) 2012, Grant Lohsen. Copyright (c) 2015, Sven Holcombe. -stlSlimVerts: finds and removes duplicated vertices. This function is written and published by Francis Esmonde-White as PATCHSLIM (http://www.mathworks.com/matlabcentral/fileexchange/29986-patch-slim--patchslim-m-). Copyright (c) 2011, Francis Esmonde-White. -stlGetVerts: returns a list of vertices that are 'opened' or 'closed' depending on the 'mode' input parameter. An 'open' vertice is the one that defines an open side. An open side is the one that only takes part of one triangle -stlDelVerts: removes a list of vertices from STL files -stlAddVerts: adds the new vertices from a list (and consequently, new faces) to a STL object -stlPlot: is an easy way to plot an STL object -stlDemo: is a collection of examples about how to use stlTools -femur_binary: is an ascii STL sample used in 'stlDemo'. It is published by Eric Johnson (http://www.mathworks.com/matlabcentral/fileexchange/22409-stl-file-reader). Copyright (c) 2011, Eric Johnson. -sphere_ascii: is a binary STL sample \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlAddVerts.m b/matlab/algorithms/plot_geom/util/stlTools/stlAddVerts.m deleted file mode 100644 index bc4ecbc..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/stlAddVerts.m +++ /dev/null @@ -1,15 +0,0 @@ -function [vnew, fnew] = stlAddVerts(v, f, list) -%STLADDVERTS adds new vertices (and consequently, new faces) to a STL object -%V is the Nx3 array of vertices -%F is the Mx3 array of faces -%LIST is the list of vertices to be added to the object -%VNEW is the new array of vertices -%FNEW is the new array of faces - -% triangulation just with the slice -faces = delaunay(list(:,1),list(:,2)); % calculate new faces -% update object -nvert = length(v); % number of original vertices -v = [v; list]; % update vertices with the ones in the list -f = [f; faces+nvert]; % update faces with the new ones -[vnew,fnew] = stlSlimVerts(v,f); % clear repeated vertices \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlDelVerts.m b/matlab/algorithms/plot_geom/util/stlTools/stlDelVerts.m deleted file mode 100644 index 718ac53..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/stlDelVerts.m +++ /dev/null @@ -1,26 +0,0 @@ -function [vnew, fnew] = stlDelVerts(v, f, list) -%STLDELVERT removes a list of vertices from STL files -%V is the Nx3 array of vertices -%F is the Mx3 array of faces -%LIST are the vertices (rows) to delete, where length(LIST) < N -%VNEW is the new array of vertices -%FNEW is the new array of faces - -% find (on the global set) the position (rows) of the vertices to be deleted -[~,vdel] = ismember(list,v,'rows'); - -% delete vertices and get new tags -vnew = v; -tags = 1:length(v); -vnew(vdel,:) = []; -tags(vdel) = []; - -% delete faces -fnew = f; -[fdel,~] = find(ismember(f,vdel)); % find the position (rows) of the faces to delete -fnew(fdel,:) = []; - -% rename faces, as some of the vertices have been deleted -flist = reshape(fnew,numel(fnew),1); -[~,ind] = ismember(flist,tags); -fnew = reshape(ind,numel(flist)/3,3); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlDemo.m b/matlab/algorithms/plot_geom/util/stlTools/stlDemo.m deleted file mode 100644 index e82d8db..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/stlDemo.m +++ /dev/null @@ -1,39 +0,0 @@ -%% STLDEMO shows how to use the functions included in the toolbox STLTOOLS - -%% EXAMPLE 1.- How to cut a sphere and close the base to get a semisphere - -% load an ascii STL sample file (STLGETFORMAT and STLREADASCII) -[vertices,faces,normals,name] = stlRead('sphere300faces.stl'); -stlPlot(vertices,faces,name); - -% the sphere is centered in the origin -% now we get a list of vertices to be deleted if (x,y,z<0) -minZ = 0; -[rows, ~] = find(vertices(:,3) < minZ); -list = vertices(rows,:); - -% if we delete the list of vertices with z<0, we get an opened semisphere -% (as the base is not closed) -[newv,newf] = stlDelVerts(vertices,faces,list); -stlPlot(newv,newf,name); - -% the next step is to identify a new list with the faces that are opened -% (that means all the sides that belong only to a unique triangle) -list = stlGetVerts(newv,newf,'opened'); - -% finally we generate all the new faces that are needed just to close the -% base of the semisphere -[vsemi,fsemi] = stlAddVerts(newv,newf,list); -stlPlot(vsemi,fsemi,'closed semisphere'); - -%% EXAMPLE 2.- How to get a section of a femur - -[vertices,faces,normals,name] = stlRead('femur_binary.stl'); -stlPlot(vertices,faces,name); - -minX = 1.2; -[rows, ~] = find(vertices(:,1) < minX); -list = vertices(rows,:); - -[newv,newf] = stlDelVerts(vertices,faces,list); -stlPlot(newv,newf,'section of the femur'); diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlGetFormat.m b/matlab/algorithms/plot_geom/util/stlTools/stlGetFormat.m deleted file mode 100644 index 6901b26..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/stlGetFormat.m +++ /dev/null @@ -1,38 +0,0 @@ -function format = stlGetFormat(fileName) -%STLGETFORMAT identifies the format of the STL file and returns 'binary' or -%'ascii' - -fid = fopen(fileName); -% Check the file size first, since binary files MUST have a size of 84+(50*n) -fseek(fid,0,1); % Go to the end of the file -fidSIZE = ftell(fid); % Check the size of the file -if rem(fidSIZE-84,50) > 0 - format = 'ascii'; -else - % Files with a size of 84+(50*n), might be either ascii or binary... - % Read first 80 characters of the file. - % For an ASCII file, the data should begin immediately (give or take a few - % blank lines or spaces) and the first word must be 'solid'. - % For a binary file, the first 80 characters contains the header. - % It is bad practice to begin the header of a binary file with the word - % 'solid', so it can be used to identify whether the file is ASCII or - % binary. - fseek(fid,0,-1); % go to the beginning of the file - header = strtrim(char(fread(fid,80,'uchar')')); % trim leading and trailing spaces - isSolid = strcmp(header(1:min(5,length(header))),'solid'); % take first 5 char - fseek(fid,-80,1); % go to the end of the file minus 80 characters - tail = char(fread(fid,80,'uchar')'); - isEndSolid = findstr(tail,'endsolid'); - - % Double check by reading the last 80 characters of the file. - % For an ASCII file, the data should end (give or take a few - % blank lines or spaces) with 'endsolid '. - % If the last 80 characters contains the word 'endsolid' then this - % confirms that the file is indeed ASCII. - if isSolid & isEndSolid - format = 'ascii'; - else - format = 'binary'; - end -end -fclose(fid); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlGetVerts.m b/matlab/algorithms/plot_geom/util/stlTools/stlGetVerts.m deleted file mode 100644 index 179eff3..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/stlGetVerts.m +++ /dev/null @@ -1,31 +0,0 @@ -function list = stlGetVerts(v, f, mode) -%GETVERTS returns the vertices that are 'opened' or 'closed' depending on -%the 'mode'. An 'open' vertice is the one that defines an open side. An -%open side is the one that only takes part of one triangle -%V is the Nx3 array of vertices -%F is the Mx3 array of faces -%MODE can be 'opened' or 'closed' depending of the kind of vertices to list -%LIST is the list of 'opened' or 'closed' vertices - -sides = sort([[f(:,1) f(:,2)]; ... - [f(:,2) f(:,3)]; ... - [f(:,3) f(:,1)]],2); - -[C,ia,ic] = unique(sides,'rows'); -ind_all = sort(ic); % open and closed sides -ind_rep = find(diff(ind_all) == 0); -ind_cls = ind_all(ind_rep); % closed sides -sides_cls = C(ind_cls,:); -ind_rep = [ind_rep; ind_rep+1]; -ind_opn = ind_all; -ind_opn(ind_rep) = []; % open sides -sides_opn = C(ind_opn,:); - -switch mode, - case'opened', - list = v(unique(sides_opn(:)),:); - case 'closed', - list = v(unique(sides_cls(:)),:); - otherwise, - error('getVerts:InvalidMode','The ''mode'' valid values are ''opened'' or ''closed'''); -end \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlPlot.m b/matlab/algorithms/plot_geom/util/stlTools/stlPlot.m deleted file mode 100644 index e9f17c5..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/stlPlot.m +++ /dev/null @@ -1,23 +0,0 @@ -function stlPlot(v, f, name) -%STLPLOT is an easy way to plot an STL object -%V is the Nx3 array of vertices -%F is the Mx3 array of faces -%NAME is the name of the object, that will be displayed as a title - -figure; -object.vertices = v; -object.faces = f; -patch(object,'FaceColor', [0.8 0.8 1.0], ... - 'EdgeColor', 'none', ... - 'FaceLighting', 'gouraud', ... - 'AmbientStrength', 0.15); - -% Add a camera light, and tone down the specular highlighting -camlight('headlight'); -material('dull'); - -% Fix the axes scaling, and set a nice view angle -axis('image'); -view([-135 35]); -grid on; -title(name); diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlRead.m b/matlab/algorithms/plot_geom/util/stlTools/stlRead.m deleted file mode 100644 index 8803516..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/stlRead.m +++ /dev/null @@ -1,13 +0,0 @@ -function [v, f, n, name] = stlRead(fileName) -%STLREAD reads any STL file not depending on its format -%V are the vertices -%F are the faces -%N are the normals -%NAME is the name of the STL object (NOT the name of the STL file) - -format = stlGetFormat(fileName); -if strcmp(format,'ascii') - [v,f,n,name] = stlReadAscii(fileName); -elseif strcmp(format,'binary') - [v,f,n,name] = stlReadBinary(fileName); -end \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlReadAscii.m b/matlab/algorithms/plot_geom/util/stlTools/stlReadAscii.m deleted file mode 100644 index 4490662..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/stlReadAscii.m +++ /dev/null @@ -1,56 +0,0 @@ -function [v, f, n, name] = stlReadAscii(fileName) -%STLREADASCII reads a STL file written in ASCII format -%V are the vertices -%F are the faces -%N are the normals -%NAME is the name of the STL object (NOT the name of the STL file) - -%====================== -% STL ascii file format -%====================== -% ASCII STL files have the following structure. Technically each facet -% could be any 2D shape, but in practice only triangular facets tend to be -% used. The present code ONLY works for meshes composed of triangular -% facets. -% -% solid object_name -% facet normal x y z -% outer loop -% vertex x y z -% vertex x y z -% vertex x y z -% endloop -% endfacet -% -% -% -% endsolid object_name - -fid = fopen(fileName); -cellcontent = textscan(fid,'%s','delimiter','\n'); % read all the file and put content in cells -content = cellcontent{:}(logical(~strcmp(cellcontent{:},''))); % remove all blank lines -fclose(fid); - -% read the STL name -line1 = char(content(1)); -if (size(line1,2) >= 7) - name = line1(7:end); -else - name = 'Unnamed Object'; -end - -% read the vector normals -normals = char(content(logical(strncmp(content,'facet normal',12)))); -n = str2num(normals(:,13:end)); - -% read the vertex coordinates (vertices) -vertices = char(content(logical(strncmp(content,'vertex',6)))); -v = str2num(vertices(:,7:end)); -nvert = size(vertices,1); % number of vertices -nfaces = sum(strcmp(content,'endfacet')); % number of faces -if (nvert == 3*nfaces) - f = reshape(1:nvert,[3 nfaces])'; % create faces -end - -% slim the file (delete duplicated vertices) -[v,f] = stlSlimVerts(v,f); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlReadBinary.m b/matlab/algorithms/plot_geom/util/stlTools/stlReadBinary.m deleted file mode 100644 index 314455d..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/stlReadBinary.m +++ /dev/null @@ -1,60 +0,0 @@ -function [v, f, n, name] = stlReadBinary(fileName) -%STLREADBINARY reads a STL file written in BINARY format -%V are the vertices -%F are the faces -%N are the normals -%NAME is the name of the STL object (NOT the name of the STL file) - -%======================= -% STL binary file format -%======================= -% Binary STL files have an 84 byte header followed by 50-byte records, each -% describing a single facet of the mesh. Technically each facet could be -% any 2D shape, but that would screw up the 50-byte-per-facet structure, so -% in practice only triangular facets are used. The present code ONLY works -% for meshes composed of triangular facets. -% -% HEADER: -% 80 bytes: Header text -% 4 bytes: (int) The number of facets in the STL mesh -% -% DATA: -% 4 bytes: (float) normal x -% 4 bytes: (float) normal y -% 4 bytes: (float) normal z -% 4 bytes: (float) vertex1 x -% 4 bytes: (float) vertex1 y -% 4 bytes: (float) vertex1 z -% 4 bytes: (float) vertex2 x -% 4 bytes: (float) vertex2 y -% 4 bytes: (float) vertex2 z -% 4 bytes: (float) vertex3 x -% 4 bytes: (float) vertex3 y -% 4 bytes: (float) vertex3 z -% 2 bytes: Padding to make the data for each facet 50-bytes in length -% ...and repeat for next facet... - -fid = fopen(fileName); -header = fread(fid,80,'int8'); % reading header's 80 bytes -name = deblank(native2unicode(header,'ascii')'); -if isempty(name) - name = 'Unnamed Object'; % no object name in binary files! -end -nfaces = fread(fid,1,'int32'); % reading the number of facets in the stl file (next 4 byters) -nvert = 3*nfaces; % number of vertices -% reserve memory for vectors (increase the processing speed) -n = zeros(nfaces,3); -v = zeros(nvert,3); -f = zeros(nfaces,3); -for i = 1 : nfaces % read the data for each facet - tmp = fread(fid,3*4,'float'); % read coordinates - n(i,:) = tmp(1:3); % x,y,z components of the facet's normal vector - v(3*i-2,:) = tmp(4:6); % x,y,z coordinates of vertex 1 - v(3*i-1,:) = tmp(7:9); % x,y,z coordinates of vertex 2 - v(3*i,:) = tmp(10:12); % x,y,z coordinates of vertex 3 - f(i,:) = [3*i-2 3*i-1 3*i]; % face - fread(fid,1,'int16'); % Move to the start of the next facet (2 bytes of padding) -end -fclose(fid); -% slim the file (delete duplicated vertices) -[v,f] = stlSlimVerts(v,f); \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlSlimVerts.m b/matlab/algorithms/plot_geom/util/stlTools/stlSlimVerts.m deleted file mode 100644 index 2781067..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/stlSlimVerts.m +++ /dev/null @@ -1,29 +0,0 @@ -function [vnew, fnew]= stlSlimVerts(v, f) -% PATCHSLIM removes duplicate vertices in surface meshes. -% -% This function finds and removes duplicate vertices. -% -% USAGE: [v, f]=patchslim(v, f) -% -% Where v is the vertex list and f is the face list specifying vertex -% connectivity. -% -% v contains the vertices for all triangles [3*n x 3]. -% f contains the vertex lists defining each triangle face [n x 3]. -% -% This will reduce the size of typical v matrix by about a factor of 6. -% -% For more information see: -% http://www.esmonde-white.com/home/diversions/matlab-program-for-loading-stl-files -% -% Francis Esmonde-White, May 2010 - -if ~exist('v','var') - error('The vertex list (v) must be specified.'); -end -if ~exist('f','var') - error('The vertex connectivity of the triangle faces (f) must be specified.'); -end - -[vnew, indexm, indexn] = unique(v, 'rows'); -fnew = indexn(f); diff --git a/matlab/algorithms/plot_geom/util/stlTools/stlWrite.m b/matlab/algorithms/plot_geom/util/stlTools/stlWrite.m deleted file mode 100644 index 0ce5d46..0000000 --- a/matlab/algorithms/plot_geom/util/stlTools/stlWrite.m +++ /dev/null @@ -1,252 +0,0 @@ -function stlWrite(filename, varargin) -%STLWRITE Write STL file from patch or surface data. -% -% STLWRITE(FILE, FV) writes a stereolithography (STL) file to FILE for a -% triangulated patch defined by FV (a structure with fields 'vertices' -% and 'faces'). -% -% STLWRITE(FILE, FACES, VERTICES) takes faces and vertices separately, -% rather than in an FV struct -% -% STLWRITE(FILE, X, Y, Z) creates an STL file from surface data in X, Y, -% and Z. STLWRITE triangulates this gridded data into a triangulated -% surface using triangulation options specified below. X, Y and Z can be -% two-dimensional arrays with the same size. If X and Y are vectors with -% length equal to SIZE(Z,2) and SIZE(Z,1), respectively, they are passed -% through MESHGRID to create gridded data. If X or Y are scalar values, -% they are used to specify the X and Y spacing between grid points. -% -% STLWRITE(...,'PropertyName',VALUE,'PropertyName',VALUE,...) writes an -% STL file using the following property values: -% -% MODE - File is written using 'binary' (default) or 'ascii'. -% -% TITLE - Header text (max 80 chars) written to the STL file. -% -% TRIANGULATION - When used with gridded data, TRIANGULATION is either: -% 'delaunay' - (default) Delaunay triangulation of X, Y -% 'f' - Forward slash division of grid quads -% 'b' - Back slash division of quadrilaterals -% 'x' - Cross division of quadrilaterals -% Note that 'f', 'b', or 't' triangulations now use an -% inbuilt version of FEX entry 28327, "mesh2tri". -% -% FACECOLOR - Single colour (1-by-3) or one-colour-per-face (N-by-3) -% vector of RGB colours, for face/vertex input. RGB range -% is 5 bits (0:31), stored in VisCAM/SolidView format -% (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL) -% -% Example 1: -% % Write binary STL from face/vertex data -% tmpvol = false(20,20,20); % Empty voxel volume -% tmpvol(8:12,8:12,5:15) = 1; % Turn some voxels on -% fv = isosurface(~tmpvol, 0.5); % Make patch w. faces "out" -% stlwrite('test.stl',fv) % Save to binary .stl -% -% Example 2: -% % Write ascii STL from gridded data -% [X,Y] = deal(1:40); % Create grid reference -% Z = peaks(40); % Create grid height -% stlwrite('test.stl',X,Y,Z,'mode','ascii') -% -% Example 3: -% % Write binary STL with coloured faces -% cVals = fv.vertices(fv.faces(:,1),3); % Colour by Z height. -% cLims = [min(cVals) max(cVals)]; % Transform height values -% nCols = 255; cMap = jet(nCols); % onto an 8-bit colour map -% fColsDbl = interp1(linspace(cLims(1),cLims(2),nCols),cMap,cVals); -% fCols8bit = fColsDbl*255; % Pass cols in 8bit (0-255) RGB triplets -% stlwrite('testCol.stl',fv,'FaceColor',fCols8bit) - -% Original idea adapted from surf2stl by Bill McDonald. Huge speed -% improvements implemented by Oliver Woodford. Non-Delaunay triangulation -% of quadrilateral surface courtesy of Kevin Moerman. FaceColor -% implementation by Grant Lohsen. -% -% Author: Sven Holcombe, 11-24-11 - - -% Check valid filename path -path = fileparts(filename); -if ~isempty(path) && ~exist(path,'dir') - error('Directory "%s" does not exist.',path); -end - -% Get faces, vertices, and user-defined options for writing -[faces, vertices, options] = parseInputs(varargin{:}); -asciiMode = strcmp( options.mode ,'ascii'); - -% Create the facets -facets = single(vertices'); -facets = reshape(facets(:,faces'), 3, 3, []); - -% Compute their normals -V1 = squeeze(facets(:,2,:) - facets(:,1,:)); -V2 = squeeze(facets(:,3,:) - facets(:,1,:)); -normals = V1([2 3 1],:) .* V2([3 1 2],:) - V2([2 3 1],:) .* V1([3 1 2],:); -clear V1 V2 -normals = bsxfun(@times, normals, 1 ./ sqrt(sum(normals .* normals, 1))); -facets = cat(2, reshape(normals, 3, 1, []), facets); -clear normals - -% Open the file for writing -permissions = {'w','wb+'}; -fid = fopen(filename, permissions{asciiMode+1}); -if (fid == -1) - error('stlwrite:cannotWriteFile', 'Unable to write to %s', filename); -end - -% Write the file contents -if asciiMode - % Write HEADER - fprintf(fid,'solid %s\r\n',options.title); - % Write DATA - fprintf(fid,[... - 'facet normal %.7E %.7E %.7E\r\n' ... - 'outer loop\r\n' ... - 'vertex %.7E %.7E %.7E\r\n' ... - 'vertex %.7E %.7E %.7E\r\n' ... - 'vertex %.7E %.7E %.7E\r\n' ... - 'endloop\r\n' ... - 'endfacet\r\n'], facets); - % Write FOOTER - fprintf(fid,'endsolid %s\r\n',options.title); - -else % BINARY - % Write HEADER - fprintf(fid, '%-80s', options.title); % Title - fwrite(fid, size(facets, 3), 'uint32'); % Number of facets - % Write DATA - % Add one uint16(0) to the end of each facet using a typecasting trick - facets = reshape(typecast(facets(:), 'uint16'), 12*2, []); - % Set the last bit to 0 (default) or supplied RGB - facets(end+1,:) = options.facecolor; - fwrite(fid, facets, 'uint16'); -end - -% Close the file -fclose(fid); -%fprintf('Wrote %d facets\n',size(facets, 2)); - - -%% Input handling subfunctions -function [faces, vertices, options] = parseInputs(varargin) -% Determine input type -if isstruct(varargin{1}) % stlwrite('file', FVstruct, ...) - if ~all(isfield(varargin{1},{'vertices','faces'})) - error( 'Variable p must be a faces/vertices structure' ); - end - faces = varargin{1}.faces; - vertices = varargin{1}.vertices; - options = parseOptions(varargin{2:end}); - -elseif isnumeric(varargin{1}) - firstNumInput = cellfun(@isnumeric,varargin); - firstNumInput(find(~firstNumInput,1):end) = 0; % Only consider numerical input PRIOR to the first non-numeric - numericInputCnt = nnz(firstNumInput); - - options = parseOptions(varargin{numericInputCnt+1:end}); - switch numericInputCnt - case 3 % stlwrite('file', X, Y, Z, ...) - % Extract the matrix Z - Z = varargin{3}; - - % Convert scalar XY to vectors - ZsizeXY = fliplr(size(Z)); - for i = 1:2 - if isscalar(varargin{i}) - varargin{i} = (0:ZsizeXY(i)-1) * varargin{i}; - end - end - - % Extract X and Y - if isequal(size(Z), size(varargin{1}), size(varargin{2})) - % X,Y,Z were all provided as matrices - [X,Y] = varargin{1:2}; - elseif numel(varargin{1})==ZsizeXY(1) && numel(varargin{2})==ZsizeXY(2) - % Convert vector XY to meshgrid - [X,Y] = meshgrid(varargin{1}, varargin{2}); - else - error('stlwrite:badinput', 'Unable to resolve X and Y variables'); - end - - % Convert to faces/vertices - if strcmp(options.triangulation,'delaunay') - faces = delaunay(X,Y); - vertices = [X(:) Y(:) Z(:)]; - else - if ~exist('mesh2tri','file') - error('stlwrite:missing', '"mesh2tri" is required to convert X,Y,Z matrices to STL. It can be downloaded from:\n%s\n',... - 'http://www.mathworks.com/matlabcentral/fileexchange/28327') - end - [faces, vertices] = mesh2tri(X, Y, Z, options.triangulation); - end - - case 2 % stlwrite('file', FACES, VERTICES, ...) - faces = varargin{1}; - vertices = varargin{2}; - - otherwise - error('stlwrite:badinput', 'Unable to resolve input types.'); - end -end - -if ~isempty(options.facecolor) % Handle colour preparation - facecolor = uint16(options.facecolor); - %Set the Valid Color bit (bit 15) - c0 = bitshift(ones(size(faces,1),1,'uint16'),15); - %Red color (10:15), Blue color (5:9), Green color (0:4) - c0 = bitor(bitshift(bitand(2^6-1, facecolor(:,1)),10),c0); - c0 = bitor(bitshift(bitand(2^11-1, facecolor(:,2)),5),c0); - c0 = bitor(bitand(2^6-1, facecolor(:,3)),c0); - options.facecolor = c0; -else - options.facecolor = 0; -end - -function options = parseOptions(varargin) -IP = inputParser; -IP.addParamValue('mode', 'binary', @ischar) -IP.addParamValue('title', sprintf('Created by stlwrite.m %s',datestr(now)), @ischar); -IP.addParamValue('triangulation', 'delaunay', @ischar); -IP.addParamValue('facecolor',[], @isnumeric) -IP.addParamValue('facecolour',[], @isnumeric) -IP.parse(varargin{:}); -options = IP.Results; -if ~isempty(options.facecolour) - options.facecolor = options.facecolour; -end - -function [F,V]=mesh2tri(X,Y,Z,tri_type) -% function [F,V]=mesh2tri(X,Y,Z,tri_type) -% -% Available from http://www.mathworks.com/matlabcentral/fileexchange/28327 -% Included here for convenience. Many thanks to Kevin Mattheus Moerman -% kevinmoerman@hotmail.com -% 15/07/2010 -%------------------------------------------------------------------------ - -[J,I]=meshgrid(1:1:size(X,2)-1,1:1:size(X,1)-1); - -switch tri_type - case 'f'%Forward slash - TRI_I=[I(:),I(:)+1,I(:)+1; I(:),I(:),I(:)+1]; - TRI_J=[J(:),J(:)+1,J(:); J(:),J(:)+1,J(:)+1]; - F = sub2ind(size(X),TRI_I,TRI_J); - case 'b'%Back slash - TRI_I=[I(:),I(:)+1,I(:); I(:)+1,I(:)+1,I(:)]; - TRI_J=[J(:)+1,J(:),J(:); J(:)+1,J(:),J(:)+1]; - F = sub2ind(size(X),TRI_I,TRI_J); - case 'x'%Cross - TRI_I=[I(:)+1,I(:); I(:)+1,I(:)+1; I(:),I(:)+1; I(:),I(:)]; - TRI_J=[J(:),J(:); J(:)+1,J(:); J(:)+1,J(:)+1; J(:),J(:)+1]; - IND=((numel(X)+1):numel(X)+prod(size(X)-1))'; - F = sub2ind(size(X),TRI_I,TRI_J); - F(:,3)=repmat(IND,[4,1]); - Fe_I=[I(:),I(:)+1,I(:)+1,I(:)]; Fe_J=[J(:),J(:),J(:)+1,J(:)+1]; - Fe = sub2ind(size(X),Fe_I,Fe_J); - Xe=mean(X(Fe),2); Ye=mean(Y(Fe),2); Ze=mean(Z(Fe),2); - X=[X(:);Xe(:)]; Y=[Y(:);Ye(:)]; Z=[Z(:);Ze(:)]; -end - -V=[X(:),Y(:),Z(:)]; \ No newline at end of file diff --git a/matlab/algorithms/plot_geom/util/translate_3d.m b/matlab/algorithms/plot_geom/util/translate_3d.m deleted file mode 100644 index bd51485..0000000 --- a/matlab/algorithms/plot_geom/util/translate_3d.m +++ /dev/null @@ -1,18 +0,0 @@ -function [ transl_vectors ] = translate_3d( vectors, transl_vec) -%% translate some vectors by a translation vector -% param vectors - the vectors to translate -% param transl_vec - vector geometry translation -% return translated_vec_geom - copy of input geometry with translated -% vectors -% -% date 09.07.2018 -% author Van Nguyen, Tim Elberfeld -% imec VisionLab -% University of Antwerp -% last mod 07.11.2018 -%% - transl_vectors = vectors; % copy input - transl = repmat(transl_vec, size(vectors, 1), 1); - transl_vectors = transl_vectors + transl; -end - diff --git a/matlab/tools/astra_plot_geom.m b/matlab/tools/astra_plot_geom.m index 3a654fd..62eed79 100644 --- a/matlab/tools/astra_plot_geom.m +++ b/matlab/tools/astra_plot_geom.m @@ -64,14 +64,16 @@ function [] = astra_plot_geom(geometry, varargin) % Contact: astra@astra-toolbox.com % Website: http://www.astra-toolbox.com/ %-------------------------------------------------------------------------- - addpath(genpath('../algorithms/plot_geom')); % add plot_geom tools to matlab path + if exist('astra_create_example_cone') ~= 2 + error('Please add astra/algorithms/plot_geom to your path to use this function') + end if is_vol_geom(geometry) - draw_vol_geom(geometry, varargin{:}); + draw.draw_vol_geom(geometry, varargin{:}); elseif is_proj_geom(geometry) - draw_proj_geom(geometry, varargin{:}); + draw.draw_proj_geom(geometry, varargin{:}); elseif ischar(geometry) % assume 'geometry' is a path to a CAD file - draw_cad_phantom(geometry, varargin{:}); + draw.draw_cad_phantom(geometry, varargin{:}); end % ---- helper functions ---- diff --git a/samples/matlab/s024_plot_geometry.m b/samples/matlab/s024_plot_geometry.m index dd57997..6c4c3f0 100644 --- a/samples/matlab/s024_plot_geometry.m +++ b/samples/matlab/s024_plot_geometry.m @@ -13,6 +13,11 @@ %% close all; +if exist('astra_create_example_cone') ~= 2 + error('Please add astra/algorithms/plot_geom to your path to use this function') +end + + % proj_geom = astra_create_example_cone('vec'); % proj_geom = astra_create_example_cone('normal'); proj_geom = astra_create_example_cone('helix'); @@ -20,7 +25,7 @@ proj_geom = astra_create_example_cone('helix'); % proj_geom = astra_create_example_fanflat('vec'); % proj_geom = astra_create_example_fanflat(); % proj_geom = astra_create_example_parallel3d(); -% proj_geom = create_example_cone('deform_vec'); +% proj_geom = astra_create_example_cone('deform_vec'); astra_plot_geom(proj_geom); hold on; -- cgit v1.2.3