Esempio n. 1
0
    def _mesh_crystal_thin_ring(self, block_shape: List(int, 3),
                                average_radius: int,
                                block_size: List(float, 3),
                                nb_blocks_per_ring: int,
                                gap: float,
                                d: int):
        if gap > 0.0:
            raise ValueError('Please use _mesh_crystal_ring instead')
        nb_crystals_per_thin_ring = block_shape[1] * nb_blocks_per_ring
        block_unit_size = [s1 / s2 for s1, s2 in zip(block_size, block_shape)]

        lors = np.zeros((nb_crystals_per_thin_ring * nb_crystals_per_thin_ring, 6),
                        dtype = np.float32)

        x = np.ones(block_shape[1], ) * average_radius
        y = (np.arange(block_shape[1]) + 0.5) * block_unit_size[1] - \
            block_size[1] / 2
        z = 0.5 * block_unit_size[2] - block_unit_size[2] * (d + 1) / 2
        xx = np.kron(x, [1] * nb_blocks_per_ring)
        yy = np.kron(y, [1] * nb_blocks_per_ring)
        theta = 2 * np.pi / nb_blocks_per_ring * np.arange(nb_blocks_per_ring)
        theta1 = np.kron(theta, [[1]] * block_shape[1]).ravel()
        xd = xx * np.cos(theta1) - yy * np.sin(theta1)
        yd = xx * np.sin(theta1) + yy * np.cos(theta1)
        zd = np.kron(z, [1] * block_shape[1] * nb_blocks_per_ring)

        lors[:, 0] = np.kron(xd, [1] * nb_crystals_per_thin_ring)
        lors[:, 1] = np.kron(yd, [1] * nb_crystals_per_thin_ring)
        lors[:, 2] = np.kron(zd, [1] * nb_crystals_per_thin_ring)
        lors[:, 3] = np.kron(xd, [[1]] * nb_crystals_per_thin_ring).ravel()
        lors[:, 4] = np.kron(yd, [[1]] * nb_crystals_per_thin_ring).ravel()
        lors[:, 5] = np.kron(zd, [[1]] * nb_crystals_per_thin_ring).ravel() + d * \
                     block_unit_size[2]

        return lors
Esempio n. 2
0
    def __call__(self, listmodes: List(Listmode), dvfs: List(Dvf)) -> Image:
        declare_eager_execution()
        x = self.emap.update(data=np.ones(self.emap.shape, dtype=np.float32))
        x_tf = x.update(data=tf.Variable(x.data))

        emap_tf = self.emap.update(data=tf.constant(self.emap.data))
        for _ in tqdm(range(self.n_iter)):
            for listmode, dvf in zip(listmodes, dvfs):
                dvf_x_tf = tf.constant(dvf.dvf_x.data)
                dvf_y_tf = tf.constant(dvf.dvf_y.data)
                dvf_z_tf = tf.constant(dvf.dvf_z.data)
                lors_tf = listmode.lors.update(
                    data=tf.constant(listmode.lors.data))
                listmode_tf = listmode.update(data=tf.constant(listmode.data),
                                              lors=lors_tf)
                _x_tf = x_tf.update(data=self._deform_invert_tf(
                    x_tf.data, dvf_x_tf, dvf_y_tf, dvf_z_tf))
                _listmode_tf = Project('tf')(_x_tf, lors_tf)
                _listmode_tf = _listmode_tf + 1e-8
                _bp = BackProject('tf')(listmode_tf / _listmode_tf, emap_tf)
                emap_tf2 = emap_tf.update(data=self._deform_tf(
                    emap_tf.data, dvf_x_tf, dvf_y_tf, dvf_z_tf)) + 1e-8
                _bp2 = _bp.update(data=self._deform_tf(_bp.data, dvf_x_tf,
                                                       dvf_y_tf, dvf_z_tf))
                x_tf = x_tf * _bp2 / emap_tf2

        return x_tf.update(data=x_tf.data.numpy())
Esempio n. 3
0
    def _mesh_crystal_full(self, nb_rings: int,
                           block_shape: List(int, 3),
                           average_radius: int,
                           block_size: List(float, 3),
                           nb_blocks_per_ring: int):
        if nb_rings > 1:
            raise ValueError('Please use _mesh_crystal_ring instead')
        block_unit_size = [s1 / s2 for s1, s2 in zip(block_size, block_shape)]
        nb_crystals_per_ring = nb_blocks_per_ring * block_shape[1] * block_shape[2]
        nb_crystals = nb_crystals_per_ring * nb_rings
        lors = np.zeros((nb_crystals * nb_crystals, 6), dtype = np.float32)

        x = np.ones(block_shape[1], ) * average_radius
        y = (np.arange(block_shape[1]) + 0.5) * block_unit_size[1] - \
            block_size[1] / 2
        z = (np.arange(block_shape[2]) + 0.5) * block_unit_size[2] - \
            block_size[2] / 2
        xx = np.kron(x, [1] * nb_blocks_per_ring)
        yy = np.kron(y, [1] * nb_blocks_per_ring)
        theta = 2 * np.pi / nb_blocks_per_ring * np.arange(nb_blocks_per_ring)
        theta1 = np.kron(theta, [[1]] * block_shape[1]).ravel()
        xx1 = xx * np.cos(theta1) - yy * np.sin(theta1)
        yy1 = xx * np.sin(theta1) + yy * np.cos(theta1)
        xd = np.kron(xx1, [[1]] * block_shape[2]).ravel()
        yd = np.kron(yy1, [[1]] * block_shape[2]).ravel()
        zd = np.kron(z, [1] * block_shape[1] * nb_blocks_per_ring)

        lors[:, 0] = np.kron(xd, [1] * nb_crystals_per_ring)
        lors[:, 1] = np.kron(yd, [1] * nb_crystals_per_ring)
        lors[:, 2] = np.kron(zd, [1] * nb_crystals_per_ring)
        lors[:, 3] = np.kron(xd, [[1]] * nb_crystals_per_ring).ravel()
        lors[:, 4] = np.kron(yd, [[1]] * nb_crystals_per_ring).ravel()
        lors[:, 5] = np.kron(zd, [[1]] * nb_crystals_per_ring).ravel()

        return lors
Esempio n. 4
0
    def __call__(self, images: List(Image), fov_centers: List(float)) -> Image:
        '''sort images according to their fov centers'''
        if len(images) == 1:
            return images[0]
        border_left = np.min(
            [image.center[2] - image.size[2] / 2 for image in images])
        border_right = np.max(
            [image.center[2] + image.size[2] / 2 for image in images])
        unit_size_z = images[0].unit_size[2]
        length = border_right - border_left
        shape_z = int(np.round(length / unit_size_z))
        size_z = shape_z * unit_size_z
        center_z = (border_left + border_right) / 2

        shape = images[0].shape[:2] + [shape_z]
        center = images[0].center[:2] + [center_z]
        size = images[0].size[:2] + [size_z]

        trans = (np.array(fov_centers[1:]) + np.array(fov_centers[:-1])) / 2
        trans_ind = np.round(
            (trans - center[2] + size[2] / 2) / 2.05).astype(int).tolist()
        trans_ind = [0] + trans_ind + [-1]
        print(trans_ind)
        img_out = Image(np.zeros(shape, np.float32), center, size)
        img_out_data = img_out.data
        for ind, img in enumerate(images):
            img_data = copy(img.data)
            img_data[:, :, :trans_ind[ind]] = 0
            img_data[:, :, trans_ind[ind + 1]:] = 0
            img_out_data += img_data
        return img_out.update(data=img_out_data)
Esempio n. 5
0
class ImageConfig(UnitSizePropertyMixin):
    """
    Image data with center and size info.
    """

    shape: List(int, 3)
    center: List(float, 3)
    size: List(float, 3)
Esempio n. 6
0
class Block(UnitSizePropertyMixin):
    size: List(float, 3)
    shape: List(int, 3)
    interval: List(float, 3)

    def __attrs_post_init__(self):
        if self.interval is None:
            object.__setattr__(self, 'interval', [0, 0, 0])
Esempio n. 7
0
class PointSource(ShapePropertyMixin, UnitSizePropertyMixin, GetItemMixin,
                  CentralSlicesPropertyMixin, CentralProfilesPropertyMixin,
                  LoadMixin, SaveMixin, ImshowMixin, ArithmeticMixin):
    data: Any
    center: List(float, 3)
    size: List(float, 3)
    pos: List(int)
    psf_type: str = attr.ib(default='xy')
Esempio n. 8
0
class Image(ShapePropertyMixin, UnitSizePropertyMixin, GetItemMixin,
            CentralSlicesPropertyMixin, CentralProfilesPropertyMixin,
            AverageProfilesPropertyMixin, LoadMixin, SaveMixin, ImshowMixin,
            ArithmeticMixin):
    """
    Image data with center and size info.
    """

    data: Any
    center: List(float, 3)
    size: List(float, 3)
Esempio n. 9
0
    def _mesh_crystal_ring_full(self, block_shape: List(int, 3),
                                average_radius: int,
                                block_size: List(float, 3),
                                nb_blocks_per_ring: int,
                                axial_length: float):
        nb_crystals_per_block = block_shape[1] * block_shape[2]
        nb_crystals_per_ring = nb_blocks_per_ring * nb_crystals_per_block
        nb_crystals_per_ring2 = (nb_blocks_per_ring - 1) * nb_crystals_per_block
        lors = np.zeros((nb_crystals_per_ring * nb_crystals_per_ring2 // 2, 6),
                        dtype = np.float32)

        block_unit_size = [s1 / s2 for s1, s2 in zip(block_size, block_shape)]

        x = np.ones(block_shape[1], ) * average_radius
        y = (np.arange(block_shape[1]) + 0.5) * block_unit_size[1] - \
            block_size[1] / 2
        z = (np.arange(block_shape[2]) + 0.5) * block_unit_size[2]

        xx = np.kron(x, [[1]] * block_shape[2]).ravel()
        yy = np.kron(y, [[1]] * block_shape[2]).ravel()
        zz = np.kron(z, [1] * block_shape[1])

        theta_list = 2 * np.pi / nb_blocks_per_ring * np.arange(nb_blocks_per_ring)

        c = 0
        N = nb_crystals_per_block ** 2
        for theta1 in theta_list:
            xx1 = xx * np.cos(theta1) - yy * np.sin(theta1)
            yy1 = xx * np.sin(theta1) + yy * np.cos(theta1)
            zz1 = zz
            for theta2 in theta_list:
                if theta2 <= theta1:
                    continue
                xx2 = xx * np.cos(theta2) - yy * np.sin(theta2)
                yy2 = xx * np.sin(theta2) + yy * np.cos(theta2)
                zz2 = zz

                lors[c: c + N, 0] = np.kron(xx1, [1] * nb_crystals_per_block)
                lors[c: c + N, 1] = np.kron(yy1, [1] * nb_crystals_per_block)
                lors[c: c + N, 2] = np.kron(zz1, [1] * nb_crystals_per_block) - axial_length / 2
                lors[c: c + N, 3] = np.kron(xx2, [[1]] * nb_crystals_per_block).ravel()
                lors[c: c + N, 4] = np.kron(yy2, [[1]] * nb_crystals_per_block).ravel()
                lors[c: c + N, 5] = np.kron(zz2, [
                    [1]] * nb_crystals_per_block).ravel() - axial_length / 2
                c += N

        return lors
Esempio n. 10
0
 def __call__(self, scanner: PetEcatScanner, config: ImageConfig,
              fov_centers: List(float)) -> Emap:
     emap = Emap(np.zeros(config.shape, np.float32), config.center,
                 config.size)
     for i in range(len(fov_centers)):
         scanner = scanner.update(center=[0, 0, fov_centers[i]])
         emap += EmapGenerator('block-full', scanner)(emap)
     return emap
Esempio n. 11
0
 def test_isinstance(self):
     list_int_3 = List(int, 3)
     for any_type in basic_type_list:
         if issubclass(any_type, list):
             for sample in basic_type_samples[any_type]:
                 if len(sample) == 3 and all(
                         map(lambda x: isinstance(x, int), sample)):
                     assert list_int_3.isinstance(sample)
                 else:
                     assert not list_int_3.isinstance(sample)
         else:
             for sample in basic_type_samples[any_type]:
                 assert not list_int_3.isinstance(sample)
Esempio n. 12
0
 def test_generic_type_isinstance_(self):
     list_int_3 = List(int, 3)
     tuple_sample = Tuple((int, float, str))
     for type_ in basic_type_list:
         for sample in basic_type_samples[type_]:
             if list_int_3.isinstance(sample):
                 assert isinstance_(sample, list_int_3)
             else:
                 assert not isinstance_(sample, list_int_3)
             if tuple_sample.isinstance(sample):
                 assert isinstance_(sample, tuple_sample)
             else:
                 assert not isinstance_(sample, tuple_sample)
Esempio n. 13
0
    def _mesh_crystal_ring(self, block_shape: List(int, 3),
                           average_radius: int,
                           block_size: List(float, 3),
                           nb_blocks_per_ring: int,
                           gap: float,
                           d: int):
        block_unit_size = [s1 / s2 for s1, s2 in zip(block_size, block_shape)]
        nb_crystals_per_ring = nb_blocks_per_ring * block_shape[1] * block_shape[2]

        lors = np.zeros((nb_crystals_per_ring * nb_crystals_per_ring, 6),
                        dtype = np.float32)

        x = np.ones(block_shape[1], ) * average_radius
        y = (np.arange(block_shape[1]) + 0.5) * block_unit_size[1] - \
            block_size[1] / 2
        z = (np.arange(block_shape[2]) + 0.5) * block_unit_size[2] - \
            block_size[2] * (d + 1) / 2
        xx = np.kron(x, [1] * nb_blocks_per_ring)
        yy = np.kron(y, [1] * nb_blocks_per_ring)
        theta = 2 * np.pi / nb_blocks_per_ring * np.arange(nb_blocks_per_ring)
        theta1 = np.kron(theta, [[1]] * block_shape[1]).ravel()
        xx1 = xx * np.cos(theta1) - yy * np.sin(theta1)
        yy1 = xx * np.sin(theta1) + yy * np.cos(theta1)
        xd = np.kron(xx1, [[1]] * block_shape[2]).ravel()
        yd = np.kron(yy1, [[1]] * block_shape[2]).ravel()
        zd = np.kron(z, [1] * block_shape[1] * nb_blocks_per_ring)

        lors[:, 0] = np.kron(xd, [1] * nb_crystals_per_ring)
        lors[:, 1] = np.kron(yd, [1] * nb_crystals_per_ring)
        lors[:, 2] = np.kron(zd, [1] * nb_crystals_per_ring)
        lors[:, 3] = np.kron(xd, [[1]] * nb_crystals_per_ring).ravel()
        lors[:, 4] = np.kron(yd, [[1]] * nb_crystals_per_ring).ravel()
        lors[:, 5] = np.kron(zd + d * (block_size[2] + gap),
                             [[1]] * nb_crystals_per_ring).ravel()

        return lors
Esempio n. 14
0
class PetCylindricalScanner(PetScanner, PropertyClass):
    inner_radius: float
    outer_radius: float
    nb_rsector: int

    nb_module: List(int, 2)  # module grid in each rsector, [trans, z]
    mv_module: List(float, 2)  # movement per module

    nb_submodule: List(int, 2)  # submodule grid in each module, [trans, z]
    mv_submodule: List(float, 2)  # movement per submodule

    nb_crystal: List(int, 2)  # crystal grid in each submodule, [trans, z]
    mv_crystal: List(float, 2)  # movement per crystal

    sz_crystal: List(float, 2)  # crystaml voxel-size

    tof: TofConfig
Esempio n. 15
0
    def test_create(self):
        list_int_3 = List(int, 3)
        assert isinstance(list_int_3, type)
        assert issubclass(list_int_3, list)

        for any_type in basic_type_list:
            if issubclass(any_type, list):
                for sample in basic_type_samples[any_type]:
                    if len(sample) == 3 and all(
                            map(lambda x: isinstance(x, int), sample)):
                        pass
                    else:
                        with pytest.raises(TypeError):
                            list_int_3(sample)
            else:
                for sample in basic_type_samples[any_type]:
                    with pytest.raises(TypeError):
                        list_int_3(sample)

        assert list_int_3.length == 3
        assert list_int_3.dtype == int
Esempio n. 16
0
 def __call__(self, listmodes: List(Listmode)) -> Listmode:
     lors = Lors(np.vstack([lm.lors.data for lm in listmodes]))
     listmode = Listmode(np.hstack([lm.data for lm in listmodes]), lors)
     return listmode