Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions miss_hit.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ copyright_entity: "Wellcome Trust Centre for Neuroimaging"
tab_width: 2

# metrics limit for the code quality (https://florianschanda.github.io/miss_hit/metrics.html)
metric "cnest": limit 5
metric "cnest": limit 4
metric "file_length": limit 1000
metric "cyc": limit 22
metric "parameters": limit 7
metric "cyc": limit 20
metric "parameters": limit 6
135 changes: 135 additions & 0 deletions src/plotting/createMontage.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
function montage = createMontage(varargin)
%
% USAGE
%
% montage = createMontage(img, ...
% 'columns', 9, ...
% 'rotate', true, ...
% 'cmap', 'gray', ...
% 'visibility', 'on', ...
% 'shape', 'max', ...
% 'cxs', [0 255])
%
%
% Simple function to create a montage /
% mosaic of multiple slices from a single 3D
% image matrix.
%
% INPUT:
% img - 3D (x,y,z) image matrix
% columns - number of columns in montage
% (rows are calculated accordingly)
% rotate - rotate images 90 deg clockwise? yes = 1; no = 0.
% cmap - figure colormap
% visibility - show figure?
%
% OUTPUT:
% output - structure with montage data

% (C) Copyright 2022 bidspm developers

% TODO: Needs improvement i.t.o RAS/LAS orientation specification
% and image layout...

args = inputParser;

addRequired(args, 'img');
addParameter(args, 'columns', 9, @isnumeric);
addParameter(args, 'rotate', true, @islogical);
addParameter(args, 'cmap', 'gray', @ischar);
addParameter(args, 'visibility', 'on', @ischar);
addParameter(args, 'shape', 'max', @ischar); % max or square
addParameter(args, 'cxs', 'auto');

parse(args, varargin{:});

img = args.Results.img;
columns = args.Results.columns;
rotate = args.Results.rotate;
cmap = args.Results.cmap;
visibility = args.Results.visibility;
shape = args.Results.shape;
cxs = args.Results.cxs;

montage = struct;
[Ni, Nj, Nk] = size(img);

% Rotate image slices if required
if rotate
img_orig = img;
clear img;
for p = 1:Nk
img(:, :, p) = rot90(img_orig(:, :, p));
end
end

% Determine amount of rows and filler slices
rows = floor(Nk / columns);
if rows == 0
rows = 1;
end
fill = mod(Nk, columns);
if fill == 0
N_fill = 0;
else
N_fill = columns - mod(Nk, columns);
end
if rotate
filler = zeros(Nj, Ni);
else
filler = zeros(Ni, Nj);
end

montage.rows = rows;
montage.columns = columns;
montage.N_fill = N_fill;

parts = {};
% 1 - Concatenate slices together horizontally, per row (except last).
% 2 - Concatenate rows together vertically
for i = 1:rows
for j = 1:columns
if j == 1
parts{i} = img(:, :, columns * (i - 1) + j);
else
parts{i} = cat(2, parts{i}, img(:, :, columns * (i - 1) + j));
end
end
if i == 1
whole = parts{i};
else
whole = cat(1, whole, parts{i});
end
end

% 1 - Concatenate filler slices to last row, if required.
% 2 - Concatenate last row to whole matrix, if required.
if N_fill ~= 0
% last row
last_parts = img(:, :, rows * columns + 1);
for k = (rows * columns + 2):Nk
last_parts = cat(2, last_parts, img(:, :, k));
end
for m = 1:N_fill
last_parts = cat(2, last_parts, filler);
end
montage.whole_img = cat(1, whole, last_parts);
else
montage.whole_img = whole;
end

f = initMontageFigure(shape, visibility);

ax = subplot(1, 1, 1);
im = imagesc(ax, montage.whole_img);

colormap(cmap);
if ~isempty(cxs)
caxis(ax, cxs);
end

montage.im = im;
montage.f = f;
montage.ax = ax;

end
133 changes: 133 additions & 0 deletions src/plotting/createOverlayMontage.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
function output = createOverlayMontage(varargin)

% (C) Copyright 2024 bidspm developers

% fmrwhy_util_createOverlayMontage(tsnr_img{i}, overlayImg, 9, 1, '', ...
% 'hot', 'off', 'max', [0 250], [33, 168, 10], tsnr_saveAss{i});

% Function to create montages of images/rois overlaid on a template image

rgbcolors = [255, 255, 191; ...
215, 25, 28; ...
253, 174, 97; ...
171, 217, 233; ...
44, 123, 182];

args = inputParser;

addRequired(args, 'templateImg');
addRequired(args, 'overlayImg');
addParameter(args, 'columns', 9, @isnumeric);
addParameter(args, 'rotate', true, @islogical);
addParameter(args, 'cmap', 'gray', @ischar);
addParameter(args, 'visibility', 'on', @ischar);
addParameter(args, 'shape', 'max', @ischar); % max or square
addParameter(args, 'cxs', 'auto');
addParameter(args, 'rgbcolors', rgbcolors);
addParameter(args, 'saveAs', '');

parse(args, varargin{:});

templateImg = args.Results.templateImg;
overlayImg = args.Results.overlayImg;
columns = args.Results.columns;
rotate = args.Results.rotate;
cmap = args.Results.cmap;
visibility = args.Results.visibility;
shape = args.Results.shape;
cxs = args.Results.cxs;
rgbcolors = args.Results.rgbcolors;
saveAs = args.Results.saveAs;

% Structure to save output
output = struct;
alpha = 0.2;
plot_contour = 1;
rgbcolors = rgbcolors / 255;

% Create background montage
montage_template = createMontage(templateImg, ...
'columns', columns, ...
'rotate', rotate, ...
'cmap', cmap, ...
'visibility', 'off', ...
'shape', shape, ...
'cxs', cxs);

% Create figures with background montage and overlaid masks
f = initMontageFigure(shape, visibility);
imagesc(montage_template.whole_img);
colormap(cmap);
if ~isempty(cxs)
caxis(cxs);
end
ax = gca;
outerpos = ax.OuterPosition;
ti = ax.TightInset;
left = outerpos(1) + ti(1);
bottom = outerpos(2) + ti(2);
ax_width = outerpos(3) - ti(1) - ti(3);
ax_height = outerpos(4) - ti(2) - ti(4);
ax.Position = [left bottom ax_width ax_height];
hold(ax, 'on');
[Nimx, Nimy] = size(montage_template.whole_img);
oo = ones(Nimx, Nimy);

if iscell(overlayImg)
for i = 1:numel(overlayImg)
montage_overlay{i} = createMontage(overlayImg{i}, ...
'columns', columns, ...
'rotate', rotate, ...
'cmap', cmap, ...
'visibility', 'off', ...
'shape', shape, ...
'cxs', 'auto');
end
else
montage_overlay = {};
montage_overlay{1} = createMontage(overlayImg, ...
'columns', columns, ...
'rotate', rotate, ...
'cmap', cmap, ...
'visibility', 'off', ...
'shape', shape, ...
'cxs', 'auto');
end

for i = 1:numel(montage_overlay)
rbgclr = rgbcolors(i, :);
clr = cat(3, rbgclr(1) * oo, rbgclr(2) * oo, rbgclr(3) * oo);
imC = imagesc(ax, clr);
set(imC, 'AlphaData', alpha * montage_overlay{i}.whole_img);
if plot_contour
bound_whole_bin = bwboundaries(montage_overlay{i}.whole_img);
Nblobs_bin = numel(bound_whole_bin);
for b = 1:Nblobs_bin
p = plot(ax, bound_whole_bin{b, 1}(:, 2), bound_whole_bin{b, 1}(:, 1), ...
'color', rbgclr, 'LineWidth', 1);
end
end
end

hold(ax, 'off');
set(ax, 'xtick', []);
set(ax, 'xticklabel', []);
set(ax, 'ytick', []);
set(ax, 'yticklabel', []);
set(ax, 'ztick', []);
set(ax, 'zticklabel', []);

output.ax = ax;
output.f = f;

if saveAs ~= 0
print(f, saveAs, '-dpng', '-r0');
end
% Close necessary figure handles
close(montage_template.f);
for i = 1:numel(montage_overlay)
close(montage_overlay{i}.f);
end
if strcmp(visibility, 'off')
close(f);
end
24 changes: 24 additions & 0 deletions src/plotting/initMontageFigure.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
function f = initMontageFigure(shape, visibility)
% (C) Copyright 2024 bidspm developers

scr_size = get(0, 'ScreenSize');
dist = scr_size(4);
if scr_size(3) < dist
dist = scr_size(3);
end
% Create figure - outerposition = [left bottom width height]

if strcmp(shape, 'max')
f = figure('visible', visibility, ...
'units', 'normalized', ...
'outerposition', [0 0 1 1]);
elseif strcmp(shape, 'square')
f = figure('visible', visibility, ...
'units', 'pixels', ...
'outerposition', [0 0 dist dist]);
else
f = figure('visible', visibility, ...
'units', 'pixels', ...
'outerposition', [0 0 dist dist]);
end
end
24 changes: 24 additions & 0 deletions untitled.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
% (C) Copyright 2022 bidspm developers
close all;

bidspm_dir = '/home/remi/github/cpp-lln-lab/bidspm';

demos_dir = fullfile(bidspm_dir, 'demos/MoAE/outputs/derivatives/');

overlay_img = fullfile(demos_dir, ...
'bidspm-stats/sub-01/task-auditory_space-MNI152NLin6Asym_FWHM-8/mask.nii');

template_img = fullfile( ...
demos_dir, ...
'bidspm-preproc', 'sub-01', 'func', ...
'sub-01_task-auditory_space-MNI152NLin6Asym_desc-smth8_bold.nii');

template_hdr = spm_vol(template_img);
template = spm_read_vols(template_hdr(1));

mask_hdr = spm_vol(overlay_img);
mask = spm_read_vols(mask_hdr);

% createMontage(template, 'shape', 'square');
createOverlayMontage(template, mask, 'rgbcolors', [255, 0, 0], ...
'shape', 'square');