-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgeneric_segmentation_gui.m
More file actions
689 lines (555 loc) · 26.9 KB
/
generic_segmentation_gui.m
File metadata and controls
689 lines (555 loc) · 26.9 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
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
function generic_segmentation_gui
% ***********************************************************************
% Description : A MATLAB based Graphical User Interface to load medical
% images, stored as mat files, to annotate labels
% UNIVERSITY OF ARIZONA
%
% Author : LU
% Date : 2021
%
% Creates a GUI window to load a mat file containing 3D image data in a
% variable called img (HxWxD). Uses information from config file to determine the
% number of ROIs that need to be annotated and their colors. Saves a
% variable called masks (HxWxDxC) where the channel dimension consists of
% masks that were annotated for each label.
% ***********************************************************************
clear; clc;
% ***********************************************************************
% Configuration variables for customizing annotation interface
cfg = readstruct('config.json');
% ***********************************************************************
% Check for compatibility. Works only if MATLAB 2017 and above
if(verLessThan('matlab','9.3'))
error('Matlab version needs to be 2017b or higher');
% return;
end
% Variables with global scope
global gui_elements gui_params gui_data
% Initialize structs for GUI
gui_params = {};
gui_elements = {};
gui_data = {};
gui_params.cfg = cfg;
% Create a figure container for the GUI
% Get current monitor screen size to display the main fig window
Current_scr_size = get(0,'ScreenSize');
% % Positioning the window
mf_frmLft = Current_scr_size(1);
mf_frmBtm = Current_scr_size(2);
mf_wt = Current_scr_size(3);
mf_ht = Current_scr_size(4);
gui_elements.main_fig = figure('Visible','off','Position',[mf_frmLft,mf_frmBtm,mf_wt,mf_ht]);
% Assign a name to appear in the window title.
gui_elements.main_fig.Name = cfg.gui_name;
% ***********************************************************************
% Create a panel to display the main push-button to load input file
% ***********************************************************************
disp_str = 'Select input';
h_panel_select_ip= uipanel('FontSize',14,'Position',[0.82,0.85,0.15,0.1]);
uicontrol('Parent',h_panel_select_ip,'Style','pushbutton',...
'Units','normalized','Position',[0.2 0.6 0.6 0.3],'FontSize',12,...
'String',disp_str,...
'FontWeight','bold','Callback',{@select_ip_Callback,cfg});
% Move the window to the center of the screen.
movegui(gui_elements.main_fig,'center')
% Make the UI visible.
gui_elements.main_fig.Visible = 'on';
% ***********************************************************************
% Create a panel to display the axial image : Main figure
% ***********************************************************************
gui_elements.h_panel_axialImage= uipanel('Title','Display Panel','FontSize',12,...
'Position',[0.2,0.05,0.6,0.9],'FontWeight','bold');
% ***********************************************************************
% Create a panel to control zoom level in the image
% ***********************************************************************
% Initialize the limits for zoom window
gui_params.limits = [];
h_panel_zoom = uipanel('Title','Zoom Settings','FontSize',12,...
'Position',[0.82,0.75,0.15,0.1]);
uicontrol('Parent',h_panel_zoom,'Style','pushbutton',...
'Units','normalized','Position',[0.2 0.3 0.3 0.4],...
'String','Zoom in','FontName','Arial','FontSize',11,...
'HorizontalAlignment','left','Callback',@createZoomInLims);
uicontrol('Parent',h_panel_zoom,'Style','pushbutton',...
'Units','normalized','Position',[0.6 0.3 0.3 0.4],...
'String','Zoom out','FontName','Arial','FontSize',11,...
'HorizontalAlignment','left','Callback',@createZoomOutLims);
% ***********************************************************************
% Create a panel to control opacity of the overlays
% ***********************************************************************
slider_incr = 0.1;
slider_range = 1;
slider_step = slider_incr/slider_range;
h_panel_opacity = uipanel('Title','Opacity Control','FontSize',12,...
'Position',[0.82,0.55,0.15,0.1]);
gui_elements.h_panel_opacity_slider = uicontrol('Parent',h_panel_opacity,'Style','slider',...
'Units','normalized','Position',[0.1 0.2 0.8 0.3],...
'SliderStep',[slider_step,slider_step],'Min',0,'Max',1,...
'Value',0.5,'Callback',{@display_slider_img});
opacity_dispStr = ['Value: ',num2str(0.5)];
gui_elements.h_panel_opacity_txt = uicontrol('Parent',h_panel_opacity,'Style','text',...
'Units','normalized','Position',[0.1 0.7 0.8 0.2],...
'String',opacity_dispStr,'FontName','Arial','FontSize',10);
% ***********************************************************************
% Create a panel to adjust Window and level in the image
% ***********************************************************************
h_panel_adjWL = uipanel('Title','Adjust Window and Level','FontSize',12,...
'Position',[0.82,0.65,0.15,0.1]);
uicontrol('Parent',h_panel_adjWL,'Style','pushbutton',...
'Units','normalized','Position',[0.2 0.3 0.3 0.4],...
'String','Adjust','FontName','Arial','FontSize',11,...
'HorizontalAlignment','left','Callback',@adjust_windowLevel);
uicontrol('Parent',h_panel_adjWL,'Style','pushbutton',...
'Units','normalized','Position',[0.6 0.3 0.3 0.4],...
'String','Done','FontName','Arial','FontSize',11,...
'HorizontalAlignment','left','Callback',@close_windowLevel);
% ***********************************************************************
% Create a panel and text box to display informational messages.
% ***********************************************************************
% Create a panel to display user messages
h_user_info_txt_0 = uipanel('Title','Message to User','FontSize',12,...
'Position',[0.82,0.35,0.15,0.2]);
% The panel acts as a container for other uicontrol buttons for which it is
% a parent!
disp_str = 'Click select input button to load a new image volume';
gui_elements.h_user_info_txt = uicontrol('Parent',h_user_info_txt_0,'Style','text',...
'Units','normalized','Position',[0.1 0.1 0.8 0.8],...
'String',disp_str,...
'FontName','Arial','FontSize',12,'HorizontalAlignment','Center');
end
function select_ip_Callback(source,eventdata, cfg)
% ***********************************************************************
% Open a dialog-box to select the nifti file of interest.
% ***********************************************************************
global gui_params gui_elements gui_data
try
% ***********************************************************************
% Load a h5 file for a subject
% ***********************************************************************
[data_file,directory]= uigetfile({'*.mat'},'Select a file',pwd);
gui_data.dataPath = [directory data_file];
gui_data.data_file = data_file;
gui_data.directory = directory;
file_disp_name = strsplit(gui_data.dataPath, filesep);
file_disp_name = [file_disp_name{end-1} filesep data_file];
% Adding data directory to path to make it saving easier.
addpath(genpath(directory));
% Load the data
temp = load(gui_data.dataPath);
img = temp.img;
[xdim,ydim,zdim] = size(img);
% Rescale img intensities to [0,255] for ease
max_ = max(img(:));
min_ = min(img(:));
gui_data.origImg = cfg.img_max_intensity * ((img - min_)./(max_ - min_));
% Check if masks exist. If not, create a new mask with label dimension
% equal to the number of labels defined in cfg
if(isfield(temp,'masks'))
gui_data.UserMask = temp.masks;
else
gui_data.UserMask = zeros(xdim,ydim,zdim,cfg.num_labels);
end
gui_params.max_slideNum = zdim;
gui_params.slideNum = round(gui_params.max_slideNum/2); % Load first image of the slide
disp_str = ['Current file : ',file_disp_name];
% ***********************************************************************
% Create a text box to display the current .mat file loaded
% ***********************************************************************
uicontrol('Parent',source.Parent,'Style','text',...
'Units','normalized','Position',[0.01 0.01 0.95 0.5],...
'String',disp_str,'FontName','Arial','FontSize',10.5, ...
'FontAngle','italic', 'HorizontalAlignment','left');
% Load the data corresponding to the current slide number on the GUI
img = gui_data.origImg(:,:,gui_params.slideNum);
mask = squeeze(gui_data.UserMask(:,:,gui_params.slideNum,:));
% Set variables to display the initial image in GUI
gui_params.min_val = double(prctile(gui_data.origImg(:),0));
gui_params.max_val = double(prctile(gui_data.origImg(:),99));
% Create figure axis handle. This will be used by all functions to make
% edits to this axis
gui_elements.axial_fig = subplot(1,1,1,'Parent',gui_elements.h_panel_axialImage);
gui_elements.axial_fig.CLim = [gui_params.min_val gui_params.max_val];
set(gui_elements.axial_fig,'position',[.05 .01 .9 .9])
temp_im = getImageWithMaskOverlay(img,mask);
% generate pixelwise alphadata
% alpha = 0.5;
alpha = max(0,gui_elements.h_panel_opacity_slider.Value);
overlay_mask = logical(squeeze(mask(:,:,1)));
for label_idx = 2 : gui_params.cfg.num_labels
overlay_mask = overlay_mask | logical(squeeze(mask(:,:,label_idx)));
end
overlay_mask = alpha .* overlay_mask;
imagesc(img);colormap gray;axis image off;
hold on;
gui_elements.h_img_fig = imagesc(temp_im,'Parent',gui_elements.axial_fig);
axis image off;
hold off;
set(gui_elements.h_img_fig,'AlphaData', overlay_mask);
gui_elements.axial_fig.CLim = [gui_params.min_val gui_params.max_val];
% ***********************************************************************
% Create a slider for the user to move across the different slices
% ***********************************************************************
slider_incr = 1;
slider_range = gui_params.max_slideNum - 1;
slider_step = slider_incr/slider_range;
% Display the slider to change the image
gui_elements.h_img_slider = uicontrol('Parent',gui_elements.h_panel_axialImage,'Style','slider',...
'Units','normalized','Position',[0.05 0.93 0.9 0.04],...
'SliderStep',[slider_step,slider_step],'Min',1,'Max',gui_params.max_slideNum,...
'Value',gui_params.slideNum,'String','Slider','Callback',{@display_slider_img});
gui_elements.h_img_slider_txt = uicontrol('Parent',gui_elements.h_panel_axialImage,'Style','text',...
'Units','normalized','Position',[0.3 0.97 0.3 0.02],...
'String',['Slide #: ',num2str(gui_params.slideNum)],'FontName','Arial','FontSize',12);
% ***********************************************************************
% Create a panel to edit annotations
% ***********************************************************************
h_panel_ROI = uipanel('Title','ROI Annotation Tools','FontSize',12,...
'Position',[0.02,0.6,0.142,0.25], 'FontWeight','bold');
annotation_label_list = cfg.label_names + " labels";
gui_elements.h_listROI_popmenu = uicontrol('Parent',h_panel_ROI,'Style','popupmenu',...
'Units','normalized','Position',[0.2 0.85 0.5 0.1],...
'FontSize',10,'FontWeight','bold',...
'String',annotation_label_list,'Callback',@change_annotation_label);
gui_params.mask_type = cfg.label_names{cfg.default_label};
[edit_ROI,del_ROI,draw_ROI,save_ROI ] = createROIbuttons(h_panel_ROI);
gui_elements.edit_ROI = edit_ROI;
gui_elements.del_ROI = del_ROI;
gui_elements.draw_ROI = draw_ROI;
gui_elements.save_ROI = save_ROI;
% Copy original limits for zoom-out function
gui_params.limits(1,:) = gui_elements.axial_fig.XLim;
gui_params.limits(2,:) = gui_elements.axial_fig.YLim;
catch
fprintf('Exception occured. Load an image file.\n');
end
end
% ***********************************************************************
% Callback for the image slider. Based on the current location of the
% slider, the image in the figure window as well as its caption is updated.
% ***********************************************************************
function display_slider_img(source,eventdata)
global gui_elements gui_params gui_data
% Based on the current value of the slider the following updates are made:
gui_params.slideNum = max(1,round(gui_elements.h_img_slider.Value));
% Update slider text
set(gui_elements.h_img_slider_txt,'String',['Slide #: ',num2str(gui_params.slideNum)]);
gui_elements.h_user_info_txt.String = 'No message to display now!';
% Opacity slider updates
alpha = max(0,gui_elements.h_panel_opacity_slider.Value);
% Update slider text
opacity_dispStr = ['Value: ',num2str(alpha)];
gui_elements.h_panel_opacity_txt.String = opacity_dispStr;
% Copy limits so that they can be applied again.
tempXLimits = gui_elements.axial_fig.XLim;
tempYLimits = gui_elements.axial_fig.YLim;
% Create figure handle
figure(gui_elements.main_fig);
axes(gui_elements.axial_fig);
gui_elements.axial_fig.CLim = [gui_params.min_val gui_params.max_val];
img = gui_data.origImg(:,:,gui_params.slideNum);
mask = squeeze(gui_data.UserMask(:,:,gui_params.slideNum,:));
% generate pixelwise alphadata
overlay_mask = logical(squeeze(mask(:,:,1)));
for label_idx = 2 : gui_params.cfg.num_labels
overlay_mask = overlay_mask | logical(squeeze(mask(:,:,label_idx)));
end
overlay_mask = alpha .* overlay_mask;
temp_im = getImageWithMaskOverlay(img,mask);
imagesc(img);colormap gray;axis off;
hold on;
% Create figure handle
gui_elements.h_img_fig = imagesc(temp_im,'Parent',gui_elements.axial_fig);
axis image off;
hold off;
set(gui_elements.h_img_fig,'AlphaData', overlay_mask);
gui_elements.axial_fig.XLim = tempXLimits;
gui_elements.axial_fig.YLim = tempYLimits;
gui_elements.axial_fig.CLim = [gui_params.min_val gui_params.max_val];
end
% ***********************************************************************
% Callback for the draw mask pushbutton.The current mask is deleted and a
% user draws the new mask using freehand
% ***********************************************************************
function draw_img_Callback(source,eventdata)
global gui_elements gui_data gui_params
source.Interruptible = 'off';
% Disable other editing tools till this action is completed
gui_elements.edit_ROI.Enable = 'off';
gui_elements.del_ROI.Enable = 'off';
gui_elements.save_ROI.Enable = 'off';
% Based on the current value of the slider the following updates are made:
slideNum = max(1,round(gui_elements.h_img_slider.Value));
% Identify which label type is this function drawing based on the value of
% gui element in roi list
label_num = gui_elements.h_listROI_popmenu.Value;
% binary mask
BW = squeeze(gui_data.UserMask(:,:,slideNum,label_num));
disp_color = gui_params.cfg.roi_display_colors{label_num};
gui_elements.h_user_info_txt.String = 'Trace the mask outline.Use add roi button to add new regions of interest to mask.';
% This is to ensure that the draw command works on the main window
axes(gui_elements.axial_fig);
mask_Main = imfreehand;
setColor(mask_Main,disp_color);
bw_use = createMask(mask_Main,gui_elements.h_img_fig);
BW = logical(BW) | logical(bw_use);
gui_data.UserMask(:,:,slideNum,label_num)= BW;
% Enable other editing tools after this action is completed
gui_elements.edit_ROI.Enable = 'on';
gui_elements.del_ROI.Enable = 'on';
gui_elements.save_ROI.Enable = 'on';
% Display the new annotations
display_slider_img(gui_elements.h_img_slider,eventdata);
end
% ***********************************************************************
% Callback for the delete mask pushbutton. The mask on the current slice of
% the image will be deleted. Based on tha value of label being edited, the
% corresponding mask would be deleted.
% ***********************************************************************
function del_img_Callback(source,eventdata)
global gui_data gui_elements gui_params
% Based on the current value of the slider the following updates are made:
slideNum = max(1,round(gui_elements.h_img_slider.Value));
% Identify which label type is this function editing based on the value of
% gui element in roi list
label_num = gui_elements.h_listROI_popmenu.Value;
label_name = gui_params.cfg.label_names{label_num};
% binary mask
BW = squeeze(gui_data.UserMask(:,:,slideNum,label_num));
if(nnz(BW)==0)
gui_elements.h_user_info_txt.String = 'No mask to delete here. Use draw option to first generate a mask.';
else
BW = zeros(size(BW));
end
gui_data.UserMask(:,:,slideNum,label_num)= BW;
disp_str = [label_name ,' mask deleted from current slice'];
gui_elements.h_user_info_txt.String = disp_str;
% Update the display figure
display_slider_img(gui_elements.h_img_slider,eventdata);
end
% ***********************************************************************
% Callback for the save mask pushbutton. Based on the mask Type, the
% corresponding label is saved
% ***********************************************************************
function save_img_Callback(~,eventdata)
global gui_data gui_elements
fileName = [gui_data.directory filesep gui_data.data_file];
masks = gui_data.UserMask;
save(fileName,'-append','masks');
gui_elements.h_user_info_txt.String = 'Masks successfully saved to mat file!';
end
% ***********************************************************************
% Callback for the edit mask pushbutton. The mask on the current slice of
% the image can be altered, based on the label type
% ***********************************************************************
function edit_img_Callback(source,eventdata)
global gui_params gui_data gui_elements
% Disable other editing tools till this action is completed
gui_elements.draw_ROI.Enable = 'off';
gui_elements.del_ROI.Enable = 'off';
gui_elements.save_ROI.Enable = 'off';
% Based on the current value of the slider the following updates are made:
slideNum = max(1,round(gui_elements.h_img_slider.Value));
% Identify which label type is this function editing based on the value of
% gui element in roi list
label_num = gui_elements.h_listROI_popmenu.Value;
% load mask from current slice and label
curr_mask = squeeze(gui_data.UserMask(:,:,slideNum,label_num));
disp_color = gui_params.cfg.roi_display_colors{label_num};
if(nnz(curr_mask)==0)
gui_elements.h_user_info_txt.String = 'No mask for this label to edit here. Use draw option first.';
else
gui_elements.h_user_info_txt.String = 'Trace the exclusion mask to exclude pixels without lifting the pen.';
% This is to ensure that the draw command works on the main window
axes(gui_elements.axial_fig);
mask_Main = imfreehand;
setColor(mask_Main,disp_color);
excl_mask = createMask(mask_Main,gui_elements.h_img_fig);
curr_mask = logical(curr_mask) & (~logical(excl_mask));
gui_data.UserMask(:,:,slideNum,label_num)= curr_mask;
% Enable other editing tools till this action is completed
gui_elements.draw_ROI.Enable = 'on';
gui_elements.del_ROI.Enable = 'on';
gui_elements.save_ROI.Enable = 'on';
display_slider_img(gui_elements.h_img_slider,eventdata);
end
end
% ***********************************************************************
% Callback for when the user presses zoom in push button. It lets the user
% zoom into the image once and saves the axes and pplies it to all
% subsequent images.
% ***********************************************************************
function createZoomInLims(source,eventdata)
global gui_elements
gui_elements.h_user_info_txt.String = 'Drag the mouse to select a region to zoom in.';
zoomObj = zoom(gui_elements.main_fig);
set(zoomObj,'ActionPostCallback', @storelimits);
zoomObj.Direction = 'in';
zoomObj.Enable = 'on';
uiwait(gui_elements.main_fig);
zoomObj.Enable = 'off';
end
% ***********************************************************************
% Callback for when the user presses zoom out push button. It resets the
% zoom level to original settings
% ***********************************************************************
function createZoomOutLims(source,eventdata)
global gui_elements gui_params
gui_elements.axial_fig.XLim = gui_params.limits(1,:);
gui_elements.axial_fig.YLim = gui_params.limits(2,:);
display_slider_img(gui_elements.h_img_slider,eventdata);
gui_elements.h_user_info_txt.String= 'Zoom reset.';
end
function storelimits(source,eventdata)
global gui_elements
uiresume(gui_elements.main_fig);
end
% ***********************************************************************
% This function is to create ROI editting buttons
% Given a parent panel, the buttons correspond to draw, edit, delete &
% save.
%*********************************************************************
function [edit_btn, del_btn, draw_btn, save_btn ] = createROIbuttons(parent_panel)
% set the foreground and background colors
bg_col = 'b';
fg_col = 'y';
% Panel Functionality edits:
draw_btn = uicontrol('Parent',parent_panel,'Style','pushbutton',...
'Units','normalized','Position',[0.05 0.5 0.3 0.25],...
'String','Draw','FontName','Arial','FontSize',12,...
'HorizontalAlignment','left','Callback',{@draw_img_Callback},...
'BackgroundColor',bg_col,'ForegroundColor',fg_col,...
'FontAngle','italic', 'FontWeight','bold');
edit_btn = uicontrol('Parent',parent_panel,'Style','pushbutton',...
'Units','normalized','Position',[0.55 0.5 0.3 0.25],...
'String','Edit','FontName','Arial','FontSize',12,...
'HorizontalAlignment','left','Callback',{@edit_img_Callback},...
'BackgroundColor',bg_col,'ForegroundColor',fg_col,...
'FontAngle','italic', 'FontWeight','bold');
del_btn = uicontrol('Parent',parent_panel,'Style','pushbutton',...
'Units','normalized','Position',[0.05 0.1 0.3 0.25],...
'String','Delete','FontName','Arial','FontSize',12,...
'HorizontalAlignment','left','Callback',{@del_img_Callback},...
'BackgroundColor',bg_col,'ForegroundColor',fg_col,...
'FontAngle','italic', 'FontWeight','bold');
save_btn = uicontrol('Parent',parent_panel,'Style','pushbutton',...
'Units','normalized','Position',[0.55 0.1 0.3 0.25],...
'String','Save','FontName','Arial','FontSize',12,...
'HorizontalAlignment','left','Callback',{@save_img_Callback},...
'BackgroundColor',bg_col,'ForegroundColor',fg_col,...
'FontAngle','italic', 'FontWeight','bold');
end
% ***********************************************************************
% This is the function that converts the image into RGB channels to overlay
% the mask boundaries on the image. Therefore, colormaps other than gray
% would not work here. I could make it to work with other colormaps, if
% required. For now, grayscale should be okay.
% ***********************************************************************
function opImg = overlayMaskOnImage(ipImg,mask,color)
if(nargin<3)
color = [255 0 0]; % Default red color
end
if max(color) <= 1
color = normalize_ipImg(color,255); % Change to uint8.
end
% Check if the image has 3-bands (RGB image).
if size(ipImg,3) == 1 % Create grayscale image.
ipImg(:,:,2) = ipImg(:,:,1);
ipImg(:,:,3) = ipImg(:,:,1);
end
% Find the outline of the mask.
[indx] = find(mask);
% Take those pixels and change their color
for i = 1:size(ipImg,3)
temp_im = ipImg(:,:,i);
temp_im(indx) = color(i);
ipImg(:,:,i) = temp_im;
end
opImg = uint8(ipImg);
end
function opImg = normalize_ipImg(ipImg,ref_val,min_val,max_val)
%**********************************************************************
% Function to normalize an input image so that the intensities are rescaled
% to 0-reference value. Here the reference value is 255
%*********************************************************************
ipImg = double(ipImg);
if(nargin < 3)
min_ = min(ipImg(:));
max_ = max(ipImg(:));
else
min_ = min_val;
max_ = max_val;
end
opImg = ref_val .* ((ipImg - min_)./(max_ - min_));
end
function op_Img = getImageWithMaskOverlay(ip_Img,ip_Mask)
global gui_params
num_labels = gui_params.cfg.num_labels;
label_colors = gui_params.cfg.roi_display_colors;
img_max_intensity = gui_params.cfg.img_max_intensity;
% Using red color for WMH lesions
ip_Img = normalize_ipImg(squeeze(ip_Img), img_max_intensity,gui_params.min_val,gui_params.max_val);
for label_idx = 1:num_labels
label_mask = ip_Mask(:,:,label_idx);
label_color = img_max_intensity * label_colors{label_idx};
op_Img = overlayMaskOnImage(ip_Img,label_mask,label_color);
ip_Img = op_Img;
end
end
% ***********************************************************************
% Callback to adjust window and level in the image displayed. This callback
% uses matlab's imcontrast tool to let the user adjust the image and saves
% the minimum and the maximum image intensities on exit. The image
% intensities for all subsequent images is also adjusted. While adjusting
% the images, MATLAB shows a new figure.Therefore, ROIs will not be visible
% until the slider is moved, such that the display slider function is
% called again.
% ***********************************************************************
function adjust_windowLevel(source,~)
global gui_elements gui_params gui_data
gui_elements.h_user_info_txt.String = 'Drag the mouse (left-right) to change window width and (up-down) to change window center. Click Done once finished';
slc_num = max(1,round(gui_elements.h_img_slider.Value));
ipImg = gui_data.origImg(:,:,slc_num);
% figure(main_fig);
% Only show contrast edits on the main window
tempXLimits = gui_elements.axial_fig.XLim;
tempYLimits = gui_elements.axial_fig.YLim;
gui_elements.h_img_fig = imshow(ipImg,[0,gui_params.cfg.img_max_intensity],'Parent',gui_elements.axial_fig);
if(~isempty(gui_params.limits))
gui_elements.axial_fig.XLim = tempXLimits;
gui_elements.axial_fig.YLim = tempYLimits;
end
gui_elements.axial_fig.CLim = [min(ipImg(:)) max(ipImg(:))];
gui_elements.hfig_contrast = imcontrast(gui_elements.h_img_fig);
set(gui_elements.hfig_contrast, 'CloseRequestFcn', @(s,e)getValues(s));
gui_elements.hfig_contrast.Visible = 'off';
end
% ***********************************************************************
% This function is to get the min and the max values from the imcontrast
% tool. This is used to set the window and the level option.
% ***********************************************************************
function getValues(hfig)
global gui_params
gui_params.min_val = str2double(get(findobj(hfig, 'tag', 'window min edit'), 'String'));
gui_params.max_val = str2double(get(findobj(hfig, 'tag', 'window max edit'), 'String'));
end
% ***********************************************************************
% Callback for closing imcontrast tool and saving the minimum and maximum
% image intensities.
% ***********************************************************************
function close_windowLevel(source,eventdata)
global gui_elements;
try
close(gui_elements.hfig_contrast);
delete(gui_elements.hfig_contrast);
gui_elements.h_user_info_txt.String = 'Contrast adjusted.';
catch
end
end
% ***********************************************************************
% This function changes the annotation label based on the value selected in
% the list window
% ***********************************************************************
function change_annotation_label(source,eventdata)
global gui_params
gui_params.mask_type = gui_params.cfg.label_names{source.Value};
end