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

speedup label2rgb using scipy #3344

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

Conversation

cmarshak
Copy link

Description

This is a pull request related to #3343. It's a speedup to label2rgb using scipy.ndimage.measurements.

I modified the functions used for label2rgb without the overlay keyword arguments.

Checklist

[It's fine to submit PRs which are a work in progress! But before they are merged, all PRs should provide:]

  • Clean style in the spirit of PEP8
  • Docstrings for all functions
  • Gallery example in ./doc/examples (new features only)
  • Benchmark in ./benchmarks, if your changes aren't covered by an
    existing benchmark - I am not sure how to do this or where to find documentation about this
  • Unit tests - i did not add more tests, but it successfully ran on the numerous tests for label2rgb intest_colorlabel.py.

[For detailed information on these and other aspects see scikit-image contribution guidelines]

References

[1] scipy.ndimage.measurements

For reviewers

(Don't remove the checklist below.)

  • Check that the PR title is short, concise, and will make sense 1 year
    later.
  • Check that new functions are imported in corresponding __init__.py.
  • Check that new features, API changes, and deprecations are mentioned in
    doc/release/release_dev.rst.
  • Consider backporting the PR with @meeseeksdev backport to v0.14.x

@pep8speaks
Copy link

pep8speaks commented Aug 12, 2018

Hello @cmarshak! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

Line 114:80: E501 line too long (97 > 79 characters)
Line 246:80: E501 line too long (83 > 79 characters)
Line 248:80: E501 line too long (80 > 79 characters)
Line 262:80: E501 line too long (85 > 79 characters)
Line 297:80: E501 line too long (83 > 79 characters)

Comment last updated at 2019-07-24 18:22:20 UTC

@codecov-io

This comment has been minimized.

@hmaarrfk
Copy link
Member

Looks cool! Would you be able to write a benchmark so that we can have a reference point before merging this in?

Copy link
Member

@jni jni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cmarshak thank you for spotting this! Yes indeed, I think I found out about labeled_comprehension long after we put this code in scikit-image, so this is a very welcome contribution. However there's still a few improvements needed to include the code. Specifically, the existing code works for multichannel images of any dimension, not just 2D, whereas the new code doesn't. I don't think it should be a big deal to fix though, since ndimage is nd to begin with!

@@ -195,34 +197,87 @@ def _label2rgb_overlay(label, image=None, colors=None, alpha=0.3,
return result


def _label2rgb_avg(label_field, image, bg_label=0, bg_color=(0, 0, 0)):
def _apply_2d_func_to_image(func, image):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to hardcode the fact that the image is 2D or 2D+c. This function makes sense for 3D images (such as 3D segmentations in microscopy).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could have multichannel=False as a keyword(-only) argument that determines whether to do apply func to the whole array or to the channels (last dim) separately. In that case, I think we already have such a function in adapt_rgb, although a better name for this would be apply_per_channel.

Copy link
Author

@cmarshak cmarshak Sep 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your feedback.

I believe adapt_rgb looks at the shape of the image to adapt a filter or func. I created a function called _apply_per_channel per your suggestion.

Additionally, I added the keyword to make this adaptable in both cases.

func : callable
A function that takes an array to another array of the same shape.
image : array
A multichannel image
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not currently accurate.

@@ -1,6 +1,8 @@
import itertools

import numpy as np
from scipy.ndimage import measurements
from scipy.ndimage import find_objects
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the rest of the library we use from scipy import ndimage as ndi. I would prefer to use the same convention here, as it makes the code easier to follow once you are familiar with that convention.

----------
band : 2d array, shape ``label_field.shape``
A multichannel image of the same spatial shape as `label_field`.
bg_label : int, optional
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This parameter list appears incorrect.

@cmarshak
Copy link
Author

Thanks for all the helpful feedback. I would be happy to make these improvements, but just started traveling and will not be available to do this for a few weeks. If that works, I can do this when I return. I am sorry for any hold up.

Also, all the comments seem pretty straightforward and will probably have to write some tests to make sure that they are covered easily. However, I am not sure how benchmarks for this project work so will need some references for this.

I really value all the great work you are each doing and allowing me to be involved even minimally. skimage has been very, very helpful for me in my actual work.

@jni
Copy link
Member

jni commented Aug 14, 2018

Enjoy your travels! Depending on priorities, we may complete your PR for you, or, more likely, this PR will be waiting for your return. (Especially since the functionality is there, just slow.) Happy to hear you found it useful and we will be very happy to have this contribution and many future ones! =)

@soupault soupault added this to the 0.15 milestone Aug 17, 2018
@soupault soupault self-assigned this Aug 17, 2018
@cmarshak
Copy link
Author

Glad I can still contribute this.

Would you be able to write a benchmark so that we can have a reference point before merging this in?

I am looking at the asv docs and this skimage example. I am assuming that I can adapt this (gist)[https://gist.github.com/cmarshak/ff9a2786d804e38d7c4bc43122509226]. Would I create a separate pull request for this?

@jni
Copy link
Member

jni commented Sep 29, 2018

@cmarshak you can append the benchmark to this PR, and post the results of the benchmark (using asv dev, not asv run), before and after the PR changes, as a comment on this thread.

You still need to remove the image.ndim check so that this works for 3D and higher multichannel images.

Thanks for picking this up again!

@soupault soupault modified the milestones: 0.15, 0.16 Apr 20, 2019
@sciunto
Copy link
Member

sciunto commented Jul 17, 2019

@cmarshak What's the status of this? Do you still have time to work on this?

For information, #4016 is a PR to provide a how to on asv.

@sciunto sciunto modified the milestones: 0.16, 0.17 Jul 17, 2019
@cmarshak
Copy link
Author

Yes, I forgot about this - I can work on this in a few weeks when I return from travel. Getting set up with asv slowed me down and then I lost track.

@cmarshak cmarshak closed this Jul 24, 2019
@cmarshak cmarshak reopened this Jul 24, 2019
@cmarshak
Copy link
Author

Whoops - I closed and commented.

@soupault
Copy link
Member

I'd recommend to have #3015 merged first.

Base automatically changed from master to main February 18, 2021 18:23
@jarrodmillman jarrodmillman modified the milestones: 0.17, 0.20 Jun 4, 2022
@mkcor
Copy link
Member

mkcor commented Aug 24, 2022

closes #3343

Comment on lines +200 to +201
"""
Apply a function to each channel of an image.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""
Apply a function to each channel of an image.
"""Apply a function to each channel of an image.

Comment on lines +227 to +228
"""
Aggregates pixel values with respect to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""
Aggregates pixel values with respect to
"""Aggregate pixel values with respect to

Reference: https://peps.python.org/pep-0257/#multi-line-docstrings

An array with the same shape and type as `image` and `label_field`
"""
if label_field.shape != image.shape:
raise ValueError('label_field and image must have the same shape as image')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raise ValueError('label_field and image must have the same shape as image')
raise ValueError('label_field must have the same shape as image')

return out


def _label2mean(label_field, image, bg_label=None, bg_color=None, multichannel=True):
"""Visualise each segment in `label_field` with its mean color in `image`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""Visualise each segment in `label_field` with its mean color in `image`.
"""Visualize each segment in `label_field` with its mean color in `image`.

(convention)

return out


def _label2mean(label_field, image, bg_label=None, bg_color=None, multichannel=True):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def _label2mean(label_field, image, bg_label=None, bg_color=None, multichannel=True):
def _label2mean(label_field, image, bg_label=None, bg_color=None, channel_axis=-1):

It would be great to update this parameter!

References:

@lagru lagru modified the milestone: 0.20 Oct 25, 2022
@stefanv stefanv removed this from the 0.20 milestone Jan 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet