def get_stain_matrix(I, threshold=0.8, lamda=0.1): """ Get 2x3 stain matrix. First row H and second row E. See the original paper for details. Also see spams docs. :param I: :param threshold: :param lamda: :return: """ mask = mu.notwhite_mask(I, thresh=threshold).reshape((-1, )) OD = mu.RGB_to_OD(I).reshape((-1, 3)) OD = OD[mask] dictionary = spams.trainDL(OD.T, K=2, lambda1=lamda, mode=2, modeD=0, posAlpha=True, posD=True, verbose=False).T if dictionary[0, 0] < dictionary[1, 0]: dictionary = dictionary[[1, 0], :] dictionary = mu.normalize_rows(dictionary) return dictionary
def get_stain_matrix(I, beta=0.15, alpha=1): """ Get the stain matrix (2x3). First row H and second row E. See the original paper for details. :param I: :param beta: :param alpha: :return: """ OD = mu.RGB_to_OD(I).reshape((-1, 3)) OD = (OD[(OD > beta).any(axis=1), :]) _, V = np.linalg.eigh(np.cov(OD, rowvar=False)) V = V[:, [2, 1]] if V[0, 0] < 0: V[:, 0] *= -1 if V[0, 1] < 0: V[:, 1] *= -1 That = np.dot(OD, V) phi = np.arctan2(That[:, 1], That[:, 0]) minPhi = np.percentile(phi, alpha) maxPhi = np.percentile(phi, 100 - alpha) v1 = np.dot(V, np.array([np.cos(minPhi), np.sin(minPhi)])) v2 = np.dot(V, np.array([np.cos(maxPhi), np.sin(maxPhi)])) if v1[0] > v2[0]: HE = np.array([v1, v2]) else: HE = np.array([v2, v1]) return mu.normalize_rows(HE)
def get_concentrations(I, stain_matrix, lamda=0.01): """ Get the concentration matrix. Suppose the input image is H x W x 3 (uint8). Define Npix = H * W. Then the concentration matrix is Npix x 2 (or we could reshape to H x W x 2). The first element of each row is the Hematoxylin concentration. The second element of each row is the Eosin concentration. We do this by 'solving' OD = C*S (Matrix product) where OD is optical density (Npix x 3),\ C is concentration (Npix x 2) and S is stain matrix (2 x 3). See docs for spams.lasso. We restrict the concentrations to be positive and penalise very large concentration values,\ so that background pixels (which can not easily be expressed in the Hematoxylin-Eosin basis) have \ low concentration and thus appear white. :param I: Image. A np array HxWx3 of type uint8. :param stain_matrix: a 2x3 stain matrix. First row is Hematoxylin stain vector, second row is Eosin stain vector. :return: """ OD = mu.RGB_to_OD(I).reshape( (-1, 3)) # convert to optical density and flatten to (H*W)x3. return spams.lasso(OD.T, D=stain_matrix.T, mode=2, lambda1=lamda, pos=True).toarray().T
def get_concentrations(I, stain_matrix): """ Perforain concentration extraction according to A. C. Ruifrok, D. A. Johnston et al., “Quantification of histochemical staining by color deconvolution,” Analytical and quantitative cytology and histology, vol. 23, no. 4, pp. 291–299, 2001. :param I: :return: """ OD = mu.RGB_to_OD(I).reshape((-1, 3)) source_concentrations = np.dot(OD, np.linalg.inv(stain_matrix)) return source_concentrations