Giter VIP home page Giter VIP logo

Comments (18)

SimonBiggs avatar SimonBiggs commented on July 23, 2024

Also, if you were open to it, part of what I would be hoping to achieve would be to make a Python wrapper around this library, and upload your package to the Python Package Index.

There is an amazing orchestration tool called CI Build Wheel (https://cibuildwheel.readthedocs.io/en/stable/) that can run with GitHub actions and create PyPI builds and releases across the range of OSes and architectures.

I'd be more than happy to build out the Python wrapper to DICOMautomation, as well as set up the automated build and release pipelines, and submit them as pull requests to your repo here.


As a first pass, the Python wrapper could be "DICOM in / DICOM out" and expose two functions that do one thing each:

import pydicom
import dicomautomaton

original_structure_dataset = pydicom.dcmread("path/to/dicom-rt-structure.dcm")
dilated_structure_dataset = dicomautomaton.dilate(
    dataset=original_structure_dataset, 
    structure_names=["list", "of", "structure", "names"], 
    distance=3
)
eroded_structure_dataset = dicomautomaton.erode(
    dataset=original_structure_dataset, 
    structure_names=["another", "list", "of", "names"], 
    distance=1
)

Or alternatively, a better API might be to collapse it into one function and mimic Shapely's buffer API:

import pydicom
import dicomautomaton

original_structure_dataset = pydicom.dcmread("path/to/dicom-rt-structure.dcm")
eroded_structure_dataset = dicomautomaton.buffer(
    dataset=original_structure_dataset, 
    structure_names=["list", "of", "structure", "names"], 
    displacement=-3  # a positive value results in dilation, negative value, erosion
)

And, as a last alternative, if it is available within DICOMautomaton currently, then we could expose different displacements along different axis, and different displacements in different directions. If that was the case, the API could look like:

import pydicom
import dicomautomaton

original_structure_dataset = pydicom.dcmread("path/to/dicom-rt-structure.dcm")
adjusted_structure_dataset = dicomautomaton.buffer(
    dataset=original_structure_dataset, 
    structure_names=["list", "of", "structure", "names"], 
    # z, y, x order
    # displacements = (
    #     (z- displacement, z+ displacement), 
    #     (y- displacement, y+ displacement), 
    #     (x- displacement, x+ displacement)
    # )
    displacements=((-2, 0), (3, 3), (3, 3))
)

from dicomautomaton.

SimonBiggs avatar SimonBiggs commented on July 23, 2024

Also, on this point within the docs:

DICOMautomaton should NOT be used for clinical purposes. It is suitable only for research purposes or in a non-critical supporting role where outputs can be easily validated.

While efforts have been made to verify integrity and validity of the code, no independent audit or review has been performed. The breadth of functionality would make it difficult to test all combinations of operations. We therefore rely on static analysis, code quality metrics, and a limited amount of integration testing for specific workflows.

I will include my own testing suite within the RAi product that covers the functionality utilised and verify that it is fit for purpose when used in combination with RAi's clinical product. In other words, I'll manage the regulatory burden of the specific functionality of the software I depend upon.

from dicomautomaton.

hdclark avatar hdclark commented on July 23, 2024

Hi @SimonBiggs. It's nice to hear from you. This sounds like a great idea!

Absolutely, feel free to use any of the code in DICOMautomaton in accordance with the license. You've mentioned above about verification, testing, and undergoing regulatory approval, but I would like to explicitly state that all of the code in DICOMautomaton should be effectively considered as software of unknown provenance. Please do not rely on it without thoroughly testing and determining fitness for your specific use-cases. No warranty is provided or implied. I know you're well aware, but I just wanted to reiterate!

The morphological operator implementation is currently a bit slow and strongly CPU-bound, so it might require some tweaking depending on your use-case. It runs on image masks, so the data flow is: (1) contours -> mask, (2) erode/dilate mask, (3) mask -> contours. If no CT images are available, a synthetic mask can be created with arbitrary resolution. It works reasonable well for moderate distances (e.g., 1-10 mm), but can be inaccurate for smaller distances and annoyingly slow for larger distances. There is a clear accuracy-speed tradeoff which would be more comfortably served by increasing mask resolution using SIMD or GPU acceleration. My plan is to add this eventually, but my wishlist and TODO lists are quite long, so I can't commit to a timeline right now.

I would very much appreciate a python wrapper or interface, which will be extremely useful! I'm happy to help facilitate this development. I recently revisited the idea and got stuck in the evaluation stage, trying to pick the best approach. Your expertise would help tremendously!!

from dicomautomaton.

hdclark avatar hdclark commented on July 23, 2024

Another quick thought: I'm not sure what exactly you have planned, but if you're going to apply morphological operators to the output of image segmentation, it will be easiest to apply them directly to the mask images. This will avoid the initial conversion from contour -> mask.

from dicomautomaton.

SimonBiggs avatar SimonBiggs commented on July 23, 2024

Absolutely, feel free to use any of the code in DICOMautomaton in accordance with the license.

Thanks @hdclark 🙂

but I would like to explicitly state that all of the code in DICOMautomaton should be effectively considered as software of unknown provenance.

Yup, most definitely. It'd be SOUP all the way.

the data flow is: (1) contours -> mask, (2) erode/dilate mask, (3) mask -> contours. ... It works reasonable well for moderate distances (e.g., 1-10 mm), but can be inaccurate for smaller distances and annoyingly slow for larger distances.

I was also reaching out to the developer over at PyGEL, and they have an approach where they create a mesh using a variation of Dual Contouring and then use distance fields from that mesh in order to undergo erosion or dilation:
janba/GEL#59

I think there might be value in pulling them both into a Python API and exposing both approaches, and then I can test the two approaches against each other under a range of various known solution cases.

What are your thoughts on an approach like that?

I would very much appreciate a python wrapper or interface, which will be extremely useful! I'm happy to help facilitate this development. I recently revisited the idea and got stuck in the evaluation stage, trying to pick the best approach. Your expertise would help tremendously!!

It would be my pleasure 🙂

Another quick thought: I'm not sure what exactly you have planned, but if you're going to apply morphological operators to the output of image segmentation, it will be easiest to apply them directly to the mask images. This will avoid the initial conversion from contour -> mask.

Yup, that is true. But I do want to also support people building structures as combinations of other structures (potentially after they've been dilated). Here's an example config I'm looking to be able to support:

https://github.com/RadiotherapyAI/raicontours/blob/c6bfb201e9cdc4ff5a66fc53320bd043da557a53/raicontours/__init__.py#L113-L178

from dicomautomaton.

hdclark avatar hdclark commented on July 23, 2024

from dicomautomaton.

SimonBiggs avatar SimonBiggs commented on July 23, 2024

I'm guessing that eroding/dilating meshes directly will be more precise but posibly slower than the mask-based approach

Given the masks are being produced via 3D UNet AI inference, I suspect that the erosion / dilation code won't be the bottleneck. So as long as the speed isn't a significant issue I'm certainly more interested in correctness.

Pulling in both libraries would still be my preference as that equips us into the future.

Do you have a preference on the name of the Python library?

  • dicomaton
  • dicomautomaton
  • pydicomautomaton

And I suspect the best place for its code to reside would be within this same repo. Would that work with you?

Potentially all of the Python code could sit within a py directory?

And, would you be okay with having GEL be included as a part of the build? Or would you prefer I do that in a separate package?

from dicomautomaton.

hdclark avatar hdclark commented on July 23, 2024

from dicomautomaton.

SimonBiggs avatar SimonBiggs commented on July 23, 2024

Shorter is certainly better with being able to import it. The DCMA name has quite unfortunate alternative connotations:

https://www.dmca.com/FAQ/What-is-a-DMCA-Takedown

One letter swapped, but a google search still finds that when searching for DCMA

from dicomautomaton.

hdclark avatar hdclark commented on July 23, 2024

from dicomautomaton.

SimonBiggs avatar SimonBiggs commented on July 23, 2024

Maybe best to just go for pydicomautomaton then?

It does feel a little too similar to the pydicom library (https://github.com/pydicom/pydicom). There's also no real harm in calling it dicomautomaton or dicomaton without the py. At the end of the day if you're downloading the python version you do know what you're getting (don't need py in front of it to tell you that...)

from dicomautomaton.

hdclark avatar hdclark commented on July 23, 2024

from dicomautomaton.

SimonBiggs avatar SimonBiggs commented on July 23, 2024

Haha, all good. I think "dicomaton" is cool, but it's not what you're naming is already, so I'll go with the python package dicomautomaton unless you object?

from dicomautomaton.

hdclark avatar hdclark commented on July 23, 2024

👍

from dicomautomaton.

SimonBiggs avatar SimonBiggs commented on July 23, 2024

Alrighty 🙂, we have a placeholder PyPI package:

https://pypi.org/project/dicomautomaton/

When you get the chance would you be able to make a PyPI account and I'll make you an owner of that package.

from dicomautomaton.

hdclark avatar hdclark commented on July 23, 2024

from dicomautomaton.

hdclark avatar hdclark commented on July 23, 2024

I've registered using the handle 'hdclark'.

from dicomautomaton.

SimonBiggs avatar SimonBiggs commented on July 23, 2024

I've registered using the handle 'hdclark'.

Beautiful. You've been added as owner 🙂

from dicomautomaton.

Related Issues (6)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.