pinn2matlab.asv 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. % pinn2matlab.m
  2. %
  3. % Ryan T Flynn 23 August 2007
  4. %
  5. % Reads in raw Pinnacle data to a MATLAB data structure. The patient CT,
  6. % ROIs, and Trial files can all be read in if available and desired. The
  7. % result is a structure called 'Geometry', which contains ROIS and Trial
  8. % fields.
  9. %
  10. % The CT image and all of the ROIs are flipped onto a coordinate system in
  11. % which the position of each voxel index (i,j,k) are given by:
  12. %
  13. % x(i) = x0 + i*delx; (i=0,...,M-1)
  14. % y(j) = y0 + j*delx; (j=0,...,N-1)
  15. % z(k) = z0 + k*delx; (k=0,...,Q-1)
  16. %
  17. % As opposed to the Pinnacle coordinate system, which
  18. %
  19. % x(i) = x0 + i*delx; (i=0,...,M-1)
  20. % y(j) = y0 + (N-1-j)*dely; (j=0,...,N-1)
  21. % z(k) = z0 + k*delz; (k=0,...,Q-1)
  22. %%%%% Start of user supplied inputs %%%%%
  23. % Read-in flags
  24. readTrial = 'no'; % either 'yes' or 'no'
  25. readROIS = 'yes'; % either 'yes' or 'no'
  26. % locations of the Pinnacle files
  27. roifile = 'C:\Documents and Settings\Steve\Desktop\steveTPS\plan\plan.roi';
  28. imageheaderfile = 'C:\Documents and Settings\Steve\Desktop\steveTPS\plan\ImageSet_0.header';
  29. imagefile = 'C:\Documents and Settings\Steve\Desktop\steveTPS\plan\ImageSet_0.img'; % CT file
  30. save_file = 'C:\Documents and Settings\Steve\Desktop\steveTPS\plan\lung.mat';
  31. %%%%% End of user supplied inputs %%%%%
  32. start_ind = '(1,1,1)'; % this tag will be added to the ROIS so it is known where the start voxel is
  33. clear roi ROIS Trial Geometry CTimage; % start with a clean slate of structures
  34. % extract geometric information from the header file
  35. fid_imageheaderfile = fopen(imageheaderfile,'r');
  36. tline = fgets(fid_imageheaderfile);
  37. while tline ~= -1
  38. % check the line for key words
  39. if length(findstr(tline,'x_dim')) & ~length(findstr(tline,'fname_index_start'))
  40. eval(tline); % run the line to get x_dim
  41. elseif length(findstr(tline,'y_dim'))
  42. eval(tline); % run the line to get y_dim
  43. elseif length(findstr(tline,'z_dim'))
  44. eval(tline); % run the line to get z_dim
  45. elseif length(findstr(tline,'x_pixdim'))
  46. eval(tline); % run the line to get x_pixdim
  47. elseif length(findstr(tline,'y_pixdim'))
  48. eval(tline); % run the line to get y_pixdim
  49. elseif length(findstr(tline,'z_pixdim'))
  50. eval(tline); % run the line to get z_pixdim
  51. elseif length(findstr(tline,'x_start'))
  52. eval(tline); % run the line to get x_start
  53. elseif length(findstr(tline,'y_start'))
  54. eval(tline); % run the line to get x_start
  55. elseif length(findstr(tline,'z_start'))
  56. eval(tline); % run the line to get x_start
  57. end
  58. tline = fgets(fid_imageheaderfile);
  59. end
  60. fclose(fid_imageheaderfile);
  61. % Read in the CT data
  62. fid_image = fopen(imagefile,'rb');
  63. CTimage = fread(fid_image,'short=>int16','ieee-be');
  64. CTimage = reshape(CTimage,x_dim,y_dim,z_dim);
  65. fclose(fid_image);
  66. % flip the CT image onto the non-Pinnacle coordinate system
  67. CTimage = flipdim(CTimage,2);
  68. % save the results to the Geometry structure
  69. Geometry.start = single([x_start y_start z_start]);
  70. Geometry.voxel_size = single([x_pixdim y_pixdim z_pixdim]);
  71. Geometry.data = single(CTimage)/1024; % convert the CT data to density data, Pinnacle style
  72. Geometry.data(Geometry.data < 0) = 0; % truncate anything less than zero
  73. clear CTimage;
  74. if strcmp(readROIS,'yes')
  75. % read in the roi file
  76. fid_roifile = fopen(roifile,'r');
  77. roinames = {}; % start a cell array of the roi names
  78. Nroi = 0; % number of rois read in
  79. % Flags to indicate which sets of angled brackets in the roi file tline is
  80. % inside.
  81. inroi = 0;
  82. incurve = 0;
  83. inpoints = 0;
  84. roi_num = 0; % current roi number
  85. tline = fgets(fid_roifile);
  86. while tline ~= -1
  87. % check the line for key words
  88. if length(findstr(tline,'roi={'))
  89. inroi = 1; % mark that we are now currently inside of an roi
  90. roi_num = roi_num + 1;
  91. % next line contains the roi name
  92. tline = fgets(fid_roifile);
  93. % pop off first token in line, the remainder of the line is the roi name
  94. [T,R] = strtok(tline);
  95. roi.name = strtrim(R);
  96. % pop off lines until we get to the number of curves in this roi
  97. while ~length(findstr(tline,'num_curve'))
  98. tline = fgets(fid_roifile);
  99. end
  100. % pop off the num_curve string
  101. [T,R] = strtok(tline);
  102. % pop off the equals sign
  103. [T,R] = strtok(R);
  104. % pop off the number of curves in this roi
  105. T = strtok(R,';');
  106. % save the number of curves to the roi stucture
  107. eval(['roi.num_curves = ' num2str(T) ';']);
  108. roi.curves = {}; % get the curves structure started
  109. % read in the next curve structure
  110. curve_num = 0; % number of the current curve
  111. while roi.num_curves > 0 & curve_num < roi.num_curves
  112. while ~length(findstr(tline,'curve={'));
  113. tline = fgets(fid_roifile);
  114. end
  115. curve_num = curve_num + 1;
  116. incurve = 1; % inside the curve structure now
  117. % find the number of points in this structure
  118. while ~length(findstr(tline,'num_points'))
  119. tline = fgets(fid_roifile);
  120. end
  121. % pop off the num_points string
  122. [T,R] = strtok(tline);
  123. % pop off the equals sign
  124. [T,R] = strtok(R);
  125. % pop off the number of points in this curve
  126. T = strtok(R,';');
  127. eval(['num_points = ' num2str(T) ';']);
  128. % find the points identifier
  129. while ~length(findstr(tline,'points={'))
  130. tline = fgets(fid_roifile);
  131. end
  132. inpoints = 1; % inside the points structure now
  133. % read in the block of points data
  134. block = fscanf(fid_roifile,'%g',[3 num_points]);
  135. % save the block of points to the roi stucture
  136. roi.curves{curve_num} = block';
  137. % read in the right parantheses for the points and curve
  138. % structures
  139. while ~length(findstr(tline,'};'))
  140. tline = fgets(fid_roifile);
  141. end
  142. inpoints = 0; % stepped outside of the points structure
  143. while ~length(findstr(tline,'};'))
  144. tline = fgets(fid_roifile);
  145. end
  146. incurve = 0; % stepped outside of the curves structure
  147. end
  148. % read until the roi closing bracket appears
  149. while ~length(findstr(tline,'};'))
  150. tline = fgets(fid_roifile);
  151. end
  152. inroi = 0; % we are now outside of the roi
  153. fprintf('read in %s roi\n',roi.name);
  154. ROIS{roi_num} = roi;
  155. end
  156. tline = fgets(fid_roifile);
  157. end
  158. fclose(fid_roifile);
  159. % ROIS have all been read-in, now just have to convert them to mask
  160. % matrices. We'll use roipoly for this.
  161. % Recall that we must use the Pinnacle coordinate system for this to work,
  162. % that is, (x,y,z) coordinates are given by:
  163. % x(i) = x_start + i*x_pixdim, i=0..x_dim-1
  164. % y(j) = y_start + (y_dim-1)*y_pixdim - j*y_pixdim, j=0..y_dim-1
  165. % z(k) = z_start + k*z_pixdim, k=0..z_dim-1
  166. %
  167. % Not all treatment planning systems use this type of coordinate system
  168. % definition, so it is very important to get them straight.
  169. %
  170. % To get around this we will manipulate the data such that we'll have:
  171. %
  172. % x(i) = x_start + i*x_pixdim, i=0..x_dim-1
  173. % y(j) = y_start + j*y_pixdim, j=0..y_dim-1
  174. % z(k) = z_start + k*z_pixdim, k=0..z_dim-1
  175. %
  176. % This can be done by a simple fliplr operation on all of the CT slices
  177. % define the coordinate system
  178. x = x_start:x_pixdim:x_start + (x_dim-1)*x_pixdim;
  179. y = y_start:y_pixdim:y_start + (y_dim-1)*y_pixdim;
  180. z = z_start:z_pixdim:z_start + (z_dim-1)*z_pixdim;
  181. % define the locations of the corners of the pixels in each slice
  182. xCorners = [x - x_pixdim/2 x(end) + x_pixdim/2];
  183. yCorners = [y - y_pixdim/2 y(end) + y_pixdim/2];
  184. % loop through all rois
  185. for roi_num=1:length(ROIS)
  186. % set up the roi mask
  187. roimask = zeros(x_dim,y_dim,z_dim,'int8');
  188. roimaskCorners = zeros(x_dim+1,y_dim+1,z_dim,'int8');
  189. % loop through all of the curves in the roi
  190. for curve_num=1:length(ROIS{roi_num}.curves)
  191. % make a copy of the curve for easy access
  192. current_curve = ROIS{roi_num}.curves{curve_num};
  193. % find the z-index (slice number) of this curve
  194. q = round((current_curve(1,3)-z_start)/z_pixdim) + 1;
  195. % put these index vectors into roipoly
  196. if q >= 1 & q <= z_dim
  197. roisliceCorners = double(roimaskCorners(:,:,q));
  198. % find which corners are inside the contour
  199. BWcorners = roipoly(yCorners,xCorners,roisliceCorners,current_curve(:,2),current_curve(:,1));
  200. % Mark all all pixels bordering corners that are inside the
  201. % contour
  202. roi_vox = sum(BWcorners(:)); % number of voxels in this ROI
  203. % find the voxel overlap between the current roi and BW:
  204. overlap_vox = sum(sum(BWcorners.*roisliceCorners));
  205. if overlap_vox == roi_vox
  206. roisliceCorners = roisliceCorners - BWcorners;
  207. else % if there is not perfect overlap, add the rois
  208. roisliceCorners = roisliceCorners + BWcorners;
  209. end
  210. roisliceCorners(roisliceCorners > 0) = 1; % make sure all mask values are unity
  211. roimaskCorners(:,:,q) = int8(roisliceCorners); % update the overall mask
  212. end
  213. end
  214. % save time be resampling only a subregion
  215. ind = find(roimaskCorners);
  216. [I,J,K] = ind2sub([x_dim+1 y_dim+1 z_dim],ind);
  217. indx = min(I)-3:max(I)+3;
  218. indy = min(J)-3:max(J)+3;
  219. indz = min(K)-3:max(K)+3;
  220. indx = indx(indx >= 1 & indx <= x_dim);
  221. indy = indy(indy >= 1 & indy <= y_dim);
  222. indz = indz(indz >= 1 & indz <= z_dim);
  223. % convert the corners to a 3-D roi mask
  224. roimask(indx,indy,indz) = ceil(gridResample3D(xCorners,yCorners,z,roimaskCorners,x(indx),y(indy),z(indz)));
  225. % save the indices of the roi mask
  226. ROIS{roi_num}.ind = int32(find(roimask ~= 0));
  227. ROIS{roi_num}.dim = [x_dim y_dim z_dim];
  228. ROIS{roi_num}.pixdim = [x_pixdim y_pixdim z_pixdim];
  229. ROIS{roi_num}.start = [x_start y_start z_start];
  230. ROIS{roi_num}.start_ind = start_ind;
  231. fprintf('Converted %s vectors to an roi mask.\n',ROIS{roi_num}.name);
  232. end
  233. % save ROIS to the Geometry structure
  234. Geometry.ROIS = ROIS;
  235. clear ROIS;
  236. end
  237. if strcmp(readTrial,'yes')
  238. % read in the Trial information
  239. fid_trialfile = fopen(trialfile,'r');
  240. tline = fgets(fid_trialfile);
  241. structstack = {}; % stack for determining which field we're inside
  242. structind = []; % structure index values for each field
  243. lines = 1;
  244. while tline ~= -1 % read through the trial file
  245. tline = regexprep(tline,'"',''''); % replace " with '
  246. tline = regexprep(tline,'[',''); % bad characters to remove
  247. tline = regexprep(tline,']',''); % bad characters to remove
  248. tline = regexprep(tline,'#','num');
  249. tline = regexprep(tline,'\\','''');
  250. % fprintf(tline);
  251. if length(findstr(tline,'{'))
  252. % mark the structure we just entered, removing any blank space
  253. structstack{length(structstack) + 1} = regexprep(strtok(tline,'='),' ','');
  254. if length(structstack) == 1
  255. structstack{1} = 'Trial'; % make sure structure name is always the same
  256. end
  257. if strcmp(structstack{end},'Beam') % found a beam structure
  258. % find the number of existing beams at this location
  259. eval_line = ['beams = getfield(' structstack{1}];
  260. for k=2:length(structstack)
  261. eval_line = [eval_line ',''' structstack{k} ''''];
  262. end
  263. eval_line = [eval_line ');'];
  264. try
  265. eval(eval_line);
  266. num_beams = length(beams) + 1; % this is the current beam number
  267. catch % there was an error, so there are no beams yet
  268. num_beams = 1; % we're on the first beam now
  269. end
  270. end
  271. elseif length(findstr(tline,'}'))
  272. structstack(end) = []; % step outside of the current field
  273. else % the line must be a subfield assignment
  274. if strcmp(structstack{end},'Points') % this case treated specially
  275. % read-in values until the next '}' is reached
  276. lines = lines + 1;
  277. mlc_vec = ['['];
  278. while ~length(findstr(tline,'}'))
  279. % build up the vector of MLC positions
  280. mlc_vec = [mlc_vec regexprep(tline,' ','')];
  281. tline = fgets(fid_trialfile);
  282. % fprintf(tline);
  283. lines = lines + 1;
  284. end
  285. mlc_vec = [mlc_vec ']'];
  286. % evaluate the points vector
  287. eval_statement = structstack{1};
  288. for k=2:length(structstack)
  289. if strcmp(structstack{k},'Beam')
  290. % include the beam number
  291. eval_statement = [eval_statement '.' structstack{k} '(' num2str(num_beams) ')'];
  292. else % non-beam structure, so don't worry about it
  293. eval_statement = [eval_statement '.' structstack{k}];
  294. end
  295. end
  296. eval_statement = [eval_statement ' = ' mlc_vec ';'];
  297. eval(eval_statement);
  298. structstack(end) = []; % step outside of the current Points[] field
  299. else
  300. % see if there are any subfields in the expression
  301. % evaluate the statement
  302. eval_statement = structstack{1};
  303. for k=2:length(structstack)
  304. if strcmp(structstack{k},'Beam')
  305. % include the beam number
  306. eval_statement = [eval_statement '.' structstack{k} '(' num2str(num_beams) ')'];
  307. else % non-beam structure, so don't worry about it
  308. eval_statement = [eval_statement '.' structstack{k}];
  309. end
  310. end
  311. eval_statement = [eval_statement '.' tline];
  312. eval(eval_statement);
  313. end
  314. end
  315. tline = fgets(fid_trialfile);
  316. lines = lines + 1;
  317. if isempty(structstack)
  318. break; % we're done if we're no longer inside any sets of curly brackets
  319. end
  320. end
  321. fclose(fid_trialfile);
  322. % dose grid dimensions
  323. xdim = Trial.DoseGrid.Dimension.X;
  324. ydim = Trial.DoseGrid.Dimension.Y;
  325. zdim = Trial.DoseGrid.Dimension.Z;
  326. siz = [xdim ydim zdim]; % dosegrid size vector
  327. % vector describing the start location of the dose grids
  328. xstart = Trial.DoseGrid.Origin.X;
  329. ystart = Trial.DoseGrid.Origin.Y;
  330. zstart = Trial.DoseGrid.Origin.Z;
  331. start = [xstart ystart zstart]; % dosegrid start vector
  332. % vector describing the size of each voxel
  333. dx = Trial.DoseGrid.VoxelSize.X;
  334. dy = Trial.DoseGrid.VoxelSize.Y;
  335. dz = Trial.DoseGrid.VoxelSize.Z;
  336. voxel_size = [dx dy dz];
  337. % Read in the beamlet dose distributions, DRRs, and fluences and store them in
  338. % Trial.BeamList.Beam(k), where k is the beam number
  339. for k=0:num_beams-1
  340. % read-in the dose distribution
  341. num_vec = num2str(k*5+4);
  342. % ensure that num_vec has a length of 3
  343. while length(num_vec) < 3
  344. num_vec = ['0' num_vec];
  345. end
  346. dose_file = [dose_file_base_name '.' num_vec];
  347. fid = fopen(dose_file,'rb','ieee-be');
  348. if fid ~= -1
  349. dose = fread(fid,'float=>float');
  350. fclose(fid);
  351. try
  352. dose = reshape(dose,siz);
  353. % flip the dose distribution in accordance with the CT image
  354. for j=1:siz(3)
  355. dose(:,:,j) = single(fliplr(double(dose(:,:,j))));
  356. end
  357. % save the dose
  358. Trial = setfield(Trial,'BeamList','Beam',{k+1},'dose',dose);
  359. catch
  360. fprintf('Dose for beam %g did not meet specifications so it was not read-in.\n',k+1);
  361. end
  362. end
  363. % read-in the DRR
  364. % find the size of this drr
  365. drr_x = Trial.BeamList.Beam(1).FilmImageList.FilmImage.Image.Dimension.X;
  366. drr_y = Trial.BeamList.Beam(1).FilmImageList.FilmImage.Image.Dimension.Y;
  367. siz_drr = [drr_x drr_y];
  368. num_vec = num2str(k*5+3);
  369. % ensure that num_vec has a length of 3
  370. while length(num_vec) < 3
  371. num_vec = ['0' num_vec];
  372. end
  373. drr_file = [dose_file_base_name '.' num_vec];
  374. fid = fopen(drr_file,'rb','ieee-be');
  375. if fid ~= -1
  376. drr = fread(fid,'float');
  377. fclose(fid);
  378. try % proceed only if the drr was read-in properly
  379. drr = reshape(drr,siz_drr);
  380. % save the DRR
  381. Trial = setfield(Trial,'BeamList','Beam',{k+1},'FilmImageList','FilmImage','Image','drr',drr);
  382. catch
  383. fprintf('DRR for beam %g did not meet specifications so it was not read-in.\n',k+1);
  384. end
  385. end
  386. % read in the fluence map
  387. num_vec = num2str(k*5+2);
  388. fluence_siz = [101 101 3]; % all fluence must have this size otherwise and error will be thrown
  389. % ensure that num_vec has a length of 3
  390. while length(num_vec) < 3
  391. num_vec = ['0' num_vec];
  392. end
  393. fluence_file = [dose_file_base_name '.' num_vec];
  394. fid = fopen(fluence_file,'rb','ieee-be');
  395. if fid ~= -1
  396. fluence = fread(fid,'float');
  397. fclose(fid);
  398. % check to see if fluence matches dose grid size
  399. if Trial.FluenceGridMatchesDoseGrid ~= 1
  400. error('Fluence grid does not match dose grid for beam %g, don''t know what to do here.',k+1);
  401. end
  402. try % proceed only if the fluence is read-in properly
  403. fluence = reshape(fluence,fluence_siz);
  404. % save the fluence
  405. Trial = setfield(Trial,'BeamList','Beam',{k+1},'FluenceMap',fluence);
  406. catch
  407. fprintf('Fluence map for beam %g did not meet specifications so it was not read-in.\n',k+1);
  408. end
  409. end
  410. end
  411. % add up all of the doses
  412. dose_tot = zeros(siz);
  413. for k=1:num_beams
  414. if isfield(Trial.BeamList.Beam(k),'dose') & ~isempty(Trial.BeamList.Beam(k).dose)
  415. dose_tot = dose_tot + double(Trial.BeamList.Beam(k).dose);
  416. end
  417. end
  418. Geometry.Trial = Trial;
  419. clear Trial;
  420. end
  421. save(save_file,'Geometry');