Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic EEG localization and labelling using Revopoint 3D #716

Open
wants to merge 130 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
130 commits
Select commit Hold shift + click to select a range
0d656e9
initial commit: enable importing wavefront obj files into brainstorm
chinmaychinara91 Jun 28, 2024
5dccc75
refactoring: add input checks, remove unwanted code
chinmaychinara91 Jul 13, 2024
9d2727a
add 'Color' field to the surfacemat structure templates
chinmaychinara91 Jul 15, 2024
adeefeb
add check for 'Color' field
chinmaychinara91 Jul 15, 2024
214ef0f
Update menu: 'Digitizer' and 'Revopoint' under the bracket 'Digitize'
chinmaychinara91 Jul 15, 2024
0f52de8
Refactor 'panel_digitize' to add conditions for 'Revopoint'
chinmaychinara91 Jul 15, 2024
507ead0
support visualizing per vertex color for imported OBJ mesh in BST
chinmaychinara91 Jul 16, 2024
06fbe04
continued: enable importing wavefront obj files into brainstorm
chinmaychinara91 Jul 16, 2024
e4616d5
External added: Piotr Image and Video Toolbox (https://github.com/pdo…
chinmaychinara91 Jul 16, 2024
0fafac6
deface a 3D mesh
chinmaychinara91 Jul 16, 2024
f5d5f64
Tag imported mesh with color as 'textured'
chinmaychinara91 Jul 17, 2024
864acfd
Handle displaying a 'textured' mesh
chinmaychinara91 Jul 17, 2024
b27bb74
Key 'c' as shortcut for collecting points from Revopoint mesh
chinmaychinara91 Jul 17, 2024
5968b4b
Refactor importing wafefront obj
chinmaychinara91 Jul 17, 2024
7ade88c
handle mesh without texture information
chinmaychinara91 Jul 18, 2024
faefed2
Update comment
chinmaychinara91 Jul 18, 2024
3066842
intial commit: automatic detection and labelling of EEG cap electrodes
chinmaychinara91 Jul 18, 2024
d40c719
custom layout EEG caps
chinmaychinara91 Jul 18, 2024
225fbc6
configure 'Edit Settings' options for Revopoint
chinmaychinara91 Jul 18, 2024
29cc58d
Option to generate 100 random headpoints
chinmaychinara91 Jul 18, 2024
2d0110b
fix typo bugs introduced in 3066842789e93a8f5c33d793fe42d73312d9dd36
chinmaychinara91 Jul 18, 2024
3c190d2
'AddMontage' function modified to handle adding Channel File as montage
chinmaychinara91 Jul 18, 2024
b4899f6
WIP: Handle ANT Waveguard 65 and Acticap 66 EEG caps
chinmaychinara91 Jul 18, 2024
4e66681
updated comment (file description)
chinmaychinara91 Jul 19, 2024
44a4152
updated cap type
chinmaychinara91 Jul 19, 2024
12a11a0
typo in file name
chinmaychinara91 Jul 19, 2024
e2d1f38
Update Color for 'textured' mesh when downsized/downsampled
chinmaychinara91 Jul 22, 2024
6c787d0
Update comments on ways to add montage
chinmaychinara91 Jul 22, 2024
d410eae
Update panel_digitize.m
chinmaychinara91 Jul 22, 2024
1b3e2c8
load the latest (last updated) mesh to work on
chinmaychinara91 Jul 22, 2024
127ae4e
add to 1b3e2c8d041e7e470024c7d245fada46956b98e2
chinmaychinara91 Jul 22, 2024
8e048a5
adding montage from text files only available for Polhemus
chinmaychinara91 Jul 22, 2024
9c1d910
better handling of saving ChannelFile info to DigitizeOptions
chinmaychinara91 Jul 23, 2024
d7fbfcc
removing 'Color' fields from template
chinmaychinara91 Jul 23, 2024
ced72dd
'Color' field added to surface when needed
chinmaychinara91 Jul 23, 2024
c67071c
remove commented code
chinmaychinara91 Jul 23, 2024
b27471d
Handle updating surface color for 'Views' menu option on 3D figure
chinmaychinara91 Jul 24, 2024
26ff5a6
making sure old naming in UI is intact for 'Digitize'
chinmaychinara91 Jul 29, 2024
68bdcca
handle 'Edit Settings' for Revopoint
chinmaychinara91 Aug 1, 2024
6039fe0
mask unwanted menu items for Revopoint
chinmaychinara91 Aug 1, 2024
ee2f978
'DelimitedTextImportOptions' support for R2016b to R2018a
chinmaychinara91 Aug 12, 2024
1ee86ce
code cleanup and reduce ambiguity
chinmaychinara91 Aug 12, 2024
f2876f8
ignore 'rmoutliers' step for < R2018b
chinmaychinara91 Aug 12, 2024
6fa568c
remove default menu size 12 for EEG cap montages
chinmaychinara91 Aug 15, 2024
d753abd
Merge remote-tracking branch 'upstream/master' into bst-revopoint-dig…
chinmaychinara91 Aug 19, 2024
582d42b
support new panel calls in the legacy panel; some code cleanup
chinmaychinara91 Aug 20, 2024
7832488
adding revopoint changes to the new panel (1) and its dependencies
chinmaychinara91 Aug 20, 2024
2bf704e
manual point collection in new panel for revopoint
chinmaychinara91 Aug 20, 2024
7e59ab0
new panel: collecting 100 random head points
chinmaychinara91 Aug 20, 2024
61673ba
legacy panel: reverting adding montage from text files
chinmaychinara91 Aug 21, 2024
13bf06b
legacy panel: refactor montage selection in menu for Revopoint
chinmaychinara91 Aug 21, 2024
b7d79db
new panel: montage menu refactoring for Revopoint
chinmaychinara91 Aug 21, 2024
4a85581
new panel: revopoint automation for detecting and labeling electrodes
chinmaychinara91 Aug 21, 2024
2eeacc7
new panel: refactor 'Edit_Settings' menu to handle Revopoint options
chinmaychinara91 Aug 21, 2024
dc8be91
new panel: allow updating a specific EEG electrode from the coordinat…
chinmaychinara91 Aug 28, 2024
f40578d
new panel: remove unused variable
chinmaychinara91 Aug 28, 2024
d96057b
new panel: handle enable/disable of the 'Auto' and 'Random' buttons
chinmaychinara91 Aug 28, 2024
6e8a2f2
new panel: User warning if 'Auto' button pressed without initializati…
chinmaychinara91 Aug 28, 2024
68b12ac
new panel: use `Digitize.Type` to define the mode used
chinmaychinara91 Aug 28, 2024
cfdd21b
legacy panel: handle 'Auto' and 'Random' visibility; some code cleanup
chinmaychinara91 Aug 28, 2024
55c912c
new and legacy panel: rename `Revopoint` to `3DScanner` for better ge…
chinmaychinara91 Aug 28, 2024
eb24205
Bugfix: support old `Digitize.Options.Montages` struct
rcassani Sep 10, 2024
d87dcea
GUI menu name updated: '3DScaner' to '3D scanner'
rcassani Sep 10, 2024
ba980ec
Bugfix: Two entries in `GlobalData.Surface` were created instead of one
rcassani Sep 10, 2024
a023781
Implement `rmoutliers` without arguments for older Matlab versions
rcassani Sep 10, 2024
71afcef
Ignore unused output arguments
rcassani Sep 10, 2024
1c2c2b0
Refactor to avoid unnecessary reads to db: `bst_get('Subject')`
rcassani Sep 10, 2024
2089adc
Gentle exit if user cancels "Import surfaces..."
rcassani Sep 10, 2024
e2edb99
Clean code. Avoid copy-paste
rcassani Sep 10, 2024
273e08c
Cleaner
rcassani Sep 10, 2024
4754b30
Add `Color` field for all surface files and loaded surfaces
rcassani Sep 11, 2024
50a60c2
Treecallback for Display texture surface
rcassani Sep 11, 2024
c2edfce
Bugfix typo
rcassani Sep 11, 2024
f9cf06e
Avoid copy-paste same method call
rcassani Sep 11, 2024
3d77e53
Parse input in `panel_digitize_2024('Start')`
rcassani Sep 11, 2024
8d6bc3b
Not apparent reason to have a different panel name
rcassani Sep 11, 2024
73328e2
Add progress bar to 'EEGAutoDetectElectrodes'
rcassani Sep 11, 2024
e673cd4
Parse input in `panel_digitize('Start')`
rcassani Sep 11, 2024
28e43c7
Refactor to avoid unnecessary reads to db: `bst_get('Subject')`
rcassani Sep 11, 2024
c857f3e
Not apparent reason to have a different panel name
rcassani Sep 11, 2024
d274a76
Code easier to read
rcassani Sep 11, 2024
128c9b0
Bugfix
rcassani Sep 11, 2024
27b2467
Remove unnecessary FOR loops
rcassani Sep 11, 2024
53f43dd
handle `Digitize` as input to `DigitizerType` parameter
chinmaychinara91 Sep 12, 2024
71956d7
Revert "handle `Digitize` as input to `DigitizerType` parameter"
chinmaychinara91 Sep 12, 2024
494a4e2
Better handling of calls to `Start` function
chinmaychinara91 Sep 12, 2024
213877f
No scaling needed as OBJ vertices are unitless
chinmaychinara91 Sep 13, 2024
371c021
new panel: avoid copy pasting; add comments
chinmaychinara91 Sep 13, 2024
3403c9e
function to compartmentalize automatic detection and labelling
chinmaychinara91 Sep 13, 2024
5bc3bcb
clean code; call compartmentalized function
chinmaychinara91 Sep 13, 2024
1280ad8
legacy panel: avoid copy paste
chinmaychinara91 Sep 15, 2024
4279fd3
bugfix: missed some call checks
chinmaychinara91 Sep 15, 2024
4bc3077
code cleanup; comments added
chinmaychinara91 Sep 16, 2024
0289582
avoid copy/paste for `Edit settings`
chinmaychinara91 Sep 16, 2024
af3c314
add comments; clean code and calls `auto_3dscanner`
chinmaychinara91 Sep 16, 2024
1b34155
changed surface description
chinmaychinara91 Sep 16, 2024
348b4bd
remove comment; `in_tess` handles node naming
chinmaychinara91 Sep 16, 2024
159925d
handle textured surface import and selection
chinmaychinara91 Sep 16, 2024
d5b14fc
do not delete `3D scanner` figure when resetting
chinmaychinara91 Sep 17, 2024
a5ded25
textured surface handling: allow user to choose from options
chinmaychinara91 Sep 17, 2024
1bdee1c
`Digitize (3D scanner)` option on right click pop up for textured sur…
chinmaychinara91 Sep 17, 2024
350d1cd
Better way to get the open surface details
chinmaychinara91 Sep 17, 2024
9ba20a4
make textured surface comments unique; show comments as choice to use…
chinmaychinara91 Sep 18, 2024
22d9916
add comments
chinmaychinara91 Sep 18, 2024
12dc130
collect 100 points without `reducepatch`
chinmaychinara91 Sep 19, 2024
058cb5e
bugfix: display correct label text on deleting-updating landmark coor…
chinmaychinara91 Sep 19, 2024
3b36367
Avoid copy-paste same method call
chinmaychinara91 Sep 19, 2024
70992ee
Fixes 128c9b0
rcassani Sep 19, 2024
bb3b3fc
Clean code
chinmaychinara91 Sep 19, 2024
84bc8b3
for `Start over`, close and reset figure for `3D Scanner`
chinmaychinara91 Sep 19, 2024
5068994
bugfix: Right click on subject > `Import surfaces`
chinmaychinara91 Sep 23, 2024
881de0c
better way to access the current surface file
chinmaychinara91 Sep 23, 2024
b1124bf
import head surface obj with units using fieldtrip's `ft_convert_units`
chinmaychinara91 Sep 23, 2024
b433621
legacy: better way to access the current surface file
chinmaychinara91 Sep 24, 2024
c49ebc6
update the correct caps based on the protocol
chinmaychinara91 Sep 24, 2024
2640241
update landmark initialization points
chinmaychinara91 Sep 24, 2024
a850326
add all other surface property calculations
chinmaychinara91 Sep 24, 2024
4f2d37a
save the surface and update the node
chinmaychinara91 Sep 24, 2024
7127fb3
check spm12 installation for `ft_convert_units`
chinmaychinara91 Sep 24, 2024
85834a6
bugfix
chinmaychinara91 Sep 24, 2024
4b1e9c5
replace `erase` with `strrep` for backward compatibility
chinmaychinara91 Sep 24, 2024
86e8d83
improve obj parsing (see description)
chinmaychinara91 Sep 25, 2024
06df252
similar to `ft_convert_units`
chinmaychinara91 Sep 25, 2024
cedc8af
remove `fieldtrip` dependency
chinmaychinara91 Sep 25, 2024
4025954
typo fix
chinmaychinara91 Sep 25, 2024
a88b339
generalize checking for initialization points
chinmaychinara91 Oct 9, 2024
2e1aae8
adding `Wearable Sensing DS-24` EEG cap layout
chinmaychinara91 Oct 9, 2024
31b1bd7
Merge branch 'master' into bst-revopoint-digitizer
rcassani Oct 24, 2024
64bb082
Update `channel_fixunits` to accept vertices
rcassani Oct 25, 2024
c9ffccb
Simpler creation of struct (`in_tess_wftobj`)
rcassani Oct 25, 2024
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
Binary file added defaults/eeg/Colin27/channel_ANT_Waveguard_65.mat
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added defaults/eeg/ICBM152/channel_ANT_Waveguard_65.mat
Binary file not shown.
Binary file not shown.
Binary file not shown.
26 changes: 26 additions & 0 deletions external/piotr_toolbox/LICENCE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Copyright (c) 2012, Piotr Dollar
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. 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.

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.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the FreeBSD Project.
77 changes: 77 additions & 0 deletions external/piotr_toolbox/tpsGetWarp.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
function [warp,L,LnInv,bendE] = tpsGetWarp( lambda, xsS, ysS, xsD, ysD )
% Given two sets of corresponding points, calculates warp between them.
%
% Uses booksteins PAMI89 method. Can then apply warp to a new set of
% points (tpsInterpolate), or even an image (tpsInterpolateIm).
% "Principal Warps: Thin-Plate Splines and the Decomposition of
% Deformations". Bookstein. PAMI 1989.
%
% USAGE
% [warp,L,LnInv,bendE] = tpsGetWarp( lambda, xsS, ysS, xsD, ysD )
%
% INPUTS
% lambda - rigidity of warp (inf means warp becomes affine)
% xsS, ysS - [1xn] correspondence points from source image
% xsD, ysD - [1xn] correspondence points from destination image
%
% OUTPUTS
% warp - bookstein warping parameters
% L, LnInv - see bookstein
% bendE - bending energy
%
% EXAMPLE - 1
% xsS=[0 -1 0 1]; ysS=[1 0 -1 0]; xsD=xsS; ysD=[3/4 1/4 -5/4 1/4];
% warp = tpsGetWarp( 0, xsS, ysS, xsD, ysD );
% [gxs, gys] = meshgrid(-1.25:.25:1.25,-1.25:.25:1.25);
% tpsInterpolate( warp, gxs, gys, 1 );
%
% EXAMPLE - 2
% xsS = [3.6929 6.5827 6.7756 4.8189 5.6969];
% ysS = [10.3819 8.8386 12.0866 11.2047 10.0748];
% xsD = [3.9724 6.6969 6.5394 5.4016 5.7756];
% ysD = [6.5354 4.1181 7.2362 6.4528 5.1142];
% warp = tpsGetWarp( 0, xsS, ysS, xsD, ysD );
% [gxs, gys] = meshgrid(3.5:.25:7, 8.5:.25: 12.5);
% tpsInterpolate( warp, gxs, gys, 1 );
%
% See also TPSINTERPOLATE, TPSINTERPOLATEIM, TPSRANDOM
%
% Piotr's Computer Vision Matlab Toolbox Version 2.0
% Copyright 2014 Piotr Dollar. [pdollar-at-gmail.com]
% Licensed under the Simplified BSD License [see https://github.com/pdollar/toolbox/blob/master/external/bsd.txt]

dim = size( xsS );
if( all(size(xsS)~=dim) || all(size(ysS)~=dim) || all(size(xsD)~=dim))
error( 'argument sizes do not match' );
end

% get L
n = size(xsS,2);
deltaXs = xsS'*ones(1,n) - ones(n,1) * xsS;
deltaYs = ysS'*ones(1,n) - ones(n,1) * ysS;
Rsq = (deltaXs .* deltaXs + deltaYs .* deltaYs);
Rsq = Rsq+eye(n); K = Rsq .* log( Rsq ); K( isnan(K) )=0;
K = K + lambda * eye( n );
P = [ ones(n,1), xsS', ysS' ];
L = [ K, P; P', zeros(3,3) ];
LInv = L^(-1);
LnInv = LInv(1:n,1:n);

% recover W's
wx = LInv * [xsD 0 0 0]';
affinex = wx(n+1:n+3);
wx = wx(1:n);
wy = LInv * [ysD 0 0 0]';
affiney = wy(n+1:n+3);
wy = wy(1:n);

% record warp
warp.wx = wx; warp.affinex = affinex;
warp.wy = wy; warp.affiney = affiney;
warp.xsS = xsS; warp.ysS = ysS;
warp.xsD = xsD; warp.ysD = ysD;

% get bending energy (without regularization)
w = [wx'; wy'];
K = K - lambda * eye( n );
bendE = trace(w*K*w')/2;
52 changes: 52 additions & 0 deletions external/piotr_toolbox/tpsInterpolate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
function [xsR,ysR] = tpsInterpolate( warp, xs, ys, show )
% Apply warp (obtained by tpsGetWarp) to a set of new points.
%
% USAGE
% [xsR,ysR] = tpsInterpolate( warp, xs, ys, [show] )
%
% INPUTS
% warp - [see tpsGetWarp] bookstein warping parameters
% xs, ys - points to apply warp to
% show - [1] will display results in figure(show)
%
% OUTPUTS
% xsR, ysR - result of warp applied to xs, ys
%
% EXAMPLE
%
% See also TPSGETWARP
%
% Piotr's Computer Vision Matlab Toolbox Version 2.0
% Copyright 2014 Piotr Dollar. [pdollar-at-gmail.com]
% Licensed under the Simplified BSD License [see https://github.com/pdollar/toolbox/blob/master/external/bsd.txt]

if( nargin<4 || isempty(show)); show = 1; end

wx = warp.wx; affinex = warp.affinex;
wy = warp.wy; affiney = warp.affiney;
xsS = warp.xsS; ysS = warp.ysS;
xsD = warp.xsD; ysD = warp.ysD;

% interpolate points (xs,ys)
xsR = f( wx, affinex, xsS, ysS, xs(:)', ys(:)' );
ysR = f( wy, affiney, xsS, ysS, xs(:)', ys(:)' );

% optionally show points (xsR, ysR)
if( show )
figure(show);
subplot(2,1,1); plot( xs, ys, '.', 'color', [0 0 1] );
hold('on'); plot( xsS, ysS, '+' ); hold('off');
subplot(2,1,2); plot( xsR, ysR, '.' );
hold('on'); plot( xsD, ysD, '+' ); hold('off');
end

function zs = f( w, aff, xsS, ysS, xs, ys )
% find f(x,y) for xs and ys given W and original points
n = size(w,1); ns = size(xs,2);
delXs = xs'*ones(1,n) - ones(ns,1)*xsS;
delYs = ys'*ones(1,n) - ones(ns,1)*ysS;
distSq = (delXs .* delXs + delYs .* delYs);
distSq = distSq + eye(size(distSq)) + eps;
U = distSq .* log( distSq ); U( isnan(U) )=0;
zs = aff(1)*ones(ns,1)+aff(2)*xs'+aff(3)*ys';
zs = zs + sum((U.*(ones(ns,1)*w')),2);
64 changes: 64 additions & 0 deletions toolbox/anatomy/tess_deface.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
function [head_surface] = tess_deface(head_surface)
% TESS_DEFACE: Removing non-essential vertices (bottom half of the subject's face in mesh) to deface the 3D mesh
%
% USAGE: [head_surface] = tess_deface(head_surface);
%
% INPUT:
% - head_surface: Brainstorm tesselation structure with fields:
% |- Vertices : {[nVertices x 3] double}, in millimeters
% |- Faces : {[nFaces x 3] double}
% |- Color : {[nColors x 3] double}, normalized between 0-1 (optional)
%
% OUTPUT:
% - head_surface: Brainstorm tesselation structure with fields:
% |- Vertices : {[nVertices x 3] double}, in millimeters
% |- Faces : {[nFaces x 3] double}
% |- Color : {[nColors x 3] double}, normalized between 0-1 (optional)
%
% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Yash Shashank Vakilna, 2024
% Chinmay Chinara, 2024

% Identify vertices to remove from the surface mesh
% Spherical coordinates
[TH,PHI,R] = cart2sph(head_surface.Vertices(:,1), head_surface.Vertices(:,2), head_surface.Vertices(:,3));
% Flat projection
R = 1 - PHI ./ pi*2;
t = (R > 1.1);

% Remove the identified vertices from the surface mesh
remove = (1:length(t));
remove = remove(t);
if ~isempty(remove)
[head_surface.Vertices, head_surface.Faces] = tess_remove_vert(head_surface.Vertices, head_surface.Faces, remove);
if isfield(head_surface, 'Color')
head_surface.Color(remove, :) = [];
end
end

head_surface.VertConn = tess_vertconn(head_surface.Vertices, head_surface.Faces);
head_surface.VertNormals = tess_normals(head_surface.Vertices, head_surface.Faces, head_surface.VertConn);
head_surface.Curvature = tess_curvature(head_surface.Vertices, head_surface.VertConn, head_surface.VertNormals, .1);
[~, head_surface.VertArea] = tess_area(head_surface.Vertices, head_surface.Faces);
head_surface.SulciMap = tess_sulcimap(head_surface);
head_surface.Comment = [head_surface.Comment '_defaced'];
head_surface = bst_history('add', head_surface, 'deface_mesh', 'mesh defaced');

end
38 changes: 24 additions & 14 deletions toolbox/anatomy/tess_downsize.m
Original file line number Diff line number Diff line change
Expand Up @@ -84,21 +84,27 @@

% Ask for resampling method
if isempty(Method)
% Downsize methods strings
methods_str = {['<HTML><B><U>Matlab''s reducepatch:</U></B><BR>' ...
'&nbsp;&nbsp;&nbsp;| - Inhomogeneous mesh: large faces at the top of the gyri<BR>' ...
'&nbsp;&nbsp;&nbsp;| - Keeps the atlases and the subjects co-registration'], ...
['<HTML><B>Matlab''s reducepatch + subdivide large faces:</B><BR>' ...
'&nbsp;&nbsp;&nbsp;| - The large faces at the top of the gyri are subdivided in three<BR>' ...
'&nbsp;&nbsp;&nbsp;| - <U>Deletes</U> the atlases and the subjects co-registration'], ...
['<HTML><B>iso2mesh/CGAL library:</B><BR>' ...
'&nbsp;&nbsp;&nbsp;| - Homogeneous mesh: all the faces have similar sizes<BR>' ...
'&nbsp;&nbsp;&nbsp;| - <U>Deletes</U> the atlases and the subject co-registration<BR>' ...
'&nbsp;&nbsp;&nbsp;| - If the downsample looks dark, right-click > Swap faces']};
% ['<HTML><B>iso2mesh/CGAL + project on the original surface:</B><BR>' ...
% '&nbsp;&nbsp;&nbsp;| - Homogeneous mesh but possible <U>topological problems</U><BR>' ...
% '&nbsp;&nbsp;&nbsp;| - <U>Damages</U> the atlases and the subject co-registration']},

% Show only 'Matlab's reducepatch' method for tess_textured surfaces
if ~isempty(regexp(TessFile, 'tess_textured', 'match'))
methods_str = methods_str(1); % Inhomogeneous mesh
end
% Ask method
ind = java_dialog('radio', 'Select the resampling method:', 'Resample surface', [], ...
{['<HTML><B><U>Matlab''s reducepatch:</U></B><BR>' ...
'&nbsp;&nbsp;&nbsp;| - Inhomogeneous mesh: large faces at the top of the gyri<BR>' ...
'&nbsp;&nbsp;&nbsp;| - Keeps the atlases and the subjects co-registration'], ...
['<HTML><B>Matlab''s reducepatch + subdivide large faces:</B><BR>' ...
'&nbsp;&nbsp;&nbsp;| - The large faces at the top of the gyri are subdivided in three<BR>' ...
'&nbsp;&nbsp;&nbsp;| - <U>Deletes</U> the atlases and the subjects co-registration'], ...
['<HTML><B>iso2mesh/CGAL library:</B><BR>' ...
'&nbsp;&nbsp;&nbsp;| - Homogeneous mesh: all the faces have similar sizes<BR>' ...
'&nbsp;&nbsp;&nbsp;| - <U>Deletes</U> the atlases and the subject co-registration<BR>' ...
'&nbsp;&nbsp;&nbsp;| - If the downsample looks dark, right-click > Swap faces']}, 1);
% ['<HTML><B>iso2mesh/CGAL + project on the original surface:</B><BR>' ...
% '&nbsp;&nbsp;&nbsp;| - Homogeneous mesh but possible <U>topological problems</U><BR>' ...
% '&nbsp;&nbsp;&nbsp;| - <U>Damages</U> the atlases and the subject co-registration']}, 1);
ind = java_dialog('radio', 'Select the resampling method:', 'Resample surface', [], methods_str, 1);
if isempty(ind)
return
end
Expand Down Expand Up @@ -128,6 +134,7 @@
% Prepare variables
TessMat.Faces = double(TessMat.Faces);
TessMat.Vertices = double(TessMat.Vertices);
TessMat.Color = double(TessMat.Color);
dsFactor = newNbVertices / size(TessMat.Vertices, 1);


Expand All @@ -145,6 +152,9 @@
% Re-order the vertices so that they are in the same order in the output surface
[I, iSort] = sort(I);
NewTessMat.Vertices = TessMat.Vertices(I,:);
if ~isempty(TessMat.Color)
NewTessMat.Color = TessMat.Color(I,:);
end
J = J(iSort);
% Re-order the vertices in the faces
iSortFaces(J) = 1:length(J);
Expand Down
7 changes: 5 additions & 2 deletions toolbox/core/bst_get.m
Original file line number Diff line number Diff line change
Expand Up @@ -3474,9 +3474,11 @@
'isSimulate', 0, ...
'Montages', [...
struct('Name', 'No EEG', ...
'Labels', []), ...
'Labels', [], ...
'ChannelFile', []), ...
struct('Name', 'Default', ...
'Labels', [])], ...
'Labels', [], ...
'ChannelFile', [])], ...
'iMontage', 1, ...
'Version', '2024'); % Version of the Digitize panel: 'legacy' or '2024'
argout1 = FillMissingFields(contextName, defPref);
Expand Down Expand Up @@ -3633,6 +3635,7 @@
{'.gii'}, 'GIfTI / World coordinates (*.gii)', 'GII-WORLD'; ...
{'.fif'}, 'MNE (*.fif)', 'FIF'; ...
{'.obj'}, 'MNI OBJ (*.obj)', 'MNIOBJ'; ...
{'.obj'}, 'Wavefront OBJ (*.obj)', 'WFTOBJ'; ...
{'.msh'}, 'SimNIBS3/headreco Gmsh4 (*.msh)', 'SIMNIBS3'; ...
{'.msh'}, 'SimNIBS4/charm Gmsh4 (*.msh)', 'SIMNIBS4'; ...
{'.tri'}, 'TRI (*.tri)', 'TRI'; ...
Expand Down
1 change: 1 addition & 0 deletions toolbox/core/bst_memory.m
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@
sSurf.Comment = surfMat.Comment;
sSurf.Faces = double(surfMat.Faces);
sSurf.Vertices = double(surfMat.Vertices);
sSurf.Color = double(surfMat.Color);
sSurf.VertConn = surfMat.VertConn;
sSurf.VertNormals = surfMat.VertNormals;
[tmp, sSurf.VertArea] = tess_area(surfMat.Vertices, surfMat.Faces);
Expand Down
2 changes: 2 additions & 0 deletions toolbox/db/db_template.m
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
'Comment', '', ...
'Vertices', [], ...
'Faces', [], ...
'Color', [], ...
'VertConn', [], ...
'VertNormals', [], ...
'Curvature', [], ...
Expand Down Expand Up @@ -673,6 +674,7 @@
'Comment', '', ...
'Vertices', [], ...
'Faces', [], ...
'Color', [], ...
'VertConn', [], ...
'VertNormals', [], ...
'VertArea', [], ...
Expand Down
33 changes: 25 additions & 8 deletions toolbox/gui/figure_3d.m
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,7 @@ function FigureMouseWheelCallback(hFig, event, target)

%% ===== KEYBOARD CALLBACK =====
function FigureKeyPressedCallback(hFig, keyEvent)
global GlobalData TimeSliderMutex;
global GlobalData TimeSliderMutex Digitize;
% Prevent multiple executions
hAxes = findobj(hFig, '-depth', 1, 'Tag', 'Axes3D');
set([hFig hAxes], 'BusyAction', 'cancel');
Expand Down Expand Up @@ -1094,7 +1094,19 @@ function FigureKeyPressedCallback(hFig, keyEvent)
case 'a'
if ismember('control', keyEvent.Modifier)
ViewAxis(hFig);
end
end
% C : Collect point
case 'c'
% for 3DScanner
if gui_brainstorm('isTabVisible', 'Digitize') && strcmpi(Digitize.Type, '3DScanner')
% Get Digitize options
DigitizeOptions = bst_get('DigitizeOptions');
panel_fun = @panel_digitize;
if isfield(DigitizeOptions, 'Version') && strcmpi(DigitizeOptions.Version, '2024')
panel_fun = @panel_digitize_2024;
end
panel_fun('ManualCollect_Callback');
end
% CTRL+D : Dock figure
case 'd'
if ismember('control', keyEvent.Modifier)
Expand Down Expand Up @@ -2808,12 +2820,17 @@ function UpdateSurfaceColor(hFig, iTess)
SulciMap = zeros(TessInfo(iTess).nVertices, 1);
end
% Compute RGB values
FaceVertexCdata = BlendAnatomyData(SulciMap, ... % Anatomy: Sulci map
TessInfo(iTess).AnatomyColor([1,end], :), ... % Anatomy: color
DataSurf, ... % Data: values map
TessInfo(iTess).DataLimitValue, ... % Data: limit value
TessInfo(iTess).DataAlpha,... % Data: transparency
sColormap); % Colormap
if ~isempty(regexp(TessInfo(iTess).SurfaceFile, 'tess_textured', 'match'))
FaceVertexCdata = TessInfo(iTess).AnatomyColor(TessInfo(iTess).nVertices+1:end, :);
else
FaceVertexCdata = BlendAnatomyData(SulciMap, ... % Anatomy: Sulci map
TessInfo(iTess).AnatomyColor([1,end], :), ... % Anatomy: color
DataSurf, ... % Data: values map
TessInfo(iTess).DataLimitValue, ... % Data: limit value
TessInfo(iTess).DataAlpha,... % Data: transparency
sColormap); % Colormap
end

% Edge display : on/off
if ~TessInfo(iTess).SurfShowEdges
EdgeColor = 'none';
Expand Down
4 changes: 3 additions & 1 deletion toolbox/gui/gui_brainstorm.m
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@
jMenuFile.addSeparator();
end
% === DIGITIZE ===
gui_component('MenuItem', jMenuFile, [], 'Digitize', IconLoader.ICON_CHANNEL, [], @(h,ev)bst_call(@panel_digitize, 'Start'), fontSize);
jSubMenu = gui_component('Menu', jMenuFile, [], 'Digitize', IconLoader.ICON_CHANNEL,[],[], fontSize);
gui_component('MenuItem', jSubMenu, [], 'Digitizer', IconLoader.ICON_CHANNEL, [], @(h,ev)bst_call(@panel_digitize, 'Start'), fontSize);
gui_component('MenuItem', jSubMenu, [], '3D scanner', IconLoader.ICON_SNAPSHOT, [], @(h,ev)bst_call(@panel_digitize, 'Start', '3DScanner'), fontSize);
gui_component('MenuItem', jMenuFile, [], 'Batch MRI fiducials', IconLoader.ICON_LOBE, [], @(h,ev)bst_call(@bst_batch_fiducials), fontSize);
jMenuFile.addSeparator();
% === QUIT ===
Expand Down
Loading