dicomrt2geometry.m 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. function Geometry = dicomrt2geometry(dicomrt_dir)
  2. %DICOMRT2GEOMETRY Import DicomRT dataset to Ryan's "Geometry" struct
  3. % Usage:
  4. % [ Geometry ] = dicomrt2geometry ( [input_dir] )
  5. % Input:
  6. % input_dir = directory contains DicomRT data
  7. % [] = prompt to select input_dir
  8. % Output:
  9. % Geometry = Ryan's Geometry struct used with RDX TPS
  10. %
  11. % This function imports DicomRT data set and create RDX TPS compatible Geometry
  12. % struct.
  13. %
  14. % TODO: Switch from filename based Dicom identification to StudyID based.
  15. %
  16. % See also readPinnGeometry.m
  17. %
  18. % Author: Xiaohu Mo
  19. % edits: Peter Ferjancic 2019/01
  20. Geometry = [];
  21. if nargin < 1
  22. % dicomrt_dir = uifile('getdir', 'Select the directory contains the DICOM-RT images');
  23. % !!! Grozomah
  24. load('WiscPlan_preferences.mat')
  25. if isfield(WiscPlan_preferences, 'inDataPath')
  26. if isstring(WiscPlan_preferences.inDataPath)
  27. else
  28. WiscPlan_preferences.inDataPath = 'C://';
  29. end
  30. else
  31. WiscPlan_preferences.inDataPath = 'C://';
  32. end
  33. dicomrt_dir = uigetdir(WiscPlan_preferences.inDataPath, 'Select the directory contains the DICOM-RT images');
  34. WiscPlan_preferences.inDataPath = dicomrt_dir;
  35. thisDir = mfilename('fullpath');
  36. idcs = strfind(thisDir,'\');
  37. prefsdir = thisDir(1:idcs(end-1)-1);
  38. save([prefsdir '\WiscPlan_preferences.mat'], 'WiscPlan_preferences')
  39. end
  40. if exist(dicomrt_dir, 'dir') ~= 7
  41. msgbox('Cannot find input directory');
  42. return;
  43. end
  44. %% -----===== Start Importing =====-----
  45. % set dicom dictionary before any dicominfo or dicomread
  46. dicomdict('factory');
  47. % change path due to the limitation of DicomRT toolbox
  48. % will cd back later
  49. previousPath = pwd;
  50. cd(dicomrt_dir);
  51. % get the list of filenames
  52. dirlist = dir(dicomrt_dir);
  53. filenames = cell(0);
  54. % remove directories
  55. for i = 1:numel(dirlist)
  56. [tilde, tilde, ext] = fileparts(dirlist(i).name);
  57. % if ~dirlist(i).isdir && strcmpi(ext, '.dcm')
  58. if ~dirlist(i).isdir && ~strcmpi(ext, '.txt') % <--- Grozomah: Fix this back to default!
  59. filenames{end+1} = dirlist(i).name;
  60. end
  61. end
  62. % get all dicominfo to a cell array the same size as filelist
  63. for i = 1:numel(filenames)
  64. dcminfo{i} = dicominfo(filenames{i});
  65. end
  66. % TODO integrity check
  67. % UID should match
  68. % should be only one RTSTRUCT file present
  69. %% -----===== Import Dicom CT data set =====-----
  70. % Create DicomRT ct list file
  71. fid = fopen('ctlist.txt', 'w');
  72. for i = 1:numel(dcminfo)
  73. if strcmpi(dcminfo{i}.Modality, 'CT')
  74. fprintf(fid, '%s\n', filenames{i});
  75. end
  76. end
  77. fclose(fid);
  78. [cellCt, ct_xmesh, ct_ymesh, ct_zmesh] = dicomrt_loadct('ctlist.txt');
  79. %% -----===== Set Downsampling flag =====-----
  80. button = questdlg('Do you want to downsample the CT dataset?', 'Downsampling', 'Yes', 'No', 'Yes');
  81. if strcmpi(button, 'yes')
  82. downsample_flag = true;
  83. else
  84. downsample_flag = false;
  85. end
  86. %% -----===== Import DicomRT structure =====-----
  87. % File DicomRT structure file
  88. for i = 1:numel(dcminfo)
  89. if strcmpi(dcminfo{i}.Modality, 'RTSTRUCT')
  90. rsfilename = fullfile(dicomrt_dir, filenames{i});
  91. end
  92. end
  93. % prompt if can not find RTSTRUCT file in this directory
  94. if isempty(rsfilename)
  95. [temp_FileName temp_PathName] = uifile('get', '*.dcm', 'Please select the DicomRT-Struct file');
  96. rsfilename = fullfile(temp_PathName, temp_FileName);
  97. end
  98. % Import the struct
  99. cellVoi = dicomrt_loadvoi(rsfilename);
  100. % Downsampling
  101. if downsample_flag == true
  102. if numel(ct_xmesh) < 128
  103. downsample_factor = 0.5;
  104. dx = ct_xmesh(2)-ct_xmesh(1);
  105. dy = ct_ymesh(2)-ct_ymesh(1);
  106. ct_xmesh = linspace(ct_xmesh(1)+dx/2, ct_xmesh(end)-dx/2, numel(ct_xmesh)*downsample_factor);
  107. ct_ymesh = linspace(ct_ymesh(1)+dy/2, ct_ymesh(end)-dy/2, numel(ct_ymesh)*downsample_factor);
  108. else
  109. downsample_factor = 0.5;
  110. downsample_factor = 1/2;
  111. dx = ct_xmesh(2)-ct_xmesh(1);
  112. dy = ct_ymesh(2)-ct_ymesh(1);
  113. ct_xmesh = linspace(ct_xmesh(1)+dx/2, ct_xmesh(end)-dx/2, numel(ct_xmesh)*downsample_factor);
  114. ct_ymesh = linspace(ct_ymesh(1)+dy/2, ct_ymesh(end)-dy/2, numel(ct_ymesh)*downsample_factor);
  115. end
  116. end
  117. ROIS = dicomrt_rasterizeVoi(cellVoi, cellCt, ct_xmesh, ct_ymesh, ct_zmesh);
  118. %% -----===== Done Importing =====-----
  119. % change the path back
  120. cd(previousPath);
  121. %% -----===== Create Geometry struct =====-----
  122. Geometry.ROIS = ROIS;
  123. Geometry.data = cellCt{2};
  124. % !!! Grozomah - added abs() to prevent errors in later functions
  125. Geometry.voxel_size = abs([ct_xmesh(2)-ct_xmesh(1) ...
  126. ct_ymesh(2)-ct_ymesh(1) ...
  127. ct_zmesh(2)-ct_zmesh(1)]);
  128. Geometry.start = [ct_xmesh(1) ct_ymesh(1) ct_zmesh(1)];
  129. if downsample_flag == true
  130. Geometry.data = resamplegrid(Geometry.data, [downsample_factor downsample_factor 1]);
  131. % Geometry.data = resamplegrid(Geometry.data, 0.5);
  132. % note that ct_xmesh, ct_ymesh, ct_zmesh is already downsampled
  133. Geometry.start(1:2) = Geometry.start(1:2) + Geometry.voxel_size(1:2) / 2;
  134. Geometry.voxel_size = Geometry.voxel_size/0.5;
  135. end
  136. Geometry.rhomw = CT2dens(Geometry.data, 'pinn');
  137. Geometry.rhomw(Geometry.rhomw < 0.0012) = 0.0012;
  138. [Geometry.Smw Geometry.Fmw2] = dens2mstp(Geometry.rhomw);