C ******************************************************************* C PROGRAM FOR TOMOGRAPHIC RECONSTRUCTON OF PARALLEL BEAM DATA C ON THE CONNECTION MACHINE CM5. C C PROGRAMMER: RAMAN RAO C DATE OF LAST REVISION: 1/2/95 C VIRGINIA POLYTECHNIC INSTITUTE AND STATE UNIVERSITY C BLACKSBURG, VA 24061 C******************************************************************** C This program carries out CT reconstruction on the CM5 C for parallel beam projection data. C C odim=object dimension C rdim=reconstruction dimension C object=object (2D) to be forward projected C lb1 = stores low bins for the forward projections C hb1=stores high bins for the forward-projections C mb1=stores the mid bin values for the forward projections C frac1=stores the fractional part of the mid bin for forward projections C step = the width of each block in the checker board C angles=number of angles at which the forward projections C are performed C mat = projection matrix (proj. data is stored here) C lb2 = stores low bins for the back-projections C hb2=stores high bins for the back-projections C mb2=stores the mid bin values for the back-projections C frac2=stores the fractional part of the mid bin for back projections C f = final density matrix for the reconstructed object C Ham=hamming window function is generated and stored here C H2=temporary row vector for storing a row C lbmat=stores the filtered proj. values corresponding to the low bin C hbmat=stores the filtred proj. values corresponding to the high bin C psum=stores the interpolated values corresponding to the mid-bins C xcen1, ycen1= center of the object dimension C xcen2, ycen2=center of the reconstructed dimension C xmax,ymax = maximum size of the z and y dimensions C mp1= mid point of the rays C tw = adjustment for keeping the mb inside the object(adjust until C the program gives no error C H1 stores the ramp function (response function) C evalh = subroutine which generates the response function C theta= angles which are used in the projection C The CMF$ commands enable the respective arrays to be executed C in parallel. C The data of dimension odimxodim is reconstructed to rdimxrdim. C In this process, zero padding is done to fill the frequency values C for dimensions greater than odim (p. 75 kak) to reduce the dishing C and dc artifacts(fig. 3.17,p.76 kak) C program filtered_bak implicit none C include the cmssl routines include '/usr/include/cm/cmssl-cmf.h' C include the timer routines include '/usr/include/cm/timer-fort.h' integer odim,rdim,step parameter (odim=16,rdim=64,step=4,angles=128) integer rows,cols,i,j,k,setup_id,ier,n1,rays,blank,i1,icen integer hb1(1:odim,1:odim,1:128),lb1(1:odim,1:odim,1:128),j1 CMF$ LAYOUT hb1(:news,:news,:news),lb1(:news,:news,:news) integer hb2(1:rdim,1:rdim,1:128),lb2(1:rdim,1:rdim,1:128) CMF$ LAYOUT hb2(:news,:news,:news),lb2(:news,:news,:news) complex mat(1:128,1:rdim),H1(1:rdim),H2(1:rdim) CMF$ LAYOUT mat(:news,:news),H1(:news),H2(:news) real tau1,tw,xcen1,xmax,ycen1,ymax,f(1:rdim,1:rdim),Ham(1:rdim) CMF$ LAYOUT f(:news,:news),Ham(1:news) real theta(1:128),frac1(1:odim,1:odim,1:128), $ mb1(1:odim,1:odim,1:128) CMF$ LAYOUT theta(:news),frac1(:news,:news,:news) CMF$ LAYOUT mb1(:news,:news,:news) real frac2(1:rdim,1:rdim,1:128),mb2(1:rdim,1:rdim,1:128) CMF$ LAYOUT frac2(:news,:news,:news),mb2(:news,:news,:news) real PI,psum(1:rdim,1:rdim,1:128),p1(1:odim,1:odim,1:128) CMF$ LAYOUT psum(:news,:news,:news),p1(:news,:news,:news) real p2(1:rdim,1:rdim,1:128) CMF$ LAYOUT p2(:news,:news,:news) real hbmat(1:rdim,1:rdim,1:128),lbmat(1:rdim,1:rdim,1:128),const CMF$ LAYOUT hbmat(:news,:news,:news), lbmat(:news,:news,:news) real object(1:odim,1:odim),den,frac CMF$ LAYOUT object(:news,:news) real xcen2,ycen2,mp1,mp2 integer lb,hb,timer1 timer1=0 C clear the timer call CM_timer_clear(timer1) C start the timer call CM_timer_start(timer1) xcen1=real(odim)/2. ycen1=real(odim)/2. xcen2 = real(rdim)/2. ycen2 = real(rdim)/2. tw = 1.0/(1.15 * sqrt(2.)) rays = odim mp1=real(rays)/2. mp2 = real(rdim)/2. n1=6 C rows = # of angles rows=128 cols=rdim PI = acos(-1.0) const = PI/real(rows) C initialize the mat, H1 (ramp function), and object forall(i=1:rows,j=1:cols) mat(i,j) = (0.0,0.0) forall(j=1:cols) H1(j) = (0.0,0.0) forall(i=1:odim,j=1:odim) object(i,j) =0.0 print *, "mat and H1 init completed" call CM_timer_stop(timer1) C this routine projects the data . The data is 128 128 x odim rows, C and the data is supposed to look like a checker board. C making the checker board blank =0 do i =1,odim,step if (blank .eq. 0) then blank = 255 else blank = 0 endif do j=1,odim,step if (blank .eq. 0) then blank = 255 else blank = 0 endif forall(i1=i:i+step,j1=j:j+step) $ object(i1,j1) = real(blank) enddo enddo call CM_timer_start(timer1) C Begins the forward projecton process. Projections are found by adding C the densities along parallel rays (since this is parallel C beam tomography) C finds theta for (in radians) for all the steps theta = real([1:128])*PI/128. print *, 'theta evaluated' C stop timer call CM_timer_stop(timer1) C finds the value of (xcos(theta)+ysin(theta)) for all the C angles and all x,y. The values below are normalized to C make the forward projection space to lie in the space (-1,1) forall(i=1:odim,j=1:odim,k=1:128) $ p1(i,j,k) = ((real(i)-xcen1)/xcen1)*cos(theta(k)) $ + ((real(j)-ycen1)/ycen1)*sin(theta(k)) print *, 'p1 evaluated' C find the mid-bin of the forward projections forall(i=1:odim,j=1:odim,k=1:128) $ mb1(i,j,k) = (p1(i,j,k)*mp1*tw) + mp1 C find the low bins lb1 = int(mb1) print *, 'lb1 evaluated' C find the fractional values frac1 = mb1-real(lb1) print *, 'frac1 evaluated' C find the high bins forall(i=1:odim,j=1:odim,k=1:128) hb1(i,j,k) = lb1(i,j,k) + 1 print *, 'hb1 evaluated' C following is executed serially: not timed as these carry out the forward C projections do i=1,odim do j=1,odim do k=1,128 lb = lb1(i,j,k) hb = hb1(i,j,k) frac = frac1(i,j,k) den = object(i,j) mat(k,lb) = mat(k,lb)+cmplx((1.0-frac)*den) mat(k,hb) = mat(k,hb)+cmplx(frac*den) enddo enddo enddo call CM_timer_start(timer1) C evaluate the response function(ref. p72 kak) call evalh(H1,tau1,n1) print *, 'H matrix evaluation completed' C Find the FFT of the projection matrix row by row. C The parallel FFT on the CM5 is used to find the fourier C transforms row by row. do i=1,rows forall(j=1:cols) H2(j) = mat(i,j) C setup the FFT variables inside the CM5 setup_id = fft_setup(H2,'CTOC',ier) call fft(H2,'CTOC',CMSSL_f_xform,setup_id,ier) if (ier .ne. 0) then write(*,*) 'error in fft','i=',i,'ier=',ier endif C deallocate the FFT setup variables call deallocate_fft_setup( setup_id) forall(j=1:cols) mat(i,j) = H2(j) enddo print *, 'forward transform of MAT completed' C point to point multiply of the two fft's-the fft of the C proj. matrix and the response function. C Multiplies each row in parallel one row at a time C Also multiplied point to point by the Hamming window function to C reduce the gibbs phenomenon (p.75 kak) forall(i = 1:cols) $ Ham(i)=(0.54-0.46*cos((2.0*(i-1)*PI)/real(cols))) do i=1,128 mat(i,:) = mat(i,:) * h1 * cmplx(Ham) enddo print *, 'point to point multiply completed' C find the inverse FFT C Inverse FFT is found by finding the complex conj of the C matrrix row by row, finding the forward FFT , again finding C the complex conj. and then scaling(ref. oppenheim and schafer C : digital signal processing, or any other dsp book) do i =1,rows forall(j=1:cols) H2(j) = mat(i,j) setup_id = fft_setup(H2,'CTOC',ier) call fft(H2,'CTOC',CMSSL_i_xform,setup_id,ier) if (ier .ne. 0) then write(*,*) 'error in ifft','i=',i,'ier=',ier endif call deallocate_fft_setup( setup_id) forall(j=1:cols) mat(i,j) = H2(j) enddo print *, 'inverse fft completed' call CM_timer_stop(timer1) write(*,*) 'time for calculating filtered projections' call CM_timer_print(timer1) call CM_timer_start(timer1) C Interpolate to find the actual values. The interpolated C values are stored in the variable 'psum' C The code below actually does the backprojection, but some C of the code which has been executed earlier is also C timed as it is required for back-projection. C Finds the value of (xcos(theta)+ysin(theta)) with x and y C normalized to lie in the space (-1,1) forall(i=1:rdim,j=1:rdim,k=1:128) $ p2(i,j,k) = ((real(i)-xcen2)/xcen2)*cos(theta(k)) $ + ((real(j)-ycen2)/ycen2)*sin(theta(k)) print *, 'p2 evaluated' C finds the mid bins in parallel forall(i=1:rdim,j=1:rdim,k=1:128) $ mb2(i,j,k) = (p2(i,j,k)*mp1*tw) + mp1 C finds the low bins in parallel lb2 = int(mb2) print *, 'lb evaluated' C finds the fractional values of the mid bins frac2 = mb2-real(lb2) print *, 'frac2 evaluated' C finds the high bins from the low bins forall(i=1:rdim,j=1:rdim,k=1:128) hb2(i,j,k) = lb2(i,j,k) + 1 print *, 'hb2 evaluated' C finds the filtered values corresponding to the low bins forall(i=1:rdim,j=1:rdim,k=1:128) $ lbmat(i,j,k) = real(mat(k,lb2(i,j,k))) print *, 'lbmat2 evaluated' C finds the filtered values corresponding to the high bins forall(i=1:rdim,j=1:rdim,k=1:128) $ hbmat(i,j,k) = real(mat(k,hb2(i,j,k))) print *, 'hbmat2 evaluated' C find the interpolated values corresponding to the fractional C values just evaluated psum = ((1.-frac2)*lbmat) + (frac2*hbmat) print *, 'psum evaluated' C finds the total summation over all the angles by summing over C all the angles f = SUM(psum,dim=3) call CM_timer_stop(timer1) call CM_timer_print(timer1) print *,'f matrix evaluated' C write the 'f' matrix to a file open(unit=11,file='cm5_f.fil',status='old',form='formatted') write(11,*), ((f(i,j),j=1,rdim),i=1,rdim) close(11) end C finds the response function directly in the frequency C domain. (Just a ramp function over the reconstruction space) subroutine evalh(H,tau,N) real tau, PI integer N,j,i,k,ii,rdim parameter (rdim=64) complex H(1:rdim),a1(32) CMF$ LAYOUT h(:news),a1(:news) PI = acos(-1.0) forall(j=1:rdim) H(j) = (0.,0.) forall (i=1:32) $ a1(i) = real(i) do i =1,rdim if (i .le. 32) then H(i) = real(i) else H(i) = 65.-real(i) endif enddo C can multipy with a Hamming function if necessary c do i = 1,rdim c H(i) = H(i)*(.54 + .46*cos(2*pi*real(i)/real(rdim))) c enddo return end