Spaces:
Runtime error
Runtime error
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) |