-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Stain normalization #2666
Stain normalization #2666
Conversation
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
… into neha/stain-norm-2
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
… into neha/stain-norm-2
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good apart from the minor comments. @Nic-Ma could you please help confirm/approve this PR?
and pseudo-max (100 - alpha percentile). Defaults to 1. | ||
beta: absorbance threshold for transparent pixels. Defaults to 0.15 | ||
max_cref: reference maximum stain concentrations for Hematoxylin & Eosin (H&E). | ||
Defaults to None. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the defauts are np.array([1.9705, 1.0308])
# reshape image and calculate absorbance | ||
image = image.reshape((-1, 3)) | ||
image = image.astype(np.float32) + 1.0 | ||
absorbance = -np.log(image.clip(max=self.tli) / self.tli) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need some validation of the input of np.log?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point! We should check if the input is intensity (0-255) and not any image or other scales. Thanks @wyli!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now it checks the image values to be between 0 and 255.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me except for some minor comments.
I didn't check whether the implementation matches some algorithm theory.
Thanks.
docs/source/apps.rst
Outdated
:members: | ||
|
||
.. automodule:: monai.apps.pathology.transforms.stain.dictionary | ||
.. autoclass:: ExtractHEStainsD |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest to use ExtractHEStainsd
to align with other docs, same as NormalizeHEStainsD
.
|
||
self.max_cref = max_cref | ||
if self.max_cref is None: | ||
self.max_cref = np.array([1.9705, 1.0308]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As @wyli commented, set default to 1.9705, 1.0308
directly.
Thanks.
"""Perform Stain Deconvolution and return stain matrix for the image. | ||
|
||
Args: | ||
img: uint8 RGB image to perform stain deconvolution of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe of
-> on
or for
?
pseudo-max (100 - alpha percentile). Defaults to 1. | ||
beta: absorbance threshold for transparent pixels. Defaults to 0.15. | ||
target_he: target stain matrix. Defaults to None. | ||
max_cref: reference maximum stain concentrations for Hematoxylin & Eosin (H&E). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default values of target_he
and max_cref
are same as the other comment.
tli: float = 240, | ||
alpha: float = 1, | ||
beta: float = 0.15, | ||
max_cref: Optional[np.ndarray] = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the other comment.
tli: float = 240, | ||
alpha: float = 1, | ||
beta: float = 0.15, | ||
target_he: Optional[np.ndarray] = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comment for default value.
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com>
…ain-normalization
* added stain norm and tests Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * import changes Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * changed stain extraction tests Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * edited stain norm tests Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * convert floats to float32 Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * added uint8 assumption to docstring Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * add error case Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * formatting change Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * modify tests wrt cupy import Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * minor change to pass lint test Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * import changes Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * refactored classes Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * Restructure and rename transforms Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * added dict transform Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * Move stain_extractor to init Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Exclude pathology transform tests from mini tests Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Fix type checking for cupy ndarray Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Include pathology transform tests Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Update to cupy 9.0.0 Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Remove exact version for cupy Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * add to docs Signed-off-by: Neha Srivathsa <nsrivathsa@nvidia.com> * Organize into stain dir Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Add/update init files Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Transit all from cupy to numpy Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Update imports Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Update test cases for numpy Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Rename to NormalizeHEStains and NormalizeHEStainsD Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Add dictionary variant names Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Fix typing and formatting Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Fix docs Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Update test cases Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Fix clip max Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Fix var typing Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Fix a typing issue Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Update default values, and change D to d Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Update docs Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Add image value check Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> * Add test cases for negative and invalid values Signed-off-by: Behrooz <3968947+behxyz@users.noreply.github.com> Co-authored-by: Neha Srivathsa <nsrivathsa@nvidia.com> Co-authored-by: nsrivathsa <81264348+nsrivathsa@users.noreply.github.com>
Description
This PR implement an H&E stain normalization for histopathology images, which contains:
Unlike the previous PR (#1998), which was based on
cupy
, its purely based onnumpy
without any CUDA dependency. It expectsnumpy.ndarray
as the input image and returnsnumpy.ndarray
.Status
Ready
Types of changes
./runtests.sh -f -u --net --coverage
../runtests.sh --quick --unittests
.make html
command in thedocs/
folder.