Exemple #1
0
def test_nrrd_dwi_roundtrip(test_nrrd_path):
    """DWI NRRD round-trip test
    - loads and saves a NRRD file via Slicer's I/O, twice
    - checks the node values against the original file each time
    """

    import tempfile

    # load and re-save NRRD once
    storagenode1 = slicer.vtkMRMLNRRDStorageNode()
    storagenode1.SetFileName(test_nrrd_path)
    dw_node1 = slicer.vtkMRMLDiffusionWeightedVolumeNode()
    storagenode1.ReadData(dw_node1)
    __f_tmp_nrrd1 = tempfile.NamedTemporaryFile(suffix=".nhdr",
                                                dir=tmp_dir,
                                                delete=False)
    tmp_nrrd1 = __f_tmp_nrrd1.name
    storagenode1.SetFileName(tmp_nrrd1)
    storagenode1.WriteData(dw_node1)

    parsed_nrrd2, dw_node2 = test_nrrd_dwi_load(test_nrrd_path, tmp_nrrd1)

    # re-save NRRD again
    storagenode2 = slicer.vtkMRMLNRRDStorageNode()
    __f_tmp_nrrd2 = tempfile.NamedTemporaryFile(suffix=".nhdr",
                                                dir=tmp_dir,
                                                delete=False)
    tmp_nrrd2 = __f_tmp_nrrd2.name
    storagenode2.SetFileName(tmp_nrrd2)
    storagenode2.WriteData(dw_node2)

    # test twice-saved file against original NRRD
    parsed_nrrd3, dw_node3 = test_nrrd_dwi_load(test_nrrd_path, tmp_nrrd2)
def test_nrrd_dwi_roundtrip(test_nrrd_path):
    """DWI NRRD round-trip test
    - loads and saves a NRRD file via Slicer's I/O, twice
    - checks the node values against the original file each time
    """

    import tempfile

    # load and re-save NRRD once
    storagenode1 = slicer.vtkMRMLNRRDStorageNode()
    storagenode1.SetFileName(test_nrrd_path)
    dw_node1 = slicer.vtkMRMLDiffusionWeightedVolumeNode()
    storagenode1.ReadData(dw_node1)
    __f_tmp_nrrd1 = tempfile.NamedTemporaryFile(suffix=".nhdr", dir=tmp_dir, delete=False)
    tmp_nrrd1 = __f_tmp_nrrd1.name
    storagenode1.SetFileName(tmp_nrrd1)
    storagenode1.WriteData(dw_node1)

    parsed_nrrd2, dw_node2 = test_nrrd_dwi_load(test_nrrd_path, tmp_nrrd1)

    # re-save NRRD again
    storagenode2 = slicer.vtkMRMLNRRDStorageNode()
    __f_tmp_nrrd2 = tempfile.NamedTemporaryFile(suffix=".nhdr", dir=tmp_dir, delete=False)
    tmp_nrrd2 = __f_tmp_nrrd2.name
    storagenode2.SetFileName(tmp_nrrd2)
    storagenode2.WriteData(dw_node2)

    # test twice-saved file against original NRRD
    parsed_nrrd3, dw_node3 = test_nrrd_dwi_load(test_nrrd_path, tmp_nrrd2)
Exemple #3
0
    def run_extract_to_bvals(tempdata, args):
        """
    returns array of bvalues
    """
        print("ExtractDWIShell runtests, running: " + repr(args))

        proc = subprocess.Popen(args)
        proc.wait()

        if proc.returncode != 0:
            print("ExtractDWIShells failed!")
            sys.exit(-1)

        # load NRRD into Slicer
        sn = slicer.vtkMRMLNRRDStorageNode()
        sn.SetFileName(tempdata)
        dw_node = slicer.vtkMRMLDiffusionWeightedVolumeNode()
        sn.ReadData(dw_node)

        bvals = vtk.util.numpy_support.vtk_to_numpy(dw_node.GetBValues())
        return bvals
Exemple #4
0
def test_nrrd_dwi_load(first_file, second_file=None):
    """
    - load a DWI NRRD file into Slicer
    - validate b values and gradient vectors against original header
        - check the values in the vtkMRMLDiffusionWeightedVolumeNode
        - check the values in the vtkMRMLDWVNode attribute dictionary
    """
    if second_file is None:
        second_file = first_file

    # load NRRD into Slicer
    storagenode = slicer.vtkMRMLNRRDStorageNode()
    storagenode.SetFileName(first_file)
    dw_node = slicer.vtkMRMLDiffusionWeightedVolumeNode()
    storagenode.ReadData(dw_node)

    slicer_grads = numpy_support.vtk_to_numpy(dw_node.GetDiffusionGradients())
    slicer_numgrads = slicer_grads.shape[0]

    # load NRRD with pure-python parser
    parsed_nrrd = parse_nhdr(second_file)

    ##################################
    # 1) check the number of gradients

    assert (len(parsed_nrrd.gradients) == slicer_numgrads)

    ##################################
    # 2) check the node b values and gradients are correct

    # Note: vtkDataArray.GetMaxNorm gives max for scalar array.
    # max b value from the node
    nose.tools.assert_equal(parsed_nrrd.bvalue,
                            dw_node.GetBValues().GetMaxNorm())

    max_parsed_grad_norm = np.max(
        np.apply_along_axis(np.linalg.norm, 1, parsed_nrrd.gradients))

    for i in range(0, slicer_numgrads):
        g_parsed_raw = parsed_nrrd.gradients[i]
        g_parsed_normed = normalize(g_parsed_raw)

        bval_parsed = parsed_nrrd.bvalue * pow(
            np.linalg.norm(g_parsed_raw) / max_parsed_grad_norm, 2)
        np.testing.assert_almost_equal(
            bval_parsed,
            dw_node.GetBValue(i),
            decimal=7,
            err_msg="MRMLNode b value does not match NRRD header")

        g_from_node = slicer_grads[i, :]

        # gradients stored in the vtkMRMLDiffusionWeightedVolumeNode must be *normalized*.
        np.testing.assert_allclose(np.linalg.norm(g_parsed_normed -
                                                  g_from_node),
                                   0.0,
                                   atol=1e-15)

    # b value from the node attribute dictionary
    np.testing.assert_equal(parsed_nrrd.bvalue,
                            float(dw_node.GetAttribute("DWMRI_b-value")))

    # 3) check gradients in the node attribute dictionary
    #    gradients must match the value on-disk.
    for i in range(0, slicer_numgrads):
        grad_key = f"DWMRI_gradient_{i:04d}"
        parsed_gradient = np.fromstring(parsed_nrrd.header[grad_key],
                                        count=3,
                                        sep=' ',
                                        dtype=np.float64)
        attr_gradient = np.fromstring(dw_node.GetAttribute(grad_key),
                                      count=3,
                                      sep=' ',
                                      dtype=np.float64)

        np.testing.assert_array_almost_equal(
            parsed_gradient,
            attr_gradient,
            decimal=12,
            err_msg=
            "NHDR gradient does not match gradient in node attribute dictionary"
        )

    return (parsed_nrrd, dw_node)
Exemple #5
0
def main():
    if "--test" in sys.argv:
        runtests(sys.argv[2])
        sys.exit(-1)  # default fail, runtests must exit(0)

    # handle arguments
    parser = argparse.ArgumentParser('Process args')
    parser.add_argument('--inputDWI', required=True, type=str)
    parser.add_argument('--bvalues', required=True, type=str)
    parser.add_argument('--tolerance', required=True, type=float)
    parser.add_argument('--outputDWI', required=True, type=str)
    parser.add_argument('--baseline_clamp', required=False, type=str)
    parser.add_argument('--test')
    args = parser.parse_args(sys.argv[1:])

    dwifile = args.inputDWI
    outfile = args.outputDWI
    target_bvals = [float(bvalue) for bvalue in args.bvalues.split(',')]
    if args.baseline_clamp:
        bval_clamp = float(args.baseline_clamp)
    bval_tolerance = args.tolerance

    # load data
    sn = slicer.vtkMRMLNRRDStorageNode()
    sn.SetFileName(dwifile)
    node_in = mrml.vtkMRMLDiffusionWeightedVolumeNode()
    print("loading: ", dwifile)
    sn.ReadData(node_in)
    dwi_in = slicer.util.arrayFromVolume(node_in)

    # sanity check that the last axis is volumes
    assert (node_in.GetNumberOfGradients() == dwi_in.shape[-1]
            ), "Number of gradients do not match the size of last image axis!"

    bvals_in = numpy_support.vtk_to_numpy(node_in.GetBValues())
    grads_in = numpy_support.vtk_to_numpy(node_in.GetDiffusionGradients())

    print("  raw input gradients: ")
    print(grads_in)
    print("  raw input bvals: ")
    print(bvals_in)

    for (i, g) in enumerate(grads_in):
        norm = np.linalg.norm(g)
        if norm > 1e-6: grads_in[i] = g * 1 / norm

    # select the indices to keep based on b value
    indices = []
    for (i, bval) in enumerate(bvals_in):
        for check_bval in target_bvals:
            if abs(bval - check_bval) < bval_tolerance:
                indices.append(i)

    print("selected indices: ", indices)

    # output shape: (3d_vol_shape..., num_indices)
    num_indices = len(indices)
    shape_out = dwi_in.shape[:-1] + (num_indices, )
    print("input shape: ", dwi_in.shape)
    print("output shape: ", shape_out)

    # construct output subset
    vol_out = np.zeros(shape_out, dtype=dwi_in.dtype)
    grads_out = np.zeros((num_indices, 3))
    bvals_out = np.zeros(num_indices)

    for (new_i, index) in enumerate(indices):
        vol_out[:, :, :, new_i] = dwi_in[:, :, :, index]
        grads_out[new_i, :] = grads_in[index, :]
        bvals_out[new_i] = bvals_in[index]

    if args.baseline_clamp:
        for (i, bval) in enumerate(bvals_out):
            if bval < bval_clamp:
                print("  clamping baseline {} (gradient {}) to zero".format(
                    bval, grads_out[i, :]))
                bvals_out[i] = 0
                grads_out[i, :] = np.array([0., 0., 0.])

    print("selected bvals: ", bvals_out)
    print("  grads_out shape:  ", grads_out.shape)
    print("  vol_out shape:    ", vol_out.shape)
    print("  output gradients: ", grads_out)

    # write output
    sn_out = slicer.vtkMRMLNRRDStorageNode()
    sn_out.SetFileName(outfile)
    node_out = mrml.vtkMRMLDiffusionWeightedVolumeNode()

    # copy image information
    node_out.Copy(node_in)
    # reset the attribute dictionary, otherwise it will be transferred over
    attrs = vtk.vtkStringArray()
    node_out.GetAttributeNames(attrs)
    for i in range(0, attrs.GetNumberOfValues()):
        node_out.SetAttribute(attrs.GetValue(i), None)

    # reset the data array to force resizing, otherwise we will just keep the old data too
    node_out.SetAndObserveImageData(None)
    slicer.util.updateVolumeFromArray(node_out, vol_out)
    node_out.SetNumberOfGradients(num_indices)
    node_out.SetBValues(numpy_support.numpy_to_vtk(bvals_out))
    node_out.SetDiffusionGradients(numpy_support.numpy_to_vtk(grads_out))
    node_out.Modified()

    sn_out.WriteData(node_out)
def test_nrrd_dwi_load(first_file, second_file=None):
    """
    - load a DWI NRRD file into Slicer
    - validate b values and gradient vectors against original header
        - check the values in the vtkMRMLDiffusionWeightedVolumeNode
        - check the values in the vtkMRMLDWVNode attribute dictionary
    """
    if second_file is None:
        second_file = first_file

    # load NRRD into Slicer
    storagenode = slicer.vtkMRMLNRRDStorageNode()
    storagenode.SetFileName(first_file)
    dw_node = slicer.vtkMRMLDiffusionWeightedVolumeNode()
    storagenode.ReadData(dw_node)

    slicer_grads = numpy_support.vtk_to_numpy(dw_node.GetDiffusionGradients())
    slicer_numgrads = slicer_grads.shape[0]

    # load NRRD with pure-python parser
    parsed_nrrd = parse_nhdr(second_file)

    ##################################
    # 1) check the number of gradients

    assert( len(parsed_nrrd.gradients) == slicer_numgrads )

    ##################################
    # 2) check the node b values and gradients are correct

    # Note: vtkDataArray.GetMaxNorm gives max for scalar array.
    # max b value from the node
    nose.tools.assert_equal(parsed_nrrd.bvalue, dw_node.GetBValues().GetMaxNorm())

    max_parsed_grad_norm = np.max(np.apply_along_axis(np.linalg.norm, 1, parsed_nrrd.gradients))

    for i in range(0, slicer_numgrads):
        g_parsed_raw = parsed_nrrd.gradients[i]
        g_parsed_normed = normalize(g_parsed_raw)

        bval_parsed = parsed_nrrd.bvalue * pow(np.linalg.norm(g_parsed_raw) / max_parsed_grad_norm, 2)
        np.testing.assert_almost_equal(bval_parsed, dw_node.GetBValue(i), decimal=7,
                                       err_msg="MRMLNode b value does not match NRRD header")

        g_from_node = slicer_grads[i, :]

        # gradients stored in the vtkMRMLDiffusionWeightedVolumeNode must be *normalized*.
        np.testing.assert_allclose(np.linalg.norm(g_parsed_normed - g_from_node), 0.0, atol=1e-15)

    # b value from the node attribute dictionary
    np.testing.assert_equal(parsed_nrrd.bvalue, float(dw_node.GetAttribute("DWMRI_b-value")))

    # 3) check gradients in the node attribute dictionary
    #    gradients must match the value on-disk.
    for i in range(0, slicer_numgrads):
        grad_key = "DWMRI_gradient_{:04d}".format(i)
        parsed_gradient = np.fromstring(parsed_nrrd.header[grad_key], count=3, sep=' ', dtype=np.float64)
        attr_gradient =   np.fromstring(dw_node.GetAttribute(grad_key), count=3, sep=' ', dtype=np.float64)

        np.testing.assert_array_almost_equal(parsed_gradient, attr_gradient, decimal=12,
                                             err_msg="NHDR gradient does not match gradient in node attribute dictionary")

    return (parsed_nrrd, dw_node)