projectionDDb.m 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. %% Author: Rodrigo de Barros Vimieiro
  2. % Date: March, 2019
  3. % rodrigo.vimieiro@gmail.com
  4. % =========================================================================
  5. %{
  6. % -------------------------------------------------------------------------
  7. % projectionDDb(data3d,param,projNumber)
  8. % -------------------------------------------------------------------------
  9. % DESCRIPTION:
  10. % This function calculates the volume projection based on the
  11. % Branchless Distance-Driven principle.
  12. % The geometry is for DBT with half cone-beam. All parameters are set
  13. % in "ParameterSettings" code.
  14. %
  15. % INPUT:
  16. %
  17. % - data3d = 3D volume for projection
  18. % - param = Parameter of all geometry
  19. % - projNumber = Vector with projections numbers to be processed
  20. %
  21. % OUTPUT:
  22. %
  23. % - proj = projections for each angle.
  24. %
  25. % Reference:
  26. % - Branchless Distance Driven Projection and Backprojection,
  27. % Samit Basu and Bruno De Man (2006)
  28. % - GPU Acceleration of Branchless Distance Driven Projection and
  29. % Backprojection, Liu et al (2016)
  30. % - GPU-Based Branchless Distance-Driven Projection and Backprojection,
  31. % Liu et al (2017)
  32. % - A GPU Implementation of Distance-Driven Computed Tomography,
  33. % Ryan D. Wagner (2017)
  34. % ---------------------------------------------------------------------
  35. % Copyright (C) <2019> <Rodrigo de Barros Vimieiro>
  36. %
  37. % This program is free software: you can redistribute it and/or modify
  38. % it under the terms of the GNU General Public License as published by
  39. % the Free Software Foundation, either version 3 of the License, or
  40. % (at your option) any later version.
  41. %
  42. % This program is distributed in the hope that it will be useful,
  43. % but WITHOUT ANY WARRANTY; without even the implied warranty of
  44. % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  45. % GNU General Public License for more details.
  46. %
  47. % You should have received a copy of the GNU General Public License
  48. % along with this program. If not, see <http://www.gnu.org/licenses/>.
  49. %}
  50. % =========================================================================
  51. %% 3-D Projection Branchless Distance Driven Code
  52. function proj = projectionDDb(data3d,param,projNumber)
  53. % Map detector and object boudaries
  54. param.us = double((param.nu:-1:0)*param.du);
  55. param.vs = double((-(param.nv)/2:1:(param.nv)/2)*param.dv);
  56. param.xs = double((param.nx:-1:0)*param.dx);
  57. param.ys = double((-(param.ny)/2:1:(param.ny)/2)*param.dy);
  58. param.zs = double((0:1:param.nz-1)*param.dz + param.DAG + (param.dz/2));
  59. % Detector boudaries coordinate sytem in (mm)
  60. [detX,detY] = meshgrid(param.us,param.vs);
  61. detZ = zeros(size(detX),'double');
  62. % Object boudaries coordinate sytem in (mm)
  63. [objX,objY] = meshgrid(param.xs,param.ys);
  64. objZ = double(param.zs); % Z object coordinates
  65. % X-ray tube initial position
  66. tubeX = double(0);
  67. tubeY = double(0);
  68. tubeZ = double(param.DSD);
  69. % Iso-center position
  70. isoY = double(0);
  71. isoZ = double(param.DDR);
  72. % Projection angles
  73. tubeAngle = double(deg2rad(param.tubeDeg));
  74. detAngle = double(deg2rad(param.detectorDeg));
  75. % Number of detector and voxels for each direction
  76. nDetX = double(param.nu);
  77. nDetY = double(param.nv);
  78. nPixX = double(param.nx);
  79. nPixY = double(param.ny);
  80. deltaDetX = double(param.du);
  81. deltaDetY = double(param.dv);
  82. deltaObjX = double(param.dx);
  83. deltaObjY = double(param.dy);
  84. nSlices = double(param.nz);
  85. nProjs = double(param.nProj);
  86. % Voxel size on Z
  87. pixsZ = double(param.dz);
  88. % Test if there's specific angles
  89. if(isempty(projNumber))
  90. projNumber = 1:nProjs;
  91. else
  92. if(max(projNumber(:)) <= nProjs)
  93. nProjs = size(projNumber,2);
  94. else
  95. error('Projection number exceeds the maximum for the equipment.')
  96. end
  97. end
  98. % Stack of projections
  99. proj = zeros(param.nv, param.nu, nProjs,'double');
  100. % Integration of 2D slices over the whole volume
  101. % (S.1. Integration. - Liu et al (2017))
  102. data3dI = integrate2D(data3d);
  103. % For each projection
  104. for p=1:nProjs
  105. % Temporary variable to acumulate all projection from the slices
  106. proj_tmp = zeros(nDetY,nDetX,'double');
  107. % Get specific projection number
  108. projN = projNumber(p);
  109. % Get specif tube angle for the projection
  110. theta = tubeAngle(projN);
  111. % Get specif detector angle for the projection
  112. phi = detAngle(projN);
  113. % Tubre rotation
  114. rtubeY = ((tubeY - isoY)*cos(theta)-(tubeZ - isoZ)*sin(theta) )+isoY;
  115. rtubeZ = ((tubeY - isoY)*sin(theta)+(tubeZ - isoZ)*cos(theta) )+isoZ;
  116. % Detector rotation
  117. rdetY = ((detY - isoY).*cos(phi)-(detZ - isoZ).*sin(phi) )+isoY;
  118. rdetZ = ((detY - isoY).*sin(phi)+(detZ - isoZ).*cos(phi) )+isoZ;
  119. % For each slice
  120. for nz=1:nSlices
  121. % Map detector onto XY plane in the specifc slice
  122. [detmX,detmY] = mapp2xyZ(tubeX,rtubeY,rtubeZ,detX,rdetY,rdetZ,objZ(nz));
  123. % Bilinear interpolation of the integrated image(slice coords) on
  124. % mapped detector coords
  125. % (S.2. Interpolation - Liu et al (2017))
  126. proj_data3dI = interp2(objX,objY,data3dI(:,:,nz),detmX,detmY,'linear',0);
  127. %figure
  128. %plot(detmX,detmY,'k*','MarkerSize',6)
  129. %hold on
  130. %plot(objX,objY,'k.','MarkerSize',6)
  131. %hold off
  132. %legend('Detector Boundaries','Pixel Boundaries')
  133. % These two lines find the max value of the integrated image, in
  134. % order to replicate it in the remaining rows
  135. [~,row_max] = max(proj_data3dI(:,end));
  136. proj_data3dI(row_max+1:end,:) = repmat(proj_data3dI(row_max,:),param.nv+1-row_max,1);
  137. for xDet=2:nDetX+1
  138. % x-ray angle in X coord
  139. gamma = atan((detX(1,xDet-1)+(deltaDetX/2)-tubeX)/rtubeZ);
  140. for yDet=2:nDetY+1
  141. % Detector X coord overlap calculation
  142. overLapX = detmX(yDet,xDet-1)-detmX(yDet,xDet);
  143. % Detector Y coord overlap calculation
  144. overLapY = detmY(yDet,1)-detmY(yDet-1,1);
  145. % x-ray angle in Y coord
  146. alpha = atan((rdetY(yDet-1,1)+(deltaDetY/2)-rtubeY)/rtubeZ);
  147. % S.3. Differentiation - Eq. 24 - Liu et al (2017)
  148. proj_tmp(yDet-1,xDet-1) = proj_tmp(yDet-1,xDet-1)...
  149. +((proj_data3dI(yDet,xDet)...
  150. -proj_data3dI(yDet,xDet-1)...
  151. -proj_data3dI(yDet-1,xDet)...
  152. +proj_data3dI(yDet-1,xDet-1))...
  153. *(deltaObjX*deltaObjX.*pixsZ./(cos(alpha)*cos(gamma)*overLapX*overLapY)));
  154. end % Loop end Y coord
  155. end % Loop end X coord
  156. end % Loop end slices
  157. proj(:,:,p) = proj_tmp;
  158. end % Loop end Projections
  159. end
  160. %% Integrate function
  161. function [Ppj] = integrate2D (imageStack)
  162. % 2-D image
  163. %
  164. % | -> J
  165. % v -------------
  166. % I | |
  167. % | |
  168. % | |
  169. % | |
  170. % -------------
  171. ni_pixel = size(imageStack,1)+1;
  172. nj_pixel = size(imageStack,2)+1;
  173. n_stack = size(imageStack,3);
  174. p_v = zeros(ni_pixel,nj_pixel,n_stack,'double'); % Pad with zeros
  175. p_v(2:end,2:end,:) = imageStack; % Load slices
  176. P_i = zeros(ni_pixel,1,n_stack,'double');
  177. P_j = zeros(1,nj_pixel,n_stack,'double');
  178. Ppj = zeros(ni_pixel,nj_pixel,n_stack,'double');
  179. % Integrate on J direction
  180. for pj=2:nj_pixel
  181. P_i = P_i + p_v(:,pj,:);
  182. Ppj(:,pj,:) = P_i;
  183. end
  184. % Integrate on I direction
  185. for pi=2:ni_pixel
  186. P_j = P_j + Ppj(pi,:,:);
  187. Ppj(pi,:,:) = P_j;
  188. end
  189. end
  190. %% Map on XY plane (on specific slice)
  191. function [x,y] = mapp2xyZ(x1,y1,z1,x2,y2,z2,z)
  192. x = ((x2-x1).*(z-z2)-(x2.*z1)+(x2.*z2))./(-z1+z2);
  193. y = ((y2-y1).*(z-z2)-(y2.*z1)+(y2.*z2))./(-z1+z2);
  194. end