File size: 13,789 Bytes
fd601de
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
% script to evaluate a network for generating synthetic CT images from XCAT
% phantom data
genDir = 'A:/MIDL/Dominik_MIDL/genCT'; % directory containing network directories with generated CT data
genList = dir(genDir); % list all files in directory
genNames = {genList(3:end).name}; % list all the filnames
nrNetworks = numel(genNames); % number of networks
%% 
%read in XCAT data
XCATDataDir = 'A:/MIDL/Dominik_MIDL/XCAT'; % directory of XCAT data used for CT generation
XCATListDir = dir(XCATDataDir); % list all files in selected directory
XCATDirNames = {XCATListDir(3:end).name}; % list all the filnames
nrXCATPhantoms = numel(XCATDirNames); % number of phantoms in directory
%%
% initialize parameters to evaluate
NoiseEvaluation = 0; % are the noise properties to be evaluated?
ReferenceNPSEvaluation = 0; % patient NPS to be evaluated?
EdgeEvaluation = 1; % are the edge and feature properties to be evaluated?
NiftiFromDicom = 1; % were the reference segmentation masks extracted from nii files converted from dicom files? Put 0 for .nrrd
DicomCTImages = 1; % were the reference patient images dicom files? Put 0 for .nrrd
%%
if EdgeEvaluation
    [Result.FSIM,Result.SSIM,Result.MAE,Result.FaultyPixel,Result.EPR,Result.EdgeGenRatio,Result.GMSdev] = deal(cell(nrXCATPhantoms,1)); %,Result.MAD,Result.NMSE
    [Data.PCBP,Data.MAE,Data.SSIM,Data.FSIM,Data.GMSD,Data.EGR] = deal(cell(nrXCATPhantoms,nrNetworks)); % container for statistics of all metrics
end
%%
if NoiseEvaluation
    %% 
    % initiale cells for metrics
    [Result.NPSAccuracy,Result.NPSCorrelation,Result.NoiseMagnitude,Result.MaxRatio] = deal(cell(nrXCATPhantoms,1));
    [Data.NM,Data.PCC,Data.MPE,Data.MMR] = deal(cell(nrXCATPhantoms,nrNetworks));
    %%
    % read segmentations of generated data
    genSegmDir = 'A:/Dominik_MIDL/genSegm'; % directories containing generated CT data
    %%
    if ReferenceNPSEvaluation
        % read in training and segmentation data to calculate real noise properties for comparison
        segmDir = 'A:/Dominik_MIDL/Patsegm'; % directories containing segmentation of real patient data
        segmList = dir(segmDir);
        segmNames = {segmList(3:end).name};
        %%
        % read patient data
%         patDir = 'D:\Russ\CT_Images\synCT\Patient'; % directories containing real patient data
        patDir = 'A:/Dominik_MIDL/Patnrrd'; % directories containing real patient data
        patList = dir(patDir);
        patNames = {patList(3:end).name};
        [Data.ReferenceNPS2D,Data.ReferenceFreq,Data.ReferenceNPScurves,Data.LiverValues] = deal(cell(numel(segmNames),1));
        %%
        % segment patient data and calculate NPS
        for i = 1:numel(segmNames)
            patScanDir = [patDir '\' patNames{i}];
            patScanList = dir(patScanDir);
            patScanNames = {patScanList(3:end).name};
            if DicomCTImages
                % sortn is third party code
                patScanNames = sortn(patScanNames); % sort the cell array in natural order, if they are dicom images
            end
            [patData,patPixelSpacing] = Read_Dicom_File(patScanDir,patScanNames);
            segmData = double(niftiread([segmDir '\' segmNames{i}]));
            if NiftiFromDicom
                segmData = Nifti_Coordinate_Trafo1(segmData); % transform the coordinate system for correct representation, depends, whether the image to be segmented was created from a nrrd file (2) or dicom file (1)
            else
                segmData = Nifti_Coordinate_Trafo2(segmData); % transform the coordinate system for correct representation, depends, whether the image to be segmented was created from a nrrd file (2) or dicom file (1)
            end    
            liverData = segmData.*patData;
            Data.ReferenceNPS2D{i} = patPixelSpacing(1)*patPixelSpacing(2)*FFT_Segmented_Noise(liverData);
            [Data.ReferenceFreq{i},Data.ReferenceNPScurves{i}] = Radial_from_2D_NPS(Data.ReferenceNPS2D{i},patPixelSpacing(1),1);   
            % calculate reference STD
            liverData(segmData==0) = NaN;
            Data.LiverSTD{i} = nanstd(liverData(:));
        end
        %%
        % compute convex hull of radial NPS in order to create a valid
        % variable space for generated NPS
        refNPS = vertcat(Data.ReferenceNPScurves{:})';
        Data.ReferenceNPS = mean(refNPS,2)';
        Data.minNPS = min(refNPS,[],2);
        Data.maxNPS = max(refNPS,[],2);
        Data.LiverNoiseMean = mean(cell2mat(Data.LiverSTD(:)));
        Data.LiverNoiseSTD = std(cell2mat(Data.LiverSTD(:)));
    end
end
clear refNPS genList XCATListDir XCATListDir segmList i liverData patData patDir patList patNames patPixelSpacing patScanDir patScanList patScanNames segmData segmDir segmNames
%%
for k = 1:nrNetworks
    %%
    % read in XCAT stuff for prepping
    [XCATData,XCATPixelSpacing,XCATSliceThickness] = Read_Dicom_File(XCATDataDir,XCATDirNames(1)); % read in first file to extract pixel spacing and slice thickness
    [nrXCATRows,nrXCATColumns,nrXCATSlices] = size(XCATData); % extract size of generated image matrix
    %%
    % read in generated image stuff
    network = genNames{k};
    genDataDir = [genDir '\' network];
    genListDir = dir(genDataDir); % list all files in selected directory
    genDirNames = {genListDir(3:end).name}; % list all the filnames
    nrGenPhantoms = numel(genDirNames); % number of phantoms in directory
    genData = Read_Dicom_File(genDataDir,genDirNames(1)); % read in first file to extract pixel spacing and slice thickness
    [nrGenRows,nrGenColumns,nrGenSlices] = size(genData); % extract size of generated image matrix
    %%
    % compare generated and XCAT data size and return error if not matching
    if nrXCATRows ~= nrGenRows || nrXCATColumns ~= nrGenColumns
        error('Size of XCAT data and generated data not matching')
    elseif nrXCATPhantoms ~= nrGenPhantoms
        error('Number of Phantoms in XCAT and generated data not matching')        
    end
    n = nrXCATSlices - nrGenSlices; % parameter depending on how many slices were used for training the networks    
    clear nrGenPhantoms nrXCATSlices XCATData nrGenRows nrGenColumns genData genListDir nrXCATRows nrXCATColumns
    %%
    for i = 1:nrXCATPhantoms
        %%
        phantom = genDirNames{i};
        genData = Read_Dicom_File(genDataDir,{phantom}); % read in generated data
        XCATData = Read_Dicom_File(XCATDataDir,XCATDirNames(i)); % read in XCAT data
        XCATData = XCATData(:,:,1+n/2:end-n/2); % first and last n/2 slices are not in synthetic CTs
        %%
        if EdgeEvaluation
            XCATContour = XCATData ~= -1000; % extract XCAT body contour, always 0 outside the body
            compXCATContour = imcomplement(XCATContour); % inverts the logical binary mask
            segmData = XCATContour.*genData;
            segmData(XCATContour==0) = -1000;
            negData = compXCATContour.*genData;
            negData(compXCATContour==0) = -2000;
            absXCAT = XCATData; % create new XCAT data with -2000 outside of the body contour for better excluding it while absolute comparison
            absXCAT(XCATContour==0) = -2000;
            absSegmData = segmData; % create new segmented data with -2000 outside of the body contour for better excluding it while absolute comparison
            absSegmData(XCATContour==0) = -2000;
            [FSIMtmp,SSIMtmp,MAEtmp,FaultyPixeltmp,EPRtmp,EdgeGenRatiotmp,GMSdevtmp] = deal(zeros(nrGenSlices,1)); %,MADtmp,NMSEtmp
            for j = 1:nrGenSlices
                % read in single axial slices
                gentmp = segmData(:,:,j);
                absGentmp = absSegmData(:,:,j);
                XCATtmp = XCATData(:,:,j);
                absXCATtmp = absXCAT(:,:,j);
                negDatatmp = negData(:,:,j);
                % evaluate the slices
                FSIMtmp(j) = FeatureSIM(rescale(XCATtmp,0,255),rescale(gentmp,0,255)); % calculates the feature similarity index
                SSIMtmp(j) = ssim(rescale(gentmp),rescale(XCATtmp)); % calculates the structural similarity index
                MAEtmp(j) = Mean_Absolute_Error(absXCATtmp,absGentmp); % calculates the mean absolute error
%                 NMSEtmp(j) = Normalized_Mean_Square_Error(absXCATtmp,absGentmp); % calculates the normalized mean square error
                FaultyPixeltmp(j) = Faulty_Pixel(negDatatmp); % calculates the number of 'faulty pixels in the generated image
                [EPRtmp(j),EdgeGenRatiotmp(j)] = Edge_Preservation_Ratio(XCATtmp,gentmp); % calculates the edge preservation ratio and
                GMSdevtmp(j) = Gradient_Magnitude_Similarity_Deviation(XCATtmp,gentmp); % calculates the gradient magnitude similarity deviation
%                 tmp = MAD_index(XCATtmp,gentmp); % calculates the most apparent distortion index
%                 MADtmp(j) = tmp.MAD;
            end
            Result.FSIM{i} = FSIMtmp;
            Data.FSIM{i,k} = FSIMtmp;
            Result.SSIM{i} = SSIMtmp;
            Data.SSIM{i,k} = SSIMtmp;
            Result.MAE{i} = MAEtmp;
            Data.MAE{i,k} = MAEtmp;
%             Result.NMSE{i} = NMSEtmp;
            Result.FaultyPixel{i} = FaultyPixeltmp;
            Data.PCBP{i,k} = FaultyPixeltmp;
            Result.EPR{i} = EPRtmp;
            Result.EdgeGenRatio{i} = EdgeGenRatiotmp;
            Data.EGR{i,k} = EdgeGenRatiotmp;
            Result.GMSdev{i} = GMSdevtmp;
            Data.GMSD{i,k} = GMSdevtmp;
%             Result.MAD{i} = MADtmp;
            clear absXCATtmp absGentmp absSegmData absXCAT tmp i j genData XCATData XCATContour compXCATContour segmData negData gentmp XCATtmp negDatatmp FSIMtmp SSIMtmp Sharpnesstmp MAEtmp NMSEtmp FaultyPixeltmp EPRtmp EdgeGenRatiotmp GMSdevtmp MADtmp
        end
        %%
        if NoiseEvaluation
            %%
            % get deep learning segmentation
            phanName = phantom(1:end-5);
            segmDir = [genSegmDir '\' network];
            segmList = dir(segmDir);
            segmList = {segmList(3:end).name};
            liverMask = 1;
            if ~isempty(segmList)
                for m = 1:numel(segmList)
                    genSegmFile = segmList{m};
                    if contains(genSegmFile,phanName) % checks if the phantom name is contained in the selected segmentation
                        liverMask = double(niftiread([segmDir '\' genSegmFile]));
                        liverMask = Nifti_Coordinate_Trafo2(liverMask);
                    end
                end
            end
            if liverMask
                % read in binary masks for liver tissue tissue
%                 liverValue = 51.26;
%                 liverMask = round(XCATData,2) == liverValue; % round due to more precision in actual values than in imshow plot
                liverValue1 = 51.72;
                liverValue2 = 52.39;
                liverValue3 = 53.42;
                liverMask = round(XCATData,2) == liverValue1;
                if numel(nonzeros(liverMask)) == 0
                    liverMask = round(XCATData,2) == liverValue2;
                end
                if numel(nonzeros(liverMask)) == 0
                    liverMask = round(XCATData,2) == liverValue3;
                end
            end
            %%
            % apply masks to CT Image
            liverData = liverMask.*genData; % segment Data using the Liver Mask
            %%
            % calculate 2D NPS
            normFactor = XCATPixelSpacing(1)*XCATPixelSpacing(2); % normalization factor depending on XCAT/gen Pixel spacing
            Data.NPS2D{i} = normFactor*FFT_Segmented_Noise(liverData);
            %%
            % calculate radial NPS, calculate the percentage of inliers and
            % NPS accuracy
            [Data.Frequency{i},Data.NPS{i}] = Radial_from_2D_NPS(Data.NPS2D{i},XCATPixelSpacing(1),1);
            Result.NPSAccuracy{i} = Generated_NPS_Accuracy(Data.NPS{i},Data.ReferenceNPS);
            Data.MPE{i,k} = Generated_NPS_Accuracy(Data.NPS{i},Data.ReferenceNPS);
            %%
            % normalize to 1 and calculate pearson correlation
            tmp = corrcoef(Data.NPS{i}/max(Data.NPS{i}(:)),Data.ReferenceNPS/max(Data.ReferenceNPS(:))); % Pearson correlation of normalized NPS
            Result.NPSCorrelation{i} = tmp(1,2);
            Data.PCC{i,k} = tmp(1,2);
            %%
            % calculate generated noise standard deviation and max ratio
            liverData(liverMask==0) = NaN;
            Result.NoiseMagnitude{i} = nanstd(liverData(:));
            Data.NM{i,k} = nanstd(liverData(:));
            Result.MaxRatio{i} = max(Data.NPS2D{i}(:))/max(Data.NPS{i}(:));
            Data.MMR{i,k} = max(Data.NPS2D{i}(:))/max(Data.NPS{i}(:));
        end  
    end
    %%
    % write the results in a csv
    % write results in csv
    Metrics = cell2table(fieldnames(Result),'VariableNames',{'Metrics'});
    data = struct2cell(Result); % writes the result data in a cell
    data = horzcat(data{:}); % unfolds the result cells in a new cell
    dataOut = cell2table(Cell_End_Results(data),'VariableNames',{network(1:end-10)});
%     dataOut = Cell_End_Results([Result.FSIM,Result.SSIM,Result.MAE,Result.FaultyPixel,Result.EPR,Result.DecVariable,Result.GMSdev]); %,Result.MAD,Result.NMSE]);
    if k == 1
        resultData = [Metrics,dataOut];
        if NoiseEvaluation
            [NPS2DData,NPSData] = deal(cell(nrXCATPhantoms,nrNetworks));
            NPS2DData(:,1) = Data.NPS2D;
            NPSData(:,1) = Data.NPS;
        end
    else
        resultData = [resultData,dataOut];
        if NoiseEvaluation
            NPS2DData(:,k) = Data.NPS2D;
            NPSData(:,k) = Data.NPS;
        end
    end
end
%%
% choose save directory
saveFile = 'A:\Dominik_MIDL\Results\';
writetable(resultData,saveFile)