# Python wrapping of plastimatch

**URL:** <https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722>\
**Category:** Development\
**Created:** [May 7, 2019, 3:17pm UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722 "2019-05-07T15:17:04Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![gcsharp](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/gcsharp/32/863_2.png) [@gcsharp](https://discourse.slicer.org/u/gcsharp)\
**Post date:** [May 7, 2019, 3:17pm UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722/1 "2019-05-07T15:17:04Z")

</div>

This morning I have been investigating python wrapping for plastimatch. It looks feasible to use the ITK wrapping method. Would this be a reasonable approach for eventually allowing python interaction within 3D Slicer? I’m a bit concerned because looking at the Slicer’s build it seems ITK itself is not wrapped and not available in Slicer python.

---

<div class="post-metadata">

**Author:** ![jcfr](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jcfr/32/17825_2.png) [@jcfr](https://discourse.slicer.org/u/jcfr)\
**Post date:** [May 7, 2019, 3:41pm UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722/2 "2019-05-07T15:41:44Z")

</div>

> investigating python wrapping for plastimatch

This is good to hear. Are you thinking about creating a dedicated “pythonic” API or a one-to-one mapping with the C++ one ?

> It looks feasible to use the ITK wrapping method

This is suitable for projects providing ITK filters and/or classes (or having functionality that could be wrapped in such a way).

If that makes sense, you could look at using the [GitHub - InsightSoftwareConsortium/ITKModuleTemplate: A template to start an ITK Module](https://github.com/InsightSoftwareConsortium/ITKModuleTemplate) as a starting point. See also [https://blog.kitware.com/python-packages-for-itk-modules/](https://blog.kitware.com/python-packages-for-itk-modules/)

> Would this be a reasonable approach for eventually allowing python interaction within 3D Slicer?

Since python packages distributed on [http://pypi.org/](http://pypi.org/) can now be installed on Linux, macOS and windows. This would work.

> Slicer’s build it seems ITK itself is not wrapped

This is correct, while there is an option called `Slicer_BUILD_ITKPython`, it not enabled by default.

> ITK itself […] not available in Slicer python

following the recent transition of Slicer to python 3.6, running `pip install itk` would allow you to use it.

### suggestions

You may want to look at using [GitHub - pybind/pybind11: Seamless operability between C++11 and Python](https://github.com/pybind/pybind11#readme) along [https://scikit-build.readthedocs.io](https://scikit-build.readthedocs.io)

---

<div class="post-metadata">

**Author:** ![gcsharp](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/gcsharp/32/863_2.png) [@gcsharp](https://discourse.slicer.org/u/gcsharp)\
**Post date:** [May 7, 2019, 6:57pm UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722/3 "2019-05-07T18:57:29Z")

</div>

Thank you for the great feedback! This is quite new area for me, and I’m still considering the best plan.

Both pybind or scikit-build look good. Do you have any idea which would be better? I note that SimpleITK seems to use scikit-build.

---

<div class="post-metadata">

**Author:** ![jcfr](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jcfr/32/17825_2.png) [@jcfr](https://discourse.slicer.org/u/jcfr)\
**Post date:** [May 7, 2019, 7:25pm UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722/4 "2019-05-07T19:25:10Z")

</div>

> Do you have any idea which would be better?

### ITKModuleTemplate

If you are already familiar with ITK and crafting a Plastimatch API built around ITK data structure is relevant, this would be a sensible approach.

You also be able to leverage the input of the community and wealth of knowledge shared on the ITK forum ([https://discourse.itk.org/](https://discourse.itk.org/))

The template would also give you CI and infrastructure for package distributions with no effort. @phcerdan works on a similar project to wrap the `proxTV` project and make it available as [GitHub - InsightSoftwareConsortium/ITKTotalVariation: External Module for Total Variation Algorithms, providing wrap for https://github.com/albarji/proxTV](https://github.com/InsightSoftwareConsortium/ITKTotalVariation) module

Cc: @thewtex

### pybind11

While this removes the need for tools like `swig`, you are still required to maintain the wrapping code. Note that I don’t have a lot of experience with it.

### suggested next steps

It may be sensible to craft a document listing the functionality and API you would like to expose to Python.

It would also be nice to listing the data structure that should not be deep-copied and are expected to be shared between VTK/ITK/etc … (if any)

### scikit-build.

This project streamlines the creation of python package (called wheel) for project using CMake. It is not responsible for any wrapping in itself and will be relevant for all approaches involving compilation of python modules.

---

<div class="post-metadata">

**Author:** ![thewtex](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/thewtex/32/32_2.png) [@thewtex](https://discourse.slicer.org/u/thewtex)\
**Post date:** [May 7, 2019, 9:27pm UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722/5 "2019-05-07T21:27:25Z")

</div>

Hi @gcsharp,

As @jcfr notes, the _ITKModuleTemplate_ may be the fastest way to get started. This avoids:

- Manually maintaining binding code (we analyize the headers with CastXML to generate the required SWIG interface files).
- The CI infrastructure to generate Windows, Linux, and macOS packages.
- The configuration to build the wheel with scikit-build and the post-processing steps to make distributable wheels.

The [ITK Software Guide](https://itk.org/ItkSoftwareGuide.pdf) has a section on writing the wrap interface files, but we would be happy to answer questions.

---

<div class="post-metadata">

**Author:** ![gcsharp](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/gcsharp/32/863_2.png) [@gcsharp](https://discourse.slicer.org/u/gcsharp)\
**Post date:** [May 7, 2019, 10:13pm UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722/6 "2019-05-07T22:13:34Z")

</div>

Got it. Thank you! I will do a pilot study.

I think for Slicer users interface with sitk might be more important than itk.

---

<div class="post-metadata">

**Author:** ![fedorov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/fedorov/32/14_2.png) [@fedorov](https://discourse.slicer.org/u/fedorov)\
**Post date:** [September 16, 2021, 3:46pm UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722/7 "2021-09-16T15:46:12Z")

</div>

@gcsharp do you have any updates on this topic?

We are using Plastimatch for developing use cases in [IDC](https://imaging.datacommons.cancer.gov/), and lacking such wrapper, Dennis Bontempi put together this as a workaround: [GitHub - AIM-Harvard/pyplastimatch: Dummy python plastimatch wrapper.](https://github.com/AIM-Harvard/pyplastimatch).

---

<div class="post-metadata">

**Author:** ![gcsharp](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/gcsharp/32/863_2.png) [@gcsharp](https://discourse.slicer.org/u/gcsharp)\
**Post date:** [September 20, 2021, 7:24pm UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722/8 "2021-09-20T19:24:42Z")

</div>

Regrettably, I have no progress. Would the method used in your/Paolo’s approach be good?

---

<div class="post-metadata">

**Author:** ![fedorov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/fedorov/32/14_2.png) [@fedorov](https://discourse.slicer.org/u/fedorov)\
**Post date:** [September 21, 2021, 1:23am UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722/9 "2021-09-21T01:23:43Z")

</div>

I will let Dennis and @PaoloZaffino respond with their thoughts. I think what would be ideal is to be able to install those wrappers with `pip`. Meanwhile, maybe Plastimatch documentation can include pointers to the existing wrappers, to save effort for the next developer?

---

<div class="post-metadata">

**Author:** ![denbonte](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/denbonte/32/12730_2.png) [@denbonte](https://discourse.slicer.org/u/denbonte)\
**Post date:** [September 21, 2021, 8:12am UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722/10 "2021-09-21T08:12:02Z")

</div>

Thanks @fedorov for the mention! (I actually remember looking at this thread while deciding what to do for the dummy wrapper - so hopefully this will be able to help someone else!)

@gcsharp what I’ve implemented on the fly (the plan is to expand it a bit, to make sure at least all the “common” operations can be launched from python scripts) is really simple and quite close to what Paolo did back in the days. The only reason I decided to implement “my own” is that I feared Paolo’s version could be outdated (with respect to Plastimatch). I also wanted to make sure a couple of features useful for the use cases were there, and forking Paolo’s implementation to then customise it didn’t look as fun 😃

Basically, it’s as simple as calling Plastimatch from python exploiting `subprocess` (any library for process management will do), and adding some other handy functionalities in the meantime (e.g., logging all the operations, and a few other scripts for visualisation etc.). This not only allows to run Plastimatch functions directly from your python scripts (of course, abstracting the OS - although I must report I have tested this exclusively on Linux), but also make use of other python functionalities that can help you process a great amount of data in less time. For instance, I have used the Plastimatch wrapper to run DICOM to NRRD conversion of hundreds/thousands of patients in parallel (with the performance/time requirements scaling almost linearly with the number of cores). In some cases, I’ve done so and then applied some pre-processing on the fly (for a total of a dozen lines of code), processing in a few minutes a dataset that would have required hours otherwise (e.g., DICOM to NRRD conversion scripting everything from bash, one subject at a time, then read the NRRD files, preprocess them exploiting python, and save them back).

The multiprocessing code I’m referring to here will be made available super soon (a matter of a couple of weeks if not less, I hope!) as part of the development of the use cases Andrey mentioned. In case you don’t want to wait though, here is an idea how you could script it using the [dummy PyPlastimatch wrapper](https://github.com/AIM-Harvard/pyplastimatch):

```auto
import os
import tqdm
import multiprocessing
import utils.pyplastimatch as pypla

# pat_config is a dictionary storing basic I/O and config info for the conversion 
def run_core(pat_config):

  # patient subfolder where all the preprocessed data will be stored
  if not os.path.exists(PAT_DIR): os.mkdir(PAT_DIR)
   
  verbose = pat_config["verbose"]
  
  # logfile for the plastimatch conversion
  LOGFILE = os.path.join(PAT_DIR, pat + '_pypla.log')
    
  # DICOM CT to NRRD conversion
  if not os.path.exists(CT_NRRD_PATH):
    convert_args_ct = {"input" : PATH_TO_DICOM_DIR,
                       "output-img" : PATH_TO_NRRD_CT}
    
    # clean old log file if it exist
    if os.path.exists(log_file_path_nrrd): os.remove(LOGFILE)
    
    pypla.convert(verbose = verbose, path_to_log_file = LOGFILE, **convert_args_ct)

```

```auto
def main(config):

  cpu_cores = config["cpu_cores"]

  if use_multiprocessing:
    pool = multiprocessing.Pool(processes = cpu_cores)

  """
  write here the code to populate "pat_config_list", a list of dictionaries storing
  the information used by the "run_core" function for the processing (e.g., paths, verbosity, etc.)
  """

  for _ in tqdm.tqdm(pool.imap_unordered(run_core, pat_config_list), total = len(pat_dict_list_mp)):
    pass

```

```auto
if __name__ == ' __main__':

  """
  Parse the config file for the "main" function here!
  """

```

(sorry if this is not a MWE - if you want to test-run your own code based on this and have problems, do reach out! As I said, such scripts and all the details will be made available as part of the on-going effort at IDC!)

P.S.

> [@fedorov](#):
>
> I think what would be ideal is to be able to install those wrappers with `pip` . Meanwhile, maybe Plastimatch documentation can include pointers to the existing wrappers, to save effort for the next developer?

That is the plan indeed (to have it documented and available through pip)!

---

<div class="post-metadata">

**Author:** ![PaoloZaffino](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/paolozaffino/32/81052_2.png) [@PaoloZaffino](https://discourse.slicer.org/u/PaoloZaffino)\
**Post date:** [September 21, 2021, 9:21am UTC](https://discourse.slicer.org/t/python-wrapping-of-plastimatch/6722/11 "2021-09-21T09:21:25Z")

</div>

Hi all,  
glad to hear my code “inspired” someone 🙂  
I agree with @denbonte , the idea is to run the executable via the python os module.  
It’s not strictly a wrapper, rather an additional layer.

My version was written for plastimatch at that time, now some commands have changed and it’s possible to have some errors (I didn’t update it).

In SlicerRT we implemented a direct bridge between the plastimatch registration algorithm and the Slicer environment. That is not an addition layer, but a real connection (Slicer infrastructure helped a lot to achieve this). After that, I think other commands have been exposed in slicer (eg DRR).

Great to hear it can be installed via pip!  
Let me know if I can help, it’s always a pleasure working on plastimatch!

Best,  
Paolo
