12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- import numpy as np
- import scipy.sparse as sp
- def sys_matrix(nx, ny, nb, na, mask):
- #function G = Glinear(nx, ny, nb, na, mask)
- #
- # Generate a geometric system matrix for tomographic projection
- # based on simple linear interpolation.
- # Contains exactly two g_{ij}'s per pixel per projection angle.
- # This system model is pretty inadequate for reconstructing
- # real tomographic data, but is useful for simple simulations.
- #
- # The image size is nx * ny.
- # The sinogram size is nb * na (n_radial_bins X n_angles).
- # Returned G is [nb * na, nx * ny] - this size is need for wtfmex saving.
- #
- # Copyright Apr 2000, Jeff Fessler, University of Michigan
- #if nargin < 1, nx = 32; end
- #if nargin < 2, ny = nx; end
- #if nargin < 3, nb = nx; end
- #if nargin < 4, na = floor(nb * pi/2); end
- #if nargin < 5, mask = logical(ones(nx,ny)); end
- #
- # default: run a test demo
- #
- #if nargin < 1
- #x = shepplogan(nx, ny, 1);
- #ix = [-(nx-1)/2:(nx-1)/2]';
- #iy = [-(ny-1)/2:(ny-1)/2];
- #rr = sqrt(outer_sum(ix.^2, iy.^2));
- #mask = rr < nx/2-1;
- #clf
- #G = Glinear(nx, ny, nb, na, mask);
- #y = G * x(:); % forward projection
- #y = reshape(y, nb, na); % reshape into sinogram array
- #sino = zeros(nb, na); sino(nb/2, 10) = 1;
- #b = reshape(G' * sino(:), nx, ny);
- #im(221, mask, 'support mask')
- #im(222, x, 'test image')
- #im(223, y, 'sinogram'), xlabel ib, ylabel ia
- #im(224, b, 'backproject 1 ray')
- #return
- #end
- #
- # pixel centers
- #
- x,y = np.meshgrid(np.arange(0,nx)-(nx-1)/2., np.arange(0,ny)-(ny-1)/2.)
- x = x[mask]
- y = y[mask]
- npts = len(x) # sum(mask(:)) - total # of support pixels
- angle = np.arange(0,na) * (np.pi/na);
- # [na,np] projected pixel center
- tau = np.outer(np.cos(angle),x) + np.outer(np.sin(angle), y)
- tau += nb/2. # counting from 0 (python)
- ibl = np.floor(tau).astype(int) # left bin
- val = 1 - (tau-ibl) # weight value for left bin
- #print(val)
- #ii is the absolute sinogram index (from 0 to na*np) in image space
- ii = ibl + nb*np.outer(np.arange(0,na),np.ones(npts)).astype(int)
- #good = ones ([na,npts])
- good = np.logical_and(ibl > -1,ibl < nb) # within FOV cases
- if not(good.any()):
- print ('FOV too small')
- return
- #print(val[good])
- #np = sum(mask(:));
- #nc = np; jj = 1:np;
- # compact G
- nc = nx * ny
- jj = mask.ravel().nonzero()
- # all-column G
- jj=np.outer(np.ones(na),jj).astype(int)
- #left bin
- G1 = sp.csc_matrix((val[good],(ii[good],jj[good])),shape=[nb*na,nc])
- #right bin
- #redefine valid indices
- good1 = (ibl > -2) & (ibl < nb-1) # within FOV cases, but shifted by one
- G2 = sp.csc_matrix((1-val[good1],(ii[good1]+1,jj[good1])),shape=[nb*na,nc])
- return G1 + G2
|