Beispiel #1
0
def create_example_parallel3d(example_type=''):
    """
    :brief:                 create an example of a parallel3d geometry
    :param example_type:    for the examples, there are different options
                            -   '' or 'normal':
                                example of a standard parallel geometry with 100 angles
                            -   'vec':
                                same geometry as for normal, but converted to a vector geometry
                                this gives a different plot visualizing the individual angles on
                                top of the geometry
    :return:                the example geometry
    """
    det_spacing = [0.035, 0.035]
    detector_px = [1000, 1000]
    angles = np.linspace(0, 2 * np.pi, 100)

    if example_type == '' or example_type == 'normal':
        proj_geom = astra.create_proj_geom('parallel3d', det_spacing[0],
                                           det_spacing[1], detector_px[0],
                                           detector_px[1], angles)
    elif example_type == 'vec':
        proj_geom = astra.geom_2vec(create_example_parallel3d())
    else:
        raise ValueError(
            "ASTRA: example type {0} not recognized for parallel3d geometry".
            format(example_type))

    return proj_geom
Beispiel #2
0
def create_example_fanflat(example_type=''):
    """
    :brief:                 create an example geometry of type fanflat
    :param example_type:    -   '' or 'normal':
                                example of a standard fanflat geometry with 100 angles
                            -   'vec':
                                same geometry as for normal, but converted to a vector geometry
                                this gives a different plot visualizing the individual angles on
                                top of the geometry
    :return:                the example geometry
    """
    def make_normal_geometry():
        det_spacing = 0.035
        detector_px = 1200
        angles = np.linspace(0, 2 * np.pi, 100)
        source_origin = 30
        origin_det = 200
        phantom_size = 5
        phantom_px = 150  # voxels for the phantom
        vx_size = phantom_size / phantom_px  # voxel size

        # now express all measurements in terms of the voxel size
        det_spacing = det_spacing / vx_size
        origin_det = origin_det / vx_size
        source_origin = source_origin / vx_size

        geom = astra.create_proj_geom('fanflat', det_spacing, detector_px,
                                      angles, source_origin, origin_det)
        return geom

    if example_type == '' or example_type == 'normal':
        proj_geom = make_normal_geometry()
    elif example_type == 'vec':
        proj_geom = astra.geom_2vec(make_normal_geometry())
    else:
        raise ValueError(
            "ASTRA: example type {0} not recognized for parallel3d geometry".
            format(example_type))

    return proj_geom
 def to_vector(self):
     return ConeVectorGeometry.from_astra(astra.geom_2vec(self.to_astra()))
Beispiel #4
0
def generate_parallel_pg(det_spacing, det_shape, num_angles):
    angles = np.linspace(0, 2 * np.pi, num_angles, False)
    pg = astra.create_proj_geom("parallel3d", *det_spacing, *det_shape, angles)
    return astra.geom_2vec(pg)
Beispiel #5
0
def generate_cone_pg(det_spacing, det_shape, num_angles, SOD, SDD):
    angles = np.linspace(0, 2 * np.pi, num_angles, False)
    pg = astra.create_proj_geom("cone", *det_spacing, *det_shape, angles, SOD,
                                SDD - SOD)
    return astra.geom_2vec(pg)
Beispiel #6
0
def _modify_astra_vector_(proj_geom, geometry):
    """
    Modify ASTRA vector using known offsets from the geometry records.
    """
    # Even if the geometry is of the type 'simple' (GEOM_SYMPLE), we need to generate ASTRA vector to be able to rotate the reconstruction volume if needed.
    proj_geom = astra.geom_2vec(proj_geom)
    vectors = proj_geom['Vectors']
    
    theta_count = vectors.shape[0]
    det_pixel = geometry['det_pixel'] * numpy.array(geometry.get('proj_sample'))
    
    # Modify vector and apply it to astra projection geometry:
    for ii in range(0, theta_count):
        
        # Compute current offsets (for this angle):
        if geometry.get('type') == GEOM_SIMPLE:
            
            det_vrt = 0 
            det_hrz = 0
            det_mag = 0
            det_rot = 0
            src_vrt = 0
            src_hrz = 0
            src_mag = 0
            axs_hrz = 0
            axs_mag = 0
        
        # Compute current offsets:
        elif geometry.get('type') == GEOM_STAOFF:
            
            det_vrt = geometry['det_vrt'] 
            det_hrz = geometry['det_hrz'] 
            det_mag = geometry['det_mag'] 
            det_rot = geometry['det_rot'] 
            src_vrt = geometry['src_vrt'] 
            src_hrz = geometry['src_hrz'] 
            src_mag = geometry['src_mag'] 
            axs_hrz = geometry['axs_hrz'] 
            axs_mag = geometry['axs_mag'] 
          
        # Use linear offsets:    
        elif geometry.get('type') == GEOM_LINOFF:
            b = (ii / (theta_count - 1))
            a = 1 - b
            det_vrt = geometry['det_vrt'][0] * a + geometry['det_vrt'][1] * b
            det_hrz = geometry['det_hrz'][0] * a + geometry['det_hrz'][1] * b  
            det_mag = geometry['det_mag'][0] * a + geometry['det_mag'][1] * b  
            det_rot = geometry['det_rot'][0] * a + geometry['det_rot'][1] * b  
            src_vrt = geometry['src_vrt'][0] * a + geometry['src_vrt'][1] * b 
            src_hrz = geometry['src_hrz'][0] * a + geometry['src_hrz'][1] * b 
            src_mag = geometry['src_mag'][0] * a + geometry['src_mag'][1] * b 
            axs_hrz = geometry['axs_hrz'][0] * a + geometry['axs_hrz'][1] * b 
            axs_mag = geometry['axs_mag'][0] * a + geometry['axs_mag'][1] * b 
            
        else: raise ValueError('Wrong geometry type: ' + geometry.get('type'))

        # Define vectors:
        src_vect = vectors[ii, 0:3]    
        det_vect = vectors[ii, 3:6]    
        det_axis_hrz = vectors[ii, 6:9]          
        det_axis_vrt = vectors[ii, 9:12]

        #Precalculate vector perpendicular to the detector plane:
        det_normal = numpy.cross(det_axis_hrz, det_axis_vrt)
        det_normal = det_normal / numpy.sqrt(numpy.dot(det_normal, det_normal))
        
        # Translations relative to the detecotor plane:
    
        #Detector shift (V):
        det_vect += det_vrt * det_axis_vrt / det_pixel[0]

        #Detector shift (H):
        det_vect += det_hrz * det_axis_hrz / det_pixel[1]

        #Detector shift (M):
        det_vect += det_mag * det_normal /  det_pixel[1]

        #Source shift (V):
        src_vect += src_vrt * det_axis_vrt / det_pixel[0]

        #Source shift (H):
        src_vect += src_hrz * det_axis_hrz / det_pixel[1]

        #Source shift (M):
        src_vect += src_mag * det_normal / det_pixel[1] 

        # Rotation axis shift:
        det_vect -= axs_hrz * det_axis_hrz  / det_pixel[1]
        src_vect -= axs_hrz * det_axis_hrz  / det_pixel[1]
        det_vect -= axs_mag * det_normal /  det_pixel[1]
        src_vect -= axs_mag * det_normal /  det_pixel[1]

        # Rotation relative to the detector plane:
        # Compute rotation matrix
    
        T = transforms3d.axangles.axangle2mat(det_normal, det_rot)
        
        det_axis_hrz[:] = numpy.dot(T.T, det_axis_hrz)
        det_axis_vrt[:] = numpy.dot(T, det_axis_vrt)
    
        # Global transformation:
        # Rotation matrix based on Euler angles:
        R = transforms3d.euler.euler2mat(geometry['vol_rot'][0], geometry['vol_rot'][1], geometry['vol_rot'][2], 'rzyx')

        # Apply transformation:
        det_axis_hrz[:] = numpy.dot(det_axis_hrz, R)
        det_axis_vrt[:] = numpy.dot(det_axis_vrt, R)
        src_vect[:] = numpy.dot(src_vect,R)
        det_vect[:] = numpy.dot(det_vect,R)            
                
        # Add translation:
        vect_norm = numpy.sqrt((det_axis_vrt ** 2).sum())

        # Take into account that the center of rotation should be in the center of reconstruction volume:        
        T = numpy.array([geometry['vol_tra'][1] * vect_norm / det_pixel[1], geometry['vol_tra'][2] * vect_norm / det_pixel[1], geometry['vol_tra'][0] * vect_norm / det_pixel[0]])    
        
        src_vect[:] -= numpy.dot(T, R)           
        det_vect[:] -= numpy.dot(T, R)
        
    proj_geom['Vectors'] = vectors
    
    return proj_geom
Beispiel #7
0
def get_geometry(dset_path,
                 projs_shape,
                 beam_geometry="cone",
                 vol_shift_mm=0.0,
                 vol_size_add=None,
                 detector_tilt_deg=None):
    config = get_scanner_conf(dset_path)

    sdd = float(config["CT-parameters IN"]["SDD"][1:-1])
    sod = float(config["CT-parameters IN"]["SOD"][1:-1])
    first_angle = float(config["CT-parameters IN"]["Start angle"][1:-1])
    last_angle = float(config["CT-parameters IN"]["Last angle"][1:-1])
    voxsize = float(config["CT-parameters IN"]["Voxel size"][1:-1])
    pixsize = float(config["CT-parameters IN"]["Pixel size"][1:-1])

    angles = np.linspace(first_angle, last_angle, projs_shape[1])
    angles = angles / 180 * np.pi

    if beam_geometry.lower() == "cone":
        sdd = sdd / voxsize
        sod = sod / voxsize
        odd = sdd - sod
        rel_pixsize = pixsize / voxsize
        vol_shift = -vol_shift_mm / pixsize

        proj_geom = astra.create_proj_geom("cone", rel_pixsize, rel_pixsize,
                                           projs_shape[0], projs_shape[2],
                                           angles, sod, odd)
        proj_geom = astra.geom_2vec(proj_geom)
        V = proj_geom["Vectors"]
        V[:, 3:6] = V[:, 3:6] + vol_shift * V[:, 6:9]
        V[:, 0:3] = V[:, 0:3] + vol_shift * V[:, 6:9]
    elif beam_geometry.lower() == "parallel":
        vol_shift = -vol_shift_mm / voxsize

        proj_geom = astra.create_proj_geom("parallel3d", 1, 1, projs_shape[0],
                                           projs_shape[2], angles)
        proj_geom = astra.geom_postalignment(proj_geom, [vol_shift, 0])

    if detector_tilt_deg is not None:
        if proj_geom["type"] in ("cone", "parallel"):
            proj_geom = astra.geom_2vec(proj_geom)
        V = proj_geom["Vectors"]
        dir_proj = V[:, 3:6] - V[:, 0:3]
        dir_proj = dir_proj / np.sqrt(np.sum(dir_proj**2, axis=1))[...,
                                                                   np.newaxis]
        for ii in range(V.shape[0]):
            t = geometry.GeometryTransformation.get_rototranslation(
                dir_proj[ii, :], detector_tilt_deg)
            V[ii,
              6:9] = np.transpose(t.apply_direction(np.transpose(V[ii, 6:9])))
            V[ii,
              9:12] = np.transpose(t.apply_direction(np.transpose(V[ii,
                                                                    9:12])))

    vol_size = np.array((projs_shape[2], projs_shape[2], projs_shape[0]),
                        dtype=np.int)
    if vol_size_add is not None:
        vol_size = (vol_size + vol_size_add).astype(np.int)
    vol_geom = astra.create_vol_geom(vol_size)

    return (proj_geom, vol_geom, vol_shift)