Repository navigation
Expand file tree
/
Copy pathimstack.m
More file actions
543 lines (436 loc) · 16.8 KB
/
Copy pathimstack.m
File metadata and controls
543 lines (436 loc) · 16.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
function hmf = imstack(IMGS, ud, MASK)
%im_stack_viewer Displays an image stack in a imtool-like window
% Allows for two-finger scroll to scrub through the images
% Right click to bring up image info and controls
% Requirements:
% ---- IMGS and MASK must be 3D or 4D matrices
% ---- Requires imopener, addRoiToolbar, orthoSlices, subtightplot
% USAGE
% imstack - brings up dialog for opening an image stack
% imstack(3D or 4D image_stack) - opens image stack. In a 4D image stack, the 3rd dimension
% holds channel intensity, and the 4th dimension is the section info
% imstack(image_stack, ud) - a ud structure must contain specific info
% about the image_stack (see init_ud)
% imstack(image_stack,ud,mask) - mask must match the same dimenions as
% image_stack
%INTERNAL INFO
% appdata:
% ---- DS - dataset created when using the count tool
% ---- IMGS - image stack
% ---- MASK - MASK stack, same size as IMGS
% ---- tool_handles - handle structure containing info for tools: count, threshold, group
% UserData:
% ---- UserData for the main figure is a structure that contains info for
% the image stack and mask.
% ---- Userdata for the children of the main figure may sometimes contain the
% handle to the main figure
% Script Folder:
% - Contains a thresh and count folder that contains scripts used by the threshold and count tools
% - Scripts can be added to customize thresholding or pixel counting
% for a given project
% - Scripts added to the these folders will automatically be detected
% by the respective tool
% TODO: add 3 simultaneous orthagonal views for scrolling
% TODO: show isosurface
% TODO: UPDATE ADDROITOOLS (buggy)
% TODO: Update Bioformats Load - eliminate subfunctions?
% TODO: Change script when loading dataset
% TODO: Reimplement DICOM Reader
% TODO: Window Clean up on close
% Written by Ernesto Salcedo, PhD
% Senior Instructor, University of Colorado School of Medicine
% 2016
% Questions: Ernesto Salcedo @ ucdenver dot edu
%% -------- CREATE FIGURE / TOOL HANDLES -----------------------------------------------
hmf = figure(...
'Tag','imstack_fig',...
'Colormap', bone(255),...
'NumberTitle', 'off',...
'DeleteFcn',@delete_imstack,...
'WindowScrollWheelFcn',@scroll_process,...
'WindowKeyPressFcn', @key_press);
axes;
toolbar_cleanup(hmf);
% Add toolbar items
addRoiToolbar(hmf);
imstack_contents = what('imstack'); % find all MATLAB related files in imstack
% Check to make sure bioformats is up to date
% bfUpgradeCheck(true)
%% -------- CREATE MENUS -----------------------------------------------
%% FILE MENU
% Setup File menu: http://undocumentedmatlab.com/blog/customizing-standard-figure-toolbar-menubar/
hMenuFile = findall(gcf,'tag','figMenuFile');
delete(allchild(hMenuFile)); % clear all built-in menu items
% import_formats = {'bioformats', 'tiff stack', 'dicom stack', 'dicom virtual', 'image folder','workspace variable'};
import_formats = {'tiff stack', 'image folder','workspace variable', 'using custom script'};
if exist('bfmatlab','dir')
import_formats = [{'bioformats'} import_formats];
else
display ('bioformats toolbox not detected. Make certain bfmatlab is added to to the path')
end
for m = 1:numel(import_formats)
uimenu('Label',sprintf('Open %s', import_formats{m}),...
'Parent',hMenuFile,...
'UserData',import_formats{m},...
'Tag', 'ims_menu_open',...
'Callback',@open_menu_callback);
end
uimenu(hMenuFile, 'Label','Revert Image Stack',...
'Tag','revert_image',...
'Separator','on',...
'UserData',hmf,...
'Accelerator','R',...
'Callback', @menu_revert_STACK)
uimenu(hMenuFile, 'Label','Revert Mask Stack',...
'Tag','revert_mask',...
'Separator','off',...
'UserData',hmf,...
'Callback', @menu_revert_STACK)
uimenu(hMenuFile,'Label','Load dataset',...
'Separator','on',...
'UserData',hmf,...
'Accelerator','l',...
'Callback', @menu_load_save_dataset_callback );
uimenu(hMenuFile,'Label','Save Dataset',...
'Accelerator','s',...
'UserData',hmf,'Callback', @menu_load_save_dataset_callback )
uimenu(hMenuFile,'Label','Save Dataset as...',...
'UserData',hmf,'Callback', @menu_load_save_dataset_callback )
uimenu(hMenuFile,'Label','Export Dataset as...',...
'UserData',hmf,'Callback', @menu_load_save_dataset_callback )
uimenu(hMenuFile,'Label','ADD Dataset to WORKSPACE',...
'UserData',hmf,'Callback', @menu_load_save_dataset_callback )
uimenu(hMenuFile,'Label', 'Add stack (and mask) to workspace', ...
'Separator','on',...
'Tag', 'fm_stack2workspace',...
'Enable', 'off',...
'Callback', @assign2workspace)
uimenu(hMenuFile,'Label', 'Add file paths to workspace', ...
'Separator','off',...
'Tag', 'fm_paths2workspace',...
'Enable', 'off',...
'Callback', @assign2workspace)
uimenu(hMenuFile,'Label', 'Add current image slice to workspace', ...
'Tag','fm_slice2workspace',...
'Callback', @assign2workspace);
uimenu(hMenuFile,'Label', 'Add imstack user data to workspace', ...
'Tag','fm_ud2workspace',...
'Callback', @assign2workspace);
uimenu(hMenuFile,'Label', 'Save MASK',...
'Separator','off',...
'Callback', @save_mask)
%% EDIT MENU
hMenuEdit = findall(gcf,'tag','figMenuEdit');
delete(allchild(hMenuEdit)); % clear all built-in menu items
uimenu(hMenuEdit,'Label', 'Crop Stack', 'Callback', @menu_crop_callback);
uimenu(hMenuEdit,'Label', 'Trim Stack', 'Callback', @menu_trim_stack_callback);
uimenu(hMenuEdit,'Label', 'Clear mask',...
'Separator','on',...
'Tag','hMenuEditMaskClear',...
'Callback', @clear_MASK);
% uimenu(hMenuEdit,'Label', 'Color Map tool', ...
% 'Separator','on',...
% 'Callback', 'imcolormaptool');
%% REMOVE INSERT MENU
delete(findall(gcf,'tag','figMenuInsert'));
%% TOOL MENU
hMenuTools = findall(gcf,'tag','figMenuTools');
delete(allchild(hMenuTools)); % clear all built-in menu items
% initialize tool handles
ht = [];
% load function handles of scripts
% REQUIRES files in DEFAULT script folder to be name 'count_default', 'thresh_default', etc.
% cd(fullfile(imstack_contents.path,'scripts','DEFAULT'))
% cd(fullfile(imstack_contents.path,'scripts'))
load(fullfile(imstack_contents.path,'scripts','last_selected.mat'))
ht.tool_path = fullfile(imstack_contents.path,'scripts',script_folder);
ht.tool_names = {'count', 'thresh', 'segment','stats'};
ht = get_tool_scripts(ht);
setappdata(hmf,'tool_handles', ht);
% Find Folder Names in Scripts folder (ignore invisible folders)
scriptsf_content = dir(fullfile(imstack_contents.path,'scripts'));
scriptsf_content(~[scriptsf_content.isdir]) = [];
scriptsf_content(~cellfun(@isempty,regexp({scriptsf_content.name},'^\.')))=[];
folder_names = {scriptsf_content.name}';
uimenu(hMenuTools, 'Label','Threshold...', ...
'Separator', 'off',...
'Accelerator','T',...
'UserData', hmf,...
'Callback', @ims_threshold_tool);
uimenu(hMenuTools, 'Label','Segmentation Tool...', ...
'Separator', 'off',...
'Accelerator','G',...
'UserData', hmf,...
'Callback', @ims_segmentation_tool);
uimenu(hMenuTools, 'Label','Count Tool...', ...
'Separator', 'off',...
'Accelerator','Y',...
'UserData', hmf,...
'Callback', @ims_count_tool);
uimenu(hMenuTools, 'Label','Filter Image Stack...', ...
'Tag', 'filter_image',...
'Separator', 'on',...
'Accelerator','F',...
'UserData', hmf,...
'Callback', @ims_filter_tool);
uimenu(hMenuTools, 'Label','Filter Mask Stack...', ...
'Tag', 'filter_mask',...
'Separator', 'off',...
'UserData', hmf,...
'Callback', @ims_filter_tool);
uimenu(hMenuTools, 'Label','Dataset Stats...', ...
'Separator', 'on',...
'UserData', hmf,...
'Callback', @ims_stats_tool);
% Create Set Scripts submenu
hMenuToolSet = uimenu(hMenuTools, 'Label','Set Tools Scripts', ...
'Separator', 'on');
for fn = 1:numel(folder_names)
hm = uimenu(hMenuToolSet, 'Label',folder_names{fn}, ...
'Separator', 'off',...
'Callback', @menu_tool_set_scripts);
if strcmp(folder_names{fn}, script_folder)
hm.Checked = 'on';
end
end
uimenu(hMenuTools,'Label','cd to scripts folder',...
'Separator','off',...
'Callback', @(varargin) cd(fullfile(imstack_contents.path,'scripts')));
%% VIEW MENU
hViewMenu = findall(gcf,'tag','figMenuView');
uimenu(hViewMenu, 'Label', 'Show Montage',...
'Separator', 'on',...
'Tag', 'vm_montage',...
'Callback', @call_montage);
uimenu(hViewMenu, 'Label', 'Show Max Projection',...
'Tag', 'max_projection',...
'Callback', @show_projection);
% uimenu(hViewMenu, 'Label', 'Projection - Split Channels',...
% 'Tag', 'vm_projection',...
% 'Callback', @show_projection);
uimenu(hViewMenu, 'Label', 'Isosurface - Mask',...
'Separator', 'on',...
'Tag', 'show_iso',...
'Callback', @show_isosurface);
%% HELP MENU
hMenuHelp = findall(gcf,'tag','figMenuHelp');
url = 'https://dl.dropboxusercontent.com/u/10600990/site/MATLAB%20functions/html/imstack_doc.html';
uimenu(hMenuHelp, 'Label','IMSTACK User Guide', ...
'Separator', 'on',...
'Callback', @(varargin) web(url,'-browser'))
% -------- END MENUS -----------------------------------------------
%% PARSE INPUTS
% if no arguments passed in, go find an image stack and display
if nargin == 0
[Selection,ok] = listdlg('ListString',import_formats,...
'PromptString', 'SELECT SOURCE',...
'SelectionMOde', 'single',...
'Name','Open Image Stack');
if ok
ok = load_IMGS(hmf, import_formats{Selection});
end
if ~ok
display('load canceled')
close(hmf)
close(findall(0,'tag','bformat_load'))
return
end
else % if arguments passed in
% If no structure passed in, get name of variable
if nargin == 1 || isempty(ud)
% handles 4D stacks that only have one channel
sz = size(IMGS);
if ndims(IMGS)>3 && sz(3) == 1
IMGS = squeeze(IMGS);
end
% get name of input variable
if ~isempty(inputname(1))
ud.StudyDescription = inputname(1);
ud.SeriesDescription = '';
else
ud.StudyDescription = 'IMGS';
ud.SeriesDescription = '';
end
end
setappdata(hmf,'IMGS', IMGS); %attach image stack to figure and display
ud = init_ud(ud, hmf, size(IMGS),false); % also clears mask app data
% if MASK passed in, attach to figure
if nargin == 3
setappdata(ud.hmf,'MASK', MASK)
end
% initialize settings
init_im_display(ud); % menu items, context menu
end
% handles = guihandles(hmf);
% guidata(hmf,handles)
end
% -------- END imstack MAIN FUNCTION-------------------------------------------
%% Subfunctions------------------------------------------------------------
%% ------------------------------------------------------------------------
function open_menu_callback(obj,~)
% callback for menu items that start with 'Open' in the File menu
menu_items = findall(get(obj,'Parent'),'Tag','ims_menu_open');
set(menu_items,'Accelerator','')
set(obj,'Accelerator','o')
load_IMGS(imgcf, get(obj,'UserData'))
end
%% ---- LOAD STACK ----------------------------------------------------------
function ok = load_IMGS(hmf, selection)
% find an image stack to load
% uses imopener - keep at this level
ok = true;
IMGS = [];
try
switch selection
case 'bioformats'
bioformats_load(hmf);
return
case 'tiff stack'
[IMGS, ud] = read_tiff_stack;
case 'image folder'
[IMGS, ud] = read_image_folder;
case 'dicom stack'
[ DCM_FULL_PATHS ] = dicom_get_paths;
[IMGS, ud] = dicom_read_engine(DCM_FULL_PATHS);
case 'dicom virtual'
[ DCM_FULL_PATHS ] = dicom_get_paths;
if isappdata(hmf, 'IMGS')
rmappdata(hmf, 'IMGS');
end
[~,ud] = imopener(DCM_FULL_PATHS{1});
setappdata(hmf,'PATHS', DCM_FULL_PATHS); % attach image stack to figure
ud = init_ud(ud, hmf, numel(DCM_FULL_PATHS), true);
case 'workspace variable'
% load workspace variable - allow for structure load
% warning allows for more than two variable selections
ws_vars = evalin('base','whos'); % retrieve varibles from workspace
names = {ws_vars.name};
[Selection,ok] = listdlg('ListString', names, ...
'SelectionMode', 'multiple',...
'Name', 'Workspace',...
'PromptString', {'Select variable'});
ws_vars = ws_vars(Selection); % reduces to only selected variables
if numel(ws_vars) > 1 % more than one variable selected
Selection = ~strcmp({ws_vars.class},'struct'); % change to logical array pointing to numeric array
ud = evalin('base',ws_vars(~Selection).name); % not selection = structure
else
ud.StudyDescription = ws_vars(Selection).name;
ud.SeriesDescription = '';
end
IMGS=evalin('base',ws_vars(Selection).name);
case 'using custom script'
[IMGS,ud] = read_script(hmf);
end
if ~isempty(IMGS) % successful open
setappdata(hmf,'IMGS', IMGS); % attach image stack to figure
ud = init_ud (ud, hmf, size(IMGS), false);
% ud = generate_adj_in(ud);
end
init_im_display(ud);
catch ME
beep
ok = false;
fprintf('\nError Loading image stack: %s\n',ME.message)
display(ME.stack)
assignin('base','ME',ME)
return
end
end
%% ------------------------------------------------------------------------
function call_montage(~,~)
% Needs to handle more than three channels
ud = get(imgcf,'UserData');
hfmontage = figure('Name',sprintf('MONTAGE: %s',ud.StudyDescription),'NumberTitle','off');
toolbar_cleanup(hfmontage);
IMGS = getappdata(ud.hmf,'IMGS');
if ud.ChannelCount < 3
IMGS(:,:,3,:) = zeros(ud.StackSize(1), ud.StackSize(2),1,ud.StackSize(4));
end
montage(IMGS)
impixelinfo
end
%% ------------------------------------------------------------------------
function delete_imstack(~,~)
% figure deletefcn
ud = get(gcbo,'UserData');
if isempty(ud)
return
end
ht = getappdata(gcbo,'tool_handles');
if isfield(ht,'tool_h')
tags = fieldnames(ht.tool_h);
% check for tool windows (thresh, count, etc) and delete
for n=1:numel(tags)
if ishandle(ht.tool_h.(tags{n}))
delete(ht.tool_h.(tags{n}))
end
end
end
if isappdata(ud.hmf,'DS')
save_data(ud.hmf,ht,'Save Dataset')
end
end
%% ------------------------------------------------------------------------
function menu_revert_STACK(obj,~)
% reverts stack to save original version (name preceded by a 'o')
% that was generated after using the filter tool
switch get(obj,'Tag')
case 'revert_image'
stack_name = 'IMGS';
case 'revert_mask'
stack_name = 'MASK';
end
hmf = get(obj,'UserData');
if isappdata(hmf,['o' stack_name])
setappdata(hmf,stack_name, getappdata(hmf,['o' stack_name]));
else
fprintf('original %s stack not found',stack_name);
% display('original stack not found')
end
end
%% ------------------------------------------------------------------------
function menu_load_save_dataset_callback(obj,~)
hmf = get(obj,'UserData');
ht = getappdata(hmf,'tool_handles');
label = get(obj,'Label');
switch label
case 'Load dataset'
% Load
data_path = get_datapath(hmf,ht,label);
if isempty(data_path)
display ('load canceled')
return
end
load(data_path); % should load a table variable named DS
if istable(DS)
setappdata(hmf,'DS', DS);
if isfield(ht,'tool_h')
structfun(@close,ht.tool_h); % close all tool windows
end
tool_path = ht.tool_path; % tool_path set at imstack start
ht = DS.Properties.UserData; % replace with ht saved data
ht.tool_path = tool_path;
ht.data_path = data_path;
ht.count.selected_row = size(DS,1); % set selection to end
set_dataset_table(ht, DS);
group_table_settings(ht)
ht = get_tool_scripts( ht);
display('Dataset loaded');
else
display('wrong *.mat file. File must return a table variable')
end
case {'Save Dataset','Save Dataset as...'}
ht = save_data(hmf,ht,label);
case 'Export Dataset as...'
DS = getappdata(hmf,'DS');
[filename,pathname] = uiputfile(fullfile(pwd,'*.csv'));
writetable(DS,fullfile(pathname,filename));
case 'Add Dataset to workspace'
DS = getappdata(hmf,'DS');
assignin('base', 'DS', DS);
otherwise
display('Sorry, I got nothing')
return
end
setappdata(hmf,'tool_handles',ht);
end