Ejemplo n.º 1
0
def create_line(param, fname, coord, nz):
    """
    Create vertical line in 3D volume
    :param param:
    :param fname:
    :param coord:
    :param nz:
    :return:
    """

    # duplicate volume (assumes input file is nifti)
    copy(fname, 'line.nii', verbose=param.verbose)

    # set all voxels to zero
    img = Image('line.nii')
    data = get_data_or_scalar('0', img.data)
    data_concat = concatenate_along_4th_dimension(img.data, data)
    img.data = np.prod(data_concat, axis=3)
    img.save()

    labels = []

    if isinstance(coord[0], Coordinate):
        for x, y, _, _ in coord:
            labels.extend([Coordinate([x, y, iz, 1]) for iz in range(nz)])
    else:
        # backwards compat
        labels.extend(
            [Coordinate([coord[0], coord[1], iz, 1]) for iz in range(nz)])

    create_labels(img, labels).save()

    return 'line.nii'
def create_line(param, fname, coord, nz):
    """
    Create vertical line in 3D volume
    :param param:
    :param fname:
    :param coord:
    :param nz:
    :return:
    """

    # duplicate volume (assumes input file is nifti)
    copy(fname, 'line.nii', verbose=param.verbose)

    # set all voxels to zero
    run_proc(['sct_maths', '-i', 'line.nii', '-mul', '0', '-o', 'line.nii'], param.verbose)

    labels = []

    if isinstance(coord[0], Coordinate):
        for x, y, _, _ in coord:
            labels.extend([Coordinate([x, y, iz, 1]) for iz in range(nz)])
    else:
        # backwards compat
        labels.extend([Coordinate([coord[0], coord[1], iz, 1]) for iz in range(nz)])

    create_labels(Image("line.nii"), labels).save(path="line.nii")

    return 'line.nii'
Ejemplo n.º 3
0
def create_labels_along_segmentation(
        img: Image, labels: Sequence[Tuple[int, int]]) -> Image:
    """
    Create an image with labels defined along the spinal cord segmentation (or centerline).
    Input image does **not** need to be RPI (re-orientation is done within this function).

    :param img: source segmentation
    :param labels: list of label tuples as (z_value, label_value)
    :returns: labeled segmentation (Image)
    """
    og_orientation = img.orientation

    if og_orientation != "RPI":
        img.change_orientation("RPI")

    out = zeros_like(img)

    for idx_label, label in enumerate(labels):
        z, value = label

        # update z based on native image orientation (z should represent superior-inferior axis)
        coord = Coordinate(
            [z, z, z]
        )  # since we don't know which dimension corresponds to the superior-inferior

        # axis, we put z in all dimensions (we don't care about x and y here)
        _, _, z_rpi = coord.permute(img, 'RPI')

        # if z=-1, replace with nz/2
        if z == -1:
            z_rpi = int(np.round(out.dim[2] / 2.0))

        # get center of mass of segmentation at given z
        x, y = ndimage.measurements.center_of_mass(
            np.array(img.data[:, :, z_rpi]))

        # round values to make indices
        x, y = int(np.round(x)), int(np.round(y))

        # display info
        logger.debug(f"Label # {idx_label}: {x}, {y}. {z_rpi} --> {value}")

        if len(out.data.shape) == 3:
            out.data[x, y, z_rpi] = value
        elif len(out.data.shape) == 2:
            if z != 0:
                raise ValueError(
                    f"2D coordinates should have a Z value of 0! Current value: {coord.z}"
                )

            out.data[x, y] = value

    if out.orientation != og_orientation:
        out.change_orientation(og_orientation)
        img.change_orientation(og_orientation)

    return out
Ejemplo n.º 4
0
    def getNonZeroCoordinates(self, sorting=None, reverse_coord=False, coordValue=False):
        """
        This function return all the non-zero coordinates that the image contains.
        Coordinate list can also be sorted by x, y, z, or the value with the parameter sorting='x', sorting='y', sorting='z' or sorting='value'
        If reverse_coord is True, coordinate are sorted from larger to smaller.
        """
        n_dim = 1
        if self.dim[3] == 1:
            n_dim = 3
        else:
            n_dim = 4
        if self.dim[2] == 1:
            n_dim = 2

        try:
            if n_dim == 3:
                X, Y, Z = (self.data > 0).nonzero()
                list_coordinates = [Coordinate([X[i], Y[i], Z[i], self.data[X[i], Y[i], Z[i]]]) for i in range(0, len(X))]
            elif n_dim == 2:
                try:
                    X, Y = (self.data > 0).nonzero()
                    list_coordinates = [Coordinate([X[i], Y[i], 0, self.data[X[i], Y[i]]]) for i in range(0, len(X))]
                except ValueError:
                    X, Y, Z = (self.data > 0).nonzero()
                    list_coordinates = [Coordinate([X[i], Y[i], 0, self.data[X[i], Y[i], 0]]) for i in range(0, len(X))]
        except Exception as e:
            sct.printv('ERROR: Exception ' + str(e) + ' caught while geting non Zeros coordinates', 1, 'error')

        if coordValue:
            from spinalcordtoolbox.types import CoordinateValue
            if n_dim == 3:
                list_coordinates = [CoordinateValue([X[i], Y[i], Z[i], self.data[X[i], Y[i], Z[i]]]) for i in range(0, len(X))]
            else:
                list_coordinates = [CoordinateValue([X[i], Y[i], 0, self.data[X[i], Y[i]]]) for i in range(0, len(X))]
        if sorting is not None:
            if reverse_coord not in [True, False]:
                raise ValueError('reverse_coord parameter must be a boolean')

            if sorting == 'x':
                list_coordinates = sorted(list_coordinates, key=lambda obj: obj.x, reverse=reverse_coord)
            elif sorting == 'y':
                list_coordinates = sorted(list_coordinates, key=lambda obj: obj.y, reverse=reverse_coord)
            elif sorting == 'z':
                list_coordinates = sorted(list_coordinates, key=lambda obj: obj.z, reverse=reverse_coord)
            elif sorting == 'value':
                list_coordinates = sorted(list_coordinates, key=lambda obj: obj.value, reverse=reverse_coord)
            else:
                raise ValueError("sorting parameter must be either 'x', 'y', 'z' or 'value'")

        return list_coordinates
Ejemplo n.º 5
0
def test_create_labels(test_image):
    a = test_image.copy()
    labels = [Coordinate(l) for l in [[0, 1, 0, 99], [0, 1, 2, 5]]]

    b = sct_labels.create_labels(a, labels)

    assert b.data[0, 1, 0] == 99
    assert b.data[0, 1, 2] == 5
Ejemplo n.º 6
0
 def create_label_along_segmentation(self):
     """
     Create an image with labels defined along the spinal cord segmentation (or centerline).
     Input image does **not** need to be RPI (re-orientation is done within this function).
     Example:
     object_define=ProcessLabels(fname_segmentation, coordinates=[coord_1, coord_2, coord_i]), where coord_i='z,value'. If z=-1, then use z=nz/2 (i.e. center of FOV in superior-inferior direction)
     Returns
     """
     # reorient input image to RPI
     im_rpi = self.image_input.copy().change_orientation('RPI')
     im_output_rpi = zeros_like(im_rpi)
     # loop across labels
     for ilabel, coord in enumerate(self.coordinates):
         # split coord string
         list_coord = coord.split(',')
         # convert to int() and assign to variable
         z, value = [int(i) for i in list_coord]
         # update z based on native image orientation (z should represent superior-inferior axis)
         coord = Coordinate(
             [z, z, z]
         )  # since we don't know which dimension corresponds to the superior-inferior
         # axis, we put z in all dimensions (we don't care about x and y here)
         _, _, z_rpi = coord.permute(self.image_input, 'RPI')
         # if z=-1, replace with nz/2
         if z == -1:
             z_rpi = int(np.round(im_output_rpi.dim[2] / 2.0))
         # get center of mass of segmentation at given z
         x, y = ndimage.measurements.center_of_mass(
             np.array(im_rpi.data[:, :, z_rpi]))
         # round values to make indices
         x, y = int(np.round(x)), int(np.round(y))
         # display info
         sct.printv(
             'Label #' + str(ilabel) + ': ' + str(x) + ',' + str(y) + ',' +
             str(z_rpi) + ' --> ' + str(value), 1)
         if len(im_output_rpi.data.shape) == 3:
             im_output_rpi.data[x, y, z_rpi] = value
         elif len(im_output_rpi.data.shape) == 2:
             assert str(
                 z
             ) == '0', "ERROR: 2D coordinates should have a Z value of 0. Z coordinate is :" + str(
                 z)
             im_output_rpi.data[x, y] = value
     # change orientation back to native
     return im_output_rpi.change_orientation(self.image_input.orientation)
def test_sct_label_utils_cubic_to_point():
    """Run the CLI script and verify the resulting center of mass coordinate."""
    fname_out = 'test_centerofmass.nii.gz'
    sct_label_utils.main(argv=[
        '-i', 't2/t2_seg-manual.nii.gz', '-cubic-to-point', '-o', fname_out
    ])
    # Note: Old, broken 'sct_testing' test used '31,28,25,1' as ground truth. Is this a regression?
    assert Image(fname_out).getNonZeroCoordinates() == [
        Coordinate([31, 27, 25, 1])
    ]
Ejemplo n.º 8
0
def test_create_labels_empty(test_image):
    a = test_image.copy()
    expected = zeros_like(a)

    labels = [Coordinate(l) for l in [[0, 0, 0, 7], [0, 1, 2, 5]]]
    expected.data[0, 0, 0] = 7
    expected.data[0, 1, 2] = 5

    b = sct_labels.create_labels_empty(a, labels)

    diff = b.data == expected.data
    assert diff.all()