function varargout = importSCaseDev(varargin) % IMPORTSCASEDEV MATLAB code for importSCaseDev.fig % IMPORTSCASEDEV, by itself, creates a new IMPORTSCASEDEV or raises the existing % singleton*. % % H = IMPORTSCASEDEV returns the handle to a new IMPORTSCASEDEV or the handle to % the existing singleton*. % % IMPORTSCASEDEV('CALLBACK',hObject,eventData,handles,...) calls the local % function named CALLBACK in IMPORTSCASEDEV.M with the given input arguments. % % IMPORTSCASEDEV('Property','Value',...) creates a new IMPORTSCASEDEV or raises the % existing singleton*. Starting from the left, property value pairs are % applied to the GUI before importSCaseDev_OpeningFcn gets called. An % unrecognized property name or invalid value makes property application % stop. All inputs are passed to importSCaseDev_OpeningFcn via varargin. % % *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one % instance to run (singleton)". % % See also: GUIDE, GUIDATA, GUIHANDLES % Edit the above text to modify the response to help importSCaseDev % Last Modified by GUIDE v2.5 15-Jan-2019 16:51:28 %% Begin initialization code - DO NOT EDIT gui_Singleton = 1; gui_State = struct('gui_Name', mfilename, ... 'gui_Singleton', gui_Singleton, ... 'gui_OpeningFcn', @importSCaseDev_OpeningFcn, ... 'gui_OutputFcn', @importSCaseDev_OutputFcn, ... 'gui_LayoutFcn', [] , ... 'gui_Callback', []); if nargin && ischar(varargin{1}) gui_State.gui_Callback = str2func(varargin{1}); end if nargout [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); else gui_mainfcn(gui_State, varargin{:}); end % End initialization code - DO NOT EDIT % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function importSCaseDev_OpeningFcn(hObject, eventdata, handles, varargin) %% --- Executes just before importSCaseDev is made visible. % This function has no output args, see OutputFcn. % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % varargin command line arguments to importSCaseDev (see VARARGIN) %-------------------------------------------------------------------------- % Choose default command line output for importSCaseDev handles.output = hObject; % Update handles structure guidata(hObject, handles); % UIWAIT makes importSCaseDev wait for user response (see UIRESUME) % uiwait(handles.figure1); movegui('center') %-------------------------------------------------------------------------- %% Customized by JSM 2018/10/26 % Setting default values for some global variables % Default directory = the current directory handles.script_dir = pwd; cd([pwd '/../../../../']); handles.home_path = pwd; cd([pwd '/data/']); handles.base_dir = pwd; cd(handles.script_dir); % Radiobuttons % *handles.acquisition_stage* => might be 'Normal' or 'Pathologic' set(handles.radiobutton_Pathologic,'Value',1); handles.patient_group="P"; % *handles.shoulder_side* => might be 'Right' or 'Left' set(handles.radiobutton_right,'Value',1); % *handles.acquisition_stage* => might be 'Preop' or 'Postop' set(handles.radiobutton_preop,'Value',1); % *handles.output_dir* => importation folder. By default the current dir. set(handles.output_dir,'String',pwd); % *handles.body* => might be 'Shoulder', 'Elbow' or 'Other[]' set(handles.radiobutton_shoulder,'Value',1); % *handles.CTlabel_text* => might be '-1', '-2', ..., '-1p', '-2p', ... set(handles.CTlabel_text,'String','-xxx'); guidata(hObject,handles); function varargout = importSCaseDev_OutputFcn(hObject, eventdata, handles) %% --- Outputs from this function are returned to the command line. % varargout cell array for returning output args (see VARARGOUT); % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Get default command line output from handles structure varargout{1} = handles.output; %% ====================================================================== %% "Create Functions" execute during object creation, after setting all properties. function patient_num_CreateFcn(hObject, eventdata, handles) %% --- Executes during object creation, after setting all properties. % hObject handle to patient_num (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: edit controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end %% --- Executes during object creation, after setting all properties. function slider_2Dslice_CreateFcn(hObject, eventdata, handles) % hObject handle to slider_2Dslice (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: slider controls usually have a light gray background. if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor',[.9 .9 .9]); end guidata(hObject,handles); function edit_otherBody_CreateFcn(hObject, eventdata, handles) %% --- Executes during object creation, after setting all properties. % hObject handle to edit_otherBody (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: edit controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end guidata(hObject,handles); function edit_extra_CreateFcn(hObject, eventdata, handles) %% --- Executes during object creation, after setting all properties. % hObject handle to edit_extra (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: edit controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end set(hObject,'String','Write here every extra info...'); % update_infoFields(handles); guidata(hObject,handles); %% ====================================================================== %% "Callback Functions" execute on hObject's action events %% ************** Patient Type (group) ************** function radiobutton_Pathologic_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_Pathologic. % hObject handle to radiobutton_Pathologic (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_Pathologic handles.patient_group="P"; set(handles.act3Dview,'value',1) act3Dview_Callback(handles.act3Dview,eventdata,handles) patient_num = get(handles.patient_num,'String'); set(handles.patient_num,'String',['P' patient_num(2:end)]); function radiobutton_Normal_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_Normal. % hObject handle to radiobutton_Normal (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_Normal handles.patient_group="N"; set(handles.act3Dview,'value',0) act3Dview_Callback(handles.act3Dview,eventdata,handles) patient_num = get(handles.patient_num,'String'); set(handles.patient_num,'String',['N' patient_num(2:end)]); %% ************** Start new Patient / sCase ************** function newPatient_Callback(hObject, eventdata, handles) %% --- Executes on button press in newPatient. % hObject handle to newPatient (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % This button lunch the initial check of a folder containing a group of % sets of CTs. It counts the files per subfolder to clasify them % Select a limit of minimun dicom files to discard scout scans & other % small scans as elbows scoutScanLimit = 30; smallScanLimit = 90; % Choose the main folder for the desired case newPath = uigetdir(handles.base_dir); % handles.patient_dir = newPath; current_dir = pwd; cd([newPath '/..']); handles.patient_dir = pwd; cd(current_dir); % Check the given path and extract data from every folder and file inside dirList = dir(newPath); % Select only the folders from the current path --> folderList folderN = 0; for k=3:length(dirList) folderN = folderN + dirList(k).isdir if folderN * dirList(k).isdir >0 folderList(folderN) = dirList(k); folderN,folderList(folderN).name end end % Check how many dicom files are in each folder (to discard ScoutScans) wb = waitbar(0,'Checking folders size'); for k=1:folderN % will contain a struct with data of files in the desired % folder waitbar(k/folderN,wb,sprintf('%s%s%s%i%s%i',"Checking directory ",... string(folderList(k).name),": ",k,"/",folderN)); files=dir([folderList(k).folder '/' folderList(k).name]); filesDicom = 0; % Initialitation of dicom files counter for n=1:length(files) % if is a file and this file is a dicom file, note it % (files.isdicom) and count it if isfile([files(n).folder '/' files(n).name]) & ... isdicom([files(n).folder '/' files(n).name]) files(n).isdicom = 1; % noting down that it is a dicom file filesDicom = filesDicom +1; % counting the dicom files % Next line builds a list of dicom file names in cell mode folderList(k).dicomList(filesDicom) = cellstr(files(n).name); else % Otherwise, is not a dicom file and we note it like that files(n).isdicom = 0; end end % Each folder has it own counter of dicom files folderList(k).dicomN = filesDicom; % We add a prefix with the number of files per CT, helping to priorize % the importation order if ~contains(folderList(k).name,['s' char(string(folderList(k).dicomN))]) movefile([folderList(k).folder '/' folderList(k).name],... [folderList(k).folder '/' 's'... char(string(folderList(k).dicomN)) '-' folderList(k).name]); folderList(k).name = ['s' char(string(folderList(k).dicomN))... '-' folderList(k).name]; end %% From here it could be commented and eliminated (JSM 25102018) % When a folder has few dicom files we can consider that it was a scan % scout instead of an interesting CT if folderList(k).dicomN < scoutScanLimit folderList(k).scanMode = 'scoutScan'; % Changing the folder name to mark it as scoutScan (if not marked % before) if ~contains(folderList(k).name,'scout') movefile([folderList(k).folder '/' folderList(k).name],... [folderList(k).folder '/' folderList(k).name '_scoutScan']); end elseif folderList(k).dicomN < smallScanLimit folderList(k).scanMode = 'smallScan'; % Changing the folder name to mark it as scoutScan (if not marked % before) if ~contains(folderList(k).name,'small') movefile([folderList(k).folder '/' folderList(k).name],... [folderList(k).folder '/' folderList(k).name '_smallScan']); end else folderList(k).scanMode = 'CT'; end % Until here end % Makes handles variable visible to other functions in this script % hanldes.dicomdir = newPath; guidata(hObject,handles); %% ************** Load next CT set ************** function Load_Next_CT_Callback(hObject, eventdata, handles) %% --- Executes on button press in Load_Next_CT. % hObject handle to Load_Next_CT (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Before loading a new set of CTs we should remove the last one clear handles.data % Output Directory update % if isfield(handles,'patient_dir') % handles.base_dir = handles.patient_dir; % else % handles.base_dir = handles.home_path; % end % Also remove the fields 'myinfo' and 'mydicom' (they could be just % cleared?) if isfield(handles, 'myinfo'); handles = rmfield(handles, 'myinfo'); % Removing 'myinfo' field from structure in handles else if isfield(handles, 'mydicom'); handles = rmfield(handles, 'mydicom');% Removing 'mydicom' field from structure in handles end end if isfield(handles,'dicomSet') handles = rmfield(handles,'dicomSet'); end if isfield(handles,'dicomSetSorted') handles = rmfield(handles,'dicomSetSorted'); end %% Loading CT files % Using last directory if isfield(handles,'patient_dir') [handles.dicomlist, handles.dicomdir] = uigetfile('*.*',... 'Select the images to load',handles.patient_dir,'MultiSelect', 'on'); elseif isfield(handles,'base_dir') [handles.dicomlist, handles.dicomdir] = uigetfile('*.*',... 'Select the images to load',handles.base_dir,'MultiSelect', 'on'); else [handles.dicomlist, handles.dicomdir] = uigetfile('*.*',... 'Select the images to load',home_path,'MultiSelect', 'on'); end % Showing the dicom name in the interface set(handles.text_dicom_name,'String',strcat(string(handles.dicomdir), string(handles.dicomlist(1)))); % Number of dicom files handles.N = length(handles.dicomlist); % Set parametres for 2D visualization set(handles.slider_2Dslice, 'Max', handles.N); set(handles.slider_2Dslice, 'Value', int32(handles.N/2)); set(handles.slider_2Dslice, 'SliderStep',[1/handles.N 10/handles.N]); set(handles.slider_2Dslice, 'Min', 1); set(handles.info_text, 'ForegroundColor', 'black', 'FontWeight', 'normal'); % Read dicom data try % This loop reads all the dicom files and builds a new struct with the % information from each row and the data (the images) wb = waitbar(0,'Loading DICOM files'); %This creates a waitbar or progressbar L = length(handles.dicomlist); % number of dicom files to load for n=1:L waitbar(n/L,wb,sprintf('%s%i%s%i',"Loading DICOM metadata ",n,"/",L)); % Reads the info from each dicomfile handles.dicomSet(n) = dicominfo(sprintf('%s%s',... handles.dicomdir, char(handles.dicomlist(n))),'UseDictionaryVR',true); end for n=1:L waitbar(n/L,wb,sprintf('%s%i%s%i',"Loading DICOM images ",n,"/",L)); handles.dicomSet(n).data = dicomread(sprintf('%s%s', ... handles.dicomdir, char(handles.dicomlist(int32(n))))); end handles.myinfo = handles.dicomSet(1); % To be removed (JSM 25102018) % % 'handles.myinfo' will keep the metadata of the dicom files loaded % handles.myinfo(1) = dicominfo(sprintf('%s%s', handles.dicomdir, ... % char(handles.dicomlist(1))),'UseDictionaryVR',true); % Temporal storing of metadata tempInfo=handles.dicomSet(1); save('tempInfo.mat','tempInfo'); % Shows few metadata in the interface: % - IPP identification number and Patient Initials set(handles.IPP_text, 'String', handles.dicomSet(1).PatientID) set(handles.initials_text,'String',sprintf('(%s%s)',... handles.dicomSet(1).PatientName.FamilyName(1),... handles.dicomSet(1).PatientName.GivenName(1))); set(handles.birthdate_text,'String',handles.dicomSet(1).PatientBirthDate); set(handles.gender_text,'String',handles.dicomSet(1).PatientSex); % - CT resolution in mm set(handles.Resolution_text, 'String', sprintf('%f mm', handles.dicomSet(1).PixelSpacing(1))); % - CT date set(handles.CTdate_text, 'String', sprintf('%s', handles.dicomSet(1).AcquisitionDate)); % The following function sort the dicomFiles by their slice location % handles.dicomSetSorted=sortStructByField(handles.dicomSet,{'SliceLocation'}); handles.dicomSetSorted=sortStructByField(handles.dicomSet,{'InstanceNumber'},handles); handles.dicomSetOld=handles.dicomSet; handles.dicomSet=handles.dicomSetSorted; 'load finished' catch except except except.identifier if strcmp(except.identifier,'Error identifier: MATLAB:nonExistentField') errordlg(except.message,'Loading Error') % return % elseif or(strcmp(except.identifier,'MATLAB:heterogeneousStrucAssignment'),... % strcmp(except.identifier,'MATLAB:heterogeneousStrucAssignment')) % f = errordlg(sprintf('%s\n\n%s\n%s', ' CT SCAN WITH UNEXPECTED ORIENTATION.',... % 'Suggestion: mark the current folder as "Wrong_Orientation"',... % 'and try with another set of CTs'),'Loading Error'); % return else errordlg(sprintf('%s%s','Error identifier: ',except.identifier)) end end %% Updating the radioButtons "NONE", "BONE"('BONE'), "SOFT"('STANDARD') if isfield(handles.dicomSet(1), 'ConvolutionKernel') if strfind(handles.dicomSet(1).ConvolutionKernel, 'BONE') set(handles.radiobutton_none, 'Value', 0); set(handles.radiobutton_sharp, 'Value', 1); set(handles.radiobutton_smooth, 'Value', 0); elseif strfind(handles.dicomSet(1).ConvolutionKernel, 'STANDARD') set(handles.radiobutton_none, 'Value', 0); set(handles.radiobutton_sharp, 'Value', 0); set(handles.radiobutton_smooth, 'Value', 1); else set(handles.radiobutton_none, 'Value', 1); set(handles.radiobutton_sharp, 'Value', 0); set(handles.radiobutton_smooth, 'Value', 0); end else set(handles.radiobutton_none, 'Value', 1); set(handles.radiobutton_sharp, 'Value', 0); set(handles.radiobutton_smooth, 'Value', 0); end %% Extracting data for interface representation handles.slice = int32(handles.N / 2); % Chooses the central slice % handles.mydicom(:,:,handles.slice) = dicomread(sprintf('%s%s', handles.dicomdir, char(handles.dicomlist(handles.slice)))); if isfield(handles,'mydicom') handles=rmfield(handles,'mydicom'); end handles.mydicom(:,:,handles.slice) = handles.dicomSet(handles.slice).data; handles.CTmin = -200; handles.CTmax = 2000; handles.bigmax = 3000; handles.bigmin = -2000; set(handles.slider_2Dcontrast, 'Max', handles.bigmax - handles.bigmin - 1); set(handles.slider_2Dcontrast, 'Min', 0); set(handles.slider_2Dcontrast, 'Value', 900); set(handles.slider_2Dbrightness, 'Max', handles.bigmax); set(handles.slider_2Dbrightness, 'Min', handles.bigmin); set(handles.slider_2Dbrightness, 'Value', 1100); set(handles.slice_num, 'String', handles.slice); axes(handles.axes_2Dviewer); % Set current axes % imshow(handles.mydicom(:,:,handles.slice), [handles.CTmin handles.CTmax]); % imshow(handles.dicomSet(handles.slice).data, [handles.CTmin handles.CTmax]); % trying dicomreadVolume % [V, SPATIAL, DIM] = dicomreadVolume(handles.dicomdir); % imshow(V(:,:,1,handles.slice), [handles.CTmin handles.CTmax]); imshow(handles.dicomSet(handles.slice).data, [handles.CTmin handles.CTmax]); %% ISOSURFACE section ==================================================== act3Dview_Callback(handles.act3Dview, eventdata, handles); axes(handles.axes_2Dviewer); % Set current axes guidata(hObject,handles); % handles if and(get(handles.patient_num,'String') ~="P###",... exist([char(get(handles.output_dir,'String')) '/readme'])==2) handles.text_readme.String="listo para leer"; end % update_infoFields(handles); % Makes handles variable visible to other functions in this script %% Reset the DB chech result info box set(handles.text_coincidences_info,'String',"Check DB for coincidences..."); guidata(hObject,handles); function act3Dview_Callback(hObject, eventdata, handles) %% --- Executes on button press in act3Dview. % hObject handle to act3Dview (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of act3Dview % handles.enable_3Dview = get(hObject,'Value') if get(hObject,'Value') C=questdlg(['The 3D viewer might create memory problems when the CT'... ' contains more than 300 slices. Do you want to activate it?'],... '3D viewer activation','Yes, Display 3D view','Abort','Abort') switch C case 'Yes, Display 3D view' handles.enable_3Dview = 1 otherwise handles.enable_3Dview = 0 set(hObject,'Value',0) end else handles.enable_3Dview = 0 end % clear handles.data axes(handles.isosurface); % Set current axes cla if isfield(handles,'N') & handles.enable_3Dview if handles.N>1 directory=handles.dicomdir; % Preparing list of dicom full names (including address) for k=1:handles.N dicomListFullName(k)=""; dicomListFullName(k)=[directory char(handles.dicomlist(k))]; end try [V,spatial,dim] = dicomreadVolume(dicomListFullName); v = squeeze(V); v = double(v); v2= imresize3(v,0.2); handles.v2 = v2; handles.isoValue = 1400; % default limit for isosurface rendering p = patch(isosurface(v2,handles.isoValue)); Sv2 = size(v2); M = max(max(max(v2))); m = min(min(min(v2))); handles.bigmax = M; handles.bigmin = m; set(handles.slider_3Dviewer, 'Max', handles.bigmax); set(handles.slider_3Dviewer, 'Min', handles.bigmin); set(handles.slider_3Dviewer, 'Value', handles.isoValue); d1=(M-m)/Sv2(1); d2=(M-m)/Sv2(2); d3=(M-m)/Sv2(3); [x,y,z]=meshgrid(m:d1:M,m:d2:M,m:d3:M); handles.x=x(1:Sv2(1),1:Sv2(2),1:Sv2(3)); handles.y=y(1:Sv2(1),1:Sv2(2),1:Sv2(3)); handles.z=z(1:Sv2(1),1:Sv2(2),1:Sv2(3)); isocolors(handles.x,handles.y,handles.z,v2,p); p.FaceColor='interp'; p.EdgeColor='none'; view(-20, 10); % isosurface(v2,1400); rotate3d on; catch except if strcmp(except.identifier,'images:dicomread:differentPatientOrientations') f = errordlg(sprintf('%s\n\n%s\n%s', ' CT SCAN WITH UNEXPECTED ORIENTATION.',... 'Suggestion: mark the current folder as "Wrong_Orientation"',... 'and try with another set of CTs'),'Loading Error'); % We change the folder name to mark it as scoutScan (if not marked before) if ~contains(handles.dicomdir,'wrong') movefile([handles.dicomdir(1:end-1)],... [handles.dicomdir(1:end-1) '_wrongOrientatedScan']); end return else errordlg(sprintf('%s%s','Error identifier: ',except.identifier)); % rethrow(except); end end end end guidata(hObject,handles); function slider_3Dviewer_Callback(hObject, eventdata, handles) %% --- Executes on slider movement. % hObject handle to slider_3Dviewer (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'Value') returns position of slider % get(hObject,'Min') and get(hObject,'Max') to determine range of slider guidata(hObject,handles); function radiobutton_left_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_left. % hObject handle to radiobutton_left (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_left handles.shoulder_side = 'Left'; update_readme_Callback(handles.update_readme,eventdata,handles); guidata(hObject,handles); function radiobutton_right_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_right. % hObject handle to radiobutton_right (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_right handles.shoulder_side = 'Right'; update_readme_Callback(handles.update_readme,eventdata,handles); guidata(hObject,handles); %% --- Executes on button press in radiobutton_preop. function radiobutton_preop_Callback(hObject, eventdata, handles) % hObject handle to radiobutton_preop (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_preop handles.acquisition_stage = 'Preop'; update_readme_Callback(handles.update_readme,eventdata,handles); % update_infoFields(handles); guidata(hObject,handles); function radiobutton_postop_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_postop. % hObject handle to radiobutton_postop (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_postop handles.acquisition_stage = 'Postop'; update_readme_Callback(handles.update_readme,eventdata,handles); % update_infoFields(handles); guidata(hObject,handles); function Check_Database_Callback(hObject, eventdata, handles) %% --- Executes on button press in Check_Database. % hObject handle to Check_Database (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) wb = waitbar(0,'Checking Excel Database'); "Openning Excel Database" % Checking Database ----------------------------------- % Importing database from excel file depending on computer system % if computer('arch')=="win64" % handles.data=importDataBaseTab('../../../../data/Excel/ShoulderDataBase.xlsx','sCase',2,2000); % excelDB = '../../../../data/Excel/ShoulderDataBase.xlsx'; % else % % path2DB=[ '/home/shoulder/data/Excel/ShoulderDataBase.xlsx']; % system('ls /home/shoulder/data/Excel/'); % path2DB=['/home/shoulder/data/Excel/ShoulderDataBase.xlsx']; % excelDB = '/home/shoulder/data/Excel/ShoulderDataBase.xlsx'; % % ls('/home/shoulder/data/Excel/') % % f=importDataBaseTab_script; % handles.data=importDataBaseTab(path2DB,'sCase',2,2000); % % end % New way of reading the Excel Database: [excelDB, DBpath, ~] = uigetfile('*.xlsx','Select the Excel Database File'); tic E = exist(sprintf('%s%s',DBpath,excelDB)); % We store the Excel file adress and name for further use handles.ExcelDB_path = DBpath; handles.ExcelDB_fullname = sprintf('%s%s',DBpath,excelDB); if E == 2 % Only if the file exist as a known format (XLS) [~,txt,raw,dates]=xlsread(handles.ExcelDB_fullname,'sCase','','',@convertSpreadsheetExcelDates); % The dates cell array will have NaN in every cell not containing a "date" dates(~cellfun(@(x) isnumeric(x) || islogical(x), dates)) = {NaN}; handles.data.headers = string(txt(1,:)); % Conversion of dates's cell array to numeric matrix dates=cell2mat(dates); % Finding columns with dates dates_CperR=find(~isnan(dates(1,:))); date_Cells{1}= dates_CperR; txt_Cells{1} = []; for p=2:size(txt,1) dates_CperR=find(~isnan(dates(p,:))); date_Cells{p}= dates_CperR; txt_CperR = find(~ismissing(txt(p,:))); txt_Cells{p} = txt_CperR; end date_columns = []; txt_columns = []; for p=1:length(date_Cells) date_columns= union(date_columns,date_Cells{p}); txt_columns = union(txt_columns,txt_Cells{p}); end num_columns = setdiff(1:size(raw,2),txt_columns); txt_columns = setdiff(txt_columns,date_columns); % Inverting the "date to number" convertion done during the importation dates_only = datetime(dates(2:end,[date_columns]),'ConvertFrom','Excel','Format','dd-MM-yyy'); % num_only = cell2mat(raw(2:end,num_columns)); for n=1:size(txt,2) % for each text headers (column) [data.(raw{1,n})]=raw(2:end,n); end k=1; for n=date_columns' % for the date columns [data.(raw{1,n})]=dates_only(:,k); k=k+1; end elseif E == 0 warndlg("Excel file not found!") else warndlg("Database file has unrecognized format. It should be an Excel file") end toc handles.data=data; % ***Obtain the first row available for a new case*** % Get the colum of sCase.id, including those from rows available sCase_list = handles.data.SCase_ID; % Cut the list from the end untill found an existing sCases [s1,s2]=size(sCase_list); s0=0; while sCase_list(end,:)=="" % Last position empty... sCase_list = sCase_list(1:end-1,:); s0=s0+1; waitbar(s0/s1,wb,'Checking Excel Database'); end sCase_N=[]; sCase_P=[]; % sCase_list_sorted=sort(sCase_list); % This helps to avoid errors if a row is eventually void sCase_list_sorted=string(sCase_list); % This have to be cleaned for n=1:s1-s0 if sCase_list_sorted(n,:)~="" L = length(char(extractAfter(sCase_list_sorted(n,:),1))); while L<3 sCase_list_sorted(n,:)=sprintf('%s%s%s',... extractBefore(sCase_list_sorted(n,:),2),... '0',extractAfter(sCase_list_sorted(n,:),1)); L = length(char(extractAfter(sCase_list_sorted(n,:),1))); end if extractBefore(sCase_list_sorted(n,:),2)=="N" sCase_N=[sCase_N; sCase_list_sorted(n,:)]; elseif extractBefore(sCase_list_sorted(n,:),2)=="P" sCase_P=[sCase_P; sCase_list_sorted(n,:)]; else "there is a row without identification (N or P) in the DataBase" end waitbar(s1-s0+n/s1,wb,'Checking Excel Database'); end end sCase_N=sort(sCase_N); sCase_P=sort(sCase_P); % Build the next sCase.id for a potential new sCase % by extracting the 'id' number of the last sCase and adding '1' if handles.patient_group=="N" new_sCase = str2num(extractAfter(char(sCase_N(end)),1))+1; % Finaly convert to string and add a 'P' for 'Pathological' new_sCase = string(['N' num2str(new_sCase)]); elseif handles.patient_group=="P" new_sCase = str2num(extractAfter(char(sCase_P(end)),1))+1; % Finaly convert to string and add a 'N' for 'Normal' new_sCase = string(['P' num2str(new_sCase)]); end handles.data.anonymity_IPP=cell2mat(handles.data.anonymity_IPP); handles.data.shoulder_side=cell2mat(handles.data.shoulder_side); % *** Q1: Does the new IPP exist in the Database yet? *** % Extract the list of patient IDs from Excel database IPP_list_DB = handles.data.anonymity_IPP; % Extracting patient ID from dicom-set info IPP_sCase = str2num(handles.myinfo(1).PatientID) % If the IPP of the current case already exist in the database, % it finds the position of the current patient ID in the list. % And for this position it extracts the case name "sCase", otherwise it % leave the variables empty % handles.patientIndex=find(handles.data.anonymityIPP==str2num(handles.myinfo(1).PatientID)) handles.patientIndex=find(IPP_list_DB==IPP_sCase); handles.sCase = handles.data.SCase_ID(handles.patientIndex); % Determine how many sCases exits with the same IPP as the current CT Ncoincidences=length(handles.sCase); % *** We start the decision tree *** if Ncoincidences==0 % This is a new sCase!! So we write a short message and set the sCase set(handles.dataCheck_text,'String', sprintf('This is a new case')); set(handles.dataCheck_panel,'BackgroundColor','g'); handles.current_sCase=new_sCase; set(handles.patient_num,'String',sprintf('%s',handles.current_sCase)); set(handles.text_coincidences_info,'String',"Current IPP not found in DB"); % If the IPP exists in the Excel Database in more than one sCase we first % can discriminate by the shoulder side (rigth or left) elseif Ncoincidences>1 % Launch a warning message set(handles.dataCheck_text,'String',... ['Patient found in ' num2str(Ncoincidences) ' sCase(s)']); set(handles.dataCheck_panel,'BackgroundColor','y'); % Shows information of the 2 first coincidences coincidences = sprintf("%s \t%s \t%s \t%s \n%s \t%s \t%s \t\t%s \n%s \t%s \t%s \t\t%s",... "SCase"," IPP "," CT_date ","Side",... string(handles.sCase(1)),... string(IPP_list_DB(handles.patientIndex(1))),... handles.data.CT_date(handles.patientIndex(1)),... handles.data.shoulder_side(handles.patientIndex(1)),... string(handles.sCase(2)),... string(IPP_list_DB(handles.patientIndex(2))),... handles.data.CT_date(handles.patientIndex(2)),... handles.data.shoulder_side(handles.patientIndex(2))); set(handles.text_coincidences_info,'String',coincidences); % *** Q2: is the current CT from the same side of one of the existing? % Get the side of the coincident sCases side_sCase = handles.data.shoulder_side(handles.patientIndex); % Launch 'question dialog' to let the user choose if one the coincident % sCases matches with the side (rigth or left) of the current CT question = sprintf("%s %s %s \n%s\n%s",... "The SCase",string(IPP_sCase),... "was found in the more than one case in the database.",... "Please, check the shoulder side of the currently loaded CT",... "and choose between the following options"); title = "SCase found in database"; btn1 = ['Existing case:' char(handles.sCase(1)) ' side:' char(side_sCase(1))]; btn2 = ['Existing case:' char(handles.sCase(2)) ' side:' char(side_sCase(2))]; btn3 = ['New case:' char(new_sCase) ' side: ?']; dfltbtn = btn3; answer = questdlg(question,title,btn1,btn2,btn3,dfltbtn); switch answer case btn1 handles.current_sCase=handles.sCase(1); answerN = 1; case btn2 handles.current_sCase=handles.sCase(2); answerN = 2; case btn3 handles.current_sCase=string(new_sCase); answerN = 3; otherwise disp("Auto Check DB -ABORTED-"); return; end disp(sprintf("%s %s",string(handles.current_sCase),"chosen")); % Update the list of sCases after selection handles.sCase=handles.current_sCase; Ncoincidences=1; % *** Q3: is the current CT date similar to the CT_date from any of the % concident sCases in the Database? *** % Get the CT's date from the coincident sCase from the Database try CTdate_DB = datestr(handles.data.CT_date(handles.patientIndex),'dd-mmm-yyyy'); catch error message = sprintf("%s\n%s\n%s\n\n%s\n%s\n%s",... "Suggested solution:",... "Opt1. Update InfoCT.xlsx and repeat the 'Auto Check DB'",... "Opt2. Check the CT_date yourself and use 'Manual sCase'",... "Error details:",... error.identifier,error.message); errordlg(message,"Not valid CT_date found in Database"); CTdate_DB = NaT; end % Get the CT's date from the new CT set current_CTdate = handles.myinfo.AcquisitionDate % Adapt date format to make it comparable current_CTdate=datestr([current_CTdate(1:4),'-',... current_CTdate(5:6),'-',current_CTdate(7:8)],'dd-mmm-yyyy') % Compare CT's dates if isequal(current_CTdate,CTdate_DB) % The sCase already exits so the user will have to decide if the CT % must be added to the case of it is already added. set(handles.dataCheck_text,'String',... ['Current CT matches in IPP, side and CTdate with others in the database']); set(handles.dataCheck_panel,'BackgroundColor','r'); set(handles.patient_num,'String',string(handles.current_sCase)); else % The user must check if the current CT set corresponds to a % post-op shoulder set(handles.dataCheck_text,'String',... ['Check if the CT is from a post-op. Current CT matches in IPP, side']); set(handles.dataCheck_panel,'BackgroundColor','r'); set(handles.patient_num,'String',string(handles.current_sCase)); end % If only one sCase was found in the Database elseif Ncoincidences==1 % Launch a warning message set(handles.dataCheck_text,'String',... ['Patient found in one sCase(s)']); set(handles.dataCheck_panel,'BackgroundColor','r'); handles.current_sCase=handles.sCase; coincidences = sprintf("%s \t%s \t%s \t%s \n%s \t%s \t%s \t\t%s",... "SCase"," IPP "," CT_date ","Side",... string(handles.sCase(1)),... string(IPP_list_DB(handles.patientIndex(1))),... handles.data.CT_date(handles.patientIndex(1)),... handles.data.shoulder_side(handles.patientIndex(1))); set(handles.text_coincidences_info,'String',coincidences); side_sCase=handles.data.shoulder_side(handles.patientIndex); % Creating question dialog to let the user choose between the found % SCase and a new SCase label question = sprintf("%s %s %s \n%s\n%s",... "The loaded SCase",string(IPP_sCase),... "was found in the SCase list in the database.",... "Please, check the shoulder side of the currently loaded CT",... "and choose between the following options"); title = "SCase found in database"; btn1 = ['Existing case:' char(handles.sCase(1)) ' side:' char(side_sCase(1))]; btn2 = ['New case:' char(new_sCase) ' side: ?']; dfltbtn = btn2; answer= questdlg(question,title,btn1,btn2,dfltbtn); switch answer case btn1 handles.current_sCase=handles.sCase(1) answerN=1; case btn2 handles.current_sCase=string(new_sCase); answerN=2; otherwise disp("Auto Check DB -ABORTED-"); return; end disp(sprintf("%s %s",string(handles.current_sCase),"chosen")); if answerN==1 % *** Q3: is the current CT date similar to the CT_date from any of the % concident sCases in the Database? *** % Get the CT's date from the coincident sCase from the Database try CTdate_DB = datestr(handles.data.CT_date(handles.patientIndex),'dd-mmm-yyyy'); catch error message = sprintf("%s\n%s\n%s\n\n%s\n%s\n%s",... "Suggested solution:",... "Opt1. Update InfoCT.xlsx and repeat the 'Auto Check DB'",... "Opt2. Check the CT_date yourself and use 'Manual sCase'",... "Error details:",... error.identifier,error.message); errordlg(message,"Not valid CT_date found in Database"); CTdate_DB = NaT; end % Get the CT's date from the new CT set current_CTdate = handles.myinfo.AcquisitionDate % Adapt date format to make it comparable current_CTdate=datestr([current_CTdate(1:4),'-',... current_CTdate(5:6),'-',current_CTdate(7:8)],'dd-mmm-yyyy') % Compare CT's dates if isequal(current_CTdate,CTdate_DB) % The sCase already exits so the user will have to decide if the CT % must be added to the case of it is already added. set(handles.dataCheck_text,'String',... ['Current CT matches in IPP, side and CTdate with others in the database']); set(handles.dataCheck_panel,'BackgroundColor','r'); set(handles.patient_num,'String',sprintf('%s',string(handles.current_sCase))); else % The user must check if the current CT set corresponds to a % post-op shoulder set(handles.dataCheck_text,'String',... ['Check if the CT is from a post-op. Current CT matches in IPP, side']); set(handles.dataCheck_panel,'BackgroundColor','r'); set(handles.patient_num,'String',sprintf('%s',string(handles.current_sCase))); end else % This is a new sCase!! So we write a short message and set the sCase set(handles.dataCheck_text,'String', sprintf('This is a new case')); set(handles.dataCheck_panel,'BackgroundColor','g'); handles.current_sCase=new_sCase; set(handles.patient_num,'String',sprintf('%s',string(handles.current_sCase))); end end F1=extractBefore(char(handles.current_sCase),2); F2=extractBetween(char(handles.current_sCase),2,2); F3=extractBetween(char(handles.current_sCase),3,3); current_dir = cd(char(strcat(handles.base_dir,'/',F1,'/',F2,'/',F3))); % saving current directory and changing to the output dir output_dir = pwd; % needed to update the output directory cd(current_dir); % back to the current directory set(handles.output_dir,'String',output_dir); % set(handles.output_dir,'String',strcat(handles.base_dir,F1,'/',F2,'/',F3));%sprintf('%s%s\%s\%s',base_dir,F1,F2,F3)); waitbar(1,wb,'Checking Excel Database'); guidata(hObject,handles); function manual_case_selection_Callback(hObject, eventdata, handles) %% --- Executes on button press in manual_case_selection. % hObject handle to manual_case_selection (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) sCase_dir = uigetdir(handles.base_dir); set(handles.output_dir,'String',sCase_dir); update_readme_Callback(handles.update_readme,eventdata,handles); warndlg('Please uptade the sCase.id accordingly with the chosen output directory') guidata(hObject,handles); function patient_num_Callback(hObject, eventdata, handles) %% Executes with 'Enter' in patient_num % hObject handle to patient_num (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'String') returns contents of patient_num as text % str2double(get(hObject,'String')) returns contents of patient_num as a double % The output directory is stablish by the automatic Check of the DB or the % manual selection. Hence, here we only check whether the sCase number % matches with the selected output directory % From "patient_num" which corresponds to sCase number patient_num = get(handles.patient_num,'String'); % Get the sCase number F0=char(extractBefore(char(patient_num),1)) F0=char(extractBefore(char(patient_num),2)) % Extract the 'N' or 'P' F1=char(extractBetween(char(patient_num),2,2)) % Extract the first digit (1 to 9) F2=char(extractBetween(char(patient_num),3,3)) % Extract the second digit (0to9) % From "output_dir" which corresponds to output directory output_dir = get(handles.output_dir,'String'); % Get the ourput directory L = length(output_dir); % lenght of the string that contains the directory D0=char(extractBetween(char(output_dir),L-4,L-4)) % Extact the 'N' or 'P' D1=char(extractBetween(char(output_dir),L-2,L-2)) % Extract the first digit (1 to 9) D2=char(extractAfter(char(output_dir),L-1)) % Extract the second digit (0 to 9) if F0==D0 & F1==D1 & F2==D2 handles.enable_importation = 1 else handles.enable_importation = 0 warndlg('Importation cancelled. The sCase (patient number) must be consistant with the Output Directory') end guidata(hObject,handles); %% --- Executes on slider movement. function slider_2Dslice_Callback(hObject, eventdata, handles) % hObject handle to slider_2Dslice (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'Value') returns position of slider % get(hObject,'Min') and get(hObject,'Max') to determine range of slider handles.slice = int32(get(hObject,'Value')); set(handles.slice_num, 'String', handles.slice); handles.mydicom(:,:,handles.slice) = handles.dicomSet(handles.slice).data; axes(handles.axes_2Dviewer) % Set current axes imshow(handles.mydicom(:,:,handles.slice), [handles.CTmin handles.CTmax]) guidata(hObject,handles); function Import2database_Callback(hObject, eventdata, handles) %% --- Executes on button press in Import2database. % hObject handle to Import2database (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) sortPictures = 1; set(handles.info_text, 'String', 'Preparing DICOM images to be imported...'); drawnow % Warning message in info panel when any patient number is found if isempty(get(handles.patient_num,'String')) set(handles.info_text, 'ForegroundColor', 'red', 'FontWeight', 'bold', 'String', 'Please give a patient number') return else patient = get(handles.patient_num,'String'); end % W if isempty(get(handles.output_dir,'String')) outputdir = uigetdir; if outputdir set(handles.output_dir,'String', outputdir); end else outputdir = get(handles.output_dir,'String'); % outputdir = outputdir{1}; end if ~outputdir set(handles.info_text, 'ForegroundColor', 'red', 'FontWeight', 'bold',... 'String', 'Please select an output directoy'); return end set(handles.info_text, 'ForegroundColor', 'black', 'FontWeight', 'normal'); % Create name string newname = [patient, '-', handles.dicomSet(1).PatientID, '_',... handles.dicomSet(1).PatientName.FamilyName(1),... handles.dicomSet(1).PatientName.GivenName(1)]; if get(handles.radiobutton_sharp,'Value') newname = [newname, '-bone.']; elseif get(handles.radiobutton_smooth,'Value') newname = [newname, '-soft.']; else newname = [newname, '.']; end % Create output directory % outputdir = sprintf('%s%s%s%s%s%s%s%s%s%s%s',outputdir,'/', patient,'-',... % handles.dicomSet(1).PatientID,'/','CT-',patient,'-',... % handles.dicomSet(1).PatientID,handles.CTlabel_text.String,'/dicom/'); suggested_outputdir = sprintf('%s%s%s%s%s%s%s%s%s%s%s',outputdir,'/', patient,'-',... handles.dicomSet(1).PatientID,'/','CT-',patient,'-',... handles.dicomSet(1).PatientID,handles.CTlabel_text.String,'/dicom/'); if exist(suggested_outputdir)==7 outputdir = sprintf('%s%s%s%s%s%s%s%s%s%s%s',outputdir,'/', patient,'-',... handles.dicomSet(1).PatientID,'/','CT-',patient,'-',... handles.dicomSet(1).PatientID,'xxx','/dicom/'); else outputdir = suggested_outputdir; end mkdir(outputdir); % Sort pictures in correct order if sortPictures == 1 for h = 1:handles.N infoTemp = dicominfo(sprintf('%s%s', handles.dicomdir,... char(handles.dicomlist(h))),'UseDictionaryVR',true); SliceLoc(h,1) = h; % sprintf('%s%s', handles.dicomdir, char(handles.dicomlist(h))); SliceLoc(h,2) = infoTemp.SliceLocation; end SliceSorted = sortrows(SliceLoc,2); end guidata(hObject,handles); % Read all data % at the importation we set the dicomSet as definitively sorted handles.dicomSet=handles.dicomSetSorted; % with this sentence we could avoid the very previous sorting... for i = 1:handles.N str = sprintf('Copying dicom...\n%d / %d\n', i, handles.N); set(handles.info_text, 'String', str); drawnow % This replace the Given Name by the patient inicials and kernel info if get(handles.radiobutton_sharp,'Value') handles.dicomSet(i).PatientName.GivenName = ... [handles.dicomSet(i).PatientName.FamilyName(1),... handles.dicomSet(i).PatientName.GivenName(1), '_bone']; elseif get(handles.radiobutton_smooth,'Value') handles.dicomSet(i).PatientName.GivenName = ... [handles.dicomSet(i).PatientName.FamilyName(1),... handles.dicomSet(i).PatientName.GivenName(1), '_soft']; else handles.dicomSet(i).PatientName.GivenName = ... [handles.dicomSet(i).PatientName.FamilyName(1),... handles.dicomSet(i).PatientName.GivenName(1)]; end % This replace the Given Name by the IPP handles.dicomSet(i).PatientName.FamilyName = [patient, '_',... handles.dicomSet(1).PatientID]; % Importation dicomwrite(handles.dicomSet(i).data,[outputdir, newname,... sprintf('%04d',i), '.dcm'], handles.dicomSet(i)); end guidata(hObject,handles); % Create readme.txt file if it does not exist already localDir = string(get(handles.output_dir,'String')); localDir = sprintf('%s%s%s%s%s%s',localDir,'/', patient,'-', handles.dicomSet(1).PatientID,'/'); if ~exist(sprintf('%s%s',localDir,'readme.txt'), 'file') readme_file=fopen(sprintf('%s%s',localDir,'readme.txt'), 'wt'); fprintf(readme_file,sprintf('%s%s%s %s %s\r\n',patient,'-',... handles.dicomSet(1).PatientID,handles.initials_text.String,... handles.shoulder_side)); fprintf(readme_file,sprintf('\r\n%s',get(handles.text_readme,'String'))); fclose(readme_file); else readme_file=fopen(sprintf('%s%s',localDir,'readme.txt'), 'at'); % opening to append text fprintf(readme_file,sprintf('\r\n%s',get(handles.text_readme,'String'))); fclose(readme_file); end set(handles.info_text, 'String', 'Copied'); guidata(hObject,handles); function output_dir_Callback(hObject, eventdata, handles) %% % hObject handle to output_dir (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'String') returns contents of output_dir as text % str2double(get(hObject,'String')) returns contents of output_dir as a double guidata(hObject,handles); function CTlabel_text_Callback(hObject, eventdata, handles) % hObject handle to CTlabel_text (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'String') returns contents of CTlabel_text as text % str2double(get(hObject,'String')) returns contents of CTlabel_text as a double update_readme_Callback(handles.update_readme,eventdata,handles); guidata(hObject,handles); function output_dir_CreateFcn(hObject, eventdata, handles) %% --- Executes during object creation, after setting all properties. % hObject handle to output_dir (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: edit controls usually have a white background on Windows. % See ISPC and COMPUTER. if ispc && isequal(get(hObject,'BackgroundColor'),... get(0,'defaultUicontrolBackgroundColor')); set(hObject,'BackgroundColor','white'); end guidata(hObject,handles); %% --- Executes during object creation, after setting all properties. function info_text_CreateFcn(hObject, eventdata, handles) % hObject handle to info_text (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called guidata(hObject,handles); %% --- Executes during object creation, after setting all properties. function DicomInfoBox_CreateFcn(hObject, eventdata, handles) % hObject handle to info_text (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called guidata(hObject,handles); %% --- Executes during object creation, after setting all properties. function slider_3Dviewer_CreateFcn(hObject, eventdata, handles) % hObject handle to slider_3Dviewer (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: slider controls usually have a light gray background. if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor',[.9 .9 .9]); end guidata(hObject,handles); %% --- Executes on button press in DicomDetails. function DicomDetails_Callback(hObject, eventdata, handles) % hObject handle to DicomDetails (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) try load tempInfo.mat tempInfo handles.DicomInfoBox.String = ['Dicom Info: ',... 'Patient Sex: ', handles.dicomSet(1).PatientSex,... '. Birthday: ', handles.dicomSet(1).PatientBirthDate]; catch exception "Dicom info not available" end guidata(hObject,handles); % function checkbox_IPP_Callback(hObject, eventdata, handles) % %% --- Executes on button press in checkbox_IPP. % % hObject handle to checkbox_IPP (see GCBO) % % eventdata reserved - to be defined in a future version of MATLAB % % handles structure with handles and user data (see GUIDATA) % % % Hint: get(hObject,'Value') returns toggle state of checkbox_IPP % if get(hObject,'Value') %the IPP must be added to the readme line % try % handles.readme.IPP = string(handles.sCase); % ['IPP info to be added to the Readme line := ' handles.readme.IPP] % catch except % sprintf('%s%s','Error identifier: ',except.identifier) % ['IPP info failed to be added to the Readme line.'] % handles.readme.IPP = ''; % end % else % handles.readme.IPP = ''; % ['IPP info not present in Readme line'] % end % % update_infoFields(handles); % update_readme_Callback(handles.update_readme,eventdata,handles); % guidata(hObject,handles); function checkbox_CTdate_Callback(hObject, eventdata, handles) %% --- Executes on button press in checkbox_CTdate. % hObject handle to checkbox_CTdate (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of checkbox_CTdate if get(hObject,'Value') %the IPP must be added to the readme line try handles.readme.CTdate = string(handles.myinfo(1).AcquisitionDate); ['CTdate info to be added to the Readme line := ' handles.readme.CTdate] catch except sprintf('%s%s','Error identifier: ',except.identifier) ['CTdate info failed to be added to the Readme line.'] handles.readme.CTdate = ''; end else handles.readme.CTdate = ''; ['CTdate info not present in Readme line'] end % update_infoFields(handles); update_readme_Callback(handles.update_readme,eventdata,handles); guidata(hObject,handles); function checkbox_resolution_Callback(hObject, eventdata, handles) %% --- Executes on button press in checkbox_resolution. % hObject handle to checkbox_resolution (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of checkbox_resolution if get(hObject,'Value') %the IPP must be added to the readme line try handles.readme.resolution = string(handles.myinfo(1).PixelSpacing(1)); ['Resolution info to be added to the Readme line := ' handles.readme.resolution] catch except sprintf('%s%s','Error identifier: ',except.identifier) ['Resolution info failed to be added to the Readme line.'] handles.readme.resolution = ''; end else handles.readme.resolution = ''; ['Resolution info not present in Readme line'] end % update_readme_line(handles) % update_infoFields(handles); update_readme_Callback(handles.update_readme,eventdata,handles); guidata(hObject,handles); function radiobutton_shoulder_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_shoulder. % hObject handle to radiobutton_shoulder (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_shoulder handles.body = 'Shoulder'; set(handles.checkbox_contralateral,'Value',0); handles.contralateral=''; update_readme_Callback(handles.update_readme, eventdata, handles); guidata(hObject,handles); function radiobutton_elbow_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_elbow. % hObject handle to radiobutton_elbow (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_elbow handles.body = 'Elbow'; set(handles.checkbox_contralateral,'Value',0); handles.contralateral=''; update_readme_Callback(handles.update_readme, eventdata, handles); guidata(hObject,handles); function radiobutton_thorax_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_thorax. % hObject handle to radiobutton_thorax (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_thorax handles.body = 'Thorax'; set(handles.checkbox_contralateral,'Value',0); handles.contralateral=''; update_readme_Callback(handles.update_readme, eventdata, handles); guidata(hObject,handles); function checkbox_contralateral_Callback(hObject, eventdata, handles) %% --- Executes on button press in checkbox_contralateral. % hObject handle to checkbox_contralateral (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of checkbox_contralateral if get(handles.checkbox_contralateral,'Value') handles.contralateral = ['Contralateral ']; else handles.contralateral = ''; end update_readme_Callback(handles.update_readme, eventdata, handles); guidata(hObject,handles); function radiobutton_otherBody_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_otherBody. % hObject handle to radiobutton_otherBody (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_otherBody set(handles.checkbox_contralateral,'Value',0); handles.contralateral=''; set(handles.edit_otherBody,'Enable','On'); handles.body = get(handles.edit_otherBody,'String'); update_readme_Callback(handles.update_readme, eventdata, handles); guidata(hObject,handles); function edit_otherBody_Callback(hObject, eventdata, handles) %% % hObject handle to edit_otherBody (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'String') returns contents of edit_otherBody as text % str2double(get(hObject,'String')) returns contents of edit_otherBody as a double handles.body = get(handles.edit_otherBody,'String'); guidata(hObject,handles); function radiobutton_sharp_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_sharp. % hObject handle to radiobutton_sharp (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_sharp % % if get(hObject,'Value') % set(handles.radiobutton_none,'Value',0); % set(handles.radiobutton_smooth,'Value',0); % else % set(hObject,'Value',1); % end handles.kernel='Sharp'; update_readme_Callback(handles.update_readme, eventdata, handles); guidata(hObject,handles); function radiobutton_smooth_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_smooth. % hObject handle to radiobutton_smooth (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_smooth % % if get(hObject,'Value') % set(handles.radiobutton_none,'Value',0); % set(handles.radiobutton_sharp,'Value',0); % else % set(hObject,'Value',1); % end handles.kernel='Smooth'; update_readme_Callback(handles.update_readme, eventdata, handles); guidata(hObject,handles); function radiobutton_none_Callback(hObject, eventdata, handles) %% --- Executes on button press in radiobutton_none. % hObject handle to radiobutton_none (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_none handles.kernel='none'; warndlg(char("IMPORTANT: The operator must choose between 'Sharp (Bone)' or 'Smooth (Soft Tissue)'")); update_readme_Callback(handles.update_readme,eventdata,handles); guidata(hObject,handles); function checkbox_with_phantoms_Callback(hObject, eventdata, handles) %% --- Executes on button press in checkbox_with_phantoms. % hObject handle to checkbox_with_phantoms (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of checkbox_with_phantoms handles.phantoms = 'with'; update_readme_Callback(handles.update_readme, eventdata, handles); guidata(hObject,handles); function radiobutton_without_phantoms_Callback(hObject, eventdata, handles) % --- Executes on button press in radiobutton_without_phantoms. % hObject handle to radiobutton_without_phantoms (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of radiobutton_without_phantoms handles.phantoms = 'without'; update_readme_Callback(handles.update_readme, eventdata, handles); guidata(hObject,handles); function edit_extra_Callback(hObject, eventdata, handles) %% % hObject handle to edit_extra (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'String') returns contents of edit_extra as text % str2double(get(hObject,'String')) returns contents of edit_extra as a double guidata(hObject,handles); function update_readme_Callback(hObject, eventdata, handles) %% --- Executes on button press in update_readme. % hObject handle to update_readme (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) if ~isfield(handles,'shoulder_side') handles.shoulder_side = '*Sh_Side*'; end if ~isfield(handles,'acquisition_stage') handles.acquisition_stage = '*Pre-o-Post_op*'; end % handles.patient_num always exists % handles.IPP_text % handles.CTdate_text % handles.Resolution_text % handles.CTlabel_text if ~isfield(handles,'body') handles.body = '*body*'; end if ~isfield(handles,'kernel') handles.kernel = '*kernel*'; end if ~isfield(handles,'phantoms') handles.phantoms = '*phantoms*'; end if ~isfield(handles,'contralateral') handles.contralateral = ''; end if ~isfield(handles,'N') handles.N = 0; end % choosing handles.CTlabel_text switch handles.acquisition_stage case 'Preop' if ~get(handles.checkbox_contralateral,'Value') switch handles.body case 'Shoulder' switch handles.phantoms case 'without' switch handles.kernel case 'Sharp' handles.CTlabel_text.String = '-1'; case 'Smooth' handles.CTlabel_text.String = '-2'; otherwise handles.CTlabel_text.String = '-xxx'; warndlg('Operator must choose between Sharp or Smooth kernel'); end case 'with' switch handles.kernel case 'Sharp' handles.CTlabel_text.String = '-3'; case 'Smooth' handles.CTlabel_text.String = '-4'; otherwise handles.CTlabel_text.String = '-xxx'; warndlg('Operator must choose between Sharp or Smooth kernel'); end otherwise handles.CTlabel_text.String = '-xxx'; end case 'Elbow' switch handles.kernel case 'Sharp' handles.CTlabel_text.String = '-5'; case 'Smooth' handles.CTlabel_text.String = '-6'; otherwise handles.CTlabel_text.String = '-xxx'; warndlg('Operator must choose between Sharp or Smooth kernel'); end case 'Thorax' switch handles.kernel case 'Sharp' handles.CTlabel_text.String = '-7'; case 'Smooth' handles.CTlabel_text.String = '-8'; otherwise handles.CTlabel_text.String = '-xxx'; warndlg('Operator must choose between Sharp or Smooth kernel'); end otherwise handles.CTlabel_text.String = '-x11'; end else switch handles.kernel case 'Sharp' handles.CTlabel_text.String = '-9'; case 'Smooth' handles.CTlabel_text.String = '-10'; otherwise handles.CTlabel_text.String = '-xxx'; warndlg('Operator must choose between Sharp or Smooth kernel'); end end case 'Postop' if ~get(handles.checkbox_contralateral,'Value') switch handles.body case 'Shoulder' switch handles.phantoms case 'without' switch handles.kernel case 'Sharp' handles.CTlabel_text.String = '-p1'; case 'Smooth' handles.CTlabel_text.String = '-p2'; otherwise handles.CTlabel_text.String = '-pxxx'; warndlg('Operator must choose between Sharp or Smooth kernel'); end case 'with' switch handles.kernel case 'Sharp' handles.CTlabel_text.String = '-p3'; case 'Smooth' handles.CTlabel_text.String = '-p4'; otherwise handles.CTlabel_text.String = '-pxxx'; warndlg('Operator must choose between Sharp or Smooth kernel'); end otherwise handles.CTlabel_text.String = '-pxxx'; end case 'Elbow' switch handles.kernel case 'Sharp' handles.CTlabel_text.String = '-p5'; case 'Smooth' handles.CTlabel_text.String = '-p6'; otherwise handles.CTlabel_text.String = '-pxxx'; warndlg('Operator must choose between Sharp or Smooth kernel'); end case 'Thorax' switch handles.kernel case 'Sharp' handles.CTlabel_text.String = '-p7'; case 'Smooth' handles.CTlabel_text.String = '-p8'; otherwise handles.CTlabel_text.String = '-pxxx'; warndlg('Operator must choose between Sharp or Smooth kernel'); end otherwise handles.CTlabel_text.String = '-px11'; end else switch handles.kernel case 'Sharp' handles.CTlabel_text.String = '-p9'; case 'Smooth' handles.CTlabel_text.String = '-p10'; otherwise handles.CTlabel_text.String = '-pxxx'; warndlg('Operator must choose between Sharp or Smooth kernel'); end end otherwise handles.CTlabel_text.String = '-xxx'; end RL = sprintf('%s%s%s%s%s %s %s %s %s %s %s %s %s ','CT-',... handles.patient_num.String,'-',... handles.IPP_text.String,... handles.CTlabel_text.String,... handles.contralateral,... handles.body,... handles.kernel,... handles.phantoms,'phantoms',... handles.Resolution_text.String,... string(handles.N),'slices'),... get(handles.edit_extra,'String'); set(handles.text_readme,'String',RL); guidata(hObject,handles); function add_newSCase_excelDB_Callback(hObject, eventdata, handles) %% --- Executes on button press in add_newSCase_excelDB. % hObject handle to add_newSCase_excelDB (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Text info to the command window sprintf('%s:\n%s, %s, %s, %s,\n%s, %s, %s,',"The parameters to write in the Excel Database are",... "SCase_ID","SCase_idx","anonymity_IPP","anonymity_initials",... "anonymity_bithDate","patient_gender","shoulder_side") % The file SCaseImport.xlsx must be located inside the subfolder % xlsFromMatlab/ which is in the same directory of the main Database Excel ExcelImport_fullname = sprintf('%s%s',handles.ExcelDB_path,"xlsFromMatlab/SCaseImport.xlsx"); sprintf("%s%s", "Writting in file ", ExcelImport_fullname) % In order to avoid the repetition of any SCase we have to read and check % the SCaseImport.xlsx file: [~,txt,raw,dates]=xlsread(ExcelImport_fullname,'SCaseImport','','',@convertSpreadsheetExcelDates); % Looking for the "desired new SCase" in the existing list of SCases of % SCaseImport.xlsx % Removing void rows raw=raw(find(string(raw(:,1))~=''),:); found_SCase_Index = find(string(raw(:,1))==handles.patient_num.String); new_SCase_Index = length(string(raw(:,1)))+1; % If there is no coincidence we set the desired SCase as a new one and can % allow to write the new line of Import Parameters. Otherwise we will ask % to overwrite the existing line of parameters or doing nothing. if isempty(found_SCase_Index) SCase_Index = new_SCase_Index; else question = "The chosen SCase already exist. Do you want to overwrite it?"; title = "WARNING: SCase repeated"; btn1 = "Cancel"; btn2 = "Overwrite"; dfltbtn = "Cancel"; answer = questdlg(question,title,btn1,btn2,dfltbtn); % Handle response switch answer case "Overwrite" SCase_Index = found_SCase_Index; case "Cancel" disp("new SCase parameter line aborted") return; otherwise disp("new SCase parameter line aborted") return; end end % I don't know why this writting is taking a wrong ROW rowNumber=SCase_Index; new_SCase_ID = {handles.patient_num.String}; % Wrtitting SCase_ID SCaseCell=sprintf('%s%i','A',rowNumber); % Security Check: avoiding doubling SCases if isempty(find(string(handles.data.SCase_ID)==string(new_SCase_ID))) "SCase_ID written" xlswrite(ExcelImport_fullname,new_SCase_ID,'SCaseImport',SCaseCell) else "The selected SCase_ID is already present in the Database" return end % Wrtitting SCase_idx IdxCell=sprintf('%s%i','B',rowNumber); xlswrite(ExcelImport_fullname,rowNumber,'SCaseImport',IdxCell) % Wrtitting anonymity_IPP IPP_number = str2num(handles.IPP_text.String); IPPCell=sprintf('%s%i','C',rowNumber); xlswrite(ExcelImport_fullname,IPP_number,'SCaseImport',IPPCell) % Wrtitting anonymity_initials Initials={extractBefore(extractAfter(handles.initials_text.String,'('),')')}; InitialsCell=sprintf('%s%i','D',rowNumber); xlswrite(ExcelImport_fullname,Initials,'SCaseImport',InitialsCell) % Wrtitting anonymity_birthDate BirthDate ={[handles.birthdate_text.String(1:4) ... '-' handles.birthdate_text.String(5:6) ... '-' handles.birthdate_text.String(7:8)]}; BirthDateCell=sprintf('%s%i','E',rowNumber); xlswrite(ExcelImport_fullname,BirthDate,'SCaseImport',BirthDateCell) % Wrtitting patient_gender GenderCell=sprintf('%s%i','F',rowNumber); Patient_Gender = handles.gender_text.String; xlswrite(ExcelImport_fullname,Patient_Gender,'SCaseImport',GenderCell) % Wrtitting shoulder_side ShSideCell=sprintf('%s%i','G',rowNumber); Shoulder_Side = handles.shoulder_side(1); xlswrite(ExcelImport_fullname,Shoulder_Side,'SCaseImport',ShSideCell) %launch 'dicominfoSCase.m' to update CTdicomInfo CSV and XLS currentFolder=pwd; cd([currentFolder '/..']) dicominfoSCase % Lauched without arguments a avoid current error (1'20") cd(currentFolder) msgbox("Operation completed!. Remember to add manually SCase_ID and SCase_idx") %% Internal functions function update_readme_line(handles) %% -- Updates readme line % Complete the line to be writen in the readme file as: % CT-P454-513554-1 sharp shoulder without phantoms 0.351562 mm 137 slices try handles.readme.IPP = handle.myinfo.PatientID; handles.readme.CTdate = handles.myinfo.AcquisitionDate; handles.readme.CT_label = handles.CTlabel_text; if handles.radiobutton_sharp handles.readme.kernel = 'Sharp (BONE)'; elseif handles.radiobutton_smooth handles.readme.kernel = 'Smooth (SOFT)'; else handles.readme.kernel = 'None'; end handles.readme.line = ['CT-' handles.readme.IPP '-' handles.readme.CT_label... ' ' handles.readme.kernel ' ' handles.readme.body ' '... handles.readme.phantoms ' ' handles.readme.resolution ' ' ... handles.readme.slices ' ' handles.readme.stage ' ' handles.readme.extra... ' '] catch except sprintf('%s%s','Error identifier: ',except.identifier) 'fields lacking' end guidata(hObject,handles); function sortedST = sortStructByField(ST,field,handles) try "internal fuction activated" STfields = fieldnames(ST); STcell = struct2cell(ST); sz = size(STcell); % Notice that this is a 3 dimensional array. % For MxN structure array with P fields, the size % of the converted cell array is PxMxN % Once it's a cell array, you can sort using sortrows: % Convert to a matrix STcell = reshape(STcell, sz(1), []); % Px(MxN) % Make each field a column STcell = STcell'; % (MxN)xP column=0 % Sort by field for k=1:length(STfields) if isequal(STfields(k),field) column = k; end end % fieldName=char(STfields(1)) % field=char(field) % fieldColum = find(fieldName(1:length(field))==field) if column == 0 ['Warning: field ' char(field) ' not found in dicom metadata'] sortedST = ST; return else fieldColumn = column; STcell = sortrows(STcell, fieldColumn); %And convert it back to a structure array: % Put back into original cell array format STcell = reshape(STcell', sz); % Convert to Struct STsorted = cell2struct(STcell, STfields, 1); sortedST = STsorted; end catch except except.identifier except.message ['exception arised during dicom sorting by field'] end % function update_infoFields(hObject, handles) % %% Updating CT labelling % % if and(get(handles.patient_num,'String') ~='P###',exist([handles.output_dir '/readme'])==2) % % set(handles.text_readme, "listo para leer") % % end % guidata(hObject,handles); %% Functions to be removed function slider_2Dcontrast_Callback(hObject, eventdata, handles) %% --- Executes on slider movement. % hObject handle to slider_2Dcontrast (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'Value') returns position of slider % get(hObject,'Min') and get(hObject,'Max') to determine range of slider if ~isfield(handles, 'mydicom'); return end handles.CTmax = (get(handles.slider_2Dbrightness,'Max') + get(handles.slider_2Dbrightness,'Min') - get(handles.slider_2Dbrightness,'Value')) + (get(hObject,'Max') - get(hObject,'Value'))/2; handles.CTmin = (get(handles.slider_2Dbrightness,'Max') + get(handles.slider_2Dbrightness,'Min') - get(handles.slider_2Dbrightness,'Value')) - (get(hObject,'Max') - get(hObject,'Value'))/2; if handles.CTmax > handles.bigmax handles.CTmax = handles.bigmax; end if handles.CTmin < handles.bigmin handles.CTmin = handles.bigmin; end imshow(handles.mydicom(:,:,handles.slice), [handles.CTmin handles.CTmax]); guidata(hObject,handles) function slider_2Dcontrast_CreateFcn(hObject, eventdata, handles) %% --- Executes during object creation, after setting all properties. % hObject handle to slider_2Dcontrast (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: slider controls usually have a light gray background. if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor',[.9 .9 .9]); end guidata(hObject,handles); function slider_2Dbrightness_Callback(hObject, eventdata, handles) %% --- Executes on slider movement. % hObject handle to slider_2Dbrightness (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hints: get(hObject,'Value') returns position of slider % get(hObject,'Min') and get(hObject,'Max') to determine range of slider if ~isfield(handles, 'mydicom'); return end handles.CTmax = (get(hObject,'Max') + get(hObject,'Min')... - get(hObject,'Value')) + (get(handles.slider_2Dcontrast,'Max')... - get(handles.slider_2Dcontrast,'Value'))/2; handles.CTmin = (get(hObject,'Max') + get(hObject,'Min')... - get(hObject,'Value')) - (get(handles.slider_2Dcontrast,'Max')... - get(handles.slider_2Dcontrast,'Value'))/2; if handles.CTmax > handles.bigmax handles.CTmax = handles.bigmax; end if handles.CTmin < handles.bigmin handles.CTmin = handles.bigmin; end imshow(handles.mydicom(:,:,handles.slice), [handles.CTmin handles.CTmax]); guidata(hObject,handles); function slider_2Dbrightness_CreateFcn(hObject, eventdata, handles) %% --- Executes during object creation, after setting all properties. % hObject handle to slider_2Dbrightness (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: slider controls usually have a light gray background. if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor',[.9 .9 .9]); end guidata(hObject,handles);