class_docstr: Class to extract a target stain from an image, using stain deconvolution (see Note).
  
  Args:
      tli: transmitted light intensity. Defaults to 240.
      alpha: tolerance in percentile for the pseudo-min (alpha percentile)
          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 (1.9705, 1.0308).
  
  Note:
      For more information refer to:
      - the original paper: Macenko et al., 2009 http://wwwx.cs.unc.edu/~mn/sites/default/files/macenko2009.pdf
      - the previous implementations:
  
        - MATLAB: https://github.com/mitkovetta/staining-normalization
        - Python: https://github.com/schaugf/HEnorm_python
docstr: Perform Stain Deconvolution and return stain matrix for the image.
  
  Args:
      image: uint8 RGB image to perform stain deconvolution on
  
  Return:
      he: H&E absorbance matrix for the image (first column is H, second column is E, rows are RGB values)
code: def _deconvolution_extract_stain(
      self, image: np.ndarray
  ) -> np.ndarray:
      """Perform Stain Deconvolution and return stain matrix for the image.
  
      Args:
          image: uint8 RGB image to perform stain deconvolution on
  
      Return:
          he: H&E absorbance matrix for the image (first column is H, second column is E, rows are RGB values)
      """
      # check image type and values
      if not isinstance(image, np.ndarray):
          raise TypeError("Image must be of type numpy.ndarray.")
      if image.min() < 0:
          raise ValueError("Image should not have negative values.")
      if image.max() > 255:
          raise ValueError(
              "Image should not have values greater than 255."
          )
  
      # reshape image and calculate absorbance
      image = image.reshape((-1, 3))
      image = image.astype(np.float32, copy=False) + 1.0
      absorbance = -np.log(image.clip(max=self.tli) / self.tli)
  
      # remove transparent pixels
      absorbance_hat = absorbance[
          np.all(absorbance > self.beta, axis=1)
      ]
      if len(absorbance_hat) == 0:
          raise ValueError(
              "All pixels of the input image are below the absorbance threshold."
          )
  
      # compute eigenvectors
      _, eigvecs = np.linalg.eigh(
          np.cov(absorbance_hat.T).astype(np.float32, copy=False)
      )
  
      # project on the plane spanned by the eigenvectors corresponding to the two largest eigenvalues
      t_hat = absorbance_hat.dot(eigvecs[:, 1:3])
  
      # find the min and max vectors and project back to absorbance space
      phi = np.arctan2(t_hat[:, 1], t_hat[:, 0])
      min_phi = np.percentile(phi, self.alpha)
      max_phi = np.percentile(phi, 100 - self.alpha)
      v_min = eigvecs[:, 1:3].dot(
          np.array(
              [(np.cos(min_phi), np.sin(min_phi))], dtype=np.float32
          ).T
      )
      v_max = eigvecs[:, 1:3].dot(
          np.array(
              [(np.cos(max_phi), np.sin(max_phi))], dtype=np.float32
          ).T
      )
  
      # a heuristic to make the vector corresponding to hematoxylin first and the one corresponding to eosin second
      if v_min[0] > v_max[0]:
          he = np.array((v_min[:, 0], v_max[:, 0]), dtype=np.float32).T
      else:
          he = np.array((v_max[:, 0], v_min[:, 0]), dtype=np.float32).T
  
      return he
  
file_path: MONAI/monai/apps/pathology/transforms/stain/array.py
imports: from __future__ import annotations
  import numpy
  from monai.transforms.transform import Transform
label_desc: Use image node_id 2 for calling the ExtractHEStains obj's underlying member method code with example usage: obj._deconvolution_extract_stain(image) and returns: he