Пример #1
0
    def process(self, out=None):

        IM = self.get_input()

        pad = False
        if len(IM.shape) == 2:
            #for 2D cases
            pad = True
            data_temp = numpy.expand_dims(IM.as_array(), axis=0)
        else:
            data_temp = IM.as_array()

        sinogram_id, arr_out = astra.create_sino3d_gpu(data_temp,
                                                       self.proj_geom,
                                                       self.vol_geom)

        astra.data3d.delete(sinogram_id)

        if pad is True:
            arr_out = numpy.squeeze(arr_out, axis=0)

        if out is None:
            out = AcquisitionData(arr_out,
                                  deep_copy=False,
                                  geometry=self.sinogram_geometry.copy(),
                                  suppress_warning=True)
            return out
        else:
            out.fill(arr_out)
Пример #2
0
 def forwprojOS(self, object3D, no_os):
     """Applying forward projection to a specific subset"""
     proj_id, proj_data = astra.create_sino3d_gpu(object3D,
                                                  self.proj_geom_OS[no_os],
                                                  self.vol_geom)
     astra.data3d.delete(proj_id)
     return proj_data
Пример #3
0
    def single_test(self, geom_type, proj_type, alg, iters, vss, dss):
        if alg == 'FBP' and 'fanflat' in geom_type:
            self.skipTest('CPU FBP is parallel-beam only')
        is3D = (geom_type in ['parallel3d', 'cone'])
        for vg in VolumeGeometries(is3D, 'FDK' not in alg):
            for pg in ProjectionGeometries(geom_type):
                if not is3D:
                    vol = np.zeros((128, 128), dtype=np.float32)
                    vol[50:70, 50:70] = 1
                else:
                    vol = np.zeros((64, 64, 64), dtype=np.float32)
                    vol[25:35, 25:35, 25:35] = 1
                options = {}
                if vss > 1:
                    options["VoxelSuperSampling"] = vss
                if dss > 1:
                    options["DetectorSuperSampling"] = vss
                proj_id = astra.create_projector(proj_type,
                                                 pg,
                                                 vg,
                                                 options=options)
                if not is3D:
                    sino_id, sinogram = astra.create_sino(vol, proj_id)
                else:
                    sino_id, sinogram = astra.create_sino3d_gpu(vol, pg, vg)
                if not is3D:
                    DATA = astra.data2d
                else:
                    DATA = astra.data3d

                rec_id = DATA.create('-vol', vg,
                                     0.0 if 'EM' not in alg else 1.0)

                cfg = astra.astra_dict(alg)
                cfg['ReconstructionDataId'] = rec_id
                cfg['ProjectionDataId'] = sino_id
                cfg['ProjectorId'] = proj_id
                alg_id = astra.algorithm.create(cfg)

                for i in range(iters):
                    astra.algorithm.run(alg_id, 1)
                rec = DATA.get(rec_id)
                astra.astra.delete([sino_id, alg_id, alg_id, proj_id])
                if not is3D:
                    val = np.sum(rec[55:65, 55:65]) / 100.
                else:
                    val = np.sum(rec[27:32, 27:32, 27:32]) / 125.
                TOL = 5e-2
                if DISPLAY and abs(val - 1.0) >= TOL:
                    print(geom_type, proj_type, alg, vg, pg)
                    print(val)
                    pylab.gray()
                    if not is3D:
                        pylab.imshow(rec)
                    else:
                        pylab.imshow(rec[:, 32, :])
                    pylab.show()
                self.assertTrue(abs(val - 1.0) < TOL)
Пример #4
0
 def process(self):
     IM = self.get_input()
     DATA = AcquisitionData(geometry=self.sinogram_geometry,
                            dimension_labels=self.output_axes_order)
     sinogram_id, DATA.array = astra.create_sino3d_gpu(
         IM.as_array(), self.proj_geom, self.vol_geom)
     astra.data3d.delete(sinogram_id)
     # 3D CUDA FP does not need scaling
     return DATA
Пример #5
0
def _basic_par3d_fp():
    import astra
    import numpy as np
    vg = astra.create_vol_geom(2, 32, 32)
    pg = astra.create_proj_geom('parallel3d', 1, 1, 32, 32, [0])
    vol = np.random.rand(32, 2, 32)
    (sino_id, sino) = astra.create_sino3d_gpu(vol, pg, vg)
    astra.data3d.delete(sino_id)
    err = np.max(np.abs(sino[:, 0, :] - np.sum(vol, axis=1)))
    return err < 1e-6
Пример #6
0
def _basic_par3d_fp():
  import astra
  import numpy as np
  vg = astra.create_vol_geom(2, 32, 32)
  pg = astra.create_proj_geom('parallel3d', 1, 1, 32, 32, [0])
  vol = np.random.rand(32, 2, 32)
  (sino_id, sino) = astra.create_sino3d_gpu(vol, pg, vg)
  astra.data3d.delete(sino_id)
  err = np.max(np.abs(sino[:,0,:] - np.sum(vol,axis=1)))
  return err < 1e-6
Пример #7
0
    def process(self, out=None):

        IM = self.get_input()

        sinogram_id, arr_out = astra.create_sino3d_gpu(IM.as_array(),
                                                       self.proj_geom,
                                                       self.vol_geom)
        astra.data3d.delete(sinogram_id)

        if out is None:
            out = AcquisitionData(arr_out,
                                  deep_copy=False,
                                  geometry=self.sinogram_geometry.copy(),
                                  suppress_warning=True)
            return out
        else:
            out.fill(arr_out)
Пример #8
0
def astra_project(obj, angles, cuda=False):
    """
    Calculate projection of a 3D object using Astra-toolbox.

    Args
    ----------
    obj : NumPy array
        Either a 2D or 3D array containing the object to project.
        If 2D, the structure is of the form [z, x] where z is the
        projection axis.  If 3D, the strucutre is [y, z, x] where y is
        the tilt axis.
    angles : list or NumPy array
        The projection angles in degrees
    cuda : boolean
        If True, perform reconstruction using the GPU-accelerated algorithm.

    Returns
    ----------
    sino : Numpy array
        3D array of the form [y, angle, x] containing the projection of
        the input object

    """
    if len(obj.shape) == 2:
        obj = np.expand_dims(obj, 0)
    thetas = np.pi * angles / 180.
    y_pix, thickness, x_pix = obj.shape
    if cuda:
        vol_geom = astra.create_vol_geom(thickness, x_pix, y_pix)
        proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, y_pix,
                                           x_pix, thetas)
        sino_id, sino = astra.create_sino3d_gpu(obj, proj_geom, vol_geom)
        astra.data3d.delete(sino_id)
    else:
        sino = np.zeros([y_pix, len(angles), x_pix], np.float32)
        vol_geom = astra.create_vol_geom(thickness, x_pix)
        proj_geom = astra.create_proj_geom('parallel', 1.0, x_pix, thetas)
        proj_id = astra.create_projector('strip', proj_geom, vol_geom)
        for i in range(0, y_pix):
            sino_id, sino[i, :, :] = astra.create_sino(obj[i, :, :], proj_id,
                                                       vol_geom)
        astra.data2d.delete(sino_id)

    sino = np.rollaxis(sino, 1)
    return sino
Пример #9
0
    def single_test_adjoint3D(self, geom_type, proj_type):
        for vg in VolumeGeometries(True, True):
            for pg in ProjectionGeometries(geom_type):
                for i in range(5):
                    X = np.random.random(astra.geom_size(vg))
                    Y = np.random.random(astra.geom_size(pg))
                    proj_id, fX = astra.create_sino3d_gpu(X, pg, vg)
                    bp_id, fTY = astra.create_backprojection3d_gpu(Y, pg, vg)

                    astra.data3d.delete([proj_id, bp_id])

                    da = np.dot(fX.ravel(), Y.ravel())
                    db = np.dot(X.ravel(), fTY.ravel())
                    m = np.abs(da - db)
                    TOL = 1e-1
                    if m / da >= TOL:
                        print(vg)
                        print(pg)
                        print(m / da, da / db, da, db)
                    self.assertTrue(m / da < TOL)
    def process(self, out=None):

        IM = self.get_input()

        pad = False
        if len(IM.shape) == 2:
            #for 2D cases
            pad = True
            data_temp = np.expand_dims(IM.as_array(), axis=0)
        else:
            data_temp = IM.as_array()

        if out is None:

            sinogram_id, arr_out = astra.create_sino3d_gpu(
                data_temp, self.proj_geom, self.vol_geom)
        else:
            if pad:
                arr_out = np.expand_dims(out.as_array(), axis=0)
            else:
                arr_out = out.as_array()

            sinogram_id = astra.data3d.link('-sino', self.proj_geom, arr_out)
            self.create_backprojection3d_gpu(data_temp, self.proj_geom,
                                             self.vol_geom, False, sinogram_id)

        #clear the memory on GPU
        astra.data3d.delete(sinogram_id)

        if pad is True:
            arr_out = np.squeeze(arr_out, axis=0)

        if out is None:
            out = AcquisitionData(arr_out,
                                  deep_copy=False,
                                  geometry=self.sinogram_geometry.copy(),
                                  suppress_warning=True)
            return out
        else:
            out.fill(arr_out)
Пример #11
0
    def run_new_scan(self, n_projections):
        x, y, z = self.__volume.shape
        print(x, y, z)
        vol_geom = astra.create_vol_geom(y, z, x)

        angles = np.linspace(0, np.pi, n_projections, False)
        proj_geom = astra.create_proj_geom('cone', 1.0, 1.0, 512, 512, angles,
                                           300000, 300)
        proj_id, proj_data = astra.create_sino3d_gpu(self.__volume, proj_geom,
                                                     vol_geom)

        rec_id = astra.data3d.create('-vol', vol_geom)
        cfg = astra.astra_dict('FDK_CUDA')
        cfg['ReconstructionDataId'] = rec_id
        cfg['ProjectionDataId'] = proj_id
        alg_id = astra.algorithm.create(cfg)
        astra.algorithm.run(alg_id)
        rec = astra.data3d.get(rec_id)

        astra.algorithm.delete(alg_id)
        astra.data3d.delete(rec_id)
        astra.data3d.delete(proj_id)

        return rec
Пример #12
0
def recon_multi_part(algon,proj_data,proj_data_low,det_move,angles,x_sub_boundaries,y_sub_boundaries,z_sub_boundaries,vol_size,det_spacing_x,det_spacing_y,x_subvol_width,y_subvol_width,z_subvol_width,n_x,n_y,n_z,nr_iterations_high,source_origin, origin_det,relaxation):
    # this part performs the reconstruction of the subvolume.
    pro_proj = proj_data - proj_data_low  # we only want to have the projection data that comes from the sub volume
    det_row_count= pro_proj.shape[0]
    det_col_count=pro_proj.shape[2]

    vectors_ROI = np.zeros((len(angles), 12)) # this vector will contain the information of the source and detector position.
    move_x,move_y,move_z=how_to_move(x_sub_boundaries,y_sub_boundaries,z_sub_boundaries,vol_size,x_subvol_width,y_subvol_width,z_subvol_width,n_x,n_y,n_z)
    for i in range(0,len(angles)):
        # source
        vectors_ROI[i,0] = np.sin(angles[i]) * (source_origin) +move_x 
        vectors_ROI[i,1] = -np.cos(angles[i]) * (source_origin) + move_y
        vectors_ROI[i,2] = move_z
        # center of detector
        vectors_ROI[i,3] = -np.sin(angles[i]) * (origin_det) + move_x 
        vectors_ROI[i,4] = np.cos(angles[i]) * (origin_det)  + move_y
        vectors_ROI[i,5] = move_z +det_move
        # vector from detector pixel 0 to 1
        vectors_ROI[i,6] = np.cos(angles[i]) *det_spacing_x    
        vectors_ROI[i,7] = np.sin(angles[i])*det_spacing_x
        vectors_ROI[i,8] = 0

        # vector from detector pixel (0,0) to (1,0)
        vectors_ROI[i,9] = 0
        vectors_ROI[i,10] = 0
        vectors_ROI[i,11] = det_spacing_y
    
            #ROI=cube[:,:,z_sub_boundaries[n_z,0]:z_sub_boundaries[n_z+1,0]]
            # mlab.figure()
            # mlab.contour3d(ROI)
    width_z=z_sub_boundaries[n_z+1,2]-z_sub_boundaries[n_z,1]
    width_y=y_sub_boundaries[n_y+1,2]-y_sub_boundaries[n_y,1]
    width_x=x_sub_boundaries[n_x+1,2]-x_sub_boundaries[n_x,1]
    
    vol_geom_ROI= astra.create_vol_geom(width_y.astype(int), width_z.astype(int), width_x.astype(int))
    proj_geom_ROI = astra.create_proj_geom('cone_vec', det_row_count, det_col_count, vectors_ROI)

    if algon[0:4] != 'EGEN':

        # Create a data object for the reconstruction


        rec_id_ROI = astra.data3d.create('-vol', vol_geom_ROI)
        sinogram_id_ROI = astra.data3d.create('-proj3d', proj_geom_ROI, pro_proj)
        if algon=='SIRT':
            algon='SIRT3D_CUDA'
        elif algon=='CGLS':
            algon='CGLS3D_CUDA'

        # Set up the parameters for a reconstruction algorithm using the GPU
        cfg = astra.astra_dict(algon)   
        cfg['ReconstructionDataId'] = rec_id_ROI
        cfg['ProjectionDataId'] = sinogram_id_ROI
        cfg['option']={}
        cfg['option']['MinConstraint'] = 0 #attenuation coefficient can't be negative
        #cfg['option']['VoxelSuperSampling'] = np.round(float(det_spacing_x)/vol_size,decimals=2)
        alg_id = astra.algorithm.create(cfg)

    print "startar algo"
    if algon == 'SIRT3D_CUDA' or algon=='CGLS3D_CUDA':
        astra.algorithm.run(alg_id,nr_iterations_high)

            
    elif algon=='EGEN_SART':

        rec_volume=(width_x.astype(int), width_y.astype(int), width_z.astype(int))
        rec_volume=np.zeros(rec_volume,dtype= np.float16)
        
        sides=[rec_volume.shape[0],rec_volume.shape[1],rec_volume.shape[2]]
        max_side=np.max(sides)
        print max_side
        h=relaxation*float(1)/(max_side)#0.00001 change to max size of y o z


        vectors=np.matrix('0 0 0 0 0 0 0 0 0 0 0 0',dtype= np.float16)
        for ii in range(0,nr_iterations_high):
            angles_ind = np.linspace(0, len(angles), len(angles),False)
            np.random.shuffle(angles_ind) #shuffle the projection angles to get faster convergence
            
            for jj in angles_ind:
                
                #proj_geom = astra.create_proj_geom('cone', det_spacing, det_spacing, det_size[1], det_size[1], angles[jj], source_to_origin_pixels,origin_to_detector_pixels)
                vectors[:,:]=vectors_ROI[jj,:]
                proj_geom_SART = astra.create_proj_geom('cone_vec', det_row_count, det_col_count, vectors)
                sinogram_id, proj_it = astra.create_sino3d_gpu(rec_volume, proj_geom_SART,vol_geom_ROI)

                proj_it=proj_it[:,0,:]


                residual=np.zeros((det_row_count,1,det_col_count))
                residual[:,0,:]=proj_it-pro_proj[:,jj,:]

                astra.data3d.store(sinogram_id, residual)

                #h=0.001
                [id, rec_volume_it] = astra.create_backprojection3d_gpu(residual, proj_geom_SART, vol_geom_ROI)
                rec_volume= rec_volume -h*rec_volume_it
                rec_volume=rec_volume*(rec_volume>0)
                astra.data3d.delete(id)
                astra.data3d.delete(sinogram_id)  
                
            

    else:
        print"algorithm is not supported"

    print "s**t algo"
    if algon[0:4] != 'EGEN':
        # Get the result
        
        rec_sub_vol=astra.data3d.get(rec_id_ROI)
    
        # Clean up. Note that GPU memory is tied up in the algorithm object,
        # and main RAM in the data objects.
        astra.algorithm.delete(alg_id)
        astra.data3d.delete(rec_id_ROI)
        astra.data3d.delete(sinogram_id_ROI)
        return rec_sub_vol
    else:
        return rec_volume



    
                        
def recon_multi_part(algon,proj_data,proj_data_low,det_move,angles,x_sub_boundaries,y_sub_boundaries,z_sub_boundaries,vol_size,det_spacing_x,det_spacing_y,x_subvol_width,y_subvol_width,z_subvol_width,n_x,n_y,n_z,nr_iterations_high,source_origin, origin_det,relaxation):
    # this part performs the reconstruction of the subvolume.
    pro_proj = proj_data - proj_data_low  # we only want to have the projection data that comes from the sub volume
    det_row_count= pro_proj.shape[0]
    det_col_count=pro_proj.shape[2]

    vectors_ROI = np.zeros((len(angles), 12)) # this vector will contain the information of the source and detector position.
    move_x,move_y,move_z=how_to_move(x_sub_boundaries,y_sub_boundaries,z_sub_boundaries,vol_size,x_subvol_width,y_subvol_width,z_subvol_width,n_x,n_y,n_z)
    for i in range(0,len(angles)):
        # source
        vectors_ROI[i,0] = np.sin(angles[i]) * (source_origin) +move_x 
        vectors_ROI[i,1] = -np.cos(angles[i]) * (source_origin) + move_y
        vectors_ROI[i,2] = move_z
        # center of detector
        vectors_ROI[i,3] = -np.sin(angles[i]) * (origin_det) + move_x 
        vectors_ROI[i,4] = np.cos(angles[i]) * (origin_det)  + move_y
        vectors_ROI[i,5] = move_z +det_move
        # vector from detector pixel 0 to 1
        vectors_ROI[i,6] = np.cos(angles[i]) *det_spacing_x    
        vectors_ROI[i,7] = np.sin(angles[i])*det_spacing_x
        vectors_ROI[i,8] = 0

        # vector from detector pixel (0,0) to (1,0)
        vectors_ROI[i,9] = 0
        vectors_ROI[i,10] = 0
        vectors_ROI[i,11] = det_spacing_y
    
            #ROI=cube[:,:,z_sub_boundaries[n_z,0]:z_sub_boundaries[n_z+1,0]]
            # mlab.figure()
            # mlab.contour3d(ROI)
    width_z=z_sub_boundaries[n_z+1,2]-z_sub_boundaries[n_z,1]
    width_y=y_sub_boundaries[n_y+1,2]-y_sub_boundaries[n_y,1]
    width_x=x_sub_boundaries[n_x+1,2]-x_sub_boundaries[n_x,1]
    
    vol_geom_ROI= astra.create_vol_geom(width_y.astype(int), width_z.astype(int), width_x.astype(int))
    proj_geom_ROI = astra.create_proj_geom('cone_vec', det_row_count, det_col_count, vectors_ROI)

    if algon[0:4] != 'EGEN':

        # Create a data object for the reconstruction


        rec_id_ROI = astra.data3d.create('-vol', vol_geom_ROI)
        sinogram_id_ROI = astra.data3d.create('-proj3d', proj_geom_ROI, pro_proj)
        if algon=='SIRT':
            algon='SIRT3D_CUDA'
        elif algon=='CGLS':
            algon='CGLS3D_CUDA'

        # Set up the parameters for a reconstruction algorithm using the GPU
        cfg = astra.astra_dict(algon)   
        cfg['ReconstructionDataId'] = rec_id_ROI
        cfg['ProjectionDataId'] = sinogram_id_ROI
        cfg['option']={}
        cfg['option']['MinConstraint'] = 0 #attenuation coefficient can't be negative
        #cfg['option']['VoxelSuperSampling'] = np.round(float(det_spacing_x)/vol_size,decimals=2)
        alg_id = astra.algorithm.create(cfg)

    print "startar algo"
    if algon == 'SIRT3D_CUDA' or algon=='CGLS3D_CUDA':
        astra.algorithm.run(alg_id,nr_iterations_high)

            
    elif algon=='EGEN_SART':

        rec_volume=(width_x.astype(int), width_y.astype(int), width_z.astype(int))
        rec_volume=np.zeros(rec_volume,dtype= np.float16)
        
        sides=[rec_volume.shape[0],rec_volume.shape[1],rec_volume.shape[2]]
        max_side=np.max(sides)
        print max_side
        h=relaxation*float(1)/(max_side)#0.00001 change to max size of y o z


        vectors=np.matrix('0 0 0 0 0 0 0 0 0 0 0 0',dtype= np.float16)
        for ii in range(0,nr_iterations_high):
            angles_ind = np.linspace(0, len(angles), len(angles),False)
            np.random.shuffle(angles_ind) #shuffle the projection angles to get faster convergence
            
            for jj in angles_ind:
                
                #proj_geom = astra.create_proj_geom('cone', det_spacing, det_spacing, det_size[1], det_size[1], angles[jj], source_to_origin_pixels,origin_to_detector_pixels)
                vectors[:,:]=vectors_ROI[jj,:]
                proj_geom_SART = astra.create_proj_geom('cone_vec', det_row_count, det_col_count, vectors)
                sinogram_id, proj_it = astra.create_sino3d_gpu(rec_volume, proj_geom_SART,vol_geom_ROI)

                proj_it=proj_it[:,0,:]


                residual=np.zeros((det_row_count,1,det_col_count))
                residual[:,0,:]=proj_it-pro_proj[:,jj,:]

                astra.data3d.store(sinogram_id, residual)

                #h=0.001
                [id, rec_volume_it] = astra.create_backprojection3d_gpu(residual, proj_geom_SART, vol_geom_ROI)
                rec_volume= rec_volume -h*rec_volume_it
                rec_volume=rec_volume*(rec_volume>0)
                astra.data3d.delete(id)
                astra.data3d.delete(sinogram_id)  
                
            

    else:
        print"algorithm is not supported"

    print "s**t algo"
    if algon[0:4] != 'EGEN':
        # Get the result
        
        rec_sub_vol=astra.data3d.get(rec_id_ROI)
    
        # Clean up. Note that GPU memory is tied up in the algorithm object,
        # and main RAM in the data objects.
        astra.algorithm.delete(alg_id)
        astra.data3d.delete(rec_id_ROI)
        astra.data3d.delete(sinogram_id_ROI)
        return rec_sub_vol
    else:
        return rec_volume
Пример #14
0
def make_reconsruction(proj_data,number_of_projections,vol_size_ratio,det_size,rec_volume,source_to_origin_pixels,origin_to_detector_pixels,nr_iterations,algo,relaxation,initializer):

    vol_geom = astra.create_vol_geom(rec_volume)
    
    angles = np.linspace(0, 2*np.pi, number_of_projections, False)
    det_spacing=np.round((float(det_size[0])/det_size[1])/vol_size_ratio,decimals=3)

    proj_geom = astra.create_proj_geom('cone', det_spacing, det_spacing, det_size[1], det_size[1], angles, source_to_origin_pixels,origin_to_detector_pixels)

    #np.round(float(rec_volume[0])/new_size[0],decimals=2)
    if algo[0:4] != 'EGEN':
        # Create projection data from this
        proj_id=4

        # Create a data object for the reconstruction
        rec_id = astra.data3d.create('-vol', vol_geom,initializer)
        sinogram_id = astra.data3d.create('-proj3d', proj_geom, proj_data)
        #Set up the parameters for a reconstruction algorithm using the GPU
        cfg = astra.astra_dict(algo)
        cfg['ReconstructionDataId'] = rec_id
        cfg['ProjectionDataId'] = sinogram_id
        cfg['option']={}
        cfg['option']['MinConstraint'] = 0 #attenuation coefficient can't be negative
 
        # Create the algorithm object from the configuration structure
        alg_id = astra.algorithm.create(cfg)

    print "startar algo"
    if algo == 'SIRT3D_CUDA' or algo=='CGLS3D_CUDA':
        astra.algorithm.run(alg_id,nr_iterations)
    elif algo=='FDK_CUDA':
        astra.algorithm.run(alg_id)
    elif algo=='EGEN_SIRT':
        if isinstance( initializer, ( int, long ) ):
            rec_volume=np.zeros(rec_volume,dtype= np.float16)
        else:
            rec_volume=initializer
        for ii in range(0,nr_iterations):

            sinogram_id, proj_it = astra.create_sino3d_gpu(rec_volume, proj_geom,vol_geom)
            residual=proj_it-proj_data

            h=relaxation*float(1)/(rec_volume.shape[0]*number_of_projections)
            [id, rec_volume_it] = astra.create_backprojection3d_gpu(residual, proj_geom, vol_geom)
            rec_volume= rec_volume -h*rec_volume_it
            rec_volume=rec_volume*(rec_volume>0)
            astra.data3d.delete(id)
            astra.data3d.delete(sinogram_id)
            
    elif algo=='EGEN_SART':
        if isinstance( initializer, ( int, long ) ):
            rec_volume=np.zeros(rec_volume,dtype= np.float16)
        else:
            rec_volume=initializer
        #print rec_volume.shape[0]
        
        for ii in range(0,nr_iterations):
            angles_ind = np.linspace(0, number_of_projections, number_of_projections,False)
            np.random.shuffle(angles_ind)

            for jj in angles_ind:
                proj_geom = astra.create_proj_geom('cone', det_spacing, det_spacing, det_size[1], det_size[1], angles[jj], source_to_origin_pixels,origin_to_detector_pixels)
            #print np.min(sub_volume_high)
                sinogram_id, proj_it = astra.create_sino3d_gpu(rec_volume, proj_geom,vol_geom)
                proj_it=proj_it[:,0,:]
                residual=np.zeros((det_size[1],1,det_size[1]))
                residual[:,0,:]=proj_it-proj_data[:,jj,:]
                #print np.shape(proj_it),np.shape(residual),np.shape(proj_data[:,jj,:])
                #astra.data3d.store(sinogram_id, residual)
                
                h=relaxation*float(1)/(rec_volume.shape[0])#0.00001
                [id, rec_volume_it] = astra.create_backprojection3d_gpu(residual, proj_geom, vol_geom)
                rec_volume= rec_volume -h*rec_volume_it
                rec_volume=rec_volume*(rec_volume>0)
                astra.data3d.delete(id)
                astra.data3d.delete(sinogram_id)    
#             pylab.figure()
#             pylab.gray()
#             pylab.imshow(rec_volume[:,:,128])
            

    else:
        print"algorithm is not supported"
        
        
    print "s**t algo"
    if algo[0:4] != 'EGEN':
        # Get the result
        rec = astra.data3d.get(rec_id)
    
        # Clean up. Note that GPU memory is tied up in the algorithm object,
        # and main RAM in the data objects.
        astra.algorithm.delete(alg_id)
        astra.data3d.delete(rec_id)
        astra.data3d.delete(proj_id)
        astra.data3d.delete(sinogram_id)
        return rec
    else:
        return rec_volume
Пример #15
0
v2 = astra.data3d.create('-vol', vol_geom, A)

# Projection data

# 2 projection directions, along x and y axis resp.
V = np.array([[1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],
              [0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1]],
             dtype=np.float)
# 32 rows (v), 64 columns (u)
proj_geom = astra.create_proj_geom('parallel3d_vec', 32, 64, V)
s0 = astra.data3d.create('-proj3d', proj_geom)

# Create a sinogram
sino_id, sino = astra.create_sino3d_gpu(A,
                                        proj_geom,
                                        vol_geom,
                                        returnData=1,
                                        gpuIndex=0)

# Initialization to a scalar or zero works exactly as with a volume.

# Initialized to a matrix:
# Coordinate order: row (v), angle, column (u)
A = np.zeros((32, 2, 64))
s1 = astra.data3d.create('-proj3d', proj_geom, A)

# Retrieve data:
R = astra.data3d.get(v1)

# Delete all created data objects
astra.data3d.delete(v0)
Пример #16
0
# initialized to a matrix. A may be a single or double array.
# Coordinate order: slice, row, column (z, y, x)
v2 = astra.data3d.create('-vol', vol_geom, A)

# Projection data

# 2 projection directions, along x and y axis resp.
V = np.array([[1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],
              [0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1]], dtype=np.float)
# 32 rows (v), 64 columns (u)
proj_geom = astra.create_proj_geom('parallel3d_vec', 32, 64, V)
s0 = astra.data3d.create('-proj3d', proj_geom)

# Create a sinogram
sino_id, sino = astra.create_sino3d_gpu(A, proj_geom, vol_geom, returnData=1,
                                        gpuIndex=0)

# Initialization to a scalar or zero works exactly as with a volume.

# Initialized to a matrix:
# Coordinate order: row (v), angle, column (u)
A = np.zeros((32, 2, 64))
s1 = astra.data3d.create('-proj3d', proj_geom, A)

# Retrieve data:
R = astra.data3d.get(v1)

# Delete all created data objects
astra.data3d.delete(v0)
astra.data3d.delete(v1)
astra.data3d.delete(v2)
Пример #17
0
def conebeam_helical_sim(phantom=None, alg_type='sirt3d', num_iterations=10, padding=(0, 0), scale_factor=1,
                         vol_init=None,
                         gpu_index=0,
                         num_voxels=None, num_pixel=None, num_angles=25):
    """Test helical conebeam reconstruction of ASTRA.

    Parameters
    ----------

    num_voxels : int, list of int
    num_voxels[0:1] are the number of transverse voxels, num_voxels[2] is the number of  voxels along the longitudinal
    direction that coincides with the helical (z) axis and along which the sample is translated.

    conebeam_helical_sim()
    """

    # Default arguments
    if not num_voxels:
        num_voxels = [100, 100, 100]
    if not num_pixel:
        num_pixel = [100, 100]

    if padding[0]:
        pass

    if scale_factor:
        pass

    detector_spacing_x = 1
    detector_spacing_y = 1
    det_row_count = num_pixel[0]
    det_col_count = num_pixel[1]
    angles_rad = np.linspace(0, 2 * np.pi, num_angles, endpoint=False)
    source_origin = 50
    origin_det = 40
    z_max = np.round(num_voxels[2] / 3)
    z_min = -np.round(num_voxels[2] / 3)
    z_range = np.linspace(z_min, z_max, num_angles, endpoint=False)

    # Create phantom object
    if phantom is None:
        phantom = 1000 / 2 * (util.phantom_ball(num_voxels, (0.45, 0.5, 0.5), 0.1)
                              + util.phantom_ball(num_voxels, (0.55, 0.5, 0.5), 0.05))

    # Create volume geometry
    vol_geom = astra.create_vol_geom(*num_voxels)

    # Create helical projection geometry
    cone_vec = np.zeros((num_angles, 12))
    # Source
    cone_vec[:, 0] = np.sin(angles_rad) * source_origin
    cone_vec[:, 1] = -np.cos(angles_rad) * source_origin
    cone_vec[:, 2] = z_range
    # Centre of detector
    cone_vec[:, 3] = -np.sin(angles_rad) * origin_det
    cone_vec[:, 4] = np.cos(angles_rad) * origin_det
    cone_vec[:, 5] = z_range
    # Vector from detector pixel (0,0) to (0,1)
    cone_vec[:, 6] = np.cos(angles_rad) * detector_spacing_x
    cone_vec[:, 7] = np.sin(angles_rad) * detector_spacing_x
    cone_vec[:, 8] = 0
    # Vector from detector pixel (0,0) to (0,1)
    cone_vec[:, 9] = 0
    cone_vec[:, 10] = 0
    cone_vec[:, 11] = detector_spacing_y

    proj_geom = astra.create_proj_geom('cone_vec', det_row_count, det_col_count, cone_vec)

    t = time.time()
    # Create a sinogram from phantom
    sinogram_id, sinogram = astra.create_sino3d_gpu(phantom, proj_geom, vol_geom, returnData=True, gpuIndex=gpu_index)

    # Set up the parameters for a reconstruction algorithm
    rec_id = astra.data3d.create('-vol', vol_geom, vol_init)
    alg_type += '_CUDA'
    alg_type = alg_type.upper()
    cfg = astra.astra_dict(alg_type)
    cfg['ReconstructionDataId'] = rec_id
    cfg['ProjectionDataId'] = sinogram_id
    cfg['option'] = {}
    cfg['option']['GPUindex'] = gpu_index

    # Iterate algorithm
    alg_id = astra.algorithm.create(cfg)
    astra.algorithm.run(alg_id, num_iterations)
    rec_vol = astra.data3d.get(rec_id)

    print("GPU index: %u" % gpu_index)
    # print("Number of projections: %u" % proj_geom['ProjectionAngles'].shape)
    print("Algorithm: %s" % cfg['type'])
    print("Elapsed time: %g s" % (time.time() - t))

    astra.algorithm.clear()
    astra.data3d.clear()
    astra.projector.clear()

    return rec_vol, sinogram, phantom, angles_rad, proj_geom
Пример #18
0
def conebeam_sim(phantom=None, alg_type='sirt3d', num_iterations=10, padding=(0, 0), scale_factor=1, vol_init=None,
                 gpu_index=0,
                 num_voxel=None, num_pixel=None, num_angles=150):
    """Test conebeam reconstruction of ASTRA.

    conebeam_sim()
    """

    # Default arguments
    if not num_voxel:
        num_voxel = [100, 100, 100]
    if not num_pixel:
        num_pixel = [112, 112]

    # print astra workspace
    if 0:
        astra.algorithm.info()
        astra.data3d.info()
        astra.projector.info()

    if padding[0]:
        pass

    if scale_factor:
        pass

    detector_spacing_x = 1
    detector_spacing_y = 1
    det_row_count = num_pixel[0]
    det_col_count = num_pixel[1]
    angles_rad = np.linspace(0, 2 * np.pi, num_angles, endpoint=True)
    source_origin = 50
    source_det = 50

    print("GPU index: %u" % gpu_index)
    # Create volume geometry
    vol_geom = astra.create_vol_geom(*num_voxel)
    # Create projection geometry
    #    proj_geom = astra.create_proj_geom('parallel3d',
    #                                       detector_spacing_x, detector_spacing_y,
    #                                       det_row_count, det_col_count,
    #                                       angles)
    proj_geom = astra.create_proj_geom('cone',
                                       detector_spacing_x, detector_spacing_y,
                                       det_row_count, det_col_count,
                                       angles_rad,
                                       source_origin, source_det)

    # Create phantom object
    if phantom is None:
        phantom = 1000 / 2 * (phantom_ball(num_voxel, (0.45, 0.5, 0.5), 0.1)
                              + phantom_ball(num_voxel, (0.55, 0.5, 0.5), 0.05))

    t = time.time()
    # Create a sinogram from phantom
    sinogram_id, sinogram = astra.create_sino3d_gpu(phantom, proj_geom, vol_geom, returnData=True, gpuIndex=gpu_index)
    print("Sinogram shape: %u, %u, %u" % (sinogram.shape))
    
    # Set up the parameters for a reconstruction algorithm using the GPU
    rec_id = astra.data3d.create('-vol', vol_geom, vol_init)
    alg_type += '_CUDA'
    alg_type = alg_type.upper()
    cfg = astra.astra_dict(alg_type)
    cfg['ReconstructionDataId'] = rec_id
    cfg['ProjectionDataId'] = sinogram_id

    # Use GPU
    cfg['option'] = {}
    cfg['option']['GPUindex'] = gpu_index

    # Iterate algorithm
    alg_id = astra.algorithm.create(cfg)
    astra.algorithm.run(alg_id, num_iterations)
    rec_vol = astra.data3d.get(rec_id)

    print("Number of projections: %u" % proj_geom['ProjectionAngles'].shape)
    print("Algorithm: %s" % cfg['type'])
    print("Elapsed time: %g s" % (time.time() - t))

    # Clean up.
    # astra.algorithm.delete(alg_id)
    # astra.data2d.delete(rec_id)
    # astra.data2d.delete(sinogram_id)
    # astra.projector.delete(proj_id)

    astra.algorithm.clear()
    astra.data2d.clear()
    astra.projector.clear()

    return rec_vol, sinogram, phantom, angles_rad
import numpy as np

# Set up multi-GPU usage.
# This only works for 3D GPU forward projection and back projection.
astra.astra.set_gpu_index([0,1])

# Optionally, you can also restrict the amount of GPU memory ASTRA will use.
# The line commented below sets this to 1GB.
#astra.astra.set_gpu_index([0,1], memory=1024*1024*1024)

vol_geom = astra.create_vol_geom(1024, 1024, 1024)

angles = np.linspace(0, np.pi, 1024,False)
proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, 1024, 1024, angles)

# Create a simple hollow cube phantom
cube = np.zeros((1024,1024,1024))
cube[128:895,128:895,128:895] = 1
cube[256:767,256:767,256:767] = 0

# Create projection data from this
proj_id, proj_data = astra.create_sino3d_gpu(cube, proj_geom, vol_geom)

# Backproject projection data
bproj_id, bproj_data = astra.create_backprojection3d_gpu(proj_data, proj_geom, vol_geom)

# Clean up. Note that GPU memory is tied up in the algorithm object,
# and main RAM in the data objects.
astra.data3d.delete(proj_id)
astra.data3d.delete(bproj_id)
Пример #20
0
 def forwproj(self, object3D):
     """Applying forward projection"""
     proj_id, proj_data = astra.create_sino3d_gpu(object3D, self.proj_geom,
                                                  self.vol_geom)
     astra.data3d.delete(proj_id)
     return proj_data
Пример #21
0
import astra
import numpy as np
import matplotlib.pyplot as plt
vol_geom = astra.create_vol_geom(128, 128, 128)

angles = np.linspace(0, np.pi, 180,False)
proj_geom = astra.create_proj_geom('parallel3d', 1.0, 1.0, 128, 192, angles)

# Create a simple hollow cube phantom
cube = np.zeros((128,128,128))
cube[17:113,17:113,17:113] = 1
cube[33:97,33:97,33:97] = 0

# Create projection data from this
proj_id, proj_data = astra.create_sino3d_gpu(cube, proj_geom, vol_geom)

# Display a single projection image

plt.gray()
plt.figure(1)
plt.imshow(proj_data[:,20,:])

# Create a data object for the reconstruction
rec_id = astra.data3d.create('-vol', vol_geom)

# Set up the parameters for a reconstruction algorithm using the GPU
cfg = astra.astra_dict('SIRT3D_CUDA')
cfg['ReconstructionDataId'] = rec_id
cfg['ProjectionDataId'] = proj_id
##################################HERE Multi resolution starts
ii=0

x_parts,y_parts, z_parts=create_parts(nr_subvol_x,nr_subvol_y,nr_subvol_z) 

vol_geom_low = astra.create_vol_geom(vol_size_low, vol_size_low, vol_size_low)
proj_geom_low = astra.create_proj_geom('cone',  det_spacing_x_low, det_spacing_y_low, det_row_count, det_col_count, angles, source_origin, origin_det)
algon_high=raw_input("Algo high: ")
for n_x in x_parts:
    for n_y in y_parts:
        for n_z in z_parts: ## nr_subvol_z
            rec_low_temp[:,:,:]=rec_low[:,:,:]
            rec_low_temp[x_sub_boundaries[n_x,1] / vol_size_ratio:x_sub_boundaries[n_x+1,2] / vol_size_ratio, y_sub_boundaries[n_y,1] / vol_size_ratio:y_sub_boundaries[n_y+1,2] / vol_size_ratio, z_sub_boundaries[n_z,1] / vol_size_ratio:z_sub_boundaries[n_z+1,2] / vol_size_ratio] = 0

            proj_id_low, proj_data_low = astra.create_sino3d_gpu(rec_low_temp, proj_geom_low, vol_geom_low)
            astra.data3d.delete(proj_id_low)
            x_start=x_sub_boundaries[n_x,1]
            x_stop=x_sub_boundaries[n_x+1,2]
            h_start=FOV/2 - x_start
            h_stop=FOV/2 - x_stop  #height
            if x_start==0:
                sin_angle_start= float(FOV/2 - x_start + FOV/2*(det/2)/(origin_det + source_origin))/(source_origin - FOV/2) #not needed
                pro_start=0
            else:
                if h_start < 0:
                    sin_angle_start= float(FOV/2 - x_start)/(source_origin + FOV/2)
                else:
                    sin_angle_start= float(FOV/2 - x_start)/(source_origin - FOV/2)
                pro_start=np.floor(det/2 -(source_origin+origin_det)*sin_angle_start)
            if x_stop == vol_size:
Пример #23
0
det_row_count = int(np.round(1.0 * nn))
det_col_count = det_row_count
angles = np.linspace(0, 2 * np.pi, 180)
source_origin = 50
source_det = 50
vol_init=None
gpu_index=0

# Create volume geometry
vol_geom = astra.create_vol_geom(*num_voxel)

# Creat projection geometry
proj_geom = astra.create_proj_geom('cone', detector_spacing_x, detector_spacing_y, det_row_count, det_col_count, angles, source_origin, source_det)
    
# Create a sinogram from phantom
sinogram_id, sinogram = astra.create_sino3d_gpu(phan, proj_geom, vol_geom, returnData=True, gpuIndex=gpu_index)

# Create 3D data object
rec_id = astra.data3d.create('-vol', vol_geom, vol_init)

# SIRT3D
alg_type = 'SIRT3D_CUDA'
cfg_sirt = astra.astra_dict(alg_type)
cfg_sirt['ReconstructionDataId'] = rec_id
cfg_sirt['ProjectionDataId'] = sinogram_id
cfg_sirt['option'] = {}
cfg_sirt['option']['GPUindex'] = gpu_index

# Create algorithm object
alg_id = astra.algorithm.create(cfg_sirt)
Пример #24
0
vol_init = None
gpu_index = 0

# Create volume geometry
vol_geom = astra.create_vol_geom(*num_voxel)

# Creat projection geometry
proj_geom = astra.create_proj_geom('cone', detector_spacing_x,
                                   detector_spacing_y, det_row_count,
                                   det_col_count, angles, source_origin,
                                   source_det)

# Create a sinogram from phantom
sinogram_id, sinogram = astra.create_sino3d_gpu(phan,
                                                proj_geom,
                                                vol_geom,
                                                returnData=True,
                                                gpuIndex=gpu_index)

# Create 3D data object
rec_id = astra.data3d.create('-vol', vol_geom, vol_init)

# SIRT3D
alg_type = 'SIRT3D_CUDA'
cfg_sirt = astra.astra_dict(alg_type)
cfg_sirt['ReconstructionDataId'] = rec_id
cfg_sirt['ProjectionDataId'] = sinogram_id
cfg_sirt['option'] = {}
cfg_sirt['option']['GPUindex'] = gpu_index

# Create algorithm object
Пример #25
0
def conebeam_helical_sim(phantom=None,
                         alg_type='sirt3d',
                         num_iterations=10,
                         padding=(0, 0),
                         scale_factor=1,
                         vol_init=None,
                         gpu_index=0,
                         num_voxels=None,
                         num_pixel=None,
                         num_angles=25):
    """Test helical conebeam reconstruction of ASTRA.

    Parameters
    ----------

    num_voxels : int, list of int
    num_voxels[0:1] are the number of transverse voxels, num_voxels[2] is the number of  voxels along the longitudinal
    direction that coincides with the helical (z) axis and along which the sample is translated.

    conebeam_helical_sim()
    """

    # Default arguments
    if not num_voxels:
        num_voxels = [100, 100, 100]
    if not num_pixel:
        num_pixel = [100, 100]

    if padding[0]:
        pass

    if scale_factor:
        pass

    detector_spacing_x = 1
    detector_spacing_y = 1
    det_row_count = num_pixel[0]
    det_col_count = num_pixel[1]
    angles_rad = np.linspace(0, 2 * np.pi, num_angles, endpoint=False)
    source_origin = 50
    origin_det = 40
    z_max = np.round(num_voxels[2] / 3)
    z_min = -np.round(num_voxels[2] / 3)
    z_range = np.linspace(z_min, z_max, num_angles, endpoint=False)

    # Create phantom object
    if phantom is None:
        phantom = 1000 / 2 * (util.phantom_ball(num_voxels,
                                                (0.45, 0.5, 0.5), 0.1) +
                              util.phantom_ball(num_voxels,
                                                (0.55, 0.5, 0.5), 0.05))

    # Create volume geometry
    vol_geom = astra.create_vol_geom(*num_voxels)

    # Create helical projection geometry
    cone_vec = np.zeros((num_angles, 12))
    # Source
    cone_vec[:, 0] = np.sin(angles_rad) * source_origin
    cone_vec[:, 1] = -np.cos(angles_rad) * source_origin
    cone_vec[:, 2] = z_range
    # Centre of detector
    cone_vec[:, 3] = -np.sin(angles_rad) * origin_det
    cone_vec[:, 4] = np.cos(angles_rad) * origin_det
    cone_vec[:, 5] = z_range
    # Vector from detector pixel (0,0) to (0,1)
    cone_vec[:, 6] = np.cos(angles_rad) * detector_spacing_x
    cone_vec[:, 7] = np.sin(angles_rad) * detector_spacing_x
    cone_vec[:, 8] = 0
    # Vector from detector pixel (0,0) to (0,1)
    cone_vec[:, 9] = 0
    cone_vec[:, 10] = 0
    cone_vec[:, 11] = detector_spacing_y

    proj_geom = astra.create_proj_geom('cone_vec', det_row_count,
                                       det_col_count, cone_vec)

    t = time.time()
    # Create a sinogram from phantom
    sinogram_id, sinogram = astra.create_sino3d_gpu(phantom,
                                                    proj_geom,
                                                    vol_geom,
                                                    returnData=True,
                                                    gpuIndex=gpu_index)

    # Set up the parameters for a reconstruction algorithm
    rec_id = astra.data3d.create('-vol', vol_geom, vol_init)
    alg_type += '_CUDA'
    alg_type = alg_type.upper()
    cfg = astra.astra_dict(alg_type)
    cfg['ReconstructionDataId'] = rec_id
    cfg['ProjectionDataId'] = sinogram_id
    cfg['option'] = {}
    cfg['option']['GPUindex'] = gpu_index

    # Iterate algorithm
    alg_id = astra.algorithm.create(cfg)
    astra.algorithm.run(alg_id, num_iterations)
    rec_vol = astra.data3d.get(rec_id)

    print("GPU index: %u" % gpu_index)
    # print("Number of projections: %u" % proj_geom['ProjectionAngles'].shape)
    print("Algorithm: %s" % cfg['type'])
    print("Elapsed time: %g s" % (time.time() - t))

    astra.algorithm.clear()
    astra.data3d.clear()
    astra.projector.clear()

    return rec_vol, sinogram, phantom, angles_rad, proj_geom
det_row_count = geometry.det_partition.shape[1]
det_col_count = geometry.det_partition.shape[0]
vec = odl.tomo.backends.astra_setup.astra_conebeam_3d_geom_to_vec(geometry)
astra_proj_geom = astra.create_proj_geom('cone_vec', det_row_count,
                                         det_col_count, vec)

# Create ASTRA projector
proj_cfg = {}
proj_cfg['type'] = 'cuda3d'
proj_cfg['VolumeGeometry'] = astra_vol_geom
proj_cfg['ProjectionGeometry'] = astra_proj_geom
proj_cfg['options'] = {}
proj_id = astra.projector3d.create(proj_cfg)

# Create sinogram
sinogram_id, sinogram = astra.create_sino3d_gpu(data, astra_proj_geom,
                                                astra_vol_geom)

# Create a data object for the reconstruction
rec_id = astra.data3d.create('-vol', astra_vol_geom)

# Set up the parameters for a reconstruction algorithm using the CUDA backend
cfg = astra.astra_dict('CGLS3D_CUDA')
cfg['ReconstructionDataId'] = rec_id
cfg['ProjectionDataId'] = sinogram_id
cfg['ProjectorId'] = proj_id

# Create the algorithm object from the configuration structure
alg_id = astra.algorithm.create(cfg)

with odl.util.Timer('ASTRA run'):
    # Run the algorithm
Пример #27
0
                                       det_col_count, angles, source_origin,
                                       origin_det)
algon_high = raw_input("Algo high: ")
for n_x in x_parts:
    for n_y in y_parts:
        for n_z in z_parts:  ## nr_subvol_z
            rec_low_temp[:, :, :] = rec_low[:, :, :]
            rec_low_temp[x_sub_boundaries[n_x, 1] /
                         vol_size_ratio:x_sub_boundaries[n_x + 1, 2] /
                         vol_size_ratio, y_sub_boundaries[n_y, 1] /
                         vol_size_ratio:y_sub_boundaries[n_y + 1, 2] /
                         vol_size_ratio, z_sub_boundaries[n_z, 1] /
                         vol_size_ratio:z_sub_boundaries[n_z + 1, 2] /
                         vol_size_ratio] = 0

            proj_id_low, proj_data_low = astra.create_sino3d_gpu(
                rec_low_temp, proj_geom_low, vol_geom_low)
            astra.data3d.delete(proj_id_low)
            x_start = x_sub_boundaries[n_x, 1]
            x_stop = x_sub_boundaries[n_x + 1, 2]
            h_start = FOV / 2 - x_start
            h_stop = FOV / 2 - x_stop  #height
            if x_start == 0:
                sin_angle_start = float(FOV / 2 - x_start + FOV / 2 *
                                        (det / 2) /
                                        (origin_det + source_origin)) / (
                                            source_origin - FOV / 2
                                        )  #not needed
                pro_start = 0
            else:
                if h_start < 0:
                    sin_angle_start = float(FOV / 2 - x_start) / (