backprojectionDDb.m 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. %% Author: Rodrigo de Barros Vimieiro
  2. % Date: March, 2019
  3. % rodrigo.vimieiro@gmail.com
  4. % =========================================================================
  5. %{
  6. % -------------------------------------------------------------------------
  7. % backprojectionDDb(proj,param,projNumber)
  8. % -------------------------------------------------------------------------
  9. % DESCRIPTION:
  10. % This function reconstruct the 3D volume from projections, based on
  11. % the 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. % - proj = 2D projections for each angle
  18. % - param = Parameter of all geometry
  19. % - projNumber = Vector with projections numbers to be processed
  20. %
  21. % OUTPUT:
  22. %
  23. % - data3d = reconstructed volume.
  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 Backprojection Branchless Distance Driven Code
  52. function data3d = backprojectionDDb(proj,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 reconstructed slices
  99. data3d = zeros(param.ny, param.nx, param.nz,'double');
  100. % Integration of each 2D projection
  101. % (S.1. Integration - Liu et al (2017))
  102. projI = integrate2D(proj);
  103. % For each projection
  104. for p=1:nProjs
  105. % Get specific projection number
  106. projN = projNumber(p);
  107. % Get specif tube angle for the projection
  108. theta = tubeAngle(projN);
  109. % Get specif detector angle for the projection
  110. phi = detAngle(projN);
  111. % Tubre rotation
  112. rtubeY = ((tubeY - isoY)*cos(theta)-(tubeZ - isoZ)*sin(theta) )+isoY;
  113. rtubeZ = ((tubeY - isoY)*sin(theta)+(tubeZ - isoZ)*cos(theta) )+isoZ;
  114. % Detector rotation
  115. rdetY = ((detY - isoY).*cos(phi)-(detZ - isoZ).*sin(phi) )+isoY;
  116. rdetZ = ((detY - isoY).*sin(phi)+(detZ - isoZ).*cos(phi) )+isoZ;
  117. % For each slice
  118. for nz=1:nSlices
  119. % Temporary variable for each slice
  120. slice = zeros(nPixY,nPixX,'double');
  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 proj(proj coords) on
  124. % image slice coords
  125. % (S.2. Interpolation - Liu et al (2017))
  126. sliceI = interp2(detmX,detmY,projI(:,:,p),objX,objY,'linear',0);
  127. for xPix=2:nPixX+1
  128. % x-ray angle in X coord
  129. gamma = atan((objX(1,xPix-1)+(deltaObjX/2)-tubeX)/(rtubeZ - objZ(nz)));
  130. for yPix=2:nPixY+1
  131. % x-ray angle in Y coord
  132. alpha = atan((objY(yPix-1,1)+(deltaObjY/2)-rtubeY)/(rtubeZ - objZ(nz)));
  133. % S.3. Differentiation - Eq. 24 - Liu et al (2017)
  134. slice(yPix-1,xPix-1) = slice(yPix-1,xPix-1)...
  135. +((sliceI(yPix,xPix)...
  136. -sliceI(yPix,xPix-1)...
  137. -sliceI(yPix-1,xPix)...
  138. +sliceI(yPix-1,xPix-1))...
  139. *(deltaDetX.*deltaDetY.*pixsZ./(cos(alpha)*cos(gamma)))...
  140. *(1/(deltaObjX*deltaObjY)));
  141. end % Loop end Y coord
  142. end % Loop end X coord
  143. % Accumulate for each proj angle
  144. data3d(:,:,nz) = data3d(:,:,nz) + slice;
  145. end % Loop end slices
  146. end % Loop end Projections
  147. data3d = data3d ./ nProjs;
  148. end
  149. %% Integrate function
  150. function [Ppj] = integrate2D (imageStack)
  151. % 2-D image
  152. %
  153. % | -> J
  154. % v -------------
  155. % I | |
  156. % | |
  157. % | |
  158. % | |
  159. % -------------
  160. ni_pixel = size(imageStack,1)+1;
  161. nj_pixel = size(imageStack,2)+1;
  162. n_stack = size(imageStack,3);
  163. p_v = zeros(ni_pixel,nj_pixel,n_stack,'double'); % Pad with zeros
  164. p_v(2:end,2:end,:) = imageStack; % Load slices
  165. P_i = zeros(ni_pixel,1,n_stack,'double');
  166. P_j = zeros(1,nj_pixel,n_stack,'double');
  167. Ppj = zeros(ni_pixel,nj_pixel,n_stack,'double');
  168. % Integrate on J direction
  169. for pj=2:nj_pixel
  170. P_i = P_i + p_v(:,pj,:);
  171. Ppj(:,pj,:) = P_i;
  172. end
  173. % Integrate on I direction
  174. for pi=2:ni_pixel
  175. P_j = P_j + Ppj(pi,:,:);
  176. Ppj(pi,:,:) = P_j;
  177. end
  178. end
  179. %% Map on XY plane (on specific slice)
  180. function [x,y] = mapp2xyZ(x1,y1,z1,x2,y2,z2,z)
  181. x = ((x2-x1).*(z-z2)-(x2.*z1)+(x2.*z2))./(-z1+z2);
  182. y = ((y2-y1).*(z-z2)-(y2.*z1)+(y2.*z2))./(-z1+z2);
  183. end