Glinear.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import numpy as np
  2. import scipy.sparse as sp
  3. def sys_matrix(nx, ny, nb, na, mask):
  4. #function G = Glinear(nx, ny, nb, na, mask)
  5. #
  6. # Generate a geometric system matrix for tomographic projection
  7. # based on simple linear interpolation.
  8. # Contains exactly two g_{ij}'s per pixel per projection angle.
  9. # This system model is pretty inadequate for reconstructing
  10. # real tomographic data, but is useful for simple simulations.
  11. #
  12. # The image size is nx * ny.
  13. # The sinogram size is nb * na (n_radial_bins X n_angles).
  14. # Returned G is [nb * na, nx * ny] - this size is need for wtfmex saving.
  15. #
  16. # Copyright Apr 2000, Jeff Fessler, University of Michigan
  17. #if nargin < 1, nx = 32; end
  18. #if nargin < 2, ny = nx; end
  19. #if nargin < 3, nb = nx; end
  20. #if nargin < 4, na = floor(nb * pi/2); end
  21. #if nargin < 5, mask = logical(ones(nx,ny)); end
  22. #
  23. # default: run a test demo
  24. #
  25. #if nargin < 1
  26. #x = shepplogan(nx, ny, 1);
  27. #ix = [-(nx-1)/2:(nx-1)/2]';
  28. #iy = [-(ny-1)/2:(ny-1)/2];
  29. #rr = sqrt(outer_sum(ix.^2, iy.^2));
  30. #mask = rr < nx/2-1;
  31. #clf
  32. #G = Glinear(nx, ny, nb, na, mask);
  33. #y = G * x(:); % forward projection
  34. #y = reshape(y, nb, na); % reshape into sinogram array
  35. #sino = zeros(nb, na); sino(nb/2, 10) = 1;
  36. #b = reshape(G' * sino(:), nx, ny);
  37. #im(221, mask, 'support mask')
  38. #im(222, x, 'test image')
  39. #im(223, y, 'sinogram'), xlabel ib, ylabel ia
  40. #im(224, b, 'backproject 1 ray')
  41. #return
  42. #end
  43. #
  44. # pixel centers
  45. #
  46. x,y = np.meshgrid(np.arange(0,nx)-(nx-1)/2., np.arange(0,ny)-(ny-1)/2.)
  47. x = x[mask]
  48. y = y[mask]
  49. npts = len(x) # sum(mask(:)) - total # of support pixels
  50. angle = np.arange(0,na) * (np.pi/na);
  51. # [na,np] projected pixel center
  52. tau = np.outer(np.cos(angle),x) + np.outer(np.sin(angle), y)
  53. tau += nb/2. # counting from 0 (python)
  54. ibl = np.floor(tau).astype(int) # left bin
  55. val = 1 - (tau-ibl) # weight value for left bin
  56. #print(val)
  57. #ii is the absolute sinogram index (from 0 to na*np) in image space
  58. ii = ibl + nb*np.outer(np.arange(0,na),np.ones(npts)).astype(int)
  59. #good = ones ([na,npts])
  60. good = np.logical_and(ibl > -1,ibl < nb) # within FOV cases
  61. if not(good.any()):
  62. print ('FOV too small')
  63. return
  64. #print(val[good])
  65. #np = sum(mask(:));
  66. #nc = np; jj = 1:np;
  67. # compact G
  68. nc = nx * ny
  69. jj = mask.ravel().nonzero()
  70. # all-column G
  71. jj=np.outer(np.ones(na),jj).astype(int)
  72. #left bin
  73. G1 = sp.csc_matrix((val[good],(ii[good],jj[good])),shape=[nb*na,nc])
  74. #right bin
  75. #redefine valid indices
  76. good1 = (ibl > -2) & (ibl < nb-1) # within FOV cases, but shifted by one
  77. G2 = sp.csc_matrix((1-val[good1],(ii[good1]+1,jj[good1])),shape=[nb*na,nc])
  78. return G1 + G2