Example #1
0
    def test_exec(self):
        """ Prepare and execute a dry-run test using the Executer.
        """
        logger.info("Test norun TRiP98 execution")

        logger.debug("Load CtxCube {:s}".format(self.ctx_path))
        c = pt.CtxCube()
        c.read(self.ctx_path)

        logger.debug("Load VdxCube {:s}".format(self.vdx_path))
        v = pt.VdxCube(c)
        v.read(self.vdx_path)

        print(v.get_voi_names())

        plan = pte.Plan(basename=self.patient_name)
        self.assertIsNotNone(plan)

        plan.ddd_dir = "~/TRiP98/base/DATA/DDD/12C/RF3MM/*"
        plan.spc_dir = "~/TRiP98/base/DATA/SPC/12C/RF3MM/*"
        plan.sis_path = "~/TRiP98/base/DATA/SIS/12C.sis"
        plan.hlut_path = "~/TRiP98/base/DATA/HLUT/19990218.hlut"
        plan.dedx_path = "~/TRiP98/base/DATA/DEDX/20040607.dedx"
        plan.working_dir = "."  # working dir must exist.

        # add the target voi to the plan
        plan.voi_target = v.get_voi_by_name('target')

        plan.rifi = 3.0
        plan.bolus = 0.0
        plan.offh2o = 1.873

        # create a field and add it to the plan
        field = pte.Field()
        self.assertIsNotNone(field)
        field.basename = self.patient_name
        field.gantry = 10.0
        field.couch = 90.0  # degrees
        field.fwhm = 4.0  # spot size in [mm]
        field.projectile = 'C'

        plan.fields.append(field)

        # flags for what output should be generated
        plan.want_phys_dose = True
        plan.want_bio_dose = False
        plan.want_dlet = True
        plan.want_rst = False

        t = pte.Execute(c, v)
        self.assertIsNotNone(t)
        t.trip_bin_path = self.trip_path
        print(self.trip_path)
        if os.name != 'nt':  # skip running fake TRiP98 on Windows as it is not supported there
            t.execute(
                plan, False
            )  # setup and make a dry-run, since TRiP98 is not installed.

        executer_str = str(t)
        self.assertGreater(len(executer_str), 1)
Example #2
0
    def test_read_with_ct(self):
        logger.info("Creating CT cube from path " + self.cube000)
        c = pt.CtxCube()
        c.read(self.cube000)
        v = pt.VdxCube("", c)
        logger.info("Adding VDX from path " + self.vdx)
        v.read(self.vdx)

        logger.info("Checking len of get_voi_names")
        self.assertEqual(len(v.get_voi_names()), 2)

        logger.info("Checking get_voi_names")
        self.assertEqual(v.get_voi_names(), ['target', 'voi_empty'])

        logger.info("Checking number of vois")
        self.assertEqual(v.number_of_vois(), 2)

        logger.info("Checking Vdx str method")
        self.assertEqual(str(v), "target&voi_empty")

        logger.info("Checking Vdx write_to_voxel method")
        fd, outfile = tempfile.mkstemp()
        v.write_to_voxel(outfile)
        self.assertTrue(os.path.exists(outfile))
        logger.info("Checking if output file " + outfile + " is not empty")
        self.assertGreater(os.path.getsize(outfile), 1)
        os.close(fd)  # Windows needs it
        os.remove(outfile)

        logger.info("Checking Vdx write method")
        fd, outfile = tempfile.mkstemp()
        v.write(outfile)
        self.assertTrue(os.path.exists(outfile))
        logger.info("Checking if output file " + outfile + " is not empty")
        self.assertGreater(os.path.getsize(outfile), 1)
        os.close(fd)  # Windows needs it
        os.remove(outfile)

        logger.info("Checking if getting non-existend VOI throws an exception")
        self.assertRaises(InputError, v.get_voi_by_name, '')

        logger.info("Checking Vdx get_voi_by_name method")
        target_voi = v.get_voi_by_name('target')
        self.assertEqual(target_voi.get_name(), 'target')
        self.assertEqual(target_voi.get_thickness(), 3)
        self.assertEqual(target_voi.number_of_slices(), 18)

        logger.info("Checking Voi get_3d_polygon method")
        self.assertIsNotNone(target_voi.get_3d_polygon())

        # TODO add some assertions
        target_voi.get_2d_projection_on_basis(basis=((1, 0, 0), (0, 2, 0)))

        # TODO add some assertions
        vc = target_voi.get_voi_cube()
        self.assertTrue(vc.is_compatible(c))

        # TODO add some assertions
        target_voi.create_point_tree()
Example #3
0
def main(args=sys.argv[1:]):
    """ Main function for trip2dicom.py
    """
    # parse arguments
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "ctx_data",
        help="location of CT file (header or data) in TRiP98 format",
        type=str)
    parser.add_argument("outputdir",
                        help="write resulting DICOM files to this directory",
                        type=str)
    parser.add_argument("-v",
                        "--verbosity",
                        action='count',
                        help="increase output verbosity",
                        default=0)
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version=pt.__version__)
    parsed_args = parser.parse_args(args)

    if parsed_args.verbosity == 1:
        logging.basicConfig(level=logging.INFO)
    elif parsed_args.verbosity > 1:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig()

    output_folder = parsed_args.outputdir

    _, data_file_name = pt.CtxCube.parse_path(parsed_args.ctx_data)
    data_file_path = pt.CtxCube.discover_file(data_file_name)

    if not os.path.exists(data_file_path):
        logger.error("CTX file missing")
        return 1

    logger.info("Convert CT images...")
    c = pt.CtxCube()
    c.read(data_file_name)

    if not os.path.exists(output_folder):
        os.makedirs(output_folder)
    c.write_dicom(output_folder)

    ctx_basename = os.path.splitext(data_file_path)[0]
    ctx_path = ctx_basename + ".vdx"
    if os.path.exists(ctx_path):
        logger.info("Convert VDX structures...")
        v = pt.VdxCube(cube=c)
        v.read(ctx_path)
        v.write_dicom(output_folder)
    else:
        logger.info("No VDX data found for conversion.")

    logger.info("Done")
    return 0
def main(args=sys.argv[1:]):
    """ Main function for dicom2trip.py
    """
    # parse arguments
    parser = argparse.ArgumentParser()
    parser.add_argument("dicom_folder",
                        help="location of folder with DICOM files",
                        type=str)
    parser.add_argument("ctx_basename",
                        help="basename of output file in TRiP98 format",
                        type=str)
    parser.add_argument("-v",
                        "--verbosity",
                        action='count',
                        help="increase output verbosity",
                        default=0)
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version=pt.__version__)
    parsed_args = parser.parse_args(args)

    if parsed_args.verbosity == 1:
        logging.basicConfig(level=logging.INFO)
    elif parsed_args.verbosity > 1:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig()

    basename = parsed_args.ctx_basename

    # import DICOM
    dcm = pt.dicomhelper.read_dicom_folder(parsed_args.dicom_folder)

    if 'images' in dcm:
        c = pt.CtxCube()
        c.read_dicom(dcm)
        logger.info("Write CtxCube header... {}".format(
            basename + pt.CtxCube.header_file_extension))
        c.write_trip_header(basename + pt.CtxCube.header_file_extension)
        logger.info("Write CtxCube...        {}".format(
            basename + pt.CtxCube.data_file_extension))
        c.write_trip_data(basename + pt.CtxCube.data_file_extension)
    else:
        logger.warning("No CT data found in {}".format(
            parsed_args.dicom_folder))
        c = None

    if 'rtss' in dcm:
        logger.info("Write VdxCube...        {}".format(basename + ".vdx"))
        vdx_cube = pt.VdxCube(cube=c)
        vdx_cube.read_dicom(dcm)
        vdx_cube.write_trip(basename + ".vdx")
    else:
        logger.warning("No RTSTRUCT data found in {}".format(
            parsed_args.dicom_folder))

    return 0
Example #5
0
    def open_voxelplan(self, ctx_path):
        """
        Open a Voxelplan type CTX and possibly a VDX if one exists with the same basename.
        """

        model = self.model  # local object of plot_model
        pm = self.model.plot  # local object of plot_model

        # Get the CTX cubes first
        logger.debug("Open CTX {:s}".format(ctx_path))
        ctx = pt.CtxCube()
        ctx.read(ctx_path)

        # update model
        model.ctx = ctx
        pm.ctx = ctx

        # Point to center of slices for default plotting
        pm.xslice = int(ctx.dimx * 0.5)
        pm.yslice = int(ctx.dimy * 0.5)
        pm.zslice = int(ctx.dimz * 0.5)
        # TODO: we assume transversal view as start. fixme.
        pm.slice_pos_idx = int(ctx.dimz * 0.5)

        # show file basename in window title
        self.app.setWindowTitle("PyTRiPGUI - {}".format(ctx.basename))

        # Check if there is a VDX file with the same basename
        logger.debug("Check for VDX")
        from pytrip.util import TRiP98FilePath
        _d = TRiP98FilePath(
            ctx_path,
            ctx).dir_basename  # returns full path, but without suffix.
        vdx_path = _d + ".vdx"

        logger.debug("Check if '{:s}' exists...".format(vdx_path))

        # If VDX is there, load it.
        if os.path.isfile(vdx_path):
            logger.debug("   Open '{:s}'".format(vdx_path))
            vdx = pt.VdxCube(self.model.ctx)
            vdx.read(vdx_path)

            # update model
            model.vdx = vdx
            pm.vdx = vdx

            # enable all VOIs to be plotted
            for voi in vdx.vois:
                pm.vois.append(voi)

        # add cube to the treeviews
        self.tree.update_tree()

        # update the canvas
        self.plot.update_viewcanvas()
Example #6
0
    def open_dicom(self, path):
        self.dcm = pt.dicomhelper.read_dicom_dir(path)

        if 'images' in self.dcm:
            self.ctx = pt.CtxCube()
            self.ctx.read_dicom(self.dcm)
            self.name = self.ctx.basename

        if 'rtss' in self.dcm:
            self.vdx = pt.VdxCube(self.ctx)
            self.vdx.read_dicom(self.dcm)
            self.name = self.vdx.basename
Example #7
0
def main(args=sys.argv[1:]):
    """ Main function for trip2dicom.py
    """
    # parse arguments
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "ctx_data",
        help="location of CT file (header or data) in TRiP98 format",
        type=str)
    parser.add_argument("outputdir",
                        help="Write resulting DICOM files to this directory.",
                        type=str)
    parser.add_argument("-v",
                        "--verbosity",
                        action='count',
                        help="increase output verbosity",
                        default=0)
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version=pt.__version__)
    args = parser.parse_args(args)

    output_folder = args.outputdir

    _, data_file_name = pt.CtxCube.parse_path(args.ctx_data)
    data_file_path = pt.CtxCube.discover_file(data_file_name)

    if not os.path.exists(data_file_path):
        print("CTX file missing")
        return 1

    print("Convert CT images")
    c = pt.CtxCube()
    c.read(data_file_name)
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)
    c.write_dicom(output_folder)

    ctx_basename = os.path.splitext(data_file_path)[0]
    ctx_path = ctx_basename + ".vdx"
    if os.path.exists(ctx_path):
        print("Convert structures")
        v = pt.VdxCube(content="", cube=c)
        v.read(ctx_path)
        v.write_dicom(output_folder)
    print("Done")
    return 0
Example #8
0
    def test_mcnamara_cube(self):
        """ McNamara test on real cubes.
        """
        dose = pt.DosCube()
        dose.read(self.cube001)
        let = pt.LETCube()
        let.read(self.cube001)
        v = pt.VdxCube(dose)
        logger.info("Adding VDX from path " + self.vdx)
        v.read(self.vdx)

        # increasing LET should increase RBE
        abx = 10.0  # alpha/beta ratio for x-rays [Gy]
        rbe1 = rbe_mcnamara(dose.cube, let.cube, abx)
        rbe2 = rbe_mcnamara(dose.cube, let.cube, 2.0)

        self.assertTrue(np.all(rbe2 >= rbe1))  # RBE goes up as abx goes down.
Example #9
0
    def open_dicom(self, ddir):
        """
        Open a DICOM directory. Images must be present. RTSS is optional.
        """
        model = self.model  # local object of plot_model
        pm = self.model.plot  # local object of plot_model

        logger.debug("open dicom '{}'".format(ddir))
        dcm = pt.dicomhelper.read_dicom_dir(ddir)

        ctx = None
        vdx = None

        if 'images' in dcm:
            logger.debug("Found images in DICOM")
            ctx = pt.CtxCube()
            ctx.read_dicom(dcm)

            model.ctx = ctx
            pm.ctx = ctx
        else:
            from pytripgui.view.dialogs import MyDialogs
            MyDialogs.show_error(
                "No images found in selected DICOM directory.")
            return

        if 'rtss' in dcm:
            logger.debug("Found rtss in DICOM")
            vdx = pt.VdxCube(cube=ctx)
            vdx.read_dicom(dcm)
            for voi in vdx.vois:
                pm.vois.append(voi)

            # This is a workaround for pytrip issue #455 https://github.com/pytrip/pytrip/issues/455
            vdx.basename = "basename"

            model.vdx = vdx
            pm.vdx = vdx

        # TODO: RTplan data

        # add cube to the treeviews
        self.tree.update_tree()

        # update the canvas
        self.plot.update_viewcanvas()
Example #10
0
    def open_voxelplan(self, ctx_path):
        """
        Open a Voxelplan type CTX and possibly a VDX if one exists with the same basename.
        """

        model = self.model  # local object of plot_model

        # Get the CTX cubes first
        logger.debug("Open CTX {:s}".format(ctx_path))
        ctx = pt.CtxCube()
        ctx.read(ctx_path)

        # update model
        model.ctx = ctx
        self.model.one_plot.set_ctx(ctx)

        # show file basename in window title
        self.app.setWindowTitle("PyTRiPGUI - {}".format(ctx.basename))

        # Check if there is a VDX file with the same basename
        logger.debug("Check for VDX")
        from pytrip.util import TRiP98FilePath
        _d = TRiP98FilePath(
            ctx_path,
            ctx).dir_basename  # returns full path, but without suffix.
        vdx_path = _d + ".vdx"

        logger.debug("Check if '{:s}' exists...".format(vdx_path))

        # If VDX is there, load it.
        if os.path.isfile(vdx_path):
            logger.debug("   Open '{:s}'".format(vdx_path))
            vdx = pt.VdxCube(self.model.ctx)
            vdx.read(vdx_path)

            # update model
            model.vdx = vdx

        # update the canvas
        self.plot.update_viewcanvas()
Example #11
0
This example shows how to use contours to select volume of interests inside a CTX cube. The VOI is then manipulated.
"""
import pytrip as pt

# first define some paths and other important parameters
ctx_path = "/home/bassler/Projects/CTdata/TST000/TST000000.ctx"
vdx_path = "/home/bassler/Projects/CTdata/TST000/TST000000.vdx"
my_target_voi = "GTV"

# load CT cube
my_ctx = pt.CtxCube()
my_ctx.read(ctx_path)

# load VOIs
my_vdx = pt.VdxCube(
    my_ctx
)  # my_vdx is the object which will hold all volumes of interest and the meta information
my_vdx.read(vdx_path)  # load the .vdx file
print(my_vdx.get_voi_names())  # show us all VOIs found in the .vdx file

# Select the requested VOI from the VdxCube object
target_voi = my_vdx.get_voi_by_name(my_target_voi)

# get_voi_cube() returns a DosCube() object, where all voxels inside the VOI holds the value 1000, and 0 elsewhere.
voi_cube = target_voi.get_voi_cube()

# Based on the retrieved DosCube() we calculate a three dimensional mask object,
# which assigns True to all voxels inside the Voi, and False elsewhere.
mask = (voi_cube.cube == 1000)

# "The mask object and the CTX cube have same dimensions (they are infact inherited from the same top level class).
Example #12
0
 def test_read_solo(self):
     logger.info("Checking reading VdxCube without CT cube loaded")
     v = pt.VdxCube()
     v.read(self.vdx)
Example #13
0
 def open_vdx(self, path):
     vdx = pt.VdxCube(self.ctx)
     vdx.read(path)
     self.vdx = vdx
     if self.name != vdx.basename:
         logger.error("CTX | VDX patient name not match")
Example #14
0
def main(args=sys.argv[1:]):
    """ Main function for dvhplot.py
    """

    # parse arguments
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "cube",
        help="Path to input cube. May also be a .dos or dosemlet.dos cube",
        type=str)
    parser.add_argument("vdx",
                        help="Path to .vdx file holding the structures",
                        type=str)
    parser.add_argument(
        "rois",
        nargs="?",
        help=
        "Comma-seperated list for ROIs to be analyzed. If not set, print list.",
        type=str,
        default=None)
    parser.add_argument("-d",
                        "--dose",
                        type=float,
                        dest='dose',
                        metavar='dose',
                        help="Taget dose in [Gy]",
                        default=-1.0)
    parser.add_argument("-o",
                        "--output",
                        type=str,
                        dest='output',
                        metavar='filename',
                        help="Don't open GUI, save to filename instead.",
                        default=None)
    parser.add_argument("-l",
                        "--legend",
                        dest='legend',
                        default=False,
                        action='store_true',
                        help="Print legend box")
    parser.add_argument("-v",
                        "--verbosity",
                        action='count',
                        help="increase output verbosity",
                        default=0)
    parser.add_argument('-V',
                        '--version',
                        action='version',
                        version=pt.__version__)
    parsed_args = parser.parse_args(args)

    if parsed_args.verbosity == 1:
        logging.basicConfig(level=logging.INFO)
    elif parsed_args.verbosity > 1:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig()

    path_cube = parsed_args.cube
    path_vdx = parsed_args.vdx
    rois_arg = parsed_args.rois
    dose = parsed_args.dose
    legend = parsed_args.legend
    outfile = parsed_args.output

    # there are some cases when this script is run on systems without DISPLAY variable being set
    # in such case matplotlib backend has to be explicitly specified
    # despite the fact interleaving imports with code lines is discouraged, we do it here
    # as it depends on the users options
    if outfile:
        matplotlib.use('Agg')
    import matplotlib.pyplot as plt

    d = pt.DosCube()
    d.read(path_cube)

    v = pt.VdxCube(d)
    v.read(path_vdx)

    vois = v.get_voi_names()

    if not rois_arg:
        print("Available ROIs:")
        for voi in vois:
            print("'{:s}'".format(voi))
        return

    rois = rois_arg.split(",")

    if d.type == 'DOS':
        if dose < 0.0:
            plt.xlabel("Dose [%]")
        else:
            plt.xlabel("Dose [Gy]")
    elif d.type == 'LET':
        plt.xlabel("LET [keV/um]")
    else:
        plt.xlabel("")  # unknown data cube

    for roi in rois:
        logger.info("Processing ROI '{:s}'...".format(roi))
        voi = v.get_voi_by_name(roi)
        x, y = volume_histogram(d.cube, voi)
        if d.type == 'DOS':
            if dose < 0.0:
                x = x * 0.1
            else:
                x = x * 0.001 * dose

        plt.plot(x, y, label=roi)

    plt.ylabel("Volume [%]")
    plt.grid(True)
    if legend:
        plt.legend()

    if outfile:
        plt.savefig(outfile)
    else:
        plt.show()
Example #15
0
def main(args=sys.argv[1:]):
    """ Main function for dvhplot.py
    """

    # parse arguments
    parser = argparse.ArgumentParser()
    parser.add_argument("cube", help="path to input cube. May also be a .dos or dosemlet.dos cube", type=str)
    parser.add_argument("vdx", help="path to .vdx file holding the structures", type=str)
    parser.add_argument("rois", nargs="?", help="comma-seperated list for ROIs to be analyzed. If not set, print list.",
                        type=str, default=None)
    parser.add_argument("-d", "--dose", type=float, dest='dose', metavar='dose',
                        help="target dose in [Gy] (if target_dose is unavailable in cube)", default=None)
    parser.add_argument("-o", "--output", type=str, dest='output', metavar='filename',
                        help="don't open GUI, save figure to <filename> instead.", default=None)
    parser.add_argument("-t", "--tofile", type=str, dest='tofile', metavar='filename',
                        help="save histogram data to <filename>.", default=None)
    parser.add_argument("-l", "--legend", dest='legend', default=False, action='store_true',
                        help="print legend box")
    parser.add_argument("-v", "--verbosity", action='count', help="increase output verbosity", default=0)
    parser.add_argument('-V', '--version', action='version', version=pt.__version__)
    parsed_args = parser.parse_args(args)

    if parsed_args.verbosity == 1:
        logging.basicConfig(level=logging.INFO)
    elif parsed_args.verbosity > 1:
        logging.basicConfig(level=logging.DEBUG)
    else:
        logging.basicConfig()

    path_cube = parsed_args.cube
    path_vdx = parsed_args.vdx
    rois_arg = parsed_args.rois
    dose = parsed_args.dose
    legend = parsed_args.legend
    outfile = parsed_args.output
    tofile = parsed_args.tofile

    # there are some cases when this script is run on systems without DISPLAY variable being set
    # in such case matplotlib backend has to be explicitly specified
    # despite the fact interleaving imports with code lines is discouraged, we do it here
    # as it depends on the users options
    if outfile:
        matplotlib.use('Agg')
    import matplotlib.pyplot as plt

    d = pt.DosCube()
    d.read(path_cube)

    v = pt.VdxCube(d)
    v.read(path_vdx)

    vois = v.voi_names()

    if not rois_arg:
        print("Available ROIs:")
        for voi in vois:
            print("'{:s}'".format(voi))
        return

    rois = rois_arg.split(",")

    for roi in rois:
        voi = v.get_voi_by_name(roi)
        vh = VolHist(d, voi, target_dose=dose)

        plt.xlabel(vh.xlabel)
        plt.ylabel(vh.ylabel)
        plt.plot(vh.x, vh.y, label=vh.name)

    plt.ylabel("Volume [%]")
    plt.grid(True)
    if legend:
        plt.legend()

    if tofile:
        logger.info("Write {}".format(tofile))
        f = open(tofile, "w+")
        for _x, _y in zip(vh.x, vh.y):
            f.write("{:.3f} {:.3f}\n".format(_x, _y))
        f.close()

    if outfile:
        plt.savefig(outfile)
    else:
        plt.show()
Example #16
0
# Fist we specify the directory where all our files are:
wdir = "/home/bassler/test"

# In TRiP, the patient "TST000" would typically carry the filename "TST000000"
patient_name = "TST000000"

# so we can construc the paths to the CTX and VDX files like this:
ctx_path = os.path.join(wdir, patient_name + ".ctx")
vdx_path = os.path.join(wdir, patient_name + ".vdx")

# Next we load the CT cube:
c = pt.CtxCube()
c.read(ctx_path)

# And load the contours
v = pt.VdxCube(c)
v.read(vdx_path)

# we may print all contours found in the Vdx file, if we want to
print(v.get_voi_names())

# Ok, we have the Contours and the CT cube ready. Next we must prepare a plan.
# We may choose any basename for the patient. All output files will be named using
# this basename.
plan = pte.Plan(basename=patient_name)

# We need to specify where the kernel files can be found. The location may depend on the ion we
# wnat to treat with. This example is for carbon ions:
plan.ddd_dir = "/home/bassler/TRiP98/base/DATA/DDD/12C/RF3MM/*"
plan.spc_dir = "/home/bassler/TRiP98/base/DATA/SPC/12C/RF3MM/*"
plan.sis_path = "/home/bassler/TRiP98/base/DATA/SIS/12C.sis"