示例#1
0
def test_label_with_dilation():
    service = VolumeService()

    ct_mask_data = numpy.array([[[0, 0, 0], [0, 1, 0], [0, 1, 0]],
                                [[1, 1, 1], [0, 0, 0], [0, 0, 0]],
                                [[0, 0, 1], [0, 0, 0], [0, 0, 1]]])
    ct_mask_volume = Volume(
        ct_mask_data, [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
        None)
    ct_mask_path = get_temporary_files_path("ct_mask.nii.gz")
    IOUtils.write_volume(ct_mask_path, ct_mask_volume)

    ct_dil_mask_data = numpy.array([[[0, 0, 0], [1, 1, 1], [0, 1, 0]],
                                    [[1, 1, 1], [0, 0, 0], [0, 0, 0]],
                                    [[0, 1, 1], [0, 0, 0], [0, 1, 1]]])
    ct_dil_mask_volume = Volume(
        ct_dil_mask_data,
        [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], None)
    ct_dil_mask_path = get_temporary_files_path("ct_dil_mask.nii.gz")
    IOUtils.write_volume(ct_dil_mask_path, ct_dil_mask_volume)

    ct_result = get_temporary_files_path("ct_res.nii.gz")

    service.label_with_dilation(ct_mask_path, ct_dil_mask_path, ct_result)

    assert os.path.exists(ct_mask_path)
    assert os.path.exists(ct_dil_mask_path)
    assert os.path.exists(ct_result)

    vol = IOUtils.read_volume(ct_result)
    assert numpy.array_equal(numpy.unique(vol.data), [0, 1, 2, 3])
示例#2
0
def test_remove_zero_connectivity():
    service = VolumeService()

    data = numpy.array([[[0, 0, 1], [2, 3, 0]], [[4, 0, 0], [0, 0, 0]]])
    volume = Volume(data,
                    [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
                    None)
    volume_path = get_temporary_files_path("tdi_lbl.nii.gz")

    IOUtils.write_volume(volume_path, volume)

    in_connectivity = numpy.array([[10, 1, 0, 3], [0, 10, 0, 2], [0, 0, 0, 0],
                                   [0, 0, 0, 10]])
    connectivity_path = get_temporary_files_path("conn.csv")
    numpy.savetxt(connectivity_path, in_connectivity, fmt='%1d')

    tract_lengths_path = get_temporary_files_path("tract_lengths.csv")
    numpy.savetxt(tract_lengths_path, in_connectivity, fmt='%1d')

    service.remove_zero_connectivity_nodes(volume_path, connectivity_path,
                                           tract_lengths_path)

    assert os.path.exists(os.path.splitext(connectivity_path)[0] + ".npy")
    assert os.path.exists(os.path.splitext(tract_lengths_path)[0] + ".npy")

    vol = IOUtils.read_volume(volume_path)
    assert len(numpy.unique(vol.data)) == 4

    conn = numpy.array(numpy.genfromtxt(connectivity_path, dtype='int64'))
    assert numpy.array_equal(conn, [[20, 1, 3], [1, 20, 2], [3, 2, 20]])
示例#3
0
    def _aparc_aseg_projection(
            self, aparc_aseg_volume: os.PathLike,
            aparc_aseg_volume_path: os.PathLike, projection: np.ndarray,
            ras: Union[np.ndarray, list], fs_to_conn_indices_mapping: dict,
            background_volume: Volume, background_volume_path: os.PathLike,
            snapshot_name: str, conn_measure: Union[np.ndarray, list]):

        try:
            slice = aparc_aseg_volume.slice_volume(projection, ras)
        except IndexError:
            new_ras = aparc_aseg_volume.get_center_point()
            slice = aparc_aseg_volume.slice_volume(projection, new_ras)
            msg = "The volume center point has been used for %s snapshot of %s."
            self.logger.info(msg, projection, aparc_aseg_volume_path)

        x_axis_coords, y_axis_coords, aparc_aseg_matrix = slice

        for i, row in enumerate(aparc_aseg_matrix):
            for j, el in enumerate(row):
                if el > 0:
                    if el in fs_to_conn_indices_mapping:
                        idx = fs_to_conn_indices_mapping.get(el)
                        new_val = conn_measure[int(idx)]
                        aparc_aseg_matrix[i, j] = new_val
                    else:
                        aparc_aseg_matrix[i, j] = -1

        if background_volume_path == '':
            self.writer.write_matrix(
                x_axis_coords, y_axis_coords, aparc_aseg_matrix,
                self.generate_file_name(projection, snapshot_name), 'hot')
        else:
            try:
                bx_axis_coords, by_axis_coords, bvolume_matrix = background_volume.slice_volume(
                    projection, ras)
            except IndexError:
                new_ras = aparc_aseg_volume.get_center_point()
                bx_axis_coords, by_axis_coords, bvolume_matrix = background_volume.slice_volume(
                    projection, new_ras)
                self.logger.info(
                    "The volume center point has been used for %s snapshot of %s and %s.",
                    projection, aparc_aseg_volume_path, background_volume_path)

            self.writer.write_2_matrices(
                bx_axis_coords, by_axis_coords, bvolume_matrix, x_axis_coords,
                y_axis_coords, aparc_aseg_matrix,
                self.generate_file_name(projection, snapshot_name))
示例#4
0
def test_simple_label_config():
    service = VolumeService()
    data = numpy.array(
        [[[0, 0, 1], [1, 2, 0]], [[2, 1, 1000], [1000, 1, 0]], [[0, 0, 1], [1, 2, 0]], [[2, 1, 1000], [3, 1, 0]]])
    in_volume = Volume(data, [], None)
    out_volume = service._label_config(in_volume)
    assert numpy.array_equal(out_volume.data, [[[0, 0, 1], [1, 2, 0]], [[2, 1, 4], [4, 1, 0]], [[0, 0, 1], [1, 2, 0]],
                                               [[2, 1, 4], [3, 1, 0]]])
示例#5
0
    def read(self, volume_path):
        image = nibabel.load(volume_path)
        header = image.header
        data = image.get_data()
        affine_matrix = image.affine
        self.logger.info("The affine matrix extracted from volume %s is %s" %
                         (volume_path, affine_matrix))

        return Volume(data, affine_matrix, header)
示例#6
0
def test_label_vol_from_tdi():
    service = VolumeService()
    data = numpy.array([[[0, 0, 1], [1, 2, 0]], [[2, 1, 3], [3, 1, 0]], [
                       [0, 0, 1], [1, 2, 0]], [[2, 1, 3], [3, 1, 0]]])
    volume = Volume(data, [], None)
    labeled_volume = service._label_volume(volume, 0.5)
    assert numpy.array_equal(labeled_volume.data,
                             [[[0, 0, 1], [2, 3, 0]], [[4, 5, 6], [7, 8, 0]], [[0, 0, 9], [10, 11, 0]],
                              [[12, 13, 14], [15, 16, 0]]])
示例#7
0
    def _aparc_aseg_projection(
            self, aparc_aseg_volume: os.PathLike, aparc_aseg_volume_path: os.PathLike, projection: np.ndarray,
            ras: Union[np.ndarray, list], fs_to_conn_indices_mapping: dict,
            background_volume: Volume, background_volume_path: os.PathLike, snapshot_name: str,
            conn_measure: Union[np.ndarray, list]):

        try:
            slice = aparc_aseg_volume.slice_volume(projection, ras)
        except IndexError:
            new_ras = aparc_aseg_volume.get_center_point()
            slice = aparc_aseg_volume.slice_volume( projection, new_ras)
            msg = "The volume center point has been used for %s snapshot of %s."
            self.logger.info(msg, projection, aparc_aseg_volume_path)

        x_axis_coords, y_axis_coords, aparc_aseg_matrix  = slice

        for i, row in enumerate(aparc_aseg_matrix):
            for j, el in enumerate(row):
                if el > 0:
                    if el in fs_to_conn_indices_mapping:
                        idx = fs_to_conn_indices_mapping.get(el)
                        new_val = conn_measure[int(idx)]
                        aparc_aseg_matrix[i, j] = new_val
                    else:
                        aparc_aseg_matrix[i, j] = -1

        if background_volume_path == '':
            self.writer.write_matrix(x_axis_coords, y_axis_coords, aparc_aseg_matrix,
                                     self.generate_file_name(projection, snapshot_name), 'hot')
        else:
            try:
                bx_axis_coords, by_axis_coords, bvolume_matrix = background_volume.slice_volume(
                    projection, ras)
            except IndexError:
                new_ras = aparc_aseg_volume.get_center_point()
                bx_axis_coords, by_axis_coords, bvolume_matrix = background_volume.slice_volume(
                    projection, new_ras)
                self.logger.info("The volume center point has been used for %s snapshot of %s and %s.", projection,
                                 aparc_aseg_volume_path, background_volume_path)

            self.writer.write_2_matrices(bx_axis_coords, by_axis_coords, bvolume_matrix, x_axis_coords,
                                         y_axis_coords,
                                         aparc_aseg_matrix,
                                         self.generate_file_name(projection, snapshot_name))
示例#8
0
 def read(self, volume_path):
     h5_file = h5py.File(volume_path, 'r', libver='latest')
     data = h5_file['/data'][()]
     h5_file.close()
     return Volume(data, [], None)
示例#9
0
    def mask_to_vol(self, in_vol_path: os.PathLike, mask_vol_path: os.PathLike,
                    out_vol_path: Optional[os.PathLike]=None, labels: Optional[Union[numpy.ndarray, list]]=None,
                    ctx: Optional[str]=None, vol2mask_path: Optional[os.PathLike]=None, vn: int=1, th: float=0.999,
                    labels_mask: Optional[os.PathLike]=None, labels_nomask: str='0'):
        """
        Identify the voxels that are neighbors within a voxel distance vn, to a mask volume, with a mask threshold of th
        Default behavior: we assume a binarized mask and set th=0.999, no neighbors search, only looking at the exact
        voxel position, i.e., vn=0. Accepted voxels retain their label, whereas rejected ones get a label of 0
        """

        # Set the target labels:
        labels = self.annotation_service.read_input_labels(
            labels=labels, ctx=ctx)
        number_of_labels = len(labels)
        # Set the labels for the selected voxels
        if labels_mask is None:
            labels_mask = labels

        else:
            # Read the labels and make sure there is one for each label
            labels_mask = numpy.array(labels_mask.split()).astype('i')

            if len(labels_mask) == 1:
                labels_mask = numpy.repeat(
                    labels_mask, number_of_labels).tolist()

            elif len(labels_mask) != number_of_labels:
                self.logger.warning("Output labels for selected voxels are neither of length 1 nor of length equal to "
                                    "the one of target labels")
                return

            else:
                labels_mask = labels_mask.tolist()

        # Read the excluded labels and make sure there is one for each label
        labels_nomask = numpy.array(labels_nomask.split()).astype('i')
        if len(labels_nomask) == 1:
            labels_nomask = numpy.repeat(
                labels_nomask, number_of_labels).tolist()

        elif len(labels_nomask) != number_of_labels:
            self.logger.warning("Output labels for excluded voxels are neither of length 1 nor of length equal to the "
                                "one of the target labels")
            return

        else:
            labels_nomask = labels_nomask.tolist()

        volume = IOUtils.read_volume(in_vol_path)

        mask_vol = IOUtils.read_volume(mask_vol_path)

        # Compute the transform from vol ijk to mask ijk:
        ijk2ijk = numpy.identity(4)

        # If vol and mask are not in the same space:
        if os.path.exists(str(vol2mask_path)):
            # read the xyz2xyz transform and apply it to the inverse mask
            # affine transform to get an ijk2ijk transform.
            xyz2xyz = numpy.loadtxt(vol2mask_path)
            ijk2ijk = volume.affine_matrix.dot(
                numpy.dot(xyz2xyz, numpy.linalg.inv(mask_vol.affine_matrix)))

        # Construct a grid template of voxels +/- vn voxels around each ijk
        # voxel, sharing at least a corner
        grid = numpy.meshgrid(list(range(-vn, vn + 1, 1)), list(
            range(-vn, vn + 1, 1)), list(range(-vn, vn + 1, 1)), indexing='ij')
        grid = numpy.c_[numpy.array(grid[0]).flatten(), numpy.array(
            grid[1]).flatten(), numpy.array(grid[2]).flatten()]
        n_grid = grid.shape[0]

        out_volume = Volume(numpy.array(volume.data),
                            volume.affine_matrix, volume.header)

        # Initialize output indexes
        out_ijk = []

        # For each target label:
        for label_index in range(number_of_labels):
            current_label = labels[label_index]
            # Get the indexes of all voxels of this label:
            label_voxels_i, label_voxels_j, label_voxels_k = numpy.where(
                volume.data == current_label)

            for voxel_index in range(label_voxels_i.size):
                current_voxel_i, current_voxel_j, current_voxel_k = \
                    label_voxels_i[voxel_index], label_voxels_j[
                        voxel_index], label_voxels_k[voxel_index]
                # TODO if necessary: deal with voxels at the edge of the image, such as brain stem ones...
                #     if any([(i==0), (i==mask_shape[0]-1),(j==0), (j==mask_shape[0]-1),(k==0), (k==mask_shape[0]-1)]):
                #               mask_shape[i,j,k]=0
                #               continue

                # ...get the corresponding voxel in the mask volume:
                ijk = numpy.round(ijk2ijk.dot(numpy.array(
                    [current_voxel_i, current_voxel_j, current_voxel_k, 1]))[:3]).astype('i')

                # Make sure this point is within image limits
                for cc in range(3):
                    if ijk[cc] < 0:
                        ijk[cc] = 0

                    elif ijk[cc] >= mask_vol.dimensions[cc]:
                        ijk[cc] = mask_vol.dimensions[cc] - 1

                # If this is a voxel to keep, set it so...
                if mask_vol.data[ijk[0], ijk[1], ijk[2]] >= th:
                    out_volume.data[current_voxel_i, current_voxel_j,
                                    current_voxel_k] = labels_mask[label_index]
                    out_ijk.append(
                        [current_voxel_i, current_voxel_j, current_voxel_k])

                elif vn > 0:
                    # If not, and as long as vn>0 check whether any of its vn neighbors is a mask voxel.
                    # Generate the specific grid centered at the vertex ijk
                    ijk_grid = grid + numpy.tile(ijk, (n_grid, 1))

                    # Remove voxels outside the mask volume
                    indexes_within_limits = numpy.all([(ijk_grid[:, 0] >= 0), (ijk_grid[:, 0] < mask_vol.dimensions[0]),
                                                       (ijk_grid[:, 1] >= 0), (ijk_grid[
                                                                               :, 1] < mask_vol.dimensions[1]),
                                                       (ijk_grid[:, 2] >= 0),
                                                       (ijk_grid[:, 2] < mask_vol.dimensions[2])],
                                                      axis=0)
                    ijk_grid = ijk_grid[indexes_within_limits, :]

                    try:
                        # If none of these points is a mask point:
                        if (mask_vol.data[ijk_grid[:, 0], ijk_grid[
                                                          :, 1], ijk_grid[:, 2]] < th).all():
                            out_volume.data[
                                current_voxel_i, current_voxel_j, current_voxel_k] = labels_nomask[label_index]

                        else:  # if any of them is a mask point:
                            out_volume.data[
                                current_voxel_i, current_voxel_j, current_voxel_k] = labels_mask[label_index]
                            out_ijk.append(
                                [current_voxel_i, current_voxel_j, current_voxel_k])

                    except ValueError:  # empty grid
                        self.logger.error("Error at voxel ( %s, %s, %s ): It appears to have no common-face neighbors "
                                          "inside the image!", str(
                            current_voxel_i), str(current_voxel_j),
                                          str(current_voxel_k))
                        return

                else:
                    out_volume.data[current_voxel_i, current_voxel_j,
                                    current_voxel_k] = labels_nomask[label_index]

        if out_vol_path is None:
            out_vol_path = in_vol_path

        IOUtils.write_volume(out_vol_path, out_volume)

        # Save the output indexes that survived masking
        out_ijk = numpy.vstack(out_ijk)
        filepath = os.path.splitext(out_vol_path)[0]
        numpy.save(filepath + "-idx.npy", out_ijk)
        numpy.savetxt(filepath + "-idx.txt", out_ijk, fmt='%d')
示例#10
0
    def vol_to_ext_surf_vol(self, in_vol_path: os.PathLike, labels: Optional[Union[numpy.ndarray, list]]=None,
                            ctx: Optional[os.PathLike]=None, out_vol_path: Optional[os.PathLike]=None,
                            labels_surf: Optional[Union[numpy.ndarray, list]]=None, labels_inner: str='0'):
        """
        Separate the voxels of the outer surface of a structure, from the inner ones. Default behavior: surface voxels
        retain their label, inner voxels get the label 0, and the input file is overwritten by the output.
        """

        labels = self.annotation_service.read_input_labels(
            labels=labels, ctx=ctx)
        number_of_labels = len(labels)
        # Set the labels for the surfaces
        if labels_surf is None:
            labels_surf = labels
        else:
            # Read the surface labels and make sure there is one for each label
            labels_surf = numpy.array(labels_surf.split()).astype('i')
            if len(labels_surf) == 1:
                labels_surf = numpy.repeat(
                    labels_inner, number_of_labels).tolist()
            elif len(labels_surf) != number_of_labels:
                self.logger.warning(
                    "Output labels for surface voxels are neither of length "
                    "1 nor of length equal to the one of target labels.")
                return
            else:
                labels_surf = labels_surf.tolist()
        # Read the inner, non-surface labels
        labels_inner = numpy.array(labels_inner.split()).astype('i')
        # ...and make sure there is one for each label
        if len(labels_inner) == 1:
            labels_inner = numpy.repeat(
                labels_inner, number_of_labels).tolist()
        elif len(labels_inner) != number_of_labels:
            self.logger.warning(
                "Output labels for inner voxels are neither of length 1 nor "
                "of length equal to the one of the target labels.")
            return
        else:
            labels_inner = labels_inner.tolist()

        # Read the input volume...
        volume = IOUtils.read_volume(in_vol_path)

        # Neigbors' grid sharing a face
        eye3 = numpy.identity(3)
        border_grid = numpy.c_[eye3, -eye3].T.astype('i')
        n_border = 6

        out_volume = Volume(numpy.array(volume.data),
                            volume.affine_matrix, volume.header)

        # Initialize output indexes
        out_ijk = []

        for label_index in range(number_of_labels):
            current_label = labels[label_index]
            # Get the indexes of all voxels of this label:
            label_volxels_i, label_voxels_j, label_voxels_k = numpy.where(
                volume.data == current_label)
            # and for each voxel
            for voxel_index in range(label_volxels_i.size):
                # indexes of this voxel:
                current_voxel_i, current_voxel_j, current_voxel_k = \
                    label_volxels_i[voxel_index], label_voxels_j[
                        voxel_index], label_voxels_k[voxel_index]
                # Create the neighbors' grid sharing a face
                ijk_grid = border_grid + \
                           numpy.tile(numpy.array(
                               [current_voxel_i, current_voxel_j, current_voxel_k]), (n_border, 1))
                # Remove voxels outside the image
                indices_inside_image = numpy.all([(ijk_grid[:, 0] >= 0), (ijk_grid[:, 0] < volume.dimensions[0]),
                                                  (ijk_grid[:, 1] >= 0), (ijk_grid[
                                                                          :, 1] < volume.dimensions[1]),
                                                  (ijk_grid[:, 2] >= 0), (ijk_grid[:, 2] < volume.dimensions[2])],
                                                 axis=0)
                ijk_grid = ijk_grid[indices_inside_image, :]
                try:
                    # If all face neighbors are of the same label...
                    if numpy.all(volume.data[ijk_grid[:, 0], ijk_grid[:, 1], ijk_grid[:, 2]] == numpy.tile(
                            volume.data[current_voxel_i,
                                        current_voxel_j, current_voxel_k],
                            (n_border, 1))):
                        # ...set this voxel to the corresponding inner target label
                        out_volume.data[current_voxel_i, current_voxel_j,
                                        current_voxel_k] = labels_inner[label_index]
                    else:
                        # ...set this voxel to the corresponding surface target label
                        out_volume.data[current_voxel_i, current_voxel_j,
                                        current_voxel_k] = labels_surf[label_index]
                        out_ijk.append(
                            [current_voxel_i, current_voxel_j, current_voxel_k])
                except ValueError:  # empty grid
                    self.logger.error("Error at voxel ( %s, %s, %s ) of label %s: It appears to have no common-face "
                                      "neighbors inside the image!", str(
                        current_voxel_i), str(current_voxel_j),
                                      str(current_voxel_k), str(current_label))
                    return

        if out_vol_path is None:
            out_vol_path = in_vol_path

        IOUtils.write_volume(out_vol_path, out_volume)

        # save the output indexes that survived masking
        out_ijk = numpy.vstack(out_ijk)
        filepath = os.path.splitext(out_vol_path)[0]
        numpy.save(filepath + "-idx.npy", out_ijk)
        numpy.savetxt(filepath + "-idx.txt", out_ijk, fmt='%d')
示例#11
0
文件: volume.py 项目: sipv/tvb-recon
    def vol_to_ext_surf_vol(self,
                            in_vol_path,
                            labels=None,
                            ctx=None,
                            out_vol_path=None,
                            labels_surf=None,
                            labels_inner='0'):
        """
        Separate the voxels of the outer surface of a structure, from the inner ones. Default behavior: surface voxels
        retain their label, inner voxels get the label 0, and the input file is overwritten by the output.
        """

        labels = self.annotation_service.read_input_labels(labels=labels,
                                                           ctx=ctx)
        number_of_labels = len(labels)
        # Set the labels for the surfaces
        if labels_surf is None:
            labels_surf = labels
        else:
            # Read the surface labels and make sure there is one for each label
            labels_surf = numpy.array(labels_surf.split()).astype('i')
            if len(labels_surf) == 1:
                labels_surf = numpy.repeat(labels_inner,
                                           number_of_labels).tolist()
            elif len(labels_surf) != number_of_labels:
                self.logger.warning(
                    "Output labels for surface voxels are neither of length "
                    "1 nor of length equal to the one of target labels.")
                return
            else:
                labels_surf = labels_surf.tolist()
        # Read the inner, non-surface labels
        labels_inner = numpy.array(labels_inner.split()).astype('i')
        # ...and make sure there is one for each label
        if len(labels_inner) == 1:
            labels_inner = numpy.repeat(labels_inner,
                                        number_of_labels).tolist()
        elif len(labels_inner) != number_of_labels:
            self.logger.warning(
                "Output labels for inner voxels are neither of length 1 nor "
                "of length equal to the one of the target labels.")
            return
        else:
            labels_inner = labels_inner.tolist()

        # Read the input volume...
        volume = IOUtils.read_volume(in_vol_path)

        # Neigbors' grid sharing a face
        eye3 = numpy.identity(3)
        border_grid = numpy.c_[eye3, -eye3].T.astype('i')
        n_border = 6

        out_volume = Volume(numpy.array(volume.data), volume.affine_matrix,
                            volume.header)

        # Initialize output indexes
        out_ijk = []

        for label_index in range(number_of_labels):
            current_label = labels[label_index]
            # Get the indexes of all voxels of this label:
            label_volxels_i, label_voxels_j, label_voxels_k = numpy.where(
                volume.data == current_label)
            # and for each voxel
            for voxel_index in range(label_volxels_i.size):
                # indexes of this voxel:
                current_voxel_i, current_voxel_j, current_voxel_k = \
                    label_volxels_i[voxel_index], label_voxels_j[
                        voxel_index], label_voxels_k[voxel_index]
                # Create the neighbors' grid sharing a face
                ijk_grid = border_grid + \
                    numpy.tile(numpy.array(
                        [current_voxel_i, current_voxel_j, current_voxel_k]), (n_border, 1))
                # Remove voxels outside the image
                indices_inside_image = numpy.all(
                    [(ijk_grid[:, 0] >= 0),
                     (ijk_grid[:, 0] < volume.dimensions[0]),
                     (ijk_grid[:, 1] >= 0),
                     (ijk_grid[:, 1] < volume.dimensions[1]),
                     (ijk_grid[:, 2] >= 0),
                     (ijk_grid[:, 2] < volume.dimensions[2])],
                    axis=0)
                ijk_grid = ijk_grid[indices_inside_image, :]
                try:
                    # If all face neighbors are of the same label...
                    if numpy.all(
                            volume.data[ijk_grid[:, 0], ijk_grid[:, 1],
                                        ijk_grid[:, 2]] == numpy.tile(
                                            volume.data[current_voxel_i,
                                                        current_voxel_j,
                                                        current_voxel_k], (
                                                            n_border, 1))):
                        # ...set this voxel to the corresponding inner target label
                        out_volume.data[
                            current_voxel_i, current_voxel_j,
                            current_voxel_k] = labels_inner[label_index]
                    else:
                        # ...set this voxel to the corresponding surface target label
                        out_volume.data[
                            current_voxel_i, current_voxel_j,
                            current_voxel_k] = labels_surf[label_index]
                        out_ijk.append([
                            current_voxel_i, current_voxel_j, current_voxel_k
                        ])
                except ValueError:  # empty grid
                    self.logger.error(
                        "Error at voxel ( %s, %s, %s ) of label %s: It appears to have no common-face "
                        "neighbors inside the image!", str(current_voxel_i),
                        str(current_voxel_j), str(current_voxel_k),
                        str(current_label))
                    return

        if out_vol_path is None:
            out_vol_path = in_vol_path

        IOUtils.write_volume(out_vol_path, out_volume)

        # save the output indexes that survived masking
        out_ijk = numpy.vstack(out_ijk)
        filepath = os.path.splitext(out_vol_path)[0]
        numpy.save(filepath + "-idx.npy", out_ijk)
        numpy.savetxt(filepath + "-idx.txt", out_ijk, fmt='%d')
示例#12
0
文件: volume.py 项目: sipv/tvb-recon
    def mask_to_vol(self,
                    in_vol_path,
                    mask_vol_path,
                    out_vol_path=None,
                    labels=None,
                    ctx=None,
                    vol2mask_path=None,
                    vn=1,
                    th=0.999,
                    labels_mask=None,
                    labels_nomask='0'):
        """
        Identify the voxels that are neighbors within a voxel distance vn, to a mask volume, with a mask threshold of th
        Default behavior: we assume a binarized mask and set th=0.999, no neighbors search, only looking at the exact
        voxel position, i.e., vn=0. Accepted voxels retain their label, whereas rejected ones get a label of 0
        """

        # Set the target labels:
        labels = self.annotation_service.read_input_labels(labels=labels,
                                                           ctx=ctx)
        number_of_labels = len(labels)
        # Set the labels for the selected voxels
        if labels_mask is None:
            labels_mask = labels

        else:
            # Read the labels and make sure there is one for each label
            labels_mask = numpy.array(labels_mask.split()).astype('i')

            if len(labels_mask) == 1:
                labels_mask = numpy.repeat(labels_mask,
                                           number_of_labels).tolist()

            elif len(labels_mask) != number_of_labels:
                self.logger.warning(
                    "Output labels for selected voxels are neither of length 1 nor of length equal to "
                    "the one of target labels")
                return

            else:
                labels_mask = labels_mask.tolist()

        # Read the excluded labels and make sure there is one for each label
        labels_nomask = numpy.array(labels_nomask.split()).astype('i')
        if len(labels_nomask) == 1:
            labels_nomask = numpy.repeat(labels_nomask,
                                         number_of_labels).tolist()

        elif len(labels_nomask) != number_of_labels:
            self.logger.warning(
                "Output labels for excluded voxels are neither of length 1 nor of length equal to the "
                "one of the target labels")
            return

        else:
            labels_nomask = labels_nomask.tolist()

        volume = IOUtils.read_volume(in_vol_path)

        mask_vol = IOUtils.read_volume(mask_vol_path)

        # Compute the transform from vol ijk to mask ijk:
        ijk2ijk = numpy.identity(4)

        # If vol and mask are not in the same space:
        if os.path.exists(str(vol2mask_path)):
            # read the xyz2xyz transform and apply it to the inverse mask
            # affine transform to get an ijk2ijk transform.
            xyz2xyz = numpy.loadtxt(vol2mask_path)
            ijk2ijk = volume.affine_matrix.dot(
                numpy.dot(xyz2xyz, numpy.linalg.inv(mask_vol.affine_matrix)))

        # Construct a grid template of voxels +/- vn voxels around each ijk
        # voxel, sharing at least a corner
        grid = numpy.meshgrid(list(range(-vn, vn + 1, 1)),
                              list(range(-vn, vn + 1, 1)),
                              list(range(-vn, vn + 1, 1)),
                              indexing='ij')
        grid = numpy.c_[numpy.array(grid[0]).flatten(),
                        numpy.array(grid[1]).flatten(),
                        numpy.array(grid[2]).flatten()]
        n_grid = grid.shape[0]

        out_volume = Volume(numpy.array(volume.data), volume.affine_matrix,
                            volume.header)

        # Initialize output indexes
        out_ijk = []

        # For each target label:
        for label_index in range(number_of_labels):
            current_label = labels[label_index]
            # Get the indexes of all voxels of this label:
            label_voxels_i, label_voxels_j, label_voxels_k = numpy.where(
                volume.data == current_label)

            for voxel_index in range(label_voxels_i.size):
                current_voxel_i, current_voxel_j, current_voxel_k = \
                    label_voxels_i[voxel_index], label_voxels_j[
                        voxel_index], label_voxels_k[voxel_index]
                # TODO if necessary: deal with voxels at the edge of the image, such as brain stem ones...
                #     if any([(i==0), (i==mask_shape[0]-1),(j==0), (j==mask_shape[0]-1),(k==0), (k==mask_shape[0]-1)]):
                #               mask_shape[i,j,k]=0
                #               continue

                # ...get the corresponding voxel in the mask volume:
                ijk = numpy.round(
                    ijk2ijk.dot(
                        numpy.array([
                            current_voxel_i, current_voxel_j, current_voxel_k,
                            1
                        ]))[:3]).astype('i')

                # Make sure this point is within image limits
                for cc in range(3):
                    if ijk[cc] < 0:
                        ijk[cc] = 0

                    elif ijk[cc] >= mask_vol.dimensions[cc]:
                        ijk[cc] = mask_vol.dimensions[cc] - 1

                # If this is a voxel to keep, set it so...
                if mask_vol.data[ijk[0], ijk[1], ijk[2]] >= th:
                    out_volume.data[current_voxel_i, current_voxel_j,
                                    current_voxel_k] = labels_mask[label_index]
                    out_ijk.append(
                        [current_voxel_i, current_voxel_j, current_voxel_k])

                elif vn > 0:
                    # If not, and as long as vn>0 check whether any of its vn neighbors is a mask voxel.
                    # Generate the specific grid centered at the vertex ijk
                    ijk_grid = grid + numpy.tile(ijk, (n_grid, 1))

                    # Remove voxels outside the mask volume
                    indexes_within_limits = numpy.all(
                        [(ijk_grid[:, 0] >= 0),
                         (ijk_grid[:, 0] < mask_vol.dimensions[0]),
                         (ijk_grid[:, 1] >= 0),
                         (ijk_grid[:, 1] < mask_vol.dimensions[1]),
                         (ijk_grid[:, 2] >= 0),
                         (ijk_grid[:, 2] < mask_vol.dimensions[2])],
                        axis=0)
                    ijk_grid = ijk_grid[indexes_within_limits, :]

                    try:
                        # If none of these points is a mask point:
                        if (mask_vol.data[ijk_grid[:, 0], ijk_grid[:, 1],
                                          ijk_grid[:, 2]] < th).all():
                            out_volume.data[
                                current_voxel_i, current_voxel_j,
                                current_voxel_k] = labels_nomask[label_index]

                        else:  # if any of them is a mask point:
                            out_volume.data[
                                current_voxel_i, current_voxel_j,
                                current_voxel_k] = labels_mask[label_index]
                            out_ijk.append([
                                current_voxel_i, current_voxel_j,
                                current_voxel_k
                            ])

                    except ValueError:  # empty grid
                        self.logger.error(
                            "Error at voxel ( %s, %s, %s ): It appears to have no common-face neighbors "
                            "inside the image!", str(current_voxel_i),
                            str(current_voxel_j), str(current_voxel_k))
                        return

                else:
                    out_volume.data[
                        current_voxel_i, current_voxel_j,
                        current_voxel_k] = labels_nomask[label_index]

        if out_vol_path is None:
            out_vol_path = in_vol_path

        IOUtils.write_volume(out_vol_path, out_volume)

        # Save the output indexes that survived masking
        out_ijk = numpy.vstack(out_ijk)
        filepath = os.path.splitext(out_vol_path)[0]
        numpy.save(filepath + "-idx.npy", out_ijk)
        numpy.savetxt(filepath + "-idx.txt", out_ijk, fmt='%d')