diff --git a/ShoulderCase/@DicomVolume/DicomVolume.m b/ShoulderCase/@DicomVolume/DicomVolume.m new file mode 100644 index 0000000..b4d1bf8 --- /dev/null +++ b/ShoulderCase/@DicomVolume/DicomVolume.m @@ -0,0 +1,55 @@ +classdef (Abstract) DicomVolume < handle + + properties + volume = [] + spatial = [] + dicomInfo = [] + dicomFolderPath = [] + end + + + + methods + function set.volume(obj,volume) + assert(length(size(volume))>=3,'Volume must be a 3D array') + obj.volume = squeeze(volume); + end + + function set.spatial(obj,spatial) + requiredStructureField = {'PatientPositions','PixelSpacings','PatientOrientations'}; + assert(all(contains(fields(spatial),requiredStructureField)),'Invalid spatial structure'); + obj.spatial = spatial; + end + + function loadDataFromFolder(obj,dicomFolderPath) + assert(obj.pathContainsDicomFiles(dicomFolderPath)); + obj.dicomFolderPath = dicomFolderPath; + [obj.volume,obj.spatial,~] = dicomreadVolume(dicomFolderPath); + obj.loadDicomInfoFromFolder(dicomFolderPath); + end + + function loadDicomInfoFromFolder(obj,dicomFolderPath) + assert(obj.pathContainsDicomFiles(dicomFolderPath)); + dicomFiles = dir(fullfile(dicomFolderPath,'*.dcm')); + obj.dicomInfo = dicominfo(fullfile(dicomFiles(1).folder,dicomFiles(1).name)); + end + + function output = pathContainsDicomFiles(obj,path) + output = false; + assert(isfolder(path),'Provided argument is not a valid folder path'); + dicomFiles = dir(fullfile(path,'*.dcm')); + assert(not(isempty(dicomFiles)),'No dicom file found there %s',path); + output = true; + end + + function output = getPointIndexInVolume(obj,point) + % the output are the three indices of the given point in the given volume. + % i,j,k: output indices + k = find(abs(obj.spatial.PatientPositions(:,3)-point(3)) == min(abs(obj.spatial.PatientPositions(:,3)-point(3)))); + i = round( (point(1) - obj.spatial.PatientPositions(k,1)) / obj.spatial.PixelSpacings(k,1) ); + j = round( (point(2) - obj.spatial.PatientPositions(k,2)) / obj.spatial.PixelSpacings(k,2) ); + assert(all([i j k] < size(obj.volume)),'Indices found are outside the volume boundaries'); + output = [i,j,k]; + end + end +end diff --git a/ShoulderCase/@DicomVolumeNormaliser/DicomVolumeNormaliser.m b/ShoulderCase/@DicomVolumeNormaliser/DicomVolumeNormaliser.m new file mode 100644 index 0000000..906df6c --- /dev/null +++ b/ShoulderCase/@DicomVolumeNormaliser/DicomVolumeNormaliser.m @@ -0,0 +1,55 @@ +classdef DicomVolumeNormaliser < handle & DicomVolume + + properties + resolution = []; + normalisedVolume = []; + end + + + + methods + + function obj = DicomVolumeNormaliser(varargin) + if (nargin == 1) + obj.loadDataFromFolder(varargin{1}); + end + end + + function setMinimalResolution(obj) + zSpacing = obj.spatial.PatientPositions(2:end,3)-obj.spatial.PatientPositions(1:end-1,3); + minZ = min(zSpacing,[],'all'); + minXY = min(obj.spatial.PixelSpacings,[],'all'); + obj.resolution = min([minXY minZ],[],'all')/2; + end + + function normalise(obj) + normalisedSizeZ = round(abs(obj.spatial.PatientPositions(1,3) - obj.spatial.PatientPositions(end,3))/obj.resolution); + normalisedSizeX = round(max(obj.spatial.PixelSpacings(:,1),[],'all')*size(obj.volume,1)/obj.resolution); + normalisedSizeY = round(max(obj.spatial.PixelSpacings(:,2),[],'all')*size(obj.volume,2)/obj.resolution); + obj.normalisedVolume = imresize3(obj.volume,[normalisedSizeX normalisedSizeY normalisedSizeZ]); + end + + function OLDnormalise(obj) + normalisedSizeZ = round(abs(obj.spatial.PatientPositions(1,3) - obj.spatial.PatientPositions(end,3))/obj.resolution); + normalisedSizeX = round(max(obj.spatial.PixelSpacings(:,1),[],'all')*size(obj.volume,1)/obj.resolution); + normalisedSizeY = round(max(obj.spatial.PixelSpacings(:,2),[],'all')*size(obj.volume,2)/obj.resolution); + obj.normalisedVolume = zeros(normalisedSizeX,normalisedSizeY,normalisedSizeZ); + for x = 1:size(obj.normalisedVolume,1) + disp(sprintf('%d', round(100*x/size(obj.normalisedVolume,1)))) + for y = 1:size(obj.normalisedVolume,2) + for z = 1:size(obj.normalisedVolume,3) + pointPosition = obj.spatial.PatientPositions(1,:)+obj.resolution*[x y z]; + try + pointIndices = obj.getPointIndexInDicomVolume(pointPosition); + catch + [x y z] + pointPosition + end + obj.normalisedVolume(x,y,z) = obj.volume(pointIndices(1),pointIndices(2),pointIndices(3)); + end + end + end + end + end + +end diff --git a/ShoulderCase/@DicomVolumeSlicer/DicomVolumeSlicer.m b/ShoulderCase/@DicomVolumeSlicer/DicomVolumeSlicer.m index 393b9fe..bee14b4 100644 --- a/ShoulderCase/@DicomVolumeSlicer/DicomVolumeSlicer.m +++ b/ShoulderCase/@DicomVolumeSlicer/DicomVolumeSlicer.m @@ -1,51 +1,30 @@ -classdef DicomVolumeSlicer < handle & MethodsMonitor +classdef DicomVolumeSlicer < handle & DicomVolume & DicomVolumeNormaliser properties - dicomPath - dicomInfo - volume - spatial - sliced slicedPixelSpacing end methods - function obj = DicomVolumeSlicer(dicomPathOrSCase) - obj.startMethodsMonitoring; - obj.setAllMethodsAvailable - - if isa(dicomPathOrSCase,'ShoulderCase') - obj.dicomPath = obj.getDicomPathFromSCase(dicomPathOrSCase); - elseif isa(dicomPathOrSCase,'char') - obj.dicomPath = dicomPathOrSCase; - else - returnedError.identifier = 'DicomVolumeSlicer:ConstructorInvalidArgument'; - returnedError.message = 'The given argument should be a ShoulderCase or a char array'; - error(returnedError); + function obj = DicomVolumeSlicer(varargin) + if (nargin == 1) + obj.loadDataFromFolder(varargin{1}); end - - obj.dicomInfo = obj.getDicomInfo; - - [obj.volume,obj.spatial,~] = dicomreadVolume(obj.dicomPath); - obj.volume = squeeze(obj.volume); end function slice(obj,point,normalVector) - pointIndices = obj.getPointIndexInDicomVolume(point); - vectorIndices = pointIndices - obj.getPointIndexInDicomVolume(point+normalVector); - obj.slicedPixelSpacing = obj.getPixelSpacingInPlane(pointIndices,vectorIndices); + pointIndices = obj.getPointIndexInVolume(point); + vectorIndices = pointIndices - obj.getPointIndexInVolume(point+normalVector); [obj.sliced,x,y,z] = obliqueslice(obj.volume,pointIndices,vectorIndices,... - 'FillValues',min(obj.volume,[],'all'),... - 'OutputSize','limit'); + 'FillValues',min(obj.volume,[],'all')); obj.sliced = obj.sliced'; obj.sliced = obj.sliced*obj.dicomInfo.RescaleSlope + obj.dicomInfo.RescaleIntercept; end end end diff --git a/ShoulderCase/@DicomVolumeSlicer/getDicomPathFromSCase.m b/ShoulderCase/@DicomVolumeSlicer/getDicomPathFromSCase.m deleted file mode 100644 index 88142f4..0000000 --- a/ShoulderCase/@DicomVolumeSlicer/getDicomPathFromSCase.m +++ /dev/null @@ -1,15 +0,0 @@ -function output = getDicomPathFromSCase(obj,SCase) - output = []; - rawDicomPath = fullfile(SCase.dataCTPath,'dicom'); - smoothDicomPath = fullfile([SCase.dataCTPath(1:end-1) '2'],'dicom'); - - if exist(smoothDicomPath,'dir') - output = smoothDicomPath; - elseif exist(rawDicomPath,'dir') - output = rawDicomPath; - else - raisedError.identifier = 'ShoulderCase:Shoulder:Muscles:getDicomPath:InvalidPath'; - raisedError.message = '%s is not a valid folder'; - error(raisedError); - end -end diff --git a/ShoulderCase/@DicomVolumeSlicer/getPixelSpacingInPlane.m b/ShoulderCase/@DicomVolumeSlicer/getPixelSpacingInPlane.m deleted file mode 100644 index e6f9bbf..0000000 --- a/ShoulderCase/@DicomVolumeSlicer/getPixelSpacingInPlane.m +++ /dev/null @@ -1,3 +0,0 @@ -function output = getPixelSpacingInPlane(obj,pointIndices,vector) - output = []; -end diff --git a/ShoulderCase/@DicomVolumeSlicer/getPointIndexInDicomVolume.m b/ShoulderCase/@DicomVolumeSlicer/getPointIndexInDicomVolume.m deleted file mode 100644 index 78b776d..0000000 --- a/ShoulderCase/@DicomVolumeSlicer/getPointIndexInDicomVolume.m +++ /dev/null @@ -1,8 +0,0 @@ -function output = getPointIndexInCurrentVolume(obj,point) - % the output are the three indices of the given point in the given volume. - % i,j,k: output indices - k = find(abs(obj.spatial.PatientPositions(:,3)-point(3)) == min(abs(obj.spatial.PatientPositions(:,3)-point(3)))); - i = round( (point(1) - obj.spatial.PatientPositions(k,1)) / obj.spatial.PixelSpacings(k,1) ); - j = round( (point(2) - obj.spatial.PatientPositions(k,2)) / obj.spatial.PixelSpacings(k,2) ); - output = [i,j,k]; -end diff --git a/ShoulderCase/@DicomVolumeSlicer/getDicomInfo.m b/ShoulderCase/@ShoulderCase/getSmoothDicomInfo.m similarity index 55% rename from ShoulderCase/@DicomVolumeSlicer/getDicomInfo.m rename to ShoulderCase/@ShoulderCase/getSmoothDicomInfo.m index a386ec3..fcbdc80 100644 --- a/ShoulderCase/@DicomVolumeSlicer/getDicomInfo.m +++ b/ShoulderCase/@ShoulderCase/getSmoothDicomInfo.m @@ -1,7 +1,6 @@ -function output = getDicomInfo(obj) - % Return the result of dicominfo() with the first dicom file found in - % the dicomPath folder given as argument. - dicomFiles = dir(fullfile(obj.dicomPath,'*.dcm')); - assert(not(isempty(dicomFiles)),'No dicom file found there %s',obj.dicomPath) +function output = getSmoothDicomInfo(obj) + % Return the result of dicominfo() with the first dicom file found + dicomFiles = dir(fullfile(obj.getSmoothDicomPath,'*.dcm')); + assert(not(isempty(dicomFiles)),'No dicom file found there %s',obj.getSmoothDicomPath); output = dicominfo(fullfile(dicomFiles(1).folder,dicomFiles(1).name)); end diff --git a/ShoulderCase/@ShoulderCase/getSmoothDicomPath.m b/ShoulderCase/@ShoulderCase/getSmoothDicomPath.m new file mode 100644 index 0000000..862c90d --- /dev/null +++ b/ShoulderCase/@ShoulderCase/getSmoothDicomPath.m @@ -0,0 +1,6 @@ +function output = getSmoothDicomPath(obj) + output = []; + smoothDicomPath = fullfile([obj.dataCTPath(1:end-1) '2'],'dicom'); + assert(isfolder(smoothDicomPath),'No smooth dicom for this SCase. %s is not a valid folder',smoothDicomPath); + output = smoothDicomPath; +end