Skip to content
This repository has been archived by the owner on May 8, 2021. It is now read-only.

numpy.linalg.LinAlgError when calling transform #40

Open
sizhe-li opened this issue Nov 9, 2019 · 2 comments
Open

numpy.linalg.LinAlgError when calling transform #40

sizhe-li opened this issue Nov 9, 2019 · 2 comments

Comments

@sizhe-li
Copy link

sizhe-li commented Nov 9, 2019

/users/sli59/anaconda3/envs/torch_lester/lib/python3.7/site-packages/staintools/stain_normalizer.py:41: RuntimeWarning: divide by zero encountered in true_divide
  source_concentrations *= (self.maxC_target / maxC_source)
/users/sli59/anaconda3/envs/torch_lester/lib/python3.7/site-packages/staintools/stain_normalizer.py:41: RuntimeWarning: invalid value encountered in multiply
  source_concentrations *= (self.maxC_target / maxC_source)
Empty Tissue Mask
multiprocessing.pool.RemoteTraceback:
"""
Traceback (most recent call last):
  File "/users/sli59/anaconda3/envs/torch_lester/lib/python3.7/multiprocessing/pool.py", line 121, in worker
    result = (True, func(*args, **kwds))
  File "normalize.py", line 40, in training_slide_range_to_images
    training_slide_to_image(slide_num)
  File "normalize.py", line 31, in training_slide_to_image
    to_transform = normalizer.transform(to_transform)
  File "/users/sli59/anaconda3/envs/torch_lester/lib/python3.7/site-packages/staintools/stain_normalizer.py", line 38, in transform
    stain_matrix_source = self.extractor.get_stain_matrix(I)
  File "/users/sli59/anaconda3/envs/torch_lester/lib/python3.7/site-packages/staintools/stain_extraction/macenko_stain_extractor.py", line 30, in get_stain_matrix
    _, V = np.linalg.eigh(np.cov(OD, rowvar=False))
  File "/users/sli59/anaconda3/envs/torch_lester/lib/python3.7/site-packages/numpy/linalg/linalg.py", line 1444, in eigh
    _assertRankAtLeast2(a)
  File "/users/sli59/anaconda3/envs/torch_lester/lib/python3.7/site-packages/numpy/linalg/linalg.py", line 207, in _assertRankAtLeast2
    'at least two-dimensional' % a.ndim)
numpy.linalg.LinAlgError: 0-dimensional array given. Array must be at least two-dimensional
"""

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "normalize.py", line 105, in <module>
    multiprocess_training_slides_to_images()
  File "normalize.py", line 78, in multiprocess_training_slides_to_images
    (start_ind, end_ind) = result.get()
  File "/users/sli59/anaconda3/envs/torch_lester/lib/python3.7/multiprocessing/pool.py", line 657, in get
    raise self._value
numpy.linalg.LinAlgError: 0-dimensional array given. Array must be at least two-dimensional

Let me know if any additional information is needed for diagnosing the problem. Thank you for your time.

@YoniSchirris
Copy link

@lester0866 I had this happen, too.

It happened for an image that was very "white". This led staintools to see each pixel as a 'background pixel'. It then creates a mask, since it only transforms non-background pixels.

This way, you can end up with 0 or 1 pixel that's left as non-background.

If it then tries to compute the eigenvalues of this 'matrix', this is not possible.

My solution was to change macenko_stain_extractor.MacenkoStainExtractor to

tissue_mask = LuminosityThresholdTissueLocator.get_tissue_mask(I, luminosity_threshold=luminosity_threshold).reshape((-1,))
        OD = convert_RGB_to_OD(I).reshape((-1, 3))
        OD = OD[tissue_mask]


        # Yoni's edit!!
        if tissue_mask.sum() <= 1: # If the tissue mask has 0 or 1 pixel the linalg does not work. We will return an untransformed image
            return False

        # Eigenvectors of cov in OD space (orthogonal as cov symmetric)
        _, V = np.linalg.eigh(np.cov(OD, rowvar=False))

And then, in stain_normalizer.StainNormalizer:

def transform(self, I, filename=''):
        """
        Transform an image.

        :param I: Image RGB uint8.
        :return:
        """
        stain_matrix_source = self.extractor.get_stain_matrix(I)

        # Yoni's edit: get_strain_matrix returns false if the linalg doesn't work out. If that doesn't work out, we return an untransformed image
        if isinstance(stain_matrix_source, np.ndarray):
            source_concentrations = get_concentrations(I, stain_matrix_source, multiThread=False)
            maxC_source = np.percentile(source_concentrations, 99, axis=0).reshape((1, 2))
            source_concentrations *= (self.maxC_target / maxC_source)
            tmp = 255 * np.exp(-1 * np.dot(source_concentrations, self.stain_matrix_target))
            return tmp.reshape(I.shape).astype(np.uint8)
        else:
            print(f"=== This image was seen as background by Macenko method, and is therefore not transformed: {filename}")
            return I.astype(np.uint8)

I hope this helps out anyone with these issues

@adelabdelli
Copy link

@YoniSchirris I did what you suggested but i am having another error, i don't know why !
The error:

Epoch 1/100 /content/src/staintools/staintools/stain_normalizer.py:43: RuntimeWarning: divide by zero encountered in true_divide source_concentrations *= (self.maxC_target / maxC_source) /content/src/staintools/staintools/stain_normalizer.py:43: RuntimeWarning: invalid value encountered in multiply source_concentrations *= (self.maxC_target / maxC_source)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants