Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gaussian smoothing #90

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open

Gaussian smoothing #90

wants to merge 13 commits into from

Conversation

mathiser
Copy link

Dear everyone,
A thing that has bugged me when using this (otherwise wonderful) package, is the jagged, unsmooth and a bit too small contours which are returned, when converting binary masks into rtss.

In this PR I propose implementation of how smoothing can be added as an option. Essentially, it is iterations of applying the following filters.

  1. Upscaling image in X and Y direction with a factor
  2. Gaussian smoothing
  3. Binary threshold

How to run it
All you have to do is to run the usual add_roi() with another parameter:

rtstruct.add_roi(
    mask=arr,
    name=name,
    color=[0,248,255],
   apply_smoothing="2d")

Furthermore, you can tweak the smoothing by parsing a dict with parameters. The setup is a little curious, and there is room for improvement, but essentially it looks like this:

 smoothing_parameters = {
         "crop_margins": [20, 20, 1],  # To improve memory efficiency - make sure to keep is well away from the gaussian kernel
      "scaling_iterations": integer,  # Number of times to run everything below
      "np_kron": {"scaling_factor": scale},
      "filter_iterations": integer,  # The number of times gaussian and threshold is run at each scaling level
      "ndimage_gaussian_filter": {"sigma": sigma, "radius": radius},  # Are passed ad kwargs, so any parameter from [the filter](https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.gaussian_filter.html#scipy.ndimage.gaussian_filter) can be set. 
      "threshold": {"threshold": threshold},  # Threshold between 0 and 1. 
 }

The above dict can be used by doing:

rtstruct.add_roi(
    mask=arr,
    name=name,
    color=[0,248,255],
    apply_smoothing="2d",
    smoothing_parameters=smoothing_parameters
)

I have added the possibility to choose running the filters in either 3d or 2d. I have done most parameter tuning in 2d, and have come up with two sets, which works well, so if

Furthermore, this is a nice entry point to add other smoothing algorithms like:

def awesome_smoothing(mask: np.ndarray, apply_smoothing: str, smoothing_parameters: Dict):
    return ItsAKindOfMagicalArray

rtstruct.add_roi(
    mask=arr,
    name=name,
    color=[0,248,255],
    apply_smoothing="2d",
    smoothing_parameters=smoothing_parameters,
    smoothing_function=awesome_smoothing
)

Other things in the code
In order to be able to add upscaled masks, there is a check in rtstruct.addroi():

        ## If upscaled coords are given, they should be adjusted accordingly
        rows = self.series_data[0][0x00280010].value
        scaling_factor = int(mask.shape[0] / rows)

This determines the scale in X, Y which will then be taken into account in image_helper.find_mask_contours():

    for i, contour in enumerate(contours):
        contours[i] = [[(contour[i][0][0] / scaling_factor), (contour[i][0][1] / scaling_factor)] for i in
                       range(0, len(contour))]

Show case
Because I work with clinical data, I do not show the underlying images. It does not matter for the impression, I guess.
Below is a image where red is the initial dicom rtss and in green is the same converted to binary nifti masks in CT-grid.
GroundTruth in dicom and nifti

Converting the green nifti directly back to dicom rtss with the current main branch gives this, where red is ground truth and blue is the converted rtss:
Vanilla vs GT

With default parameters of this PR the same conversion yields the following, where red is ground truth and blue is conversion:
Dicom GT and smooth consversion

Purpose of the PR
I do not know what the maintainers thinks about implementing this into the standard package, but to me and my work, well-working smoothing is a game-changer. I hope we can discuss if other algorithms should be implemented too or if the interface should look different.

Looking forward to hear your thoughts,
Mathis

@mathiser
Copy link
Author

Really?! Not a single comment from maintainers? Perhaps it is time to expand the group of maintainers to make the repo a bit more active....

@awtkns
Copy link
Contributor

awtkns commented Jun 29, 2023

Hi @mathiser sorry about this. Thanks for such a high quality write up on this.

Unfortunately @asim-shrestha and I have been tied up as of late working on our own startup (we actually left the qurit team close to three years ago). As such this project has seemed to fall through the cracks, which is a shame.

Tagging the qurit team so this can get reviewed hopefully @carluri @ivankzn @qurit-frizi :)

@awtkns
Copy link
Contributor

awtkns commented Jun 29, 2023

I do agree that this project needs an expanded set of maintainers so that great features like this can get in

@mathiser
Copy link
Author

Thanks for your reply, @awtkns. I did suspect that the situation was something like this, which I totally understand.
The thing is that rt_utils is (AFAIK) still the only tool out there to perform this task in a sober and simple manner. Lots of out work rely on the package There is so much potential in this and a variety of features to be added.

BTW,this PR was also opened in the hope that people could share some insights in the post-processing contours. It is quite likely that the style of coding is not appropriate in this repo - and I haven't added any tests either....

@mathiser
Copy link
Author

Lastly, I have done some more parameter tweaking and nursing on the code. I won't bother updating the PR if the interest is limited...

@plesqui
Copy link
Collaborator

plesqui commented Jul 19, 2023

Hi @mathiser ,

I have just joined the team and will be helping with maintenance and developing new features. It will take me a couple of weeks to get up to speed but I hope to start reviewing and supporting this project as much as possible.

Thanks again for your contributions and for your patience. We really appreciate it! I'll be back into this PR soon.

@plesqui plesqui self-requested a review July 19, 2023 12:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants