コード例 #1
0
ファイル: test_foo.py プロジェクト: take5v/StainTools
def test_is_uint8_image():
    R = np.array([[0., 55., 250.], [1., 3., 7.], [2., 4., 7.]])
    G = np.array([[0., 55., 250.], [1., 3., 7.], [2., 4., 7.]])
    B = np.array([[0., 55., 250.], [1., 3., 7.], [2., 4., 7.]])

    I = np.array([R, G, B])
    assert not is_uint8_image(I)
    I = I.astype(np.uint8)
    assert is_uint8_image(I)
    I = I / 255
    assert not is_uint8_image(I)
コード例 #2
0
    def get_stain_matrix(I, luminosity_threshold=0.8, regularizer=0.1):
        """
        Stain matrix estimation via method of:
        A. Vahadane et al. 'Structure-Preserving Color Normalization and Sparse Stain Separation for Histological Images'

        :param I: Image RGB uint8.
        :param luminosity_threshold:
        :param regularizer:
        :return:
        """
        assert is_uint8_image(I), "Image should be RGB uint8."
        # convert to OD and ignore background
        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]

        # do the dictionary learning
        dictionary = spams.trainDL(X=OD.T,
                                   K=2,
                                   lambda1=regularizer,
                                   mode=2,
                                   modeD=0,
                                   posAlpha=True,
                                   posD=True,
                                   verbose=False).T

        # order H and E.
        # H on first row.
        if dictionary[0, 0] < dictionary[1, 0]:
            dictionary = dictionary[[1, 0], :]

        return normalize_matrix_rows(dictionary)
コード例 #3
0
    def get_stain_matrix(I, luminosity_threshold=0.8, angular_percentile=99):
        """
        Stain matrix estimation via method of:
        M. Macenko et al. 'A method for normalizing histology slides for quantitative analysis'

        :param I: Image RGB uint8.
        :param luminosity_threshold:
        :param angular_percentile:
        :return:
        """
        assert is_uint8_image(I), "Image should be RGB uint8."
        # Convert to OD and ignore background
        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))

        # The two principle eigenvectors
        V = V[:, [2, 1]]

        # Make sure vectors are pointing the right way
        if V[0, 0] < 0: V[:, 0] *= -1
        if V[0, 1] < 0: V[:, 1] *= -1

        # Project on this basis.
        That = np.dot(OD, V)

        # Angular coordinates with repect to the prinicple, orthogonal eigenvectors
        phi = np.arctan2(That[:, 1], That[:, 0])

        # Min and max angles
        minPhi = np.percentile(phi, 100 - angular_percentile)
        maxPhi = np.percentile(phi, angular_percentile)

        # the two principle colors
        v1 = np.dot(V, np.array([np.cos(minPhi), np.sin(minPhi)]))
        v2 = np.dot(V, np.array([np.cos(maxPhi), np.sin(maxPhi)]))

        # Order of H and E.
        # H first row.
        if v1[0] > v2[0]:
            HE = np.array([v1, v2])
        else:
            HE = np.array([v2, v1])

        return normalize_matrix_rows(HE)
コード例 #4
0
 def lab_split(I):
     """
     Convert from RGB uint8 to LAB and split into channels.
     :param I: Image RGB uint8.
     :return:
     """
     assert is_uint8_image(I), "Should be a RGB uint8 image"
     I = cv.cvtColor(I, cv.COLOR_RGB2LAB)
     I_float = I.astype(np.float32)
     I1, I2, I3 = cv.split(I_float)
     I1 /= 2.55  # should now be in range [0,100]
     I2 -= 128.0  # should now be in range [-127,127]
     I3 -= 128.0  # should now be in range [-127,127]
     return I1, I2, I3
コード例 #5
0
    def get_mean_std(self, I):
        """
        Get mean and standard deviation of each channel.

        :param I: Image RGB uint8.
        :return:
        """
        assert is_uint8_image(I), "Should be a RGB uint8 image"
        I1, I2, I3 = self.lab_split(I)
        m1, sd1 = cv.meanStdDev(I1)
        m2, sd2 = cv.meanStdDev(I2)
        m3, sd3 = cv.meanStdDev(I3)
        means = m1, m2, m3
        stds = sd1, sd2, sd3
        return means, stds
コード例 #6
0
    def standardize(I, percentile=95):
        """
        Transform image I to standard brightness.
        Modifies the luminosity channel such that a fixed percentile is saturated.

        :param I: Image uint8 RGB.
        :param percentile: Percentile for luminosity saturation. At least (100 - percentile)% of pixels should be fully luminous (white).
        :return: Image uint8 RGB with standardized brightness.
        """
        assert is_uint8_image(I), "Image should be RGB uint8."
        I_LAB = cv.cvtColor(I, cv.COLOR_RGB2LAB)
        L_float = I_LAB[:, :, 0].astype(float)
        p = np.percentile(L_float, percentile)
        I_LAB[:, :, 0] = np.clip(255 * L_float / p, 0, 255).astype(np.uint8)
        I = cv.cvtColor(I_LAB, cv.COLOR_LAB2RGB)
        return I
コード例 #7
0
 def get_mean_std(self, I, mask):
     """
     Get mean and standard deviation of each channel.
     :param I: Image RGB uint8.
     :return:
     """
     assert is_uint8_image(I), "Should be a RGB uint8 image"
     I1, I2, I3 = self.lab_split(I)
     m1 = np.mean(I1[mask])
     sd1 = np.std(I1[mask])
     m2 = np.mean(I2[mask])
     sd2 = np.std(I2[mask])
     m3 = np.mean(I3[mask])
     sd3 = np.std(I3[mask])
     means = m1, m2, m3
     stds = sd1, sd2, sd3,
     return means, stds
コード例 #8
0
    def get_tissue_mask(I, luminosity_threshold=0.8):
        """
        Get a binary mask where true denotes pixels with a luminosity less than the specified threshold.
        Typically we use to identify tissue in the image and exclude the bright white background.

        :param I: RGB uint 8 image.
        :param luminosity_threshold: Luminosity threshold.
        :return: Binary mask.
        """
        assert is_uint8_image(I), "Image should be RGB uint8."
        I_LAB = cv.cvtColor(I, cv.COLOR_RGB2LAB)
        L = I_LAB[:, :, 0] / 255.0  # Convert to range [0,1].
        mask = L < luminosity_threshold

        # Check it's not empty
        if mask.sum() == 0:
            raise TissueMaskException("Empty tissue mask computed")

        return mask
コード例 #9
0
 def test_is_uint8_image_is_false_for_floats(self):
     rgb = np.random.uniform(0, 256, [2, 7, 3])
     get = is_uint8_image(rgb)
     self.assertFalse(get)
コード例 #10
0
 def test_is_uint8_image_is_false_for_ints_outside_0_255(self):
     rgb = np.random.randint(0, 300, [5, 2, 3])
     get = is_uint8_image(rgb)
     self.assertFalse(get)
コード例 #11
0
 def test_is_uint8_image_is_true_for_ints_in_0_255(self):
     rgb = np.random.randint(0, 256, [5, 4, 3]).astype(np.uint8)
     get = is_uint8_image(rgb)
     self.assertTrue(get)