createFrames.m 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. function createFrames()
  2. %%%%%%%%%%%%%%%%%% DLB created 5/21/07 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. %
  4. % VERSION 2.3
  5. %
  6. % Updated: 2/23/09
  7. %
  8. % USEAGE: >> createFrames *hit Enter* :p
  9. %
  10. % DEPENDENCIES:
  11. % - you need a C:\Data folder (you should have this in Jeraj's grp
  12. % - need a data set WITH a .header file that was obtained using
  13. % Robert Pyzalski's adv2fl, adv2float, or Get_image program
  14. %
  15. % WHAT IT DOES:
  16. % this function converts anything from pyzalski's script into amira format
  17. % and puts the .am files in their appropriate places.
  18. % breaks up dynamic (4D) PET scans of any size and
  19. % correctly writes them as SUV or MBq/ml into Amira format regardless
  20. % of: the number of frames, pixel size, FOV size, recon grid. Currently
  21. % only C-11, F-18, Cu-61, and Cu-64 tracers have been put in. It
  22. % shouldn't be too much trouble to add others if ever the need arises.
  23. %
  24. % YES I'M AWARE THAT I DON'T APPLY THE 1/2 VOXEL SHIFT TO THE CT
  25. % Change amiraCTWriter if it bothers you.
  26. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  27. %
  28. % CHANGES to createFrames:
  29. %
  30. % VERSION 2.3
  31. % edit: removed the char(13) problem from certain headers that add extra
  32. % carrage returns, Ngoneh spotted it
  33. % - I changed the syntax that searches through the header files
  34. % DLB - 2/23/09
  35. %
  36. % VERSION 2.2
  37. % edit: Matt V pointed out MBq to mCi conversion still incorrect
  38. % - from *0.037 to /37. Finally correct
  39. % - FIXED 'static' and 'dynamic' string length bug that would ignore
  40. % any 'static' scan mode. Used 'else' to rename scan_mode for 'static'
  41. % cases. WILL NOT WORK with strcmp for future reference.
  42. % DLB - 1/6/09
  43. %
  44. % VERSION 2.1
  45. % edit: Matt V noted that my MBq to mCi conversion was incorrect
  46. % - fixed both from *0.037 to /37 dumb mistake
  47. % DLB - 11/5/08
  48. %
  49. % edit: Added stuff to the GUI that automatically updates
  50. % - mCi and uCi values for Matt V
  51. % - SUV factor for awesomeness
  52. % DLB - 10/24/08
  53. %
  54. % edit:
  55. % - Fixed flipz for all the PET's
  56. % - Added a mCi indicator to GUI
  57. % - Changed injection time and scan start times
  58. % DLB - 10/23/08
  59. %
  60. % VERSION 2.0
  61. % edit: After renaming this createStatic, I've switched back because I
  62. % like createFrames better (as does everyone else). Now the program:
  63. % - reads any size CT (converts them to shorts, thanks Keisha).
  64. % - has a nice SUV GUI with units and matching colours
  65. % - automatically flips the z dimension without asking
  66. % - added amiraCTWriter, amiraWriter, and checkHeader
  67. % - still need to write the WriteToHeader function!! lazy lazy
  68. % DLB - 10/17/08
  69. %
  70. % VERSION 1.0
  71. % edit: Added the _SUV_fr and _MBq_fr to the file ID (fid).
  72. % DLB - 12/13/07
  73. %
  74. % edit: Keisha pointed out the SUV calc was wrong along with a host of
  75. % other problems (radionuclide_name, logical check). I removed the ~
  76. % from logical and all seems to work fine.
  77. % DLB - 12/12/07
  78. %
  79. % edit: now added error messages and changes in case the header file has
  80. % insufficient information for the SUV calculation. cut out a bunch of
  81. % redundant code.
  82. % DLB - 11/28/07
  83. %
  84. % edit: now the ultimate... prompts you for MBq/ml or SUV values.
  85. % also prompts you for z-flipping. correctly decay corrects residual
  86. % to the initial syringe measurement, then corrects that value to the
  87. % start of the scan. all this is done by reading the header. no
  88. % more createFrames('flip')! won't work!
  89. % DLB - 11/27/07
  90. %
  91. % edit: added varargin to handle flipdim(?,3).
  92. % usage: createFrames('flip') - DLB 9/20/07
  93. % or createFrames <enter> for regular mode
  94. %
  95. % future will put in 'SUV' option as well
  96. %
  97. % edit: added half a voxel length to amira images, b/c that's how amira
  98. % reads them in. we've been doing it wrong all along!! - DLB 9/20/07
  99. %
  100. % edit: Changed the XYZBox in writing to Amira such that
  101. % everything is centered relative to a 50 cm CT FOV. ex. a 38 cm FOV is
  102. % centered so that it is in the center of the bounding box. - DLB 9/20/07
  103. % ____________ ____________
  104. % | | | | ______ |
  105. % | 30 | | to | | | |
  106. % |______| | | | 30 | |
  107. % | 50 | | |______| | <-- 50 cm
  108. % |____________| |____________|
  109. %
  110. % edit: Super huge update. Can now read multiple or single files of any
  111. % size file input without running out of memory!! 256x256 for 33
  112. % frames tested, works. This thing can handle it all now - DLB
  113. % 9/(18-19)/07
  114. % edit: now can read 1 file at a time again isa() - DLB 9/18/07
  115. % edit: now reads multiple files at once - DLB 9/16/07
  116. % edit: reads 4 unit frames e.g. 1120 - DLB summer 07
  117. % edit: reads header info now - DLB 5/22/07
  118. %
  119. % STOLE THE fprintp stuff from RTF's geom2am.m
  120. %
  121. warning off;
  122. s = pwd;
  123. cd C:\Data\
  124. %% here I'm just going to flip everything by default, uncomment the dialog for else
  125. % flip = questdlg('Flip the z dimension for everything you select?','Z-flip','Yes','No','Cancel');
  126. flip = 'Yes';
  127. % GUI for picking your .img files
  128. [filename, pathname, filterindex] = uigetfile({'*.img';'*.*'},'File Selector','Multiselect','on');
  129. if isequal(filename,0)
  130. disp('User selected Cancel')
  131. fclose all
  132. return
  133. else
  134. if isa(filename,'cell')
  135. for k = 1:length(filename)
  136. disp(['User selected ', fullfile(pathname, filename{k})])
  137. leng = length(filename);
  138. end
  139. else
  140. disp(['User selected ', fullfile(pathname, filename)])
  141. leng = 1;
  142. end
  143. end
  144. for numFile = 1:leng
  145. header_filename = filename;
  146. % open the .img file and associated .header file
  147. if isa(filename,'cell')
  148. header_fid = fopen([pathname strrep(header_filename{numFile},'.img','.header')],'r','ieee-be');
  149. fil = filename{numFile};
  150. else
  151. header_fid = fopen([pathname strrep(header_filename,'.img','.header')],'r','ieee-be');
  152. fil = filename;
  153. end
  154. header_num = fread(header_fid,inf);
  155. header = char(header_num(find(header_num~=13)))';
  156. % find dimensions of image
  157. modality = header(findstr(header,'modality = ')+11:findstr(header,'scan_mode = ')-2);
  158. XCount = str2num(header(findstr(header,'x_dim = ')+7:findstr(header,'y_dim')-2));
  159. YCount = str2num(header(findstr(header,'y_dim = ')+8:findstr(header,'z_dim')-2));
  160. ZCount = str2num(header(findstr(header,'z_dim = ')+8:findstr(header,'x_pixdim')-2));
  161. xpixdim = str2num(header(findstr(header,'x_pixdim = ')+11:findstr(header,'y_pixdim = ')-2));
  162. ypixdim = str2num(header(findstr(header,'y_pixdim = ')+11:findstr(header,'z_pixdim = ')-2));
  163. zpixdim = str2num(header(findstr(header,'z_pixdim = ')+11:findstr(header,'plane_thickness')-2));
  164. % I dont' know why I put this in. CT doesn't write 'scan_mode =' maybe?
  165. if isempty(modality)
  166. modality = header(findstr(header,'modality = ')+11:findstr(header,'image1_datetime = ')-2);
  167. end
  168. switch modality
  169. case 'CT'
  170. cd(pathname);
  171. cd('..');
  172. if exist('Formatted','dir') ~= 7
  173. mkdir Formatted
  174. end
  175. cd('Formatted');
  176. data = reshape(fread(fopen([pathname fil],'r','ieee-be'),inf,'float=>short'),XCount,YCount,ZCount);
  177. if strcmp(flip,'Yes')
  178. data = flipdim(data,3);
  179. end
  180. amiraCTWriter(data,strrep(fil,'.img','.am'),xpixdim,ypixdim,zpixdim,XCount,YCount,ZCount,xpixdim*XCount,zpixdim*ZCount);
  181. case 'PET' % this can only be a string of 2 characters for comparison to 'CT'
  182. voxel_value = questdlg(['Output voxel values for: ' fil],'Voxel Values','SUV','MBq/ml','Both','Cancel');
  183. scan_mode = header(findstr(header,'scan_mode = ')+12:findstr(header,'radionuclide_name = ')-2);
  184. % check to see if scan is dynamic or static
  185. if strcmp(scan_mode,'dynamic')
  186. frames = str2num(header(findstr(header,'number_of_frames = ')+18:findstr(header,'scan_datetime')-2));
  187. ZCount = ZCount/frames; % should always be 35 b/c # of axial PET slices
  188. else
  189. scan_mode = 'static';
  190. end
  191. % you need to make sure voxel_value is only 3 elements long for
  192. % the OR if statements later on. stupid need to find a more
  193. % elegent fix.
  194. switch length(voxel_value)
  195. case 4
  196. voxel_value = 'Bot';
  197. case 6
  198. voxel_value = 'MBq';
  199. end
  200. if ((strcmp(voxel_value,'SUV')) | (strcmp(voxel_value,'Bot')))
  201. if isempty(findstr(header,'patient_wt (kg)'))
  202. patient_wt = 0;
  203. tracer_activity = str2num(header(findstr(header,'tracer_activity = ')+17:findstr(header,'meas_datetime')-2));
  204. else
  205. patient_wt = str2num(header(findstr(header,'patient_wt (kg) = ')+17:findstr(header,'meas_datetime')-2));
  206. tracer_activity = str2num(header(findstr(header,'tracer_activity = ')+17:findstr(header,'patient_wt (kg) = ')-2));
  207. end
  208. meas_datetime = header(findstr(header,'meas_datetime')+27:findstr(header,'pre_inj_volume')-2);
  209. meas_datetime = meas_datetime(find((1-isspace(meas_datetime)))); % sparses the string (removes any spaces)
  210. scan_datetime = header(findstr(header,'scan_datetime = ')+27:findstr(header,'frame1_date')-2);
  211. scan_datetime = scan_datetime(find((1-isspace(scan_datetime)))); % sparses the string (removes any spaces)
  212. admin_datetime = header(findstr(header,'admin_datetime = ')+28:findstr(header,'post_inj_activity')-2);
  213. admin_datetime = admin_datetime(find((1-isspace(admin_datetime)))); % sparses the string (removes any spaces)
  214. post_inj_activity = str2num(header(findstr(header,'post_inj_activity = ')+20:findstr(header,'post_inj_datetime')-2));
  215. post_inj_datetime = header(findstr(header,'post_inj_datetime = ')+ 31:findstr(header,'decay_corr')-2);
  216. post_inj_datetime = post_inj_datetime(find((1-isspace(post_inj_datetime)))); % sparses the string (removes any spaces)
  217. radionuclide_name = header(findstr(header,'radionuclide_name = ')+20:findstr(header,'tracer_name')-2);
  218. radionuclide_name = radionuclide_name(find((1-isspace(radionuclide_name)))); % sparses the string (removes any spaces)
  219. if isempty(meas_datetime)
  220. meas_datetime = '00:00:00';
  221. end
  222. if isempty(admin_datetime)
  223. admin_datetime = '00:00:00';
  224. end
  225. if isempty(post_inj_datetime)
  226. post_inj_datetime = '00:00:00';
  227. end
  228. [status,patient_wt, tracer_activity, meas_datetime, scan_datetime, admin_datetime, post_inj_activity, post_inj_datetime, radionuclide_name] = checkHeader(fil,patient_wt, tracer_activity, meas_datetime, scan_datetime, admin_datetime, post_inj_activity, post_inj_datetime, radionuclide_name);
  229. % stop this program if the gui heard "cancel"
  230. if status == 'kill'
  231. disp('Cancelled at header GUI');
  232. return
  233. end
  234. % finding the time difference between the measured activity
  235. % time and the residual measured time, in seconds
  236. delta_hr = (str2num([post_inj_datetime(1) post_inj_datetime(2)])-str2num([meas_datetime(1) meas_datetime(2)]))*3600;
  237. delta_min = (str2num([post_inj_datetime(4) post_inj_datetime(5)])-str2num([meas_datetime(4) meas_datetime(5)]))*60;
  238. delta_sec = (str2num([post_inj_datetime(7) post_inj_datetime(8)])-str2num([meas_datetime(7) meas_datetime(8)]));
  239. delta_time = delta_hr + delta_min + delta_sec;
  240. switch radionuclide_name
  241. % all half life in sec
  242. case '61Cu'
  243. t_half = 3.333*3600;
  244. case '18F'
  245. t_half = 6588;
  246. case '64Cu'
  247. t_half = 45720;
  248. case '11C'
  249. t_half = 20.334*60;
  250. end
  251. % correcting the measured syringe activity by subtracting
  252. % off the decay corrected residual activity
  253. true_inj_activity = tracer_activity - post_inj_activity*exp(delta_time*log(2)/t_half);
  254. % finding the time difference between the measured activity
  255. % time and the start of the scan
  256. scan_delta_hr = (str2num([scan_datetime(1) scan_datetime(2)])-str2num([meas_datetime(1) meas_datetime(2)]))*3600;
  257. scan_delta_min = (str2num([scan_datetime(4) scan_datetime(5)])-str2num([meas_datetime(4) meas_datetime(5)]))*60;
  258. scan_delta_sec = (str2num([scan_datetime(7) scan_datetime(8)])-str2num([meas_datetime(7) meas_datetime(8)]));
  259. scan_delta_time = scan_delta_hr + scan_delta_min + scan_delta_sec;
  260. % decay correcting the injected dose to the start of the scan
  261. true_inj_activity_at_scan_start = true_inj_activity*exp(-scan_delta_time*log(2)/t_half);
  262. %prepare to open and write the PET_SUV
  263. cd(pathname)
  264. cd('..')
  265. if exist('Processed','dir') ~= 7
  266. mkdir Processed
  267. end
  268. cd Processed
  269. switch scan_mode
  270. case 'dynamic'
  271. if exist('frames','dir') ~= 7
  272. mkdir frames;
  273. end
  274. cd frames
  275. file_id = fopen([pathname fil],'r','ieee-be');
  276. for t = 1:frames
  277. data = reshape(fread(file_id,XCount*YCount*ZCount,'float'),XCount,YCount,ZCount);
  278. data = data./(true_inj_activity_at_scan_start/(patient_wt*1000));
  279. if strcmp(flip,'Yes')
  280. data = flipdim(data,3);
  281. end
  282. amiraWriter(data,[strrep(fil,'.img','_SUV_fr') int2str(t) '.am'],xpixdim,ypixdim,zpixdim,XCount,YCount,ZCount,xpixdim*XCount,zpixdim*ZCount);
  283. end
  284. case 'static'
  285. data = reshape(fread(fopen([pathname fil],'r','ieee-be'),inf,'float'),XCount,YCount,ZCount);
  286. data = data./(true_inj_activity_at_scan_start/(patient_wt*1000));
  287. if strcmp(flip,'Yes')
  288. data = flipdim(data,3);
  289. end
  290. amiraWriter(data,strrep(fil,'.img','_SUV.am'),xpixdim,ypixdim,zpixdim,XCount,YCount,ZCount,xpixdim*XCount,zpixdim*ZCount);
  291. end
  292. clear data;
  293. end
  294. if ((strcmp(voxel_value,'MBq')) | (strcmp(voxel_value,'Bot')))
  295. %prepare to open and write the PET_SUV
  296. cd(pathname)
  297. cd('..')
  298. if exist('Formatted','dir') ~= 7
  299. mkdir Formatted
  300. end
  301. cd Formatted
  302. switch scan_mode
  303. case 'dynamic'
  304. fseek(header_fid,findstr(header,'number_of_frames')+18,'bof');
  305. frames = str2num(char(fread(header_fid,findstr(header,'scan_datetime')-findstr(header,'number_of_frames')-20,'char')'));
  306. if exist('frames','dir') ~= 7
  307. mkdir frames
  308. end
  309. cd frames
  310. file_id = fopen([pathname fil],'r','ieee-be');
  311. for t = 1:frames
  312. data = reshape(fread(file_id,XCount*YCount*ZCount,'float'),XCount,YCount,ZCount);
  313. if strcmp(flip,'Yes')
  314. data = flipdim(data,3);
  315. end
  316. amiraWriter(data,[strrep(fil,'.img','_MBq_fr') int2str(t) '.am'],xpixdim,ypixdim,zpixdim,XCount,YCount,ZCount,xpixdim*XCount,zpixdim*ZCount);
  317. end
  318. case 'static'
  319. data = reshape(fread(fopen([pathname fil],'r','ieee-be'),inf,'float'),XCount,YCount,ZCount);
  320. if strcmp(flip,'Yes')
  321. data = flipdim(data,3);
  322. end
  323. amiraWriter(data,strrep(fil,'.img','_MBq.am'),xpixdim,ypixdim,zpixdim,XCount,YCount,ZCount,xpixdim*XCount,zpixdim*ZCount);
  324. clear data;
  325. end
  326. end
  327. end
  328. end
  329. fclose all;
  330. cd(s);
  331. end
  332. %% BELOW ARE FUNCTIONS THAT THIS PROGRAM NEEDS TO EXECUTE %%
  333. %
  334. % DO NOT MESS WITH THESE OR YOU WILL INCUR MY WRATH!!!
  335. %
  336. % amiraWriter
  337. % amiraCTWriter
  338. % checkHeader
  339. %
  340. % Seriously, hands off!!!
  341. %
  342. %% amiraWriter
  343. function amiraWriter(data,filename,dx,dy,dz,M,N,P,FOV,zFOV)
  344. fid = fopen([filename],'w');
  345. fprintf(fid,'# AmiraMesh 3D BINARY 2.0\n\n');
  346. fprintf(fid,['# CreationDate: ' datestr(now,'ddd mmm') datestr(now,' dd HH:MM:SS yyyy') '\n\n']);
  347. fprintf(fid,'define Lattice %g %g %g\n\n',M,N,P);
  348. fprintf(fid,'Parameters {\n');
  349. fprintf(fid,' Content "%gx%gx%g %s, uniform coordinates",',M,N,P,'float');
  350. fprintf(fid,' BoundingBox %g %g %g %g %g %g,\n',(50-FOV)/2+dx/2,50-(50-FOV)/2-dx/2,(50-FOV)/2+dy/2,50-(50-FOV)/2-dy/2,0,zFOV-dz);
  351. fprintf(fid,' CoordType "uniform"\n');
  352. fprintf(fid,'}\n\n');
  353. fprintf(fid,'Lattice { %s Data } @1\n\n','float');
  354. fprintf(fid,'# Data section follows\n');
  355. fprintf(fid,'@1\n');
  356. fclose(fid); % close the text part of the file
  357. fid = fopen([filename],'ab','ieee-be');
  358. fwrite(fid,data(:,:,:),'float');
  359. fclose(fid);
  360. disp(['Wrote to ' filename]);
  361. end
  362. %% amiraCTWriter
  363. function amiraCTWriter(data,filename,dx,dy,dz,M,N,P,FOV,zFOV)
  364. fid = fopen([filename],'w');
  365. fprintf(fid,'# AmiraMesh 3D BINARY 2.0\n\n');
  366. fprintf(fid,['# CreationDate: ' datestr(now,'ddd mmm') datestr(now,' dd HH:MM:SS yyyy') '\n\n']);
  367. fprintf(fid,'define Lattice %g %g %g\n\n',M,N,P);
  368. fprintf(fid,'Parameters {\n');
  369. fprintf(fid,' Content "%gx%gx%g %s, uniform coordinates",',M,N,P,'short');
  370. fprintf(fid,' BoundingBox %g %g %g %g %g %g,\n',0,FOV-dx,0,FOV-dy,0,zFOV-dz);
  371. fprintf(fid,' CoordType "uniform"\n');
  372. fprintf(fid,'}\n\n');
  373. fprintf(fid,'Lattice { %s Data } @1\n\n','short');
  374. fprintf(fid,'# Data section follows\n');
  375. fprintf(fid,'@1\n');
  376. fclose(fid); % close the text part of the file
  377. fid = fopen([filename],'ab','ieee-be');
  378. fwrite(fid,data(:,:,:),'short');
  379. fclose(fid);
  380. end
  381. %% checkHeader
  382. function [status,patient_wt, tracer_activity, meas_datetime, scan_datetime, injection_time, post_inj_activity, post_inj_datetime, radionuclide_name] = checkHeader(study_name,patient_wt,tracer_activity,meas_datetime,scan_datetime,injection_time,post_inj_activity,post_inj_datetime,radionuclide_name)
  383. global okay_val
  384. global cancel_val
  385. global writeit_val
  386. okay_val = 0;
  387. cancel_val = 0;
  388. writeit_val = 0;
  389. status = 1; % this tells createStatic to stop trying to process data. status = 'kill'
  390. gui = figure('Position',[700,500,310,303]);
  391. patient_ID_txt = uicontrol('Style','text','String','Patient ID:','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','right','Position',[8 272 80 20]);
  392. patient_ID = uicontrol('Style','text','String',study_name,'BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left','Position',[92 272 180 20]);
  393. patient_wt_txt = uicontrol('Style','text','String','Patient Weight:','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','right','Position',[8 246 80 20]);
  394. patient_wt_units = uicontrol('Style','text','String','kgs','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left','Position',[150 246 25 20]);
  395. tracer_activity_txt = uicontrol('Style','text','String','Tracer Activity:','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','right','Position',[8 220 80 20]);
  396. % all the txt in the gui
  397. meas_datetime_units = uicontrol('Style','text','String','MBq @','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left','Position',[150 220 35 20]);
  398. meas_datetime_mCi = uicontrol('Style','text','String','mCi','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left','Position',[150 194 35 20]);
  399. scan_datetime_time = uicontrol('Style','text','String','hh:mm:ss','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left','Position',[246 220 46 20]);
  400. scan_datetime_txt = uicontrol('Style','text','String','Scan Start Time:','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','right','Position',[8 168 80 20]);
  401. scan_datetime_hh = uicontrol('Style','text','String','hh:mm:ss','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left','Position',[150 168 46 20]);
  402. injection_time_txt = uicontrol('Style','text','String','Injection Time:','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','right','Position',[8,142,80,20]);
  403. scan_datetime_txt2 = uicontrol('Style','text','String','hh:mm:ss','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left','Position',[150 142 46 20]);
  404. post_inj_activity_txt = uicontrol('Style','text','String','Post Inj Activity:','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','right','Position',[8 116 80 20]);
  405. post_inj_datetime_txt = uicontrol('Style','text','String','MBq @','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left','Position',[150,116,35,20]);
  406. post_inj_datetime_time = uicontrol('Style','text','String','hh:mm:ss','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left','Position',[246 116 46 20]);
  407. post_inj_datetime_uCi = uicontrol('Style','text','String','uCi','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left','Position',[150 90 35 20]);
  408. radionuclide_name_txt = uicontrol('Style','text','String','Radionuclide:','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','right','Position',[8,64,80,20]);
  409. radionuclide_name_txt2 = uicontrol('Style','text','String','ex: 18F or 61Cu','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','left','Position',[150 64 80 20]);
  410. SUV_factor_txt = uicontrol('Style','text','String','SUV Factor:','BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','right','Position',[8,38,80,20]);
  411. % all the editable fields
  412. patient_wt_var = uicontrol('Style','edit','String',patient_wt,'BackgroundColor','white','Position',[92 250 55 20]);
  413. tracer_activity_var = uicontrol('Style','edit','String',tracer_activity,'BackgroundColor','white','Position',[92 224 55 20]);
  414. tracer_activity_mCi = uicontrol('Style','text','String',num2str(tracer_activity/37),'BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','center','Position',[92 194 55 20]);
  415. meas_datetime_var = uicontrol('Style','edit','String',meas_datetime,'BackgroundColor','white','Position',[188 224 55 20]);
  416. scan_datetime_var = uicontrol('Style','edit','String',scan_datetime,'BackgroundColor','white','Position',[92 172 55 20]);
  417. injection_time_var = uicontrol('Style','edit','String',injection_time,'BackgroundColor','white','Position',[92 146 55 20]);
  418. post_inj_activity_var = uicontrol('Style','edit','String',post_inj_activity,'BackgroundColor','white','Position',[92 120 55 20]);
  419. post_inj_datetime_var = uicontrol('Style','edit','String',post_inj_datetime,'BackgroundColor','white','Position',[188 120 55 20]);
  420. post_inj_activity_uCi = uicontrol('Style','text','String',num2str(post_inj_activity/37*1000),'BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','center','Position',[92 90 55 20]);
  421. radionuclide_name_var = uicontrol('Style','edit','String',radionuclide_name,'BackgroundColor','white','Position',[92 68 55 20]);
  422. okay = uicontrol('Style','pushbutton','String','Okay','Position',[25,5,70,25],'Callback',@okay_Callback);
  423. cancel = uicontrol('Style','pushbutton','String','Cancel','Position',[105,5,70,25],'Callback',@cancel_Callback);
  424. writeit = uicontrol('Style','pushbutton','String','Write to header','Position',[185,5,100,25],'Callback',@writeit_Callback);
  425. wait_for_it = 0;
  426. while wait_for_it == 0
  427. pause(1); % listen for a button push
  428. % listen for updates to Tracer Activity and update the mCi box
  429. tracer_activity = str2num(get(tracer_activity_var,'String'));
  430. tracer_activity_mCi = uicontrol('Style','text','String',num2str(tracer_activity/37),'BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','center','Position',[92 194 55 20]);
  431. post_inj_activity = str2num(get(post_inj_activity_var,'String'));
  432. post_inj_activity_uCi = uicontrol('Style','text','String',num2str(post_inj_activity/37*1000),'BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','center','Position',[92 90 55 20]);
  433. %% this part calculates the SUV factor with the parameters shown
  434. tracer_activity = str2num(get(tracer_activity_var,'String'));
  435. post_inj_activity = str2num(get(post_inj_activity_var,'String'));
  436. radionuclide_name = get(radionuclide_name_var,'String');
  437. post_inj_datetime = get(post_inj_datetime_var,'String');
  438. meas_datetime = get(meas_datetime_var,'String');
  439. scan_datetime = get(scan_datetime_var,'String');
  440. patient_wt = str2num(get(patient_wt_var,'String'));
  441. % finding the time difference between the measured activity
  442. % time and the residual measured time, in seconds
  443. delta_hr = (str2num([post_inj_datetime(1) post_inj_datetime(2)])-str2num([meas_datetime(1) meas_datetime(2)]))*3600;
  444. delta_min = (str2num([post_inj_datetime(4) post_inj_datetime(5)])-str2num([meas_datetime(4) meas_datetime(5)]))*60;
  445. delta_sec = (str2num([post_inj_datetime(7) post_inj_datetime(8)])-str2num([meas_datetime(7) meas_datetime(8)]));
  446. delta_time = delta_hr + delta_min + delta_sec;
  447. switch radionuclide_name
  448. case '61Cu'
  449. t_half = 3.333*3600; % half life in sec
  450. case '18F'
  451. t_half = 6588;
  452. case '64Cu'
  453. t_half = 45720;
  454. case '11C'
  455. t_half = 20.334*60;
  456. end
  457. % correcting the measured syringe activity by subtracting
  458. % off the decay corrected residual activity
  459. true_inj_activity = tracer_activity - post_inj_activity*exp(delta_time*log(2)/t_half);
  460. % finding the time difference between the measured activity
  461. % time and the start of the scan
  462. scan_delta_hr = (str2num([scan_datetime(1) scan_datetime(2)])-str2num([meas_datetime(1) meas_datetime(2)]))*3600;
  463. scan_delta_min = (str2num([scan_datetime(4) scan_datetime(5)])-str2num([meas_datetime(4) meas_datetime(5)]))*60;
  464. scan_delta_sec = (str2num([scan_datetime(7) scan_datetime(8)])-str2num([meas_datetime(7) meas_datetime(8)]));
  465. scan_delta_time = scan_delta_hr + scan_delta_min + scan_delta_sec;
  466. % decay correcting the injected dose to the start of the scan
  467. true_inj_activity_at_scan_start = true_inj_activity*exp(-scan_delta_time*log(2)/t_half);
  468. SUV_factor = 1/(true_inj_activity_at_scan_start/(patient_wt*1000));
  469. SUV_factor_var = uicontrol('Style','text','String',SUV_factor,'BackgroundColor',[0.8 0.8 0.8],'HorizontalAlignment','center','Position',[92 38 55 20]);
  470. % Listen for hit
  471. if okay_val == 1
  472. patient_wt = str2num(get(patient_wt_var,'String'));
  473. tracer_activity = str2num(get(tracer_activity_var,'String'));
  474. meas_datetime = get(meas_datetime_var,'String');
  475. scan_datetime = get(scan_datetime_var,'String');
  476. injection_time = get(injection_time_var,'String');
  477. post_inj_activity = str2num(get(post_inj_activity_var,'String'));
  478. post_inj_datetime = get(post_inj_datetime_var,'String');
  479. radionuclide_name = get(radionuclide_name_var,'String');
  480. wait_for_it = 1;
  481. close(gui);
  482. end
  483. if cancel_val == 1
  484. disp('Cancel was hit');
  485. close(gui);
  486. wait_for_it = 1;
  487. status = 'kill';
  488. return
  489. end
  490. if writeit_val == 1
  491. disp('Cancel was hit');
  492. close(gui);
  493. wait_for_it = 1;
  494. return
  495. end
  496. end
  497. end
  498. function okay_Callback(source,eventdata)
  499. global okay_val
  500. global cancel_val
  501. global writeit_val
  502. okay_val = 1;
  503. cancel_val = 0;
  504. writeit_val = 0;
  505. end
  506. function cancel_Callback(source,eventdata)
  507. global okay_val
  508. global cancel_val
  509. global writeit_val
  510. okay_val = 0;
  511. cancel_val = 1;
  512. writeit_val = 0;
  513. end
  514. function writeit_Callback(source,eventdata)
  515. global okay_val
  516. global cancel_val
  517. global writeit_val
  518. okay_val = 0;
  519. cancel_val = 0;
  520. writeit_val = 0;
  521. disp('Write to header dun work yet!');
  522. end