예제 #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)
예제 #2
0
 def test_create_voi_cyl(self):
     logger.info("Creating CT cube from path " + self.cube000)
     c = pt.CtxCube()
     c.read(self.cube000)
     logger.info("Generating and adding cylinder VOI")
     v = create_cylinder(c, name="cube2", center=[10, 10, 10], radius=4, depth=8)
     self.assertEqual(v.number_of_slices(), 3)
예제 #3
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__)
    args = parser.parse_args(args)

    basename = args.ctx_basename

    # import DICOM
    dcm = pt.dicomhelper.read_dicom_folder(args.dicom_folder)
    c = pt.CtxCube()
    c.read_dicom(dcm)

    c.write_trip_header(basename + ".hed")
    c.write_trip_data(basename + ".ctx")
    return 0
예제 #4
0
 def test_create_voi_cube(self):
     logger.info("Creating CT cube from path " + self.cube000)
     c = pt.CtxCube()
     c.read(self.cube000)
     logger.info("Generating and adding cube VOI")
     v = create_cube(c, name="cube1", center=[10, 10, 10], width=4, height=4, depth=8)
     self.assertEqual(v.number_of_slices(), 3)
예제 #5
0
def load_ct_cube(filename):
    """ loads the CT cube

    :params str filename: path to filename which must be loaded
    :returns: a CtxCube object and a str containing the path to the basename.
    """

    if not filename:
        logger.warn("Empty CT cube filename")
        return None, None

    logger.info("Reading " + filename)
    ctx_header, _ = pt.CtxCube.parse_path(filename)

    if ctx_header is None:
        logger.warn("Path " + filename +
                    " doesn't seem to point to proper CT cube")
        return None, None

    basename_cube = os.path.splitext(ctx_header)[0]
    c = pt.CtxCube()
    c.read(filename)
    logger.info("CT cube shape" + str(c.cube.shape))

    cmax = c.cube.max()
    cmin = c.cube.min()
    logger.info("CT min, max values: {:d} {:d}".format(cmin, cmax))

    return c, basename_cube
예제 #6
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
예제 #7
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()
예제 #8
0
 def test_create_voi_2(self):
     logger.info("Testing cube from path " + self.cube000)
     c = pt.CtxCube()
     c.read(self.cube000)
     logger.info("Generating VOI from cube")
     v = create_voi_from_cube(c, name="cube4")
     # TODO check if v was created correctly
     self.assertEqual(v.number_of_slices(), 0)
예제 #9
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
예제 #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
        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()
예제 #11
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
예제 #12
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
예제 #13
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()
예제 #14
0
파일: cubeslice.py 프로젝트: ljelen/pytrip
def load_ct_cube(filename):
    """ loads the CT cube

    :params str filename: path to filename which must be loaded
    :returns: a CtxCube object and a str containing the path to the basename.
    """

    if not filename:
        logger.warning("Empty CT cube filename")
        return None, None

    logger.info("Reading " + filename)
    c = pt.CtxCube()
    c.read(filename)
    logger.info("CT cube shape" + str(c.cube.shape))

    cmax = c.cube.max()
    cmin = c.cube.min()
    logger.info("CT min, max values: {:d} {:d}".format(cmin, cmax))

    return c, c.basename
예제 #15
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()
예제 #16
0
#
#    You should have received a copy of the GNU General Public License
#    along with PyTRiP98.  If not, see <http://www.gnu.org/licenses/>.
#
"""
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()
예제 #17
0
    def test_create_voi_sphere(self):
        logger.info("Creating CT cube from path " + self.cube000)
        c = pt.CtxCube()
        c.read(self.cube000)
        logger.info("Generating and adding sphere VOI")
        v = create_sphere(c, name="cube3", center=[10, 10, 10], radius=8)
        self.assertEqual(v.number_of_slices(), 6)

        logger.info("Checking Voi vdx_string method")
        self.assertGreater(len(v.vdx_string()), 1)

        logger.info("Checking Voi get_slice_at_pos method, non-existent slice")
        self.assertIsNone(v.get_slice_at_pos(137))

        logger.info("Checking Voi get_slice_at_pos method, good slice")
        s = v.get_slice_at_pos(11)
        self.assertIsNotNone(s)

        logger.info("Checking Slice vdx_string method")
        self.assertGreater(len(s.vdx_string()), 1)

        logger.info("Checking Slice number_of_contours method")
        self.assertEqual(s.number_of_contours(), 1)

        logger.info("Checking Contour create_dicom_contours method")
        dicom_cont = s.create_dicom_contours(v.cube.create_dicom())
        self.assertEqual(len(dicom_cont), 1)

        contour = s.contours[0]

        logger.info("Checking Contour calculate_center method")
        center, area = contour.calculate_center()
        self.assertAlmostEqual(center[0], 10.0)
        self.assertAlmostEqual(center[1], 10.0)
        self.assertAlmostEqual(center[2], 12.0)  # TODO why 12 ?
        self.assertGreater(area, 100.0)

        logger.info("Checking Contour vdx_string method")
        self.assertGreater(len(contour.vdx_string()), 1)

        logger.info("Checking Contour number_of_points method")
        self.assertEqual(contour.number_of_points(), 99)

        logger.info("Checking Contour has_childs method")
        self.assertFalse(
            contour.has_childs())  # TODO why doesn't have children ?
        contour.print_child(level=0)

        logger.info("Test of Voi get_min_max method")
        s_min, s_max = v.get_min_max()
        self.assertIsNotNone(s_min)
        self.assertIsNotNone(s_max)
        # TODO check why get_min_max returns tuple, not a number
        self.assertEqual(s_max[2], 18.0)
        self.assertEqual(s_min[2], 3.0)

        logger.info(
            "Subsequent test of Voi get_min_max method, as it modifies the object"
        )
        s_min, s_max = v.get_min_max()
        self.assertIsNotNone(s_min)
        self.assertIsNotNone(s_max)
        # TODO check why get_min_max returns tuple, not a number
        self.assertEqual(s_max[2], 18.0)
        self.assertEqual(s_min[2], 3.0)

        logger.info("Test of Voi get_2d_slice method (sagittal)")
        s2 = v.get_2d_slice(plane=pt.Voi.sagittal, depth=10.0)
        self.assertIsNotNone(s2)

        logger.info("Test of Voi get_2d_slice method (coronal)")
        s3 = v.get_2d_slice(plane=pt.Voi.coronal, depth=5.0)
        self.assertIsNotNone(s3)

        logger.info("Test of Voi get_2d_projection_on_basis method")
        v.get_2d_projection_on_basis(basis=((1, 0, 0), (0, 2, 0)))

        logger.info("Test of Voi create_point_tree method")
        v.create_point_tree()
        self.assertIsNotNone(v.points)
        self.assertEqual(len(v.points), 496)

        logger.info("Test of Voi get_row_intersections method")
        isec = v.get_row_intersections(pos=(10, 10, 9))
        self.assertIsNotNone(isec)
        self.assertEqual(len(isec), 2)

        logger.info("Test of Voi get_voi_cube method")
        vc = v.get_voi_cube()
        self.assertIsNotNone(vc)

        center_pos = v.calculate_center()
        self.assertAlmostEqual(center_pos[0], 10.0)
예제 #18
0
logger = logging.getLogger(__name__)
logging.basicConfig(
    level=logging.INFO)  # give some output on what is going on.

# 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
예제 #19
0
 def open_ctx(self, path):
     ctx = pt.CtxCube()
     ctx.read(path)
     self.ctx = ctx
     self.name = ctx.basename