diff --git a/ShoulderCase/@RotatorCuff/createSliceNathan.m b/ShoulderCase/@RotatorCuff/createSliceNathan.m index 0fbc652..cd072b1 100644 --- a/ShoulderCase/@RotatorCuff/createSliceNathan.m +++ b/ShoulderCase/@RotatorCuff/createSliceNathan.m @@ -1,367 +1,367 @@ function createSliceNathan(obj) % This function and its results might be reffered as % Nathan algorithm and Nathan slices in some studies. % %One needs to create two empty files in the current directory : %data_degenerescence.mat (a table) and Didnotwork.mat (a %string) % % This script calculates the degeneration of the 4 muscles % of the rotator cuff : SS, SC, IS, TM. It is composed of four % different steps : % - Load CT images (DICOM files) in order to create a 3D matrix % consituted with HU (Hounsfield unit) values % - Create a slice of this 3D matrix along a patient-specific % plane. Do image processing and set saving format usable by % automatic segmentation code (Python's code from ARTORG team % (UNIBE)) % - Execute automatic segmentation code on the new created % images % - Apply degeneration code (from Laboratoire de biom�canique % orthop�dique (EPFL)) on new images with automatic % segmentation and on image with manual segmentation (from CHUV % radiologist). Save degeneration values under the "muscles" % properties of each case in the LBO database % % Some "try-catch" are present in order to catch the errors % while keeping running the script on the rest of the database. % They are summarized underneath : % (DicomReadVolume) : do not manage to load the dicoms % Nothing : Automatic segmentation does not work (generally for TM) % * : slice function does not work % ** : does not want to crop image % *** : black image, don't want to save png % Main code starts here ! %% Load dicom SCase = obj.shoulder.SCase; dataCTPath = SCase.dataCTPath; % Create "muscles" folder (and its 4 subfolders) if it does not exist folder_muscle=[dataCTPath '/muscles']; if isfolder(folder_muscle) else mkdir(dataCTPath,'muscles'); mkdir(folder_muscle,'IS'); mkdir(folder_muscle,'SS'); mkdir(folder_muscle,'SC'); mkdir(folder_muscle,'TM'); end % Use folder "CT-2" (smoothed kernel) if it exists dataCTPath2=dataCTPath; dataCTPath2(1,end)='2'; if isfolder(dataCTPath2) dataCTPath0=dataCTPath2; else dataCTPath0=dataCTPath; end dicomFolder = [dataCTPath0 '/dicom']; %Extract the images as a 4D matrix where spatial is the %positions of the Pixels in the CT coordinate system % Return the case's number if it does not manage to load the DICOM files try [V,spatial,dim] = dicomreadVolume(dicomFolder); catch outputArg=1; return; end %V needs to be 3D matrix containing the value in HU of the %corresponding voxel V = squeeze(V) ; %Read the information from the middle dicom image (all image %informations are the same for all dicom files) to avoid a problem %if other files are located at the beginning or end of the %folder dicomList = dir(dicomFolder) ; size_list = size(dicomList) ; dicom_information = dicominfo([dicomFolder '/' dicomList(round(size_list(1)/2)).name]); %Take into account that the data will need to be linearly transformed %from stored space to memory to come back to true HU units afterwards: Rescale_slope = dicom_information.RescaleSlope; Rescale_intercept = dicom_information.RescaleIntercept; %Convert to double type to be able to multiply it with a int64 %matrix afterwards V = double(V); % To filter hard kernel images if not(isfolder(dataCTPath2)) V = imgaussfilt3(V,1) ; end size_V = size(V); %Extract position of each first pixel of each image (upper left corner) PatientPositions = spatial.PatientPositions ; %Get the distance between each pixel in neighboring rows and %columns PixelSpacings = spatial.PixelSpacings; % Get local coordinate system from parent scapula object(glenoid center) origin = obj.shoulder.scapula.coordSys.origin; % do not mix up with origin_image, "origin" is the origin of the Scapula Coordinate System xAxis = obj.shoulder.scapula.coordSys.PA; yAxis = obj.shoulder.scapula.coordSys.IS; zAxis = obj.shoulder.scapula.coordSys.ML; %% Slice from the CT data set %Get the position of the upper left pixel of the first image %and calculate the position of each pixel in the x,y %and z direction starting from the "origin" pixel origin_image = PatientPositions(1,:); % coordinates of the first pixel x_max = origin_image(1)+PixelSpacings(1,1)*(size_V(1)-1); y_max = origin_image(2)+PixelSpacings(1,2)*(size_V(2)-1); z_max = PatientPositions(end,3); %Calculate the coefficient of the linear transformation (CT-scan %coordinate system (x,y,z) to images coordinates system (i,j,k)) coefficients_i = polyfit([1 size_V(1)],[origin_image(1) , x_max],1); a_i = coefficients_i(1); b_i = coefficients_i(2); coefficients_j = polyfit([1 size_V(2)],[origin_image(2) , y_max],1); a_j = coefficients_j(1); b_j = coefficients_j(2); coefficients_k = polyfit([1 size_V(3)],[origin_image(3) , z_max],1); a_k = coefficients_k(1); b_k = coefficients_k(2); Pixel_pos_x=(1:size_V(1))*a_i+b_i; % Create the position vector along x-axis Pixel_pos_y=(1:size_V(2))*a_j+b_j; Pixel_pos_z=(1:size_V(3))*a_k+b_k; PixSize_z=(z_max-origin_image(3))/(size_V(3)-1); % Space between 2 slices % The oblique slice to be created is perpendicular to the z % axis of the scapula CS and passes through the origin point. % We will apply the matlab function "slice", to create the % oblique slice. One must first create a slice parallel to 2 % system's axis. Here we take a plane parallel to the (x,y) % plane, passing through the point "origin". Then, we need to % rotate this plane so that it becomes normal to the zAxis. V1 % is the vector normal to the horizontal slice and v2 the % vector normal to the final oblique slice, parallel to the % zAxis. We need to rotate around a vector v3 and from an angle % given by "vrrotvec(v1,v2)". v1=[0,0,1]; v2=zAxis/norm(zAxis); rotation_info=vrrotvec(v1,v2); v3=rotation_info(1:3); theta=rotation_info(4)/pi*180; % Convert it in degrees % Create the plane to be rotated [x,y,z] = meshgrid(Pixel_pos_x,Pixel_pos_y,Pixel_pos_z); s=1000; % Extension factor of the slice in order to cut the whole matrix.Set arbitrarily but sufficiently big so that it works for every patient Pixel_pos_x_enlarged=[origin_image(1)+(-PixelSpacings(1,1)*s:PixelSpacings(1,1):-PixelSpacings(1,1)) Pixel_pos_x x_max+(PixelSpacings(1,1):PixelSpacings(1,1):PixelSpacings(1,1)*s)]; % Create the position vector along x-axis, long enough to fill the diagonal Pixel_pos_y_enlarged=[origin_image(2)+(-PixelSpacings(1,2)*s:PixelSpacings(1,2):-PixelSpacings(1,2)) Pixel_pos_y y_max+(PixelSpacings(1,2):PixelSpacings(1,2):PixelSpacings(1,2)*s)]; figure('visible','off'); hsp = surf(Pixel_pos_x_enlarged,Pixel_pos_y_enlarged,origin(3)*ones(length(Pixel_pos_y_enlarged),length((Pixel_pos_x_enlarged)))); rotate(hsp,v3,theta,origin); xd_0 = hsp.XData; % x-coordinates of the plane's points yd_0 = hsp.YData; % y-coordinates of the plane's points zd_0 = hsp.ZData; % z-coordinates of the plane's points % Slice the 3D matrix of CT-scan try % Return case's number in case slice does not work figure('visible','off'); hss=slice(x,y,z,V,xd_0,yd_0,zd_0,'Linear'); % Linear interpolation by default. 'Cubic' or 'Nearest' catch outputArg=2; return end HU_0 = get(hss,'CData'); % HU values at each point of the plane NaNplaces_0=find(isnan(HU_0)); HU_1=HU_0*Rescale_slope+Rescale_intercept; % getting true HU values p_0=10e6; % value outside 3D matrix, set to a high distinguishable number HU_1(NaNplaces_0)=p_0; % If it's a right shoulder or left one, has to be turned in a % particular way if obj.shoulder.side=='R' HU_1=flipud(HU_1'); else HU_1=HU_1'; end % Find the new pixel's sizes necessary to obtain a 1024*1024 % shoulder slice. The largest diagonal's length is set to 1024 % pixels [left_1,left_2]=find(HU_1~=p_0,1); left_r=left_1; left_c=left_2; [right_1,right_2]=find(rot90(HU_1,2)~=p_0,1); right_r=right_1; right_c=size(HU_1,2)-right_2+1; [up_1,up_2]=find(rot90(HU_1)~=p_0,1); up_c=size(HU_1)-up_1+1; up_r=up_2; [down_1,down_2]=find(rot90(HU_1,3)~=p_0,1); down_r=size(HU_1,1)-down_2+1; down_c=down_1; % In case the slice does not cut the whole matrix (which % normally never happens), ask to double "s" parameter if or(or(right_c==size(HU_1,2),left_c==1),or(up_r==1,down_r==size(HU_1,1))) outputArg = 3; return end % Find which diagonal of the matrix' effective slice is the largest w=right_c-left_c; % width h=down_r-up_r; % height if h>w % Set the largest diagonal at 1024 pixels l=h; else l=w; end % Define new pixel's size NewPixSize_x=PixelSpacings(1,1)*l/1023; NewPixSize_y=PixelSpacings(1,2)*l/1023; % New plane with the new pixel's sizes Pixel_pos_x_enlarged_2=[origin_image(1)+(-NewPixSize_x*s:NewPixSize_x:-NewPixSize_x) origin_image(1):NewPixSize_x:x_max x_max+(NewPixSize_x:NewPixSize_x:NewPixSize_x*s)]; % Create the position vector along x-axis, long enough to fill the diagonal Pixel_pos_y_enlarged_2=[origin_image(2)+(-NewPixSize_y*s:NewPixSize_y:-NewPixSize_y) origin_image(2):NewPixSize_y:y_max y_max+(NewPixSize_y:NewPixSize_y:NewPixSize_y*s)]; figure('visible','off'); hsp2 = surf(Pixel_pos_x_enlarged_2,Pixel_pos_y_enlarged_2,origin(3)*ones(length(Pixel_pos_y_enlarged_2),length((Pixel_pos_x_enlarged_2)))); rotate(hsp2,v3,theta,origin); xd = hsp2.XData; % x-coordinates of the rotated plane's points. yd = hsp2.YData; % y-coordinates of the rotated plane's points. zd = hsp2.ZData; % z-coordinates of the rotated plane's points. % New slice with the good resolution (1024*1024) figure('visible','off'); hss=slice(x,y,z,V,xd,yd,zd,'Linear'); % Linear interpolation by default. 'Cubic' or 'Nearest' HU_2 = get(hss,'CData'); % HU values at each point of the plane NaNplaces=find(isnan(HU_2)); HU_slice=HU_2*Rescale_slope+Rescale_intercept; HU_slice_8_bit=HU_slice; p_tif=0; % value outside 3D matrix, for the tif image p_png=85; % for the png image HU_slice(NaNplaces)=p_tif; % Scaling to fit the training set (for the png only, grayscale) HU_interval_png=[-100 160]; lin_coef=[HU_interval_png(1) 1 ; HU_interval_png(2) 1]^(-1)*[0 255]'; HU_slice_8_bit=lin_coef(1)*HU_slice_8_bit+lin_coef(2); HU_slice_8_bit(NaNplaces)=p_png; % If it a right shoulder or left one, has to be turned in a % particular way if obj.shoulder.side=='R' HU_slice=flipud(HU_slice'); HU_slice_8_bit=flipud(HU_slice_8_bit'); else HU_slice=HU_slice'; HU_slice_8_bit=HU_slice_8_bit'; end % Determine the location of the 4 corners of the slice [left_1,left_2]=find(HU_slice~=p_tif,1); left_r=left_1; left_c=left_2; [right_1,right_2]=find(rot90(HU_slice,2)~=p_tif,1); right_r=right_1; right_c=size(HU_slice,2)-right_2+1; [up_1,up_2]=find(rot90(HU_slice)~=p_tif,1); up_c=size(HU_slice,2)-up_1+1; up_r=up_2; [down_1,down_2]=find(rot90(HU_slice,3)~=p_tif,1); down_r=size(HU_slice,1)-down_2+1; down_c=down_1; Folder=[dataCTPath '/matlab']; % Crop the image try % If cropping does not work, return case's number HU_slice=HU_slice(up_r:up_r+1023,left_c:left_c+1023); HU_slice_8_bit=HU_slice_8_bit(up_r:up_r+1023,left_c:left_c+1023); HU_slice=int16(HU_slice); % convert into 16-bit catch outputArg=4; return end % Create '.tif' file file_name_tif=[SCase.id '.tif']; t = Tiff(fullfile(Folder,file_name_tif),'w'); setTag(t,'Photometric',Tiff.Photometric.MinIsBlack); setTag(t,'Compression',Tiff.Compression.None); setTag(t,'BitsPerSample',16); setTag(t,'SamplesPerPixel',1); setTag(t,'ImageLength',1024); setTag(t,'ImageWidth',1024); setTag(t,'PlanarConfiguration',Tiff.PlanarConfiguration.Chunky); setTag(t,'SampleFormat',Tiff.SampleFormat.Int); write(t,HU_slice); close(t); % Create 8 bit '.png' file and save it at the right places % (matlab folder and python's input folder) file_name_png=[SCase.id '.png']; HU_slice_8_bit=uint8(HU_slice_8_bit); figure('visible','off'); image(HU_slice_8_bit); colormap(gray(256)); try % return case's number if does not manage to write png in the "matlab" folder because it is a black image imwrite(HU_slice_8_bit,[Folder '/' file_name_png]); catch outputArg=5; return end - pythonDir = ConfigFileExtractor.getVariable('pythonDir'); + pythonDir = getConfig("convertTextToString", false).pythonDir; Folder_input_py= [pythonDir '/input']; imwrite(HU_slice_8_bit,[Folder_input_py '/' file_name_png]); % write png file in the python input folder % imwrite(HU_slice_8_bit,['./rcseg/' file_name_png]); % write png file in local /rceg folder % Create .txt file with pixel dimensions file_name_info=[SCase.id '.info']; text1='# Amira Stacked Slices' ; text2=['pixelsize ', num2str(NewPixSize_x),' ',num2str(NewPixSize_y)]; fileID = fopen([Folder '/' file_name_info],'w'); fprintf(fileID,'%s\r\n\r\n',text1); fprintf(fileID,'%s\n',text2); fclose(fileID); close all; sliceName = "rotatorCuffNathan"; imwrite(HU_slice_8_bit,fullfile(obj.dataSlicesPath,sliceName + "_ForSegmentation.png")); imageForMeasurements = HU_slice; save(fullfile(obj.dataSlicesPath,sliceName + "_ForMeasurements.mat"),'imageForMeasurements'); imagesPixelSpacings = [NewPixSize_x NewPixSize_y]; save(fullfile(obj.dataSlicesPath,sliceName + "_PixelSpacings.mat"),'imagesPixelSpacings'); end diff --git a/ShoulderCase/@RotatorCuff/segmentMuscles.m b/ShoulderCase/@RotatorCuff/segmentMuscles.m index 302f293..3f0c082 100644 --- a/ShoulderCase/@RotatorCuff/segmentMuscles.m +++ b/ShoulderCase/@RotatorCuff/segmentMuscles.m @@ -1,64 +1,64 @@ function segmentMuscles(obj, sliceName, maskName) % sliceName is the part before the '_ForSegmentation.png' part of the name of % the file that is sent to rcseg. % maskName is the part before the '_Mask.png' part of the name of % the file that is saved in the SCase folder. cleanRotatorCuffSegmentationWorkspace(obj); sendImageToRotatorCuffSegmentationWorkspace(obj,sliceName); callRotatorCuffSegmentation(obj); saveSegmentationResults(obj,maskName); cleanRotatorCuffSegmentationWorkspace(obj); end function cleanRotatorCuffSegmentationWorkspace(obj) - rotatorCuffSegmentationPath = ConfigFileExtractor.getVariable('pythonDir'); + rotatorCuffSegmentationPath = getConfig().pythonDir; delete(fullfile(rotatorCuffSegmentationPath,'input','*')); delete(fullfile(rotatorCuffSegmentationPath,'IS','*')); delete(fullfile(rotatorCuffSegmentationPath,'SC','*')); delete(fullfile(rotatorCuffSegmentationPath,'SS','*')); delete(fullfile(rotatorCuffSegmentationPath,'TM','*')); end function sendImageToRotatorCuffSegmentationWorkspace(obj,sliceName) SCase = obj.shoulder.SCase; - rotatorCuffSegmentationPath = ConfigFileExtractor.getVariable('pythonDir'); + rotatorCuffSegmentationPath = getConfig().pythonDir; imageForSegmentationPath = fullfile(obj.dataSlicesPath,sliceName + "_ForSegmentation.png"); copyfile(imageForSegmentationPath,fullfile(rotatorCuffSegmentationPath,'input',[SCase.id '.png'])); end function callRotatorCuffSegmentation(obj) %% Apply UNIBE method to automatically segment normal muscle - pythonDir = ConfigFileExtractor.getVariable('pythonDir'); + pythonDir = getConfig().pythonDir; pythonCommandActivateEnvironment= ['source ' fullfile(pythonDir,'venv','bin','activate') ';']; pythonCommandMoveToSegmentationWorkspace = ['cd ' pythonDir ';']; pythonCommandExecuteSegmentation = [fullfile(pythonDir,'rcseg.py') ' segment input' ';']; [~, pythonCommandOutput] = system([pythonCommandActivateEnvironment,... pythonCommandMoveToSegmentationWorkspace,... pythonCommandExecuteSegmentation]); disp(pythonCommandOutput); end function saveSegmentationResults(obj,maskName) SCaseID = obj.shoulder.SCase.id; - rotatorCuffSegmentationPath = ConfigFileExtractor.getVariable('pythonDir'); + rotatorCuffSegmentationPath = getConfig().pythonDir; for muscleName = ["SC", "SS", "IS", "TM"] try copyfile(fullfile(rotatorCuffSegmentationPath,muscleName,SCaseID + ".png"),... fullfile(obj.(muscleName).dataMaskPath,maskName + "_Mask.png") ); catch ME warning(ME.message) end end end diff --git a/ShoulderCase/@SCaseIDParser/SCaseIDParser.m b/ShoulderCase/@SCaseIDParser/SCaseIDParser.m index 3cb9959..fdb5f51 100644 --- a/ShoulderCase/@SCaseIDParser/SCaseIDParser.m +++ b/ShoulderCase/@SCaseIDParser/SCaseIDParser.m @@ -1,84 +1,84 @@ classdef SCaseIDParser < handle % Used to validate shoulder case ID. % Check the shoulder case type (first character of the ID). % Check the shoulder case number (last characters) % % Can give the shoulder case ID with filled digits. % This has been implemented to give ShoulderCase.id4c. properties (Access = private) maxDigits SCaseValidTypes rawID end methods function obj = SCaseIDParser(rawID) if isstring(rawID) rawID = convertStringsToChars(rawID); end obj.rawID = rawID; assert(ischar(rawID),'Input argument must be a char array.'); - obj.maxDigits = ConfigFileExtractor.getVariable('maxSCaseIDDigits'); + obj.maxDigits = getConfig().maxSCaseIDDigits; assert(not(isempty(obj.maxDigits)),'maxDigits property is empty'); - obj.SCaseValidTypes = ConfigFileExtractor.getVariable('SCaseIDValidTypes'); + obj.SCaseValidTypes = getConfig().SCaseIDValidTypes; assert(not(isempty(obj.SCaseValidTypes)),'SCaseValidTypes property is empty'); end function output = isValidID(obj) types = obj.SCaseValidTypes; maxDigits = obj.maxDigits; output = obj.SCaseIDHasTypesAndMaxDigits(types,maxDigits); end function output = isNormalCase(obj) types = 'N'; maxDigits = obj.maxDigits; output = obj.SCaseIDHasTypesAndMaxDigits(types,maxDigits); end function output = isPathologicalCase(obj) types = 'P'; maxDigits = obj.maxDigits; output = obj.SCaseIDHasTypesAndMaxDigits(types,maxDigits); end function output = getID(obj) output = obj.rawID; end function output = getIDWithNumberOfDigits(obj,size) assert(obj.isValidID,'%s is not a valid ID.',obj.getID); type = obj.getCaseType; number = obj.getCaseNumber; fillingZeros = repmat('0',1,size-length(number)); output = [type fillingZeros number]; end end methods (Access = private) function output = SCaseIDHasTypesAndMaxDigits(obj,types,maxDigits) expression = ['^[' types ']\d{1,' num2str(maxDigits) '}$']; output = obj.textMatchesExpression(obj.rawID,expression); end function output = getCaseType(obj) output = obj.rawID(1); end function output = getCaseNumber(obj) output = obj.rawID(2:end); end end end diff --git a/ShoulderCase/@ShoulderCase/ShoulderCase.m b/ShoulderCase/@ShoulderCase/ShoulderCase.m index 9703be5..a839c54 100755 --- a/ShoulderCase/@ShoulderCase/ShoulderCase.m +++ b/ShoulderCase/@ShoulderCase/ShoulderCase.m @@ -1,843 +1,843 @@ classdef ShoulderCase < handle % Properties and methods associated to the SoulderCase object. % Author: Alexandre Terrier, EPFL-LBO % Matthieu Boubat, EPFL-LBO % Creation date: 2018-07-01 % Revision date: 2020-07-23 % TODO: % Need method to load properties (from amira, matlab, excel, SQL) % Need method to save properties (in matlab, excel, SQL) % Remove datapath from constants % properties id = []; % id of the shoulder case, as it appears in the database (Pnnn) id4C = []; % SCaseId with P/N followed by 3 digits --> 4 char diagnosis = []; treatment = []; outcome = []; patient = []; shoulderManual = []; shoulderAuto = []; study = []; comment = []; dataCTPath = []; end methods (Access = ?ShoulderCaseLoader) function obj = ShoulderCase(SCaseID,dataCTPath) % SCaseID validation rawSCaseID = SCaseIDParser(SCaseID); assert(rawSCaseID.isValidID,'The input argument is not a valid SCaseID.') obj.id = SCaseID; obj.id4C = rawSCaseID.getIDWithNumberOfDigits(3); % path attribution obj.dataCTPath = dataCTPath; % Folder creation if not(isfolder(obj.dataMatlabPath)) mkdir(obj.dataMatlabPath); end % Initialsation obj.patient = Patient(obj); obj.shoulderManual = ShoulderManual(obj); obj.shoulderAuto = ShoulderAuto(obj); end end methods function output = dataPath(obj) output = fileparts(obj.dataCTPath); end function output = dataAmiraPath(obj) output = fullfile(obj.dataCTPath, "amira"); end function output = dataMatlabPath(obj) output = fullfile(obj.dataCTPath, "matlab"); end function output = dataDicomPath(obj) output = fullfile(obj.dataCTPath, "dicom"); end function output = dataSlicerPath(obj) output = fullfile(obj.dataCTPath, "slicer"); end function outputArg = output(obj, varargin) % Below is copy/past from previous version % This function is used to output the variable Results, used % by scapula_measurePKG the modified funcion scapula_measure. % inputArg could be as in scapula_calculation % 'density', 'References', 'obliqueSlice', 'display' Result.SCase_id = obj.id; % 1 Result.glenoid_Radius = obj.shoulderManual.scapula.glenoid.radius; % 2 Result.glenoid_radiusRMSE = obj.shoulderManual.scapula.glenoid.fittedSphere.RMSE; % 3 % 3 %Result.glenoidSphericity = ' '; %Result.glenoid_biconcave = ' '; Result.glenoid_depth = obj.shoulderManual.scapula.glenoid.depth; % 4 Result.glenoid_width = obj.shoulderManual.scapula.glenoid.width; % 5 Result.glenoid_height = obj.shoulderManual.scapula.glenoid.height; % 6 Result.glenoid_center_PA = obj.shoulderManual.scapula.glenoid.centerLocal(1); % 7 Result.glenoid_center_IS = obj.shoulderManual.scapula.glenoid.centerLocal(2); % 8 Result.glenoid_center_ML = obj.shoulderManual.scapula.glenoid.centerLocal(3); % 9 Result.glenoid_version_ampl = obj.shoulderManual.scapula.glenoid.versionAmplitude; % 10 Result.glenoid_version_orient = obj.shoulderManual.scapula.glenoid.versionOrientation; % 11 Result.glenoid_Version = obj.shoulderManual.scapula.glenoid.version; % 12 Result.glenoid_Inclination = obj.shoulderManual.scapula.glenoid.inclination; % 13 Result.humerus_joint_radius = ' '; % 14 Result.humeral_head_radius = obj.shoulderManual.humerus.radius; % 15 % Result.humerus_GHsublux_2D = ' '; % Result.humerus_SHsublux_2D = ' '; Result.humerus_GHsubluxation_ampl = obj.shoulderManual.humerus.GHSAmpl; % 16 Result.humerus_GHsubluxation_orient = obj.shoulderManual.humerus.GHSOrient; % 17 Result.humerus_SHsubluxation_ampl = obj.shoulderManual.humerus.SHSAmpl; % 18 Result.humerus_SHsubluxation_orient = obj.shoulderManual.humerus.SHSOrient; % 19 Result.scapula_CSA = obj.shoulderManual.scapula.acromion.criticalShoulderAngle; % radCSA; % 5 Lines below should be updated Result.scapula_CTangle = 0; %CTorientation; %20 Result.scapula_CTangleVersion = 0; % WearPlaneAngle; %21 Result.scapula_CTangleSHS = 0; % SHSPlaneAngle; % 22 Result.scapula_CTangleGHS = 0; % GHSPlaneAngle; % 23 Result.scapula_PlaneRMSE = 0; %PlaneRMSE;%24 Result.scapula_AI = obj.shoulderManual.scapula.acromion.acromionIndex; outputArg = Result; end function outputArg = saveMatlab(obj) % Save SCase to matlab file dir = obj.dataMatlabPath; % Create dir if not exist try if ~exist(dir, 'dir') % create directory if it does not exist mkdir(dir); end catch fprintf('Error creating the matlab directory \n'); % Should be in log end % Save SCase in matlab directoty, in a file named SCaseCNNN.m filename = 'SCase'; filename = fullfile(obj.dataMatlabPath, filename + ".mat"); dataCTPath = obj.dataCTPath; try SCase = obj; % Delete CT path wich must be set when loading/creating the % SCase to avoid messing with paths on different systems. SCase.dataCTPath = []; save(filename, 'SCase'); outputArg = 1; catch fprintf('Error creating SCase matlab file \n'); % Should be in log outputArg = -1; end obj.dataCTPath = dataCTPath; end function outputArg = appendToCSV(obj,filename) % Save SCase to csv file logFid = fopen('log/measureSCase.log', 'a'); - dataDir = ConfigFileExtractor.getVariable('dataDir'); + dataDir = getConfig().dataDir; xlsDir = [dataDir '/Excel/xlsFromMatlab']; fid = fopen([xlsDir '/' filename],'a'); fprintf(fid,[... obj.id ','... % SCase_id obj.shoulderManual.side ','... % shoulder_side num2str(obj.shoulderManual.scapula.glenoid.radius) ','... % glenoid_radius num2str(obj.shoulderManual.scapula.glenoid.fittedSphere.RMSE) ','... % glenoid_sphereRMSE num2str(obj.shoulderManual.scapula.glenoid.depth) ','... % glenoid_depth num2str(obj.shoulderManual.scapula.glenoid.width) ','... % glenoid_width num2str(obj.shoulderManual.scapula.glenoid.height) ','... % glenoid_height num2str(obj.shoulderManual.scapula.glenoid.centerLocal.x) ','... % glenoid_centerPA num2str(obj.shoulderManual.scapula.glenoid.centerLocal.y) ','... % glenoid_centerIS num2str(obj.shoulderManual.scapula.glenoid.centerLocal.z) ','... % glenoid_centerML num2str(obj.shoulderManual.scapula.glenoid.versionAmplitude) ','... % glenoid_versionAmpl num2str(obj.shoulderManual.scapula.glenoid.versionOrientation) ','... % glenoid_versionOrientation num2str(obj.shoulderManual.scapula.glenoid.version) ','... % glenoid_version num2str(obj.shoulderManual.scapula.glenoid.inclination) ','... % glenoid_inclination num2str(obj.shoulderManual.humerus.jointRadius) ','... % humerus_jointRadius num2str(obj.shoulderManual.humerus.radius) ','... % humerus_headRadius num2str(obj.shoulderManual.humerus.GHSAmpl) ','... % humerus_GHSAmpl num2str(obj.shoulderManual.humerus.GHSOrient) ','... % humerus_GHSOrient num2str(obj.shoulderManual.humerus.SHSAmpl) ','... % humerus_SHSAmpl num2str(obj.shoulderManual.humerus.SHSOrient) ','... % humerus_SHSOrient num2str(obj.shoulderManual.humerus.SHSAngle) ','... % humerus_SHSAgle num2str(obj.shoulderManual.humerus.SHSPA) ','... % humerus_SHSPA num2str(obj.shoulderManual.humerus.SHSIS) ','... % humerus_SHSIS num2str(obj.shoulderManual.scapula.acromion.AI) ','... % acromion_AI num2str(obj.shoulderManual.scapula.acromion.CSA) ','... % acromion_CSA num2str(obj.shoulderManual.scapula.acromion.PSA) ','... % acromion_PSA num2str(obj.shoulderManual.scapula.acromion.AAA) '\n'... % acromion_AAA ]); fclose(fid); fclose(logFid); outputArg = 1; end function outputArg = saveExcel(~) % Save SCase to Excel file outputArg = 1; end function outputArg = saveSQL(~) % Save SCase to MySQL database outputArg = 1; end function outputArg = SCaseDataToTable(obj, varargin) % This method export all of the measurements and data of a % SCase to a table, wgich then can be used to export all of the % measurements as csv or excel file (see exportSCaseData function) %char(n), nan(a, b) and "" are where the calculations have not %been done. I used these based on the field of data in other %SCases. For examnple where we want char, I used char(nan). Result.SCase_id = obj.id; if isnan(obj.diagnosis) Result.SCase_diagnosis = char(nan); else Result.SCase_diagnosis = obj.diagnosis; end if isempty(obj.treatment) Result.SCase_treatment = char(nan); elseif isnan(obj.treatment) Result.SCase_treatment = char(nan); else Result.SCase_treatment = obj.treatment; end if isempty(obj.outcome) Result.SCase_outcome = char(nan); else Result.SCase_outcome = obj.outcome; end %Result.patient_id = obj.patient.id; %Result.patient_idMed = obj.patient.idMed; Result.patient_gender = obj.patient.gender; Result.patient_age = obj.patient.age; Result.patient_ethnicity = obj.patient.ethnicity; Result.patient_weight = obj.patient.weight; Result.patient_height = obj.patient.height; if isempty(obj.patient.BMI) Result.patient_BMI = nan; elseif obj.patient.BMI(1) == '#' Result.patient_BMI = nan; else Result.patient_BMI = obj.patient.BMI; end Result.patient_comment = obj.patient.comment; %shoulderManual Result.shoulderManual_side = obj.shoulderManual.side; if isempty(obj.shoulderManual.scapula.angulusInferior) Result.shoulderManual_scapula_angulusInferior = nan(1,3); Result.shoulderManual_scapula_angulusInferiorLocal = nan(1,3); Result.shoulderManual_scapula_trigonumSpinae = nan(1,3); Result.shoulderManual_scapula_processusCoracoideus = nan(1,3); Result.shoulderManual_scapula_acromioClavicular = nan(1,3); Result.shoulderManual_scapula_angulusAcromialis = nan(1,3); Result.shoulderManual_scapula_spinoGlenoidNotch = nan(1,3); else Result.shoulderManual_scapula_angulusInferior = obj.shoulderManual().scapula.angulusInferior; Result.shoulderManual_scapula_angulusInferiorLocal = obj.shoulderManual().scapula.angulusInferiorLocal; Result.shoulderManual_scapula_trigonumSpinae = obj.shoulderManual().scapula.trigonumSpinae; Result.shoulderManual_scapula_processusCoracoideus = obj.shoulderManual().scapula.processusCoracoideus; Result.shoulderManual_scapula_acromioClavicular = obj.shoulderManual().scapula.acromioClavicular; Result.shoulderManual_scapula_angulusAcromialis = obj.shoulderManual().scapula.angulusAcromialis; Result.shoulderManual_scapula_spinoGlenoidNotch = obj.shoulderManual().scapula.spinoGlenoidNotch; end if isempty(obj.shoulderManual.scapula.coordSys.ML) Result.shoulderManual_scapula_coordSys_ML = nan(1,3); Result.shoulderManual_scapula_coordSys_PA = nan(1,3); Result.shoulderManual_scapula_coordSys_IS = nan(1,3); Result.shoulderManual_scapula_coordSys_origin = nan(1,3); else Result.shoulderManual_scapula_coordSys_ML = obj.shoulderManual.scapula.coordSys.ML; Result.shoulderManual_scapula_coordSys_PA = obj.shoulderManual.scapula.coordSys.PA; Result.shoulderManual_scapula_coordSys_IS = obj.shoulderManual.scapula.coordSys.IS; Result.shoulderManual_scapula_coordSys_origin = obj.shoulderManual.scapula.coordSys.origin; end if isempty(obj.shoulderManual.scapula.glenoid.center) Result.shoulderManual_scapula_glenoid_center = nan(1,3); Result.shoulderManual_scapula_glenoid_centerLocal_x = nan; Result.shoulderManual_scapula_glenoid_centerLocal_y = nan; Result.shoulderManual_scapula_glenoid_centerLocal_z = nan; Result.shoulderManual_scapula_glenoid_radius = nan; Result.shoulderManual_scapula_glenoid_centerLine = nan(1,3); else Result.shoulderManual_scapula_glenoid_center = obj.shoulderManual.scapula.glenoid.center; Result.shoulderManual_scapula_glenoid_centerLocal_x = obj.shoulderManual.scapula.glenoid.centerLocal.x; Result.shoulderManual_scapula_glenoid_centerLocal_y = obj.shoulderManual.scapula.glenoid.centerLocal.y; Result.shoulderManual_scapula_glenoid_centerLocal_z = obj.shoulderManual.scapula.glenoid.centerLocal.z; Result.shoulderManual_scapula_glenoid_radius = obj.shoulderManual.scapula.glenoid.radius; Result.shoulderManual_scapula_glenoid_centerLine = obj.shoulderManual.scapula.glenoid.centerLine; end if isempty(obj.shoulderManual.scapula.glenoid.depth) Result.shoulderManual_scapula_glenoid_depth = nan; else Result.shoulderManual_scapula_glenoid_depth = obj.shoulderManual.scapula.glenoid.depth; end if isempty(obj.shoulderManual.scapula.glenoid.width) Result.shoulderManual_scapula_glenoid_width = nan; else Result.shoulderManual_scapula_glenoid_width = obj.shoulderManual.scapula.glenoid.width; end if isempty(obj.shoulderManual.scapula.glenoid.height) Result.shoulderManual_scapula_glenoid_height = nan; else Result.shoulderManual_scapula_glenoid_height = obj.shoulderManual.scapula.glenoid.height; end if isempty(obj.shoulderManual.scapula.glenoid.anteroSuperiorAngle) Result.shoulderManual_scapula_glenoid_anteroSuperiorAngle = nan; else Result.shoulderManual_scapula_glenoid_anteroSuperiorAngle = obj.shoulderManual.scapula.glenoid.anteroSuperiorAngle; end if isempty(obj.shoulderManual.scapula.glenoid.versionAmplitude) Result.shoulderManual_scapula_glenoid_versionAmplitude = nan; Result.shoulderManual_scapula_glenoid_versionOrientation = nan; Result.shoulderManual_scapula_glenoid_version = nan; Result.shoulderManual_scapula_glenoid_inclination = nan; else Result.shoulderManual_scapula_glenoid_versionAmplitude = obj.shoulderManual.scapula.glenoid.versionAmplitude; Result.shoulderManual_scapula_glenoid_versionOrientation = obj.shoulderManual.scapula.glenoid.versionOrientation; Result.shoulderManual_scapula_glenoid_version = obj.shoulderManual.scapula.glenoid.version; Result.shoulderManual_scapula_glenoid_inclination = obj.shoulderManual.scapula.glenoid.inclination; end if isempty(obj.shoulderManual.scapula.glenoid.density) Result.shoulderManual_scapula_glenoid_density = nan(1, 6); else Result.shoulderManual_scapula_glenoid_density = obj.shoulderManual.scapula.glenoid.density; end if isempty(obj.shoulderManual.scapula.glenoid.comment) Result.shoulderManual_scapula_glenoid_comment = nan; else Result.shoulderManual_scapula_glenoid_comment = obj.shoulderManual.scapula.glenoid.comment; end if isempty(obj.shoulderManual.scapula.glenoid.fittedSphere.center) Result.shoulderManual_scapula_glenoid_fittedSphere_center = nan(1,3); Result.shoulderManual_scapula_glenoid_fittedSphere_radius = nan; Result.shoulderManual_scapula_glenoid_fittedSphere_R2 = nan; Result.shoulderManual_scapula_glenoid_fittedSphere_RMSE = nan; else Result.shoulderManual_scapula_glenoid_fittedSphere_center = ... obj.shoulderManual.scapula.glenoid.fittedSphere.center; Result.shoulderManual_scapula_glenoid_fittedSphere_radius = ... obj.shoulderManual.scapula.glenoid.fittedSphere.radius; Result.shoulderManual_scapula_glenoid_fittedSphere_R2 = ... obj.shoulderManual.scapula.glenoid.fittedSphere.R2; Result.shoulderManual_scapula_glenoid_fittedSphere_RMSE = ... obj.shoulderManual.scapula.glenoid.fittedSphere.RMSE; end if isempty(obj.shoulderManual.scapula.glenoid.walch) Result.shoulderManual_scapula_glenoid_walch = char(nan); elseif isnan(obj.shoulderManual.scapula.glenoid.walch) Result.shoulderManual_scapula_glenoid_walch = char(nan); else Result.shoulderManual_scapula_glenoid_walch = obj.shoulderManual.scapula.glenoid.walch; end if isempty(obj.shoulderManual.scapula.acromion.AI) Result.shoulderManual_scapula_acromion_AI = nan; Result.shoulderManual_scapula_acromion_CSA = nan; Result.shoulderManual_scapula_acromion_PSA = nan; Result.shoulderManual_scapula_acromion_PSL = nan; Result.shoulderManual_scapula_acromion_AAA = nan; Result.shoulderManual_scapula_acromion_AAL = nan; Result.shoulderManual_scapula_acromion_AAx = nan; Result.shoulderManual_scapula_acromion_AAy = nan; Result.shoulderManual_scapula_acromion_AAz = nan; Result.shoulderManual_scapula_acromion_ACx = nan; Result.shoulderManual_scapula_acromion_ACy = nan; Result.shoulderManual_scapula_acromion_ACz = nan; else Result.shoulderManual_scapula_acromion_AI = obj.shoulderManual.scapula.acromion.AI; Result.shoulderManual_scapula_acromion_CSA = obj.shoulderManual.scapula.acromion.CSA; Result.shoulderManual_scapula_acromion_PSA = obj.shoulderManual.scapula.acromion.PSA; Result.shoulderManual_scapula_acromion_PSL = obj.shoulderManual.scapula.acromion.PSL; Result.shoulderManual_scapula_acromion_AAA = obj.shoulderManual.scapula.acromion.AAA; Result.shoulderManual_scapula_acromion_AAL = obj.shoulderManual.scapula.acromion.AAL; Result.shoulderManual_scapula_acromion_AAx = obj.shoulderManual.scapula.acromion.AAx; Result.shoulderManual_scapula_acromion_AAy = obj.shoulderManual.scapula.acromion.AAy; Result.shoulderManual_scapula_acromion_AAz = obj.shoulderManual.scapula.acromion.AAz; Result.shoulderManual_scapula_acromion_ACx = obj.shoulderManual.scapula.acromion.ACx; Result.shoulderManual_scapula_acromion_ACy = obj.shoulderManual.scapula.acromion.ACy; Result.shoulderManual_scapula_acromion_ACz = obj.shoulderManual.scapula.acromion.ACz; end if isempty(obj.shoulderManual.humerus.center) Result.shoulderManual_humerus_center = nan(1,3); Result.shoulderManual_humerus_radius = nan; else Result.shoulderManual_humerus_center = obj.shoulderManual.humerus.center; Result.shoulderManual_humerus_radius = obj.shoulderManual.humerus.radius; end if isempty(obj.shoulderManual.humerus.jointRadius) Result.shoulderManual_humerus_jointRadius = nan; else Result.shoulderManual_humerus_jointRadius = obj.shoulderManual.humerus.jointRadius; end if isempty(obj.shoulderManual.humerus.SHSAngle) Result.shoulderManual_humerus_SHSAngle = nan; Result.shoulderManual_humerus_SHSPA = nan; Result.shoulderManual_humerus_SHSIS = nan; Result.shoulderManual_humerus_SHSAmpl = nan; Result.shoulderManual_humerus_SHSOrient = nan; Result.shoulderManual_humerus_GHSAmpl = nan; Result.shoulderManual_humerus_GHSOrient = nan; else Result.shoulderManual_humerus_SHSAngle = obj.shoulderManual.humerus.SHSAngle; Result.shoulderManual_humerus_SHSPA = obj.shoulderManual.humerus.SHSPA; Result.shoulderManual_humerus_SHSIS = obj.shoulderManual.humerus.SHSIS; Result.shoulderManual_humerus_SHSAmpl = obj.shoulderManual.humerus.SHSAmpl; Result.shoulderManual_humerus_SHSOrient = obj.shoulderManual.humerus.SHSOrient; Result.shoulderManual_humerus_GHSAmpl = obj.shoulderManual.humerus.GHSAmpl; Result.shoulderManual_humerus_GHSOrient = obj.shoulderManual.humerus.GHSOrient; end if isempty(obj.shoulderManual.rotatorCuff) Result.shoulderManual_muscles_IS_segmentationSet = char(nan); Result.shoulderManual_muscles_IS_sliceName = char(nan); Result.shoulderManual_muscles_IS_PCSA = ""; Result.shoulderManual_muscles_IS_atrophy = ""; Result.shoulderManual_muscles_IS_fat = ""; Result.shoulderManual_muscles_IS_osteochondroma = ""; Result.shoulderManual_muscles_IS_degeneration = ""; Result.shoulderManual_muscles_SS_segmentationSet = char(nan); Result.shoulderManual_muscles_SS_sliceName = char(nan); Result.shoulderManual_muscles_SS_PCSA = ""; Result.shoulderManual_muscles_SS_atrophy = ""; Result.shoulderManual_muscles_SS_fat = ""; Result.shoulderManual_muscles_SS_osteochondroma = ""; Result.shoulderManual_muscles_SS_degeneration = ""; Result.shoulderManual_muscles_SC_segmentationSet = char(nan); Result.shoulderManual_muscles_SC_sliceName = char(nan); Result.shoulderManual_muscles_SC_PCSA = ""; Result.shoulderManual_muscles_SC_atrophy = ""; Result.shoulderManual_muscles_SC_fat = ""; Result.shoulderManual_muscles_SC_osteochondroma = ""; Result.shoulderManual_muscles_SC_degeneration = ""; Result.shoulderManual_muscles_TM_segmentationSet = char(nan); Result.shoulderManual_muscles_TM_sliceName = char(nan); Result.shoulderManual_muscles_TM_PCSA = ""; Result.shoulderManual_muscles_TM_atrophy = ""; Result.shoulderManual_muscles_TM_fat = ""; Result.shoulderManual_muscles_TM_osteochondroma = ""; Result.shoulderManual_muscles_TM_degeneration = ""; else try Result.shoulderManual_muscles_IS_segmentationSet = obj.shoulderManual.rotatorCuff.IS.segmentationSet; Result.shoulderManual_muscles_IS_sliceName = obj.shoulderManual.rotatorCuff.IS.sliceName; Result.shoulderManual_muscles_IS_PCSA = obj.shoulderManual.rotatorCuff.IS.PCSA; Result.shoulderManual_muscles_IS_atrophy = obj.shoulderManual.rotatorCuff.IS.atrophy; Result.shoulderManual_muscles_IS_fat = obj.shoulderManual.rotatorCuff.IS.fat; Result.shoulderManual_muscles_IS_osteochondroma = obj.shoulderManual.rotatorCuff.IS.osteochondroma; Result.shoulderManual_muscles_IS_degeneration = obj.shoulderManual.rotatorCuff.IS.degeneration; Result.shoulderManual_muscles_SS_segmentationSet = obj.shoulderManual.rotatorCuff.SS.segmentationSet; Result.shoulderManual_muscles_SS_sliceName = obj.shoulderManual.rotatorCuff.SS.sliceName; Result.shoulderManual_muscles_SS_PCSA = obj.shoulderManual.rotatorCuff.SS.PCSA; if isempty(obj.shoulderManual.rotatorCuff.SS.atrophy) Result.shoulderManual_muscles_SS_atrophy = nan; else Result.shoulderManual_muscles_SS_atrophy = obj.shoulderManual.rotatorCuff.SS.atrophy; end if isempty(obj.shoulderManual.rotatorCuff.SS.fat) Result.shoulderManual_muscles_SS_fat = nan; else Result.shoulderManual_muscles_SS_fat = obj.shoulderManual.rotatorCuff.SS.fat; end if isempty(obj.shoulderManual.rotatorCuff.SS.osteochondroma) Result.shoulderManual_muscles_SS_osteochondroma = nan; else Result.shoulderManual_muscles_SS_osteochondroma = obj.shoulderManual.rotatorCuff.SS.osteochondroma; end if isempty(obj.shoulderManual.rotatorCuff.SS.degeneration) Result.shoulderManual_muscles_SS_degeneration = nan; else Result.shoulderManual_muscles_SS_degeneration = obj.shoulderManual.rotatorCuff.SS.degeneration; end Result.shoulderManual_muscles_SC_segmentationSet = obj.shoulderManual.rotatorCuff.SC.segmentationSet; Result.shoulderManual_muscles_SC_sliceName = obj.shoulderManual.rotatorCuff.SC.sliceName; Result.shoulderManual_muscles_SC_PCSA = obj.shoulderManual.rotatorCuff.SC.PCSA; Result.shoulderManual_muscles_SC_atrophy = obj.shoulderManual.rotatorCuff.SC.atrophy; Result.shoulderManual_muscles_SC_fat = obj.shoulderManual.rotatorCuff.SC.fat; Result.shoulderManual_muscles_SC_osteochondroma = obj.shoulderManual.rotatorCuff.SC.osteochondroma; Result.shoulderManual_muscles_SC_degeneration = obj.shoulderManual.rotatorCuff.SC.degeneration; Result.shoulderManual_muscles_TM_segmentationSet = obj.shoulderManual.rotatorCuff.TM.segmentationSet; Result.shoulderManual_muscles_TM_sliceName = obj.shoulderManual.rotatorCuff.TM.sliceName; Result.shoulderManual_muscles_TM_PCSA = obj.shoulderManual.rotatorCuff.TM.PCSA; if isempty(obj.shoulderManual.rotatorCuff.TM.atrophy) Result.shoulderManual_muscles_TM_atrophy = nan; else Result.shoulderManual_muscles_TM_atrophy = obj.shoulderManual.rotatorCuff.TM.atrophy; end if isempty(obj.shoulderManual.rotatorCuff.TM.fat) Result.shoulderManual_muscles_TM_fat = nan; else Result.shoulderManual_muscles_TM_fat = obj.shoulderManual.rotatorCuff.TM.fat; end if isempty(obj.shoulderManual.rotatorCuff.TM.osteochondroma) Result.shoulderManual_muscles_TM_osteochondroma = nan; else Result.shoulderManual_muscles_TM_osteochondroma = obj.shoulderManual.rotatorCuff.TM.osteochondroma; end if isempty(obj.shoulderManual.rotatorCuff.TM.degeneration) Result.shoulderManual_muscles_TM_degeneration = nan; else Result.shoulderManual_muscles_TM_degeneration = obj.shoulderManual.rotatorCuff.TM.degeneration; end catch Result.shoulderManual_muscles_IS_segmentationSet = 0; Result.shoulderManual_muscles_IS_sliceName = 0; Result.shoulderManual_muscles_IS_PCSA = 0; Result.shoulderManual_muscles_IS_atrophy = 0; Result.shoulderManual_muscles_IS_fat = 0; Result.shoulderManual_muscles_IS_osteochondroma = 0; Result.shoulderManual_muscles_IS_degeneration = 0; Result.shoulderManual_muscles_SS_segmentationSet = 0; Result.shoulderManual_muscles_SS_sliceName = 0; Result.shoulderManual_muscles_SS_PCSA = 0; Result.shoulderManual_muscles_SS_atrophy = 0; Result.shoulderManual_muscles_SS_fat = 0; Result.shoulderManual_muscles_SS_osteochondroma = 0; Result.shoulderManual_muscles_SS_degeneration = 0; Result.shoulderManual_muscles_SC_segmentationSet = 0; Result.shoulderManual_muscles_SC_sliceName = 0; Result.shoulderManual_muscles_SC_PCSA = 0; Result.shoulderManual_muscles_SC_atrophy = 0; Result.shoulderManual_muscles_SC_fat = 0; Result.shoulderManual_muscles_SC_osteochondroma = 0; Result.shoulderManual_muscles_SC_degeneration = 0; Result.shoulderManual_muscles_TM_segmentationSet = 0; Result.shoulderManual_muscles_TM_sliceName = 0; Result.shoulderManual_muscles_TM_PCSA = 0; Result.shoulderManual_muscles_TM_atrophy = 0; Result.shoulderManual_muscles_TM_fat = 0; Result.shoulderManual_muscles_TM_osteochondroma = 0; Result.shoulderManual_muscles_TM_degeneration = 0; end end Result.shoulderAuto_side = obj.shoulderAuto().side; if isempty(obj.shoulderAuto().scapula.angulusInferior) Result.shoulderAuto_scapula_angulusInferior = nan(1,3); else Result.shoulderAuto_scapula_angulusInferior = obj.shoulderAuto().scapula.angulusInferior; end if isempty(obj.shoulderAuto().scapula.angulusInferiorLocal) Result.shoulderAuto_scapula_angulusInferiorLocal = nan(1,3); else Result.shoulderAuto_scapula_angulusInferiorLocal = obj.shoulderAuto().scapula.angulusInferiorLocal; end if isempty(obj.shoulderAuto().scapula.trigonumSpinae) Result.shoulderAuto_scapula_trigonumSpinae = nan(1,3); else Result.shoulderAuto_scapula_trigonumSpinae = obj.shoulderAuto().scapula.trigonumSpinae; end if isempty(obj.shoulderAuto().scapula.processusCoracoideus) Result.shoulderAuto_scapula_processusCoracoideus = nan(1,3); Result.shoulderAuto_scapula_acromioClavicular = nan(1,3); Result.shoulderAuto_scapula_angulusAcromialis = nan(1,3); Result.shoulderAuto_scapula_spinoGlenoidNotch = nan(1,3); else Result.shoulderAuto_scapula_processusCoracoideus = obj.shoulderAuto.scapula.processusCoracoideus; Result.shoulderAuto_scapula_acromioClavicular = obj.shoulderAuto.scapula.acromioClavicular; Result.shoulderAuto_scapula_angulusAcromialis = obj.shoulderAuto.scapula.angulusAcromialis; Result.shoulderAuto_scapula_spinoGlenoidNotch = obj.shoulderAuto.scapula.spinoGlenoidNotch; end if isempty(obj.shoulderAuto.scapula.coordSys.ML) Result.shoulderAuto_scapula_coordSys_ML = nan(1,3); else Result.shoulderAuto_scapula_coordSys_ML = obj.shoulderAuto.scapula.coordSys.ML; end if isempty(obj.shoulderAuto.scapula.coordSys.PA) Result.shoulderAuto_scapula_coordSys_PA = nan(1,3); else Result.shoulderAuto_scapula_coordSys_PA = obj.shoulderAuto.scapula.coordSys.PA; end if isempty(obj.shoulderAuto.scapula.coordSys.IS) Result.shoulderAuto_scapula_coordSys_IS = nan(1,3); else Result.shoulderAuto_scapula_coordSys_IS= obj.shoulderAuto.scapula.coordSys.IS; end if isempty(obj.shoulderAuto.scapula.coordSys.origin) Result.shoulderAuto_scapula_coordSys_origin = nan(1,3); else Result.shoulderAuto_scapula_coordSys_origin = obj.shoulderAuto.scapula.coordSys.origin; end if isempty(obj.shoulderAuto.scapula.glenoid.center) Result.shoulderAuto_scapula_glenoid_center = nan(1,3); Result.shoulderAuto_scapula_glenoid_centerLocal_x = nan; Result.shoulderAuto_scapula_glenoid_centerLocal_y = nan; Result.shoulderAuto_scapula_glenoid_centerLocal_z = nan; Result.shoulderAuto_scapula_glenoid_radius = nan; Result.shoulderAuto_scapula_glenoid_centerLine = nan(1,3); Result.shoulderAuto_scapula_glenoid_depth = nan; Result.shoulderAuto_scapula_glenoid_width = nan; Result.shoulderAuto_scapula_glenoid_height = nan; Result.shoulderAuto_scapula_glenoid_anteroSuperiorAngle = nan; Result.shoulderAuto_scapula_glenoid_versionAmplitude = nan; Result.shoulderAuto_scapula_glenoid_versionOrientation = nan; Result.shoulderAuto_scapula_glenoid_version = nan; Result.shoulderAuto_scapula_glenoid_inclination = nan; else Result.shoulderAuto_scapula_glenoid_center = obj.shoulderAuto.scapula.glenoid.center; Result.shoulderAuto_scapula_glenoid_centerLocal_x = obj.shoulderAuto.scapula.glenoid.centerLocal.x; Result.shoulderAuto_scapula_glenoid_centerLocal_y = obj.shoulderAuto.scapula.glenoid.centerLocal.y; Result.shoulderAuto_scapula_glenoid_centerLocal_z = obj.shoulderAuto.scapula.glenoid.centerLocal.z; Result.shoulderAuto_scapula_glenoid_radius = obj.shoulderAuto.scapula.glenoid.radius; Result.shoulderAuto_scapula_glenoid_centerLine = obj.shoulderAuto.scapula.glenoid.centerLine; Result.shoulderAuto_scapula_glenoid_depth = obj.shoulderAuto.scapula.glenoid.depth; Result.shoulderAuto_scapula_glenoid_width = obj.shoulderAuto.scapula.glenoid.width; Result.shoulderAuto_scapula_glenoid_height = obj.shoulderAuto.scapula.glenoid.height; Result.shoulderAuto_scapula_glenoid_anteroSuperiorAngle = obj.shoulderAuto.scapula.glenoid.anteroSuperiorAngle; Result.shoulderAuto_scapula_glenoid_versionAmplitude = obj.shoulderAuto.scapula.glenoid.versionAmplitude; Result.shoulderAuto_scapula_glenoid_versionOrientation = obj.shoulderAuto.scapula.glenoid.versionOrientation; Result.shoulderAuto_scapula_glenoid_version = obj.shoulderAuto.scapula.glenoid.version; Result.shoulderAuto_scapula_glenoid_inclination = obj.shoulderAuto.scapula.glenoid.inclination; end if isempty(obj.shoulderAuto.scapula.glenoid.density) Result.shoulderAuto_scapula_glenoid_density = nan(1, 6); else Result.shoulderAuto_scapula_glenoid_density = obj.shoulderAuto.scapula.glenoid.density; end if isempty(obj.shoulderAuto.scapula.glenoid.comment) Result.shoulderAuto_scapula_glenoid_comment = nan; else Result.shoulderAuto_scapula_glenoid_comment = obj.shoulderAuto.scapula.glenoid.comment; end if isempty(obj.shoulderAuto.scapula.glenoid.fittedSphere.center) Result.shoulderAuto_scapula_glenoid_fittedSphere_center = nan(1,3); Result.shoulderAuto_scapula_glenoid_fittedSphere_radius = nan; Result.shoulderAuto_scapula_glenoid_fittedSphere_R2 = nan; Result.shoulderAuto_scapula_glenoid_fittedSphere_RMSE = nan; else Result.shoulderAuto_scapula_glenoid_fittedSphere_center = ... obj.shoulderAuto.scapula.glenoid.fittedSphere.center; Result.shoulderAuto_scapula_glenoid_fittedSphere_radius = ... obj.shoulderAuto.scapula.glenoid.fittedSphere.radius; Result.shoulderAuto_scapula_glenoid_fittedSphere_R2 = ... obj.shoulderAuto.scapula.glenoid.fittedSphere.R2; Result.shoulderAuto_scapula_glenoid_fittedSphere_RMSE = ... obj.shoulderAuto.scapula.glenoid.fittedSphere.RMSE; end if isempty(obj.shoulderAuto.scapula.glenoid.walch) Result.shoulderAuto_scapula_glenoid_walch = char(nan); elseif isnan(obj.shoulderAuto.scapula.glenoid.walch) Result.shoulderAuto_scapula_glenoid_walch = char(nan); else Result.shoulderAuto_scapula_glenoid_walch = obj.shoulderAuto.scapula.glenoid.walch; end if isempty(obj.shoulderAuto.scapula.acromion.AI) Result.shoulderAuto_scapula_acromion_AI = nan; Result.shoulderAuto_scapula_acromion_CSA = nan; Result.shoulderAuto_scapula_acromion_PSA = nan; Result.shoulderAuto_scapula_acromion_PSL = nan; Result.shoulderAuto_scapula_acromion_AAA = nan; Result.shoulderAuto_scapula_acromion_AAL = nan; Result.shoulderAuto_scapula_acromion_AAx = nan; Result.shoulderAuto_scapula_acromion_AAy = nan; Result.shoulderAuto_scapula_acromion_AAz = nan; Result.shoulderAuto_scapula_acromion_ACx = nan; Result.shoulderAuto_scapula_acromion_ACy = nan; Result.shoulderAuto_scapula_acromion_ACz = nan; else Result.shoulderAuto_scapula_acromion_AI = obj.shoulderAuto.scapula.acromion.AI; Result.shoulderAuto_scapula_acromion_CSA = obj.shoulderAuto.scapula.acromion.CSA; Result.shoulderAuto_scapula_acromion_PSA = obj.shoulderAuto.scapula.acromion.PSA; Result.shoulderAuto_scapula_acromion_PSL = obj.shoulderAuto.scapula.acromion.PSL; Result.shoulderAuto_scapula_acromion_AAA = obj.shoulderAuto.scapula.acromion.AAA; Result.shoulderAuto_scapula_acromion_AAL = obj.shoulderAuto.scapula.acromion.AAL; Result.shoulderAuto_scapula_acromion_AAx = obj.shoulderAuto.scapula.acromion.AAx; Result.shoulderAuto_scapula_acromion_AAy = obj.shoulderAuto.scapula.acromion.AAy; Result.shoulderAuto_scapula_acromion_AAz = obj.shoulderAuto.scapula.acromion.AAz; Result.shoulderAuto_scapula_acromion_ACx = obj.shoulderAuto.scapula.acromion.ACx; Result.shoulderAuto_scapula_acromion_ACy = obj.shoulderAuto.scapula.acromion.ACy; Result.shoulderAuto_scapula_acromion_ACz = obj.shoulderAuto.scapula.acromion.ACz; end if isempty(obj.shoulderAuto.scapula.glenoid.center) Result.shoulderAuto_humerus_center = nan(1,3); Result.shoulderAuto_humerus_radius = nan; else Result.shoulderAuto_humerus_center = obj.shoulderAuto.scapula.glenoid.center; Result.shoulderAuto_humerus_radius = obj.shoulderAuto.scapula.glenoid.radius; end if isempty(obj.shoulderAuto.scapula.glenoid.comment) Result.shoulderAuto_humerus_jointRadius = nan; else Result.shoulderAuto_humerus_jointRadius = obj.shoulderAuto.scapula.glenoid.comment; end if isempty(obj.shoulderAuto.humerus.SHSAngle) Result.shoulderAuto_humerus_SHSAngle = nan; Result.shoulderAuto_humerus_SHSPA = nan; Result.shoulderAuto_humerus_SHSIS = nan; Result.shoulderAuto_humerus_SHSAmpl = nan; Result.shoulderAuto_humerus_SHSOrient = nan; Result.shoulderAuto_humerus_GHSAmpl = nan; Result.shoulderAuto_humerus_GHSOrient = nan; Result.shoulderAuto_humerus_GHSAmpl = nan; else Result.shoulderAuto_humerus_SHSAngle = obj.shoulderAuto.humerus.SHSAngle; Result.shoulderAuto_humerus_SHSPA = obj.shoulderAuto.humerus.SHSPA; Result.shoulderAuto_humerus_SHSIS = obj.shoulderAuto.humerus.SHSIS; Result.shoulderAuto_humerus_SHSAmpl = obj.shoulderAuto.humerus.SHSAmpl; Result.shoulderAuto_humerus_SHSOrient = obj.shoulderAuto.humerus.SHSOrient; Result.shoulderAuto_humerus_GHSAmpl = obj.shoulderAuto.humerus.GHSAmpl; Result.shoulderAuto_humerus_GHSOrient = obj.shoulderAuto.humerus.GHSOrient; Result.shoulderAuto_humerus_GHSAmpl = obj.shoulderAuto.humerus.GHSAmpl; end try Result.shoulderAuto_muscles_IS_segmentationSet = obj.shoulderAuto.rotatorCuff.IS.segmentationSet; Result.shoulderAuto_muscles_IS_sliceName = obj.shoulderAuto.rotatorCuff.IS.sliceName; Result.shoulderAuto_muscles_IS_PCSA = obj.shoulderAuto.rotatorCuff.IS.PCSA; if isempty(obj.shoulderAuto.rotatorCuff.IS.atrophy) Result.shoulderAuto_muscles_IS_atrophy = nan; else Result.shoulderAuto_muscles_IS_atrophy = obj.shoulderAuto.rotatorCuff.IS.atrophy; end if isempty(obj.shoulderAuto.rotatorCuff.IS.fat) Result.shoulderAuto_muscles_IS_fat = nan; else Result.shoulderAuto_muscles_IS_fat = obj.shoulderAuto.rotatorCuff.IS.fat; end if isempty(obj.shoulderAuto.rotatorCuff.IS.osteochondroma) Result.shoulderAuto_muscles_IS_osteochondroma = nan; else Result.shoulderAuto_muscles_IS_osteochondroma = obj.shoulderAuto.rotatorCuff.IS.osteochondroma; end if isempty(obj.shoulderAuto.rotatorCuff.IS.degeneration) Result.shoulderAuto_muscles_IS_degeneration = nan; else Result.shoulderAuto_muscles_IS_degeneration = obj.shoulderAuto.rotatorCuff.IS.degeneration; end Result.shoulderAuto_muscles_SS_segmentationSet = obj.shoulderAuto.rotatorCuff.SS.segmentationSet; Result.shoulderAuto_muscles_SS_sliceName = obj.shoulderAuto.rotatorCuff.SS.sliceName; Result.shoulderAuto_muscles_SS_PCSA = obj.shoulderAuto.rotatorCuff.SS.PCSA; if isempty(obj.shoulderAuto.rotatorCuff.SS.atrophy) Result.shoulderAuto_muscles_SS_atrophy = nan; else Result.shoulderAuto_muscles_SS_atrophy = obj.shoulderAuto.rotatorCuff.SS.atrophy; end if isempty(obj.shoulderAuto.rotatorCuff.SS.fat) Result.shoulderAuto_muscles_SS_fat = nan; else Result.shoulderAuto_muscles_SS_fat = obj.shoulderAuto.rotatorCuff.SS.fat; end if isempty(obj.shoulderAuto.rotatorCuff.SS.osteochondroma) Result.shoulderAuto_muscles_SS_osteochondroma = nan; else Result.shoulderAuto_muscles_SS_osteochondroma = obj.shoulderAuto.rotatorCuff.SS.osteochondroma; end if isempty(obj.shoulderAuto.rotatorCuff.SS.degeneration) Result.shoulderAuto_muscles_SS_degeneration = nan; else Result.shoulderAuto_muscles_SS_degeneration = obj.shoulderAuto.rotatorCuff.SS.degeneration; end Result.shoulderAuto_muscles_SC_segmentationSet = obj.shoulderAuto.rotatorCuff.SC.segmentationSet; Result.shoulderAuto_muscles_SC_sliceName = obj.shoulderAuto.rotatorCuff.SC.sliceName; Result.shoulderAuto_muscles_SC_PCSA = obj.shoulderAuto.rotatorCuff.SC.PCSA; if isempty(obj.shoulderAuto.rotatorCuff.SC.atrophy) Result.shoulderAuto_muscles_SC_atrophy = nan; else Result.shoulderAuto_muscles_SC_atrophy = obj.shoulderAuto.rotatorCuff.SC.atrophy; end if isempty(obj.shoulderAuto.rotatorCuff.SC.fat) Result.shoulderAuto_muscles_SC_fat = nan; else Result.shoulderAuto_muscles_SC_fat = obj.shoulderAuto.rotatorCuff.SC.fat; end if isempty(obj.shoulderAuto.rotatorCuff.SC.osteochondroma) Result.shoulderAuto_muscles_SC_osteochondroma = nan; else Result.shoulderAuto_muscles_SC_osteochondroma = obj.shoulderAuto.rotatorCuff.SC.osteochondroma; end if isempty(obj.shoulderAuto.rotatorCuff.SC.degeneration) Result.shoulderAuto_muscles_SC_degeneration = nan; else Result.shoulderAuto_muscles_SC_degeneration = obj.shoulderAuto.rotatorCuff.SC.degeneration; end Result.shoulderAuto_muscles_TM_segmentationSet = obj.shoulderAuto.rotatorCuff.TM.segmentationSet; Result.shoulderAuto_muscles_TM_sliceName = obj.shoulderAuto.rotatorCuff.TM.sliceName; Result.shoulderAuto_muscles_TM_PCSA = obj.shoulderAuto.rotatorCuff.TM.PCSA; if isempty(obj.shoulderAuto.rotatorCuff.TM.atrophy) Result.shoulderAuto_muscles_TM_atrophy = nan; else Result.shoulderAuto_muscles_TM_atrophy = obj.shoulderAuto.rotatorCuff.TM.atrophy; end if isempty(obj.shoulderAuto.rotatorCuff.TM.fat) Result.shoulderAuto_muscles_TM_fat = nan; else Result.shoulderAuto_muscles_TM_fat = obj.shoulderAuto.rotatorCuff.TM.fat; end if isempty(obj.shoulderAuto.rotatorCuff.TM.osteochondroma) Result.shoulderAuto_muscles_TM_osteochondroma = nan; else Result.shoulderAuto_muscles_TM_osteochondroma = obj.shoulderAuto.rotatorCuff.TM.osteochondroma; end if isempty(obj.shoulderAuto.rotatorCuff.TM.degeneration) Result.shoulderAuto_muscles_TM_degeneration = nan; else Result.shoulderAuto_muscles_TM_degeneration = obj.shoulderAuto.rotatorCuff.TM.degeneration; end catch ME Result.shoulderAuto_muscles_IS_segmentationSet = char(nan); Result.shoulderAuto_muscles_IS_sliceName = char(nan); Result.shoulderAuto_muscles_IS_PCSA = ""; Result.shoulderAuto_muscles_IS_atrophy = ""; Result.shoulderAuto_muscles_IS_fat = ""; Result.shoulderAuto_muscles_IS_osteochondroma = ""; Result.shoulderAuto_muscles_IS_degeneration = ""; Result.shoulderAuto_muscles_SS_segmentationSet = char(nan); Result.shoulderAuto_muscles_SS_sliceName = char(nan); Result.shoulderAuto_muscles_SS_PCSA = ""; Result.shoulderAuto_muscles_SS_atrophy = ""; Result.shoulderAuto_muscles_SS_fat = ""; Result.shoulderAuto_muscles_SS_osteochondroma = ""; Result.shoulderAuto_muscles_SS_degeneration = ""; Result.shoulderAuto_muscles_SC_segmentationSet = char(nan); Result.shoulderAuto_muscles_SC_sliceName = char(nan); Result.shoulderAuto_muscles_SC_PCSA = ""; Result.shoulderAuto_muscles_SC_atrophy = ""; Result.shoulderAuto_muscles_SC_fat = ""; Result.shoulderAuto_muscles_SC_osteochondroma = ""; Result.shoulderAuto_muscles_SC_degeneration = ""; Result.shoulderAuto_muscles_TM_segmentationSet = char(nan); Result.shoulderAuto_muscles_TM_sliceName = char(nan); Result.shoulderAuto_muscles_TM_PCSA = ""; Result.shoulderAuto_muscles_TM_atrophy = ""; Result.shoulderAuto_muscles_TM_fat = ""; Result.shoulderAuto_muscles_TM_osteochondroma = ""; Result.shoulderAuto_muscles_TM_degeneration = ""; end outputArg = struct2table(Result, 'AsArray', 1); end end end \ No newline at end of file diff --git a/ShoulderCase/@ShoulderCaseLoader/ShoulderCaseLoader.m b/ShoulderCase/@ShoulderCaseLoader/ShoulderCaseLoader.m index 6b82983..4b97126 100644 --- a/ShoulderCase/@ShoulderCaseLoader/ShoulderCaseLoader.m +++ b/ShoulderCase/@ShoulderCaseLoader/ShoulderCaseLoader.m @@ -1,49 +1,49 @@ classdef ShoulderCaseLoader < handle % Class to interact with the database. % % The main purpose of the ShoulderCaseLoader is to % easily load the cases. By initialisation, a % ShoulderCaseLoader instance will set its dataRootPath % property to the dataDir variable found in the % config.txt file. % % Because of cross-systems utilisation of the database % the paths stored in the ShoulderCase instances may % vary from one execution to the other. % Thus, this class evolved to be the access point to % the ShoulderCase constructor, to avoid misusing % the paths. This was also the incentive to create the % ShoulderCase.propagateDataPath() method. % % example: % database = ShoulderCaseLoader() % SCase = database.loadCase('P500'); properties (Access = private) shoulderCasePath = containers.Map; dataRootPath = ''; allCasesFound = false; end methods function obj = ShoulderCaseLoader() try - obj.setDataRootPath(ConfigFileExtractor.getVariable('dataDir')); + obj.setDataRootPath(getConfig().dataDir); end end end methods (Access = private) caseHasBeenFound = findCase(obj,SCaseID); findAllCases(obj); end end \ No newline at end of file diff --git a/ShoulderCase/@ShoulderCaseLoader/findAllCases.m b/ShoulderCase/@ShoulderCaseLoader/findAllCases.m index 1980985..31c1d9f 100644 --- a/ShoulderCase/@ShoulderCaseLoader/findAllCases.m +++ b/ShoulderCase/@ShoulderCaseLoader/findAllCases.m @@ -1,30 +1,30 @@ function findAllCases(obj) if obj.allCasesFound return end - types = ConfigFileExtractor.getVariable('SCaseIDValidTypes'); - maxSCaseNumber = 10^ConfigFileExtractor.getVariable('maxSCaseIDDigits')-1; + types = getConfig().SCaseIDValidTypes; + maxSCaseNumber = 10^(getConfig().maxSCaseIDDigits)-1; progression = UpdatableText('',' All valid cases are being looked for.'); for i = 1:length(types) for j = 1:maxSCaseNumber progression.printPercent(getProgressionFraction(i,j,length(types),maxSCaseNumber)); progression.printProgressBar(getProgressionFraction(i,j,length(types),maxSCaseNumber)); - SCaseID = [types(i) int2str(j)]; + SCaseID = types(i) + int2str(j); try obj.findCase(SCaseID); end end end obj.allCasesFound = true; end function output = getProgressionFraction(i,j,numberOfTypes,maxSCaseNumber) currentNumber = (i-1)*(maxSCaseNumber+1)+j; maxNumber = numberOfTypes*(maxSCaseNumber+1)-1; output = currentNumber/maxNumber; end \ No newline at end of file diff --git a/ShoulderCase/@ShoulderCaseLoader/findCase.m b/ShoulderCase/@ShoulderCaseLoader/findCase.m index fc78d74..6c8e5fc 100644 --- a/ShoulderCase/@ShoulderCaseLoader/findCase.m +++ b/ShoulderCase/@ShoulderCaseLoader/findCase.m @@ -1,29 +1,29 @@ function output = findCase(obj,SCaseID) % Case already found if obj.shoulderCasePath.isKey(SCaseID) output = true; return end output = false; % Format ID to construct the case's path givenID = SCaseIDParser(SCaseID); assert(givenID.isValidID,'%s is not a valid ID.',SCaseID); - SCaseIDmaxDigits = givenID.getIDWithNumberOfDigits(ConfigFileExtractor.getVariable('maxSCaseIDDigits')); + SCaseIDmaxDigits = givenID.getIDWithNumberOfDigits(getConfig().maxSCaseIDDigits); SCasePath = fullfile(obj.dataRootPath,... SCaseIDmaxDigits(1),... % SCaseID type SCaseIDmaxDigits(2),... % SCaseID hundreds SCaseIDmaxDigits(3),... % SCaseID tens string(SCaseID) + "*"); % SCaseID folder whatever the IPP is SCaseFound = dir(SCasePath); if isempty(SCaseFound) return end obj.shoulderCasePath(SCaseID) = fullfile(SCaseFound.folder,SCaseFound.name); output = true; end \ No newline at end of file diff --git a/getConfig.m b/getConfig.m index 81b58a0..81fe9d0 100644 --- a/getConfig.m +++ b/getConfig.m @@ -1,56 +1,62 @@ function output = getConfig(varargin) % Extract config parameters out of a json file. % % Output: Structure resulting from jsondecode() function. % % Inputs: % ("filename", filename) filename is the full path (with file extension) to % the json file to read. % Default: "config.json" % % ("convertTextToString", boolean) MATLAB jsondecode parser automatically % translate text to char arrays. This option replace these char arrays with % strings. % Default: true % % ("parameters", [parameter1, parameter2]) the output structure only contains % the parameters specified in the given string array/scalar. The default value % return all the parameters. % Default: "*" % % Example: % getConfig("filename", "simulationConfig.json",... % "convertTextToString", false,... % "parameters", ["simulationModel" "patientParameters"]); % % Tips: % getConfig("parameters", "foo") % is equivalent to % getConfig().foo options = inputParser; addOptional(options, "filename", "config.json"); addOptional(options, "convertTextToString", true); addOptional(options, "parameters", "*"); parse(options, varargin{:}); options = options.Results; config = jsondecode(fileread(options.filename)); if not(isequal(options.parameters, "*")) allParameters = string(fields(config))'; parametersToRemove = allParameters(not(ismember(allParameters, options.parameters))); config = rmfield(config, parametersToRemove); end if options.convertTextToString parameters = string(fields(config))'; for parameter = parameters if ischar(config.(parameter)) config.(parameter) = string(config.(parameter)); end + + if iscell(config.(parameter)) + if all(cellfun(@ischar, config.(parameter))) + config.(parameter) = string(config.(parameter))'; + end + end end end output = config; end \ No newline at end of file diff --git a/listSCase.m b/listSCase.m index e534ca3..55976bf 100755 --- a/listSCase.m +++ b/listSCase.m @@ -1,262 +1,262 @@ function SCaseList = listSCase(varargin) %LISTSCASE output list of sCases (id and path), accordind to inputList or %filter arguments. % Each sCase directory should at least contain at % directory with a name staring with 'CT' and ending with either % '-1' : preop/shoulder/sharp/noPhantom % '-2' : preop/shoulder/smooth/noPhantom % '-3' : preop/shoulder/sharp/phantom % '-4' : preop/shoulder/smooth/phantom % and containing a 'dicom' subdirectory. The priority is '1', '2', '3', '4', % unless there is a amira folder already present in one of these diretories. % % The optional input argument inputList if an array of SCaseID, or 'N' or % 'P'. If empty, listSCase will search for all SCaseID. The optional % input argument filter can restrict le list. % The fonction can be run from server (lbovenus) with % cd /home/shoulder/methods/matlab/database; matlab -nojvm -nodisplay -nosplash -r "listSCase;quit" % For 700 cases, it takes less than 60 seconds (when executed from server) % Progress can be be checked throuhth log file with following shell command % cd /home/shoulder/methods/matlab/database;tail -f log/listSCase.log % Input: % inputArg: can be nothing (=all), 'N', 'P', or SCase(s) % % Output: % outputArg: 1 if ok and 0 otherwise % % Example: listSCase, listSCase('P'), listSCase('P001','P002') % Other M-files required: None % Subfunctions: None % See also: Used by dicominfoSCase, measureSCase, % % Author: Alexandre Terrier % EPFL-LBO % Creation date: 2018-07-01 % Revision date: 2018-12-30 % % TODO % Two main looops might be merged in one, to avoid duplicagte post % treatment %% Open log file logFileID = openLogFile('listSCase.log'); % %% Set the data directory from the configuration file config.txt -% dataDir = ConfigFileExtractor.getVariable('dataDir'); +% dataDir = getConfig().dataDir; %% Struct contains id and associated directory SCaseList = struct(... 'id' ,[],... 'dir' ,[],... 'comment' ,[]... % Might be used later ); %% Check varargin dirL0Array = ''; SCaseListIn = {}; switch nargin case 0 % All SCase, default when no argument dirL0Array = ['N';'P']; fprintf(logFileID, '\nGet list of all SCase with a valid dicom folder'); % Set the data directory from the configuration file config.txt - dataDir = ConfigFileExtractor.getVariable('dataDir'); + dataDir = getConfig().dataDir; case 1 if exist(varargin{1},'dir') % Assumes the input is the data directory dataDir = varargin{1}; % All SCase as default when no more arguments dirL0Array = ['N';'P']; % All SCase, default when no argument fprintf(logFileID, '\nGet list of all SCase with a valid dicom folder'); else % When the only argument is not a directory % Set the data directory from the configuration file config.txt - dataDir = ConfigFileExtractor.getVariable('dataDir'); + dataDir = getConfig().dataDir; % Assumes the argument is 'N', 'P' or a list of SCases switch varargin{1} case 'N' % All normal SCase dirL0Array = 'N'; fprintf(logFileID, '\nGet list of all normal SCase with a valid dicom folder'); case 'P' % All pathological SCase dirL0Array = 'P'; fprintf(logFileID, '\nGet list of all pathological SCase with a valid dicom folder'); otherwise % A specific SCase fprintf(logFileID, '\nGet list of a SCase with a valid dicom folder'); SCaseListIn = varargin; end end otherwise if exist(varargin{1},'dir') % Assumes the input is the data directory dataDir = varargin{1}; switch varargin{2} case 'N' % All normal SCase dirL0Array = 'N'; fprintf(logFileID, '\nGet list of all normal SCase with a valid dicom folder'); case 'P' % All pathological SCase dirL0Array = 'P'; fprintf(logFileID, '\nGet list of all pathological SCase with a valid dicom folder'); otherwise % Some specific SCase (wrong) fprintf(logFileID, '\nGet list of a SCase with a valid dicom folder'); SCaseListIn = varargin; SCaseListIn(1) = []; % removing the dataDir from the argument list end else % When the first argument is not a directory, assumes it is a list of SCases % Set the data directory from the configuration file config.txt - dataDir = ConfigFileExtractor.getVariable('dataDir'); + dataDir = getConfig().dataDir; % list of multiple SCase given in varargin fprintf(logFileID, '\nGet list of a SCase with a valid dicom folder'); SCaseListIn = varargin; end end %% Only one of the two loops below are performed SCaseListIdx = 0; % Used in one of two loops below %% Loop over SCase (N, P, or both), if length(dirL0Array) > 1 for dirL0idx = 1:length(dirL0Array) % N or P for dirL1idx = 0:9 % Hunderts dir for dirL2idx = 0:9 % Tens dir dirL0Str = dirL0Array(dirL0idx); dirL1Str = num2str(dirL1idx); dirL2Str = num2str(dirL2idx); dirTens = [dataDir '/' dirL0Str '/' dirL1Str '/' dirL2Str]; dirTensList = dir(dirTens); % List all directories in tens dir dirTensList = dirTensList(~ismember({dirTensList.name},{'.','..'})); % Remove . and .. % We might add here a filter (only diretories, {N/P} followed % by digits for dirL3idx = 1:numel(dirTensList) sCaseDirName = dirTensList(dirL3idx).name; % Root directory of this case sCaseDirPath = dirTensList(dirL3idx).folder; % Check if this SCaseID has a CT dir [CT?*-?] with a valid preoprative CT SCaseID = strtok(sCaseDirName, '-'); % Get chars before '-' CTdirList = dir([sCaseDirPath '/' sCaseDirName '/CT-*']); % List directories with CT iCTdirAmira = 0; iCTdir2use = 0; for iCTdirList = length(CTdirList):-1:1 % Loop from last to first (4 to 1) CTdir = CTdirList(iCTdirList); % Check that dir name ends with -1,-2,-3,-4 dirName = CTdir.name; if strcmp(dirName(end-1),'-') % Exclude postoperative 'p' CT CTnum = str2num(dirName(end)); if CTnum <= 4 % Exlude non shoulder (elbow) CT % Check that the dir contains a dicom dir CTdir = [CTdir.folder '/' CTdir.name]; dicomDir = [CTdir '/dicom']; if exist(dicomDir, 'dir') % Chech if amira dir exist amiraDir = [CTdir '/amira']; if exist(amiraDir, 'dir') % This is the CT folder to use iCTdirAmira = iCTdirList; end iCTdir2use = iCTdirList; end end end end if iCTdir2use == 0 fprintf(logFileID, ['\n', SCaseID, ' has no valid dicom directory']); else if iCTdirAmira % If amira dir exist, use it iCTdir2use = iCTdirAmira; end CTdir = CTdirList(iCTdir2use); SCaseListIdx = SCaseListIdx + 1; SCaseList(SCaseListIdx).id = SCaseID; CTdirPath = [CTdir.folder '/' CTdir.name]; SCaseList(SCaseListIdx).dir = CTdirPath; if CTnum ~= 1 fprintf(logFileID, ['\n', SCaseID, ' dicom directory is CT-' num2str(CTnum)]); end end end end end end %% Loop over input SCase list (given as input argument), if length(SCaseListIn) > 0 for iSCaseListIn = 1:length(SCaseListIn) % Check if there is a valid dicom directory for this SCaseID SCaseID = char(SCaseListIn{iSCaseListIn}); % Build directory from SCaseID (as in function ShoulderCase.path) % The validity of the format should be either Pnnn or Nnnn. if (numel(regexp(SCaseID,'^[PN]\d{1,3}$')) == 0) error(['Invalid format of SCaseID: ' SCaseID{1} '. CaseID must start with "P" or "N" and be followed by 1 to 3 digits.']); end % Set the folder of the SCaseID SCaseDirLevelPN = SCaseID(1); % Either 'P' or 'N' strLengthSCaseID = strlength(SCaseID(2:end)); if (strLengthSCaseID < 2) SCaseDirLevel2 = '0'; % Hunderets SCaseDirLevel1 = '0'; % Dozent elseif (strLengthSCaseID < 3) SCaseDirLevel2 = '0'; % Hunderets SCaseDirLevel1 = SCaseID(2); % Dozent else SCaseDirLevel2 = SCaseID(2); % Hunderets SCaseDirLevel1 = SCaseID(3); % Dozent end % Set SCaseID with fixed 3 digits after P/N (needed when id < % 10 inloading of data in amira directory. SCaseID4C = [SCaseDirLevelPN SCaseDirLevel2 SCaseDirLevel1 SCaseID(end)]; % Check if a (!unique! to be done) directory exists for this SCaseID FindSCaseIDFolder = dir([dataDir '/' SCaseDirLevelPN '/' SCaseDirLevel2 '/' SCaseDirLevel1 '/' SCaseID '*']); if (isempty(FindSCaseIDFolder)) % No directory for this SCaseID error(['Missing directory for SCaseID: ' SCaseID]); end SCaseDirLevel0 = FindSCaseIDFolder.name; SCaseDir = [dataDir '/' SCaseDirLevelPN '/' SCaseDirLevel2 '/' SCaseDirLevel1 '/' SCaseDirLevel0]; % Check if this SCaseID has a CT directory with a valid preoprative CT CTdirList=dir([SCaseDir '/CT-*']); % List directories with CT iCTdirAmira = 0; iCTdir2use = 0; for iCTdirList = length(CTdirList):-1:1 % Loop from last to first (4 to 1) CTdir = CTdirList(iCTdirList); % Check that dir name ends with -1,-2,-3,-4 dirName = CTdir.name; if strcmp(dirName(end-1),'-') % Exclude postoperative 'p' CT CTnum = str2num(dirName(end)); if CTnum <= 4 % Exlude non shoulder (elbow) CT % Check that the dir contains a dicom dir CTdir = [CTdir.folder '/' CTdir.name]; dicomDir = [CTdir '/dicom']; if exist(dicomDir, 'dir') % Chech if amira dir exist amiraDir = [CTdir '/amira']; if exist(amiraDir, 'dir') % This is the CT folder to use iCTdirAmira = iCTdirList; end iCTdir2use = iCTdirList; end end end end if iCTdir2use == 0 fprintf(logFileID, ['\n', SCaseID, ' has no valid dicom directory']); else if iCTdirAmira % If amira dir exist, use it iCTdir2use = iCTdirAmira; end CTdir = CTdirList(iCTdir2use); SCaseListIdx = SCaseListIdx + 1; SCaseList(SCaseListIdx).id = SCaseID; CTdirPath = [CTdir.folder '/' CTdir.name]; SCaseList(SCaseListIdx).dir = CTdirPath; if CTnum ~= 1 fprintf(logFileID, ['\n', SCaseID, ' dicom directory is CT-' num2str(CTnum)]); end end end fprintf(logFileID, ['\nNumber of SCase: ' num2str(length(SCaseList))]); fclose(logFileID); % Close log file end diff --git a/measureSCase.m b/measureSCase.m index 3a8c221..cbf33c1 100755 --- a/measureSCase.m +++ b/measureSCase.m @@ -1,689 +1,689 @@ function [status,message] = measureSCase(varargin) % MEASURESCASE Update the entire SCase DB with anatomical measurements. % The function should be run from the server (lbovenus), from the user account containing the git repository, % with the following shell command % matlab -nodisplay -nosplash -r "measureSCase;quit" % For long calculations, it can be run in the background using tmux, followed % by Ctrl+b d to detach the session and keep the process running. % Progress can be checked through log file with following shell command % tail -f log/measureSCase.log % It take ~30 min for 700 cases when run from server. % After run from server, the output file % /shoulder/data/Excel/xlsFromMatlab/anatomy.csv % must be open from Excel and saved % as xls at the same location. Excel file % /shoulder/data/Excel/ShoulderDataBase.xlsx should also be open, updated, and saved. % The script measureSCase was replacing 3 previous functions % 1) rebuildDatabaseScapulaMeasurements.m --> list of all SCases --> execute scapula_measure.m % 2) scapula_measure.m --> execute scapula_calculation and save results in Excel and SQL % 3) scapula_calculation.m --> perform anatomical analysis --> results variable % Input arguments can be one or several among: % {Empty,'glenoidDensity', 'update', 'musclesDegeneration' '[NP][1-999]', '[NP]'} % % If there is no argument the function will measure every new case. % The 'N' or 'P' given as an argument will load all the Normal or Pathological cases. % % The measurements are divided into three measurements: "morphology", "glenoidDensity", % and "musclesDegeneration". The default measurement is the "morphology" one, the % two others has to be given in arguments in order to be done.% % % Examples: % measureSCase() % is a valid instruction where on every new case is done the % "morphology" measurement. % measureSCase('glenoidDensity','musclesDegeneration') % is a valid instruction where on every cases are done the % "morphology","glenoidDensity", and "musclesDegeneration" measurements % if one of these measurements is missing. % measureSCase('P400','N520') % is a valid instruction where on the cases 'P400' and 'N520' is % done the "morphology" measurement only if they have not already % been measured yet (new cases). % measureSCase('P400','N520','update') % is a valid instruction where on the cases 'P400' and 'N520' is % done the "morphology" measurement whether they have already been % measured yet or not. % measureSCase('glenoidDensity','P400','N520','update','P') % is a valid instruction where on all the 'P' cases and the case N520 % are done the "morphology" and "glenoidDensity" measurements whether % they have been measured yet or not. % Output % File /shoulder/data/Excel/xlsFromMatlab/anatomy.csv % File /shoulder/data/Excel/xlsFromMatlab/anatomy.xls (only windows) % File /home/shoulder/data/matlab/SCaseDB.mat % File {SCaseId}.mat in each {SCaseId}/{CT}/matlab directory % logs in /log/measureSCase.log % Authors: Alexandre Terrier, EPFL-LBO % Matthieu Boubat, EPFL-LBO % Creation date: 2018-07-01 % Revision date: 2020-06-09 % TO DO: % Read first last anatomy.csv and/or SCaseDB.mat % Fill with patient and clinical data, from excel or MySQL % use argument to redo or update % Save csv within the main loop (not sure it's a good idea) % Add more message in log % Add more test to assess validity of data % Update MySQL % Rename all objects with a capital % Make it faster by not loading scapula surface if already in SCaseDB.mat % Add argument 'load' to force reload files even if they are alerady in DB % Add argument 'measure' to force re-measuring event if measurement is already in DB % Add "scapula_addmeasure.m" --> should be coded in ShoulderCase class startTime = datetime('now'); %% Add environment to path addpath(genpath(pwd)); %% Open log file logFileID = openLogFile('measureSCase.log'); %% Set the data directory from the configuration file config.txt -dataDir = ConfigFileExtractor.getVariable('dataDir'); +dataDir = getConfig("convertTextToString", false).dataDir; %% Location of the XLS ShoulderDatabase xlsDir = [dataDir '/Excel/xlsFromMatlab']; matlabDir = [dataDir '/matlab']; %% Instanciate case loader database = ShoulderCaseLoader(); %% Get list of all SCase % Get list of SCases from varargin % Delault value for varargin calcGlenoidDensity = false; calcMusclesDegeneration = false; updateCalculations = false; specificCases = true; fprintf(logFileID, '\n\nList of SCase'); allCases = database.getAllCasesID(); assert(not(isempty(allCases)),'The database is empty, check that the provided data path is valid.'); requestedCases = {}; for argument = 1:nargin switch lower(varargin{argument}) % Test every argument in varargin. case 'glenoiddensity' calcGlenoidDensity = true; case 'musclesdegeneration' calcMusclesDegeneration = true; case 'update' updateCalculations = true; case regexp(lower(varargin{argument}),'[p]','match') % Detect if argument is 'P'. requestedCases = [requestedCases database.getAllPathologicalCasesIDs()]; case regexp(lower(varargin{argument}),'[n]','match') % Detect if argument is 'N'. requestedCases = [requestedCases database.getAllNormalCasesIDs()]; case regexp(lower(varargin{argument}),'[np][1-9][0-9]{0,2}','match') % Test for a correct argument [NP][1-999] if database.containsCase(varargin{argument}) requestedCases = [requestedCases varargin{argument}]; end otherwise warning(['\n "%s" is not a valid argument and has not been added to the'... ' list of cases.\n measureSCase arguments format must be "[npNP]",'... ' "[npNP][1-999]", "GlenoidDensity", or "update"'],varargin{argument}) end end SCaseList = allCases(find(ismember(allCases,requestedCases))); % Remove cases that appears multiple times if isempty(SCaseList) disp('No valid ShoulderCase have been given in argument. All the cases found in the database will be measured.'); SCaseList = allCases; end %% Load current xls database (for clinical data) fprintf(logFileID, '\nLoad xls database\n\n'); addpath('XLS_MySQL_DB'); filename = [dataDir '/Excel/ShoulderDataBase.xlsx']; excelRaw = rawFromExcel(filename); % cell array excelSCaseID = excelRaw(2:end, 1); excelDiagnosis = excelRaw(2:end, 4); excelPatientHeight = excelRaw(2:end, 23); excelGlenoidWalch = excelRaw(2:end, 55); % Lines below adapted from XLS_MySQL_DB/MainExcel2XLS % Excel.diagnosisList = diagnosisListFromExcel(Excel.Raw); % Excel.treatmentList = treatmentListFromExcel(Excel.Raw); % ExcelData.Patient = patientFromExcel(excelRaw); % Structure with patient data % Excel.shoulder = shoulderFromExcel(Excel.patient, Excel.Raw); % [Excel.SCase, Excel.diagnosis, Excel.treatment, Excel.outcome, Excel.study] = SCaseFromExcel(... % Excel.shoulder, Excel.patient, Excel.diagnosisList, Excel.treatmentList, Excel.Raw); % fprintf(logFileID, ': OK'); %% Add path to ShoulderCase class addpath('ShoulderCase'); %% Instance of a ShoulderCase object if (exist('SCase','var') > 0) clear SCase; % Check for delete method end SCaseDB = {}; SCase = []; % %%%% definition of analysis variables % % % % % manual % % % ok = {}; % amira = {}; % scapulaLoad = {}; % scapulaCoord = {}; % degeneration = {}; % glenoidLoad = {}; % glenoidMorphology = {}; % glenoidDensity = {}; % humerusLoad = {}; % humerusSubluxation = {}; % acromionMorphology = {}; % % % % % auto % % % autoOk = {}; % autoScapulaLoad = {}; % autoScapulaCoord = {}; % %autoDegeneration = {}; % autoGlenoidLoad = {}; % autoGlenoidMorphology = {}; % autoGlenoidDensity = {}; % %autoHumerusLoad = {}; % %autoHumerusSubluxation = {}; % autoAcromionMorphology = {}; % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Start loop over SCases in SCaseList nSCase = length(SCaseList); % Number of SCases for iSCaseID = 1:nSCase SCaseID = SCaseList{iSCaseID}; if not(updateCalculations) try SCase = database.loadCase(SCaseID); catch ME SCase = database.createEmptyCase(SCaseID); warning(ME.message); end else SCase = database.createEmptyCase(SCaseID); end % newSCase = ShoulderCase(SCaseID); % SCase = newSCase; % SCase.dataPath = dataDir; % Set dataDir for SCase manualMeasurementAvailable = not(isempty(dir(SCase.dataAmiraPath))); % Set data path of this SCase autoMeasurementsAvailable = not(isempty(dir([SCase.dataMatlabPath '/scapulaLandmarksAuto*.mat']))); percentProgress = num2str(iSCaseID/nSCase*100, '%3.1f'); fprintf(logFileID, ['\n___________________________________\n|\n| SCaseID: ' SCaseID ' (' percentProgress '%%)']); %% The following section is a temporary solution to the arguments handling. %% It splits the measurements process into six parts (shoulderMorphology, %% glenoidDensity, musclesDegeneration for both manual and auto cases). %% Each part are independently 'ordered' based on some conditions. orderMorphologyMeasurementManual = false; orderDensityMeasurementManual = false; orderDegenerationMeasurementManual = false; orderMorphologyMeasurementAuto = false; orderDensityMeasurementAuto = false; orderDegenerationMeasurementAuto = false; if or(not(exist([SCase.dataMatlabPath '/SCase.mat'],'file')), updateCalculations) orderMorphologyMeasurementManual = true; orderMorphologyMeasurementAuto = true; if (calcGlenoidDensity) orderDensityMeasurementManual = true; orderDensityMeasurementAuto = true; end if (calcMusclesDegeneration) orderDegenerationMeasurementManual = true; orderDegenerationMeasurementAuto = true; end else loadedSCase = database.loadCase(SCase.id); rotatorCuffManual = loadedSCase.shoulderManual.rotatorCuff; rotatorCuffAuto = loadedSCase.shoulderAuto.rotatorCuff; if and(calcGlenoidDensity, isempty(loadedSCase.shoulderManual.scapula.glenoid.density)) orderMorphologyMeasurementManual = true; orderDensityMeasurementManual = true; SCase = loadedSCase; end if and(calcGlenoidDensity, isempty(loadedSCase.shoulderAuto.scapula.glenoid.density)) orderMorphologyMeasurementAuto = true; orderDensityMeasurementAuto = true; SCase = loadedSCase; end if and(calcMusclesDegeneration, any(isnan(rotatorCuffManual.summary.PCSA)) ) orderMorphologyMeasurementManual = true; orderDegenerationMeasurementManual = true; SCase = loadedSCase; end if and(calcMusclesDegeneration, any(isnan(rotatorCuffAuto.summary.PCSA)) ) orderMorphologyMeasurementAuto = true; orderDegenerationMeasurementAuto = true; SCase = loadedSCase; end end %% %% The section above (and basically all the measureSCase function) will be removed %% in the upcoming implementation of ShoulderCase measurements. %% Matthieu Boubat, 06.03.2020 %% % There are 3 parts within this SCase loop: % 1) Load & analyses manual data from amira % 2) Load & analyses auto data from matlab (Statistical Shape Model) % 3) Load clinical data from Excel database, and set them to SCase % 4) Save SCase in file SCaseID/matlab/SCase.mat % 1) Load & analyses manual data from amira if manualMeasurementAvailable tic; fprintf(logFileID, '\n| Segmentation manual '); try if orderMorphologyMeasurementManual measureShoulderMorphology(SCase.shoulderManual,logFileID); end catch ME fprintf(logFileID,ME.message); end try if orderDensityMeasurementManual measureGlenoidDensity(SCase.shoulderManual,logFileID); end catch ME fprintf(logFileID,ME.message); end try if orderDegenerationMeasurementManual measureMusclesDegeneration(SCase.shoulderManual,logFileID); end catch ME fprintf(logFileID,ME.message); end fprintf(logFileID, '\n| Elapsed time (s): %s\n|', num2str(toc)); end % 2) Load & analyses auto data from matlab if autoMeasurementsAvailable tic; fprintf(logFileID, '\n| Segmentation auto '); try if orderMorphologyMeasurementAuto measureShoulderMorphology(SCase.shoulderAuto,logFileID); end catch ME fprintf(logFileID,ME.message); end try if orderDensityMeasurementAuto measureGlenoidDensity(SCase.shoulderAuto,logFileID); end catch ME fprintf(logFileID,ME.message); end try if orderDegenerationMeasurementAuto measureMusclesDegeneration(SCase.shoulderAuto,logFileID); end catch ME fprintf(logFileID,ME.message); end fprintf(logFileID, '\n| Elapsed time (s): %s\n|', num2str(toc)); end % 3) Set clinical data from Excel database to SCase fprintf(logFileID, '\n|\n| Set clinical data from Excel'); % Get idx of excelRaw for SCaseID % Use cell2struct when dots are removed from excel headers try idx = find(strcmp(excelRaw, SCaseID)); % Index of SCaseID in excelRaw SCase.diagnosis = excelRaw{idx,4}; SCase.treatment = excelRaw{idx,9}; SCase.patient.gender = excelRaw{idx,19}; SCase.patient.age = excelRaw{idx,21}; SCase.patient.height = excelRaw{idx,23}; SCase.patient.weight = excelRaw{idx,24}; SCase.patient.BMI = excelRaw{idx,25}; SCase.shoulderAuto.scapula.glenoid.walch = excelRaw{idx,55}; SCase.shoulderManual.scapula.glenoid.walch = excelRaw{idx,55}; fprintf(logFileID, ': OK'); catch fprintf(logFileID, ': ERROR'); end % 4) Save SCase try fprintf(logFileID, '\n| Save SCase.mat'); SCase.saveMatlab; fprintf(logFileID, ': OK'); catch fprintf(logFileID, ': ERROR'); end fprintf(logFileID, '\n|___________________________________\n\n'); % 4) Load & analyses auto data from matlab (Statistical Shape Model) % Load scapula surface and landmarks % save('measureSCase_analysis.mat',... % 'ok','amira','scapulaLoad','scapulaCoord',... % 'degeneration','glenoidLoad','glenoidMorphology','glenoidDensity',... % 'humerusLoad','humerusSubluxation','acromionMorphology',... % 'autoOk','autoScapulaLoad','autoScapulaCoord','autoGlenoidLoad',... % 'autoGlenoidMorphology','autoGlenoidDensity','autoAcromionMorphology') end % End of loop on SCaseList %% Write csv file % This might be a function (SCase.csvSave()). The input would be a filename and a structure % data % Replace header and data by structure. Currently not working %{ txtFilename = [xlsDir, '/anatomy.txt']; % Name of the txt file DataStruc = struc(... 'SCase_id', SCase.id, ... 'shoulder_side', SCase.shoulder.side,... 'glenoid_radius', SCase.shoulder.scapula.glenoid.radius,... 'glenoid_sphereRMSE', SCase.shoulder.scapula.glenoid.sphereRMSE,... 'glenoid_depth', SCase.shoulder.scapula.glenoid.depth,... 'glenoid_width', SCase.shoulder.scapula.glenoid.width,... 'glenoid_height', SCase.shoulder.scapula.glenoid.height,... 'glenoid_centerPA', SCase.shoulder.scapula.glenoid.centerLocal(1),... 'glenoid_centerIS', SCase.shoulder.scapula.glenoid.centerLocal(2),... 'glenoid_centerML', SCase.shoulder.scapula.glenoid.centerLocal(3),... 'glenoid_versionAmpl', SCase.shoulder.scapula.glenoid.versionAmpl,... 'glenoid_versionOrient', SCase.shoulder.scapula.glenoid.versionOrient,... 'glenoid_version', SCase.shoulder.scapula.glenoid.version,... 'glenoid_inclination', SCase.shoulder.scapula.glenoid.inclination,... 'humerus_jointRadius', SCase.shoulder.humerus.jointRadius,... 'humerus_headRadius', SCase.shoulder.humerus.radius,... 'humerus_GHSAmpl', SCase.shoulder.humerus.GHSAmpl,... 'humerus_GHSOrient', SCase.shoulder.humerus.GHSOrient,... 'humerus_SHSAmpl', SCase.shoulder.humerus.SHSAmpl,... 'humerus_SHSOrient', SCase.shoulder.humerus.SHSOrient,... 'humerus_SHSAngle', SCase.shoulder.humerus.SHSAngle,... 'humerus_SHSPA', SCase.shoulder.humerus.SHSPA,... 'humerus_SHSIS', SCase.shoulder.humerus.SHSIS,... 'acromion_AI', SCase.shoulder.scapula.acromion.AI,... 'acromion_CSA', SCase.shoulder.scapula.acromion.CSA,... 'acromion_PS', SCase.shoulder.scapula.acromion.PS... ); DataTable = strct2table(Data); writetable(DataTable,filename); %} % Header of the csv file dataHeader = [... 'SCase_id,' ... 'shoulder_side,' ... 'glenoid_radius,' ... 'glenoid_sphereRMSE,' ... 'glenoid_depth,' ... 'glenoid_width,' ... 'glenoid_height,' ... 'glenoid_centerPA,' ... 'glenoid_centerIS,' ... 'glenoid_centerML,' ... 'glenoid_versionAmpl,' ... 'glenoid_versionOrient,' ... 'glenoid_version,' ... 'glenoid_inclination,' ... 'humerus_jointRadius,' ... 'humerus_headRadius,' ... 'humerus_GHSAmpl,' ... 'humerus_GHSOrient,' ... 'humerus_SHSAmpl,' ... 'humerus_SHSOrient,' ... 'humerus_SHSAngle,' ... 'humerus_SHSPA,' ... 'humerus_SHSIS,' ... 'acromion_AI,' ... 'acromion_CSA,' ... 'acromion_PSA,'... 'acromion_AAA\n'... ]; fprintf(logFileID, '\n\nSave anatomy.csv file'); fid = fopen([xlsDir, '/anatomy.csv'],'w'); %Last csv is deleted and a new one, updated is being created fprintf(fid,dataHeader); fclose(fid); % The following lines re-create the SCaseDB.mat and contruct the anatomy.csv file SCaseDB = database.loadAllCases(); cellfun(@(SCase)SCase.appendToCSV('anatomy.csv'),SCaseDB); % Call method appendToCSV() on all element of the SCaseDB cell array fprintf(logFileID, ': OK'); %% Save the entire SCaseDB array as a matlab file fprintf(logFileID, '\n\nSave SCase database'); filename = 'SCaseDB'; filename = [matlabDir '/' filename '.mat']; try save(filename, 'SCaseDB'); fprintf(logFileID, ': OK'); catch fprintf(logFileID, ': Error'); end %fprintf(logFileID, [': ' csvFilename]); %% Write xls file (Windows only) % [~,message] = csv2xlsSCase(csvFilename); % fprintf(logFileID, message); % If run from non-windows system, only csv will be produced. The xls can be % produced by opening the csv from Excel and save as xls. % Could be a function with 1 input (cvsFilenames %{ xlsFilename = strrep(csvFilename, '.csv', '.xls'); % Replace .csv by .xls if ispc % Check if run from windows! % Read cvs file as table and write the table as xls cvsTable = readtable(csvFilename); % Get table from csv (only way to read non-numeric data) cvsCell = table2cell(cvsTable); % Tranform table cell array dataHeader = cvsTable.Properties.VariableNames; % Get header cvsCell = [dataHeader; cvsCell]; % Add header sheet = 'anatomy'; % Sheet name of the xls file [status,message] = xlswrite(xlsFilename, cvsCell, sheet); % Save xls if status fprintf(logFileId, ['\nSaved ' xlsFilename]); else fprintf(logFileId, ['\nCould not save ' xlsFilename]); fprintf(logFileId, ['\n' message.identifier]); fprintf(logFileId, ['\n' message.message]); end else fprintf(logFileId, ['\n' xlsFilename ' not saved. Open and save as xls from Excel']); end %} %% Close log file fprintf(logFileID, '\n\nSCase measured: %s', num2str(length(SCaseList))); % Number of SCases measured elapsedTime = char(datetime('now')-startTime); elapsedTime = [elapsedTime(1:2) ' hours ' elapsedTime(4:5) ' minutes ' elapsedTime(7:8) ' seconds']; fprintf(logFileID, ['\nTotal Elapsed time: ' elapsedTime ]); fprintf(logFileID, '\n'); fclose(logFileID); % Close log file %% Output of the SCase if required by argument % SCase.output % inputArg = abaqus/density/references/ % update mySQL % SCase.sqlSave status = 1; message = 'OK'; end function measureShoulderMorphology(shoulder,logFileID) fprintf(logFileID, '\n| Load scapula surface and landmarks'); output = shoulder.scapula.load; if ~output fprintf(logFileID, ': ERROR'); % scapulaLoad{end+1} = SCaseID; return end fprintf(logFileID, ': OK'); fprintf(logFileID, '\n| Set coord. syst.'); output = shoulder.scapula.coordSysSet; if ~output fprintf(logFileID, ': ERROR'); % scapulaCoord{end+1} = SCaseID; return; end fprintf(logFileID, ': OK'); fprintf(logFileID, '\n| Load glenoid surface'); output = shoulder.scapula.glenoid.load; if ~output fprintf(logFileID, '\n| glenoid surface loading error'); % glenoidLoad{end+1} = SCaseID; return; end fprintf(logFileID, ': OK'); fprintf(logFileID, '\n| Measure glenoid anatomy'); output = shoulder.scapula.glenoid.morphology; if ~output fprintf(logFileID, ': ERROR'); % glenoidMorphology{end+1} = SCaseID; return; end fprintf(logFileID, ': OK'); fprintf(logFileID, '\n| Load humerus data'); output = shoulder.humerus.load; if ~output fprintf(logFileID, ': ERROR'); % humerusLoad{end+1} = SCaseID; return; end fprintf(logFileID, ': OK'); fprintf(logFileID, '\n| Measure humerus subluxation'); output = shoulder.humerus.subluxation; if ~output fprintf(logFileID, ': ERROR'); % humerusSubluxation{end+1} = SCaseID; return; end fprintf(logFileID, ': OK'); fprintf(logFileID, '\n| Measure acromion anatomy'); % Should be run after SCase.shoulderManual.humerus (for AI) output = shoulder.scapula.acromion.morphology; if ~output fprintf(logFileID, ': ERROR'); % acromionMorphology{end+1} = SCaseID; return; end fprintf(logFileID, ': OK'); end function measureGlenoidDensity(shoulder,logFileID) fprintf(logFileID, '\n| Measure glenoid density'); output = shoulder.scapula.glenoid.calcDensity; if ~output fprintf(logFileID, ': Density calculus error. Could not read dicom'); return; end fprintf(logFileID, ': OK'); end function measureMusclesDegeneration(shoulder,logFileID) fprintf(logFileID, '\n| Measure muscle''s degeneration'); % auto segmentation with most recent slicing methods try shoulder.rotatorCuff.createSliceMatthieu(); shoulder.rotatorCuff.segmentMuscles('rotatorCuffMatthieu','autoMatthieu'); catch ME fprintf(logFileID,ME.message); end % auto segmentation with former slicing methods try shoulder.rotatorCuff.createSliceNathan(); shoulder.rotatorCuff.segmentMuscles('rotatorCuffNathan','autoNathan'); catch ME fprintf(logFileID,ME.message); end % muscles measurements try shoulder.rotatorCuff.measure('rotatorCuffMatthieu','autoMatthieu'); catch ME fprintf(logFileID,ME.message); end fprintf(logFileID, ': OK'); end