def rgb_perturb_stain_concentration(im_rgb, stain_unmixing_routine_params=None, **kwargs): """Apply wrapper that calls perturb_stain_concentration() on RGB. Parameters ------------ im_rgb : array_like An RGB image (m x n x 3) to color normalize stain_unmixing_routine_params : dict kwargs to pass as-is to the color_deconvolution_routine(). kwargs : k,v pairs Passed as-is to perturb_stain_concentration() Returns -------- array_like Color augmented RGB image (m x n x 3) """ stain_unmixing_routine_params = { 'stains': ['hematoxylin', 'eosin'], 'stain_unmixing_method': 'macenko_pca', } if stain_unmixing_routine_params is None else stain_unmixing_routine_params _, StainsFloat, W_source = color_deconvolution_routine( im_rgb, W_source=None, **stain_unmixing_routine_params) return perturb_stain_concentration(StainsFloat, W_source, **kwargs)
def find_potentially_cellular_regions(self): """Find regions that are potentially cellular.""" mask_out = self.labeled != self.cdt.GTcodes.loc["not_specified", "GT_code"] # deconvolvve to ge hematoxylin channel (cellular areas) # hematoxylin channel return shows MINIMA so we invert self.tissue_htx, _, _ = color_deconvolution_routine( self.tissue_rgb, mask_out=mask_out, **self.cdt.stain_unmixing_routine_params) self.tissue_htx = 255 - self.tissue_htx[..., 0] # get cellular regions by threshold HTX stain channel self.maybe_cellular, _ = get_tissue_mask( self.tissue_htx.copy(), deconvolve_first=False, n_thresholding_steps=1, sigma=self.cdt.cellular_step1_sigma, min_size=self.cdt.cellular_step1_min_size) # Second, low-pass filter to dilate and smooth a bit self.maybe_cellular = gaussian(0 + (self.maybe_cellular > 0), sigma=self.cdt.cellular_step2_sigma, output=None, mode='nearest', preserve_range=True) # find connected components self.maybe_cellular, _ = ndimage.label(self.maybe_cellular) # restrict cellular regions to not-otherwise-specified self.maybe_cellular[mask_out] = 0 # assign to mask self.labeled[self.maybe_cellular > 0] = self.cdt.GTcodes.loc[ 'maybe_cellular', 'GT_code']
def get_maskrcnn_representations(fold: int, cfg, model_root: str, model_name: str, savedir: str, subset='train'): assert subset in ['train', 'test'] # paths model_folder = opj(model_root, f'fold_{fold}') checkpoint_path = opj(model_folder, f'{model_name}.ckpt') p1 = opj(savedir, model_name) savepath = opj(p1, f'fold_{fold}_{subset}_FEATS') maybe_mkdir(p1) maybe_mkdir(savepath) # load model model = PartialMaskRCNN(**cfg.MaskRCNNConfigs.maskrcnn_params) ckpt = load_ckp(checkpoint_path=checkpoint_path, model=model) model = ckpt['model'] model.eval() cpu_device = torch.device('cpu') model.transform.densify_mask = False # prep data loader slides = read_csv(opj( model_folder, f'fold_{fold}_{subset}.csv')).loc[:, 'slide_name'].tolist() dataset = NucleusDatasetMask( root=CoreSetQC.dataset_root, dbpath=CoreSetQC.dbpath, slides=slides, **cfg.MaskDatasetConfigs.test_dataset, ) dataiter = iter(dataset) NUCLID = 0 # go through fovs and fetch features nfovs = len(dataset) for fovno in range(nfovs): print(f'fov {fovno + 1} of {nfovs}') overwrite = NUCLID < 1 # do inference imgtensor, target = next(dataiter) output = model([imgtensor]) output = [{k: v.to(cpu_device) for k, v in t.items()} for t in output] output = output[0] n_nuclei = len(output['labels']) nuclidxs = [f'nucls_{i + NUCLID}' for i in range(1, n_nuclei + 1)] # metadata about each detection nmetas = _parse_nucleus_metas_df(nuclidxs=nuclidxs, dataset=dataset, target=target, output=output) nmetas.to_csv(opj(savepath, f'nucleus_metadata.csv'), mode='w' if overwrite else 'a', header=overwrite) # save box features (-> box regression) # & cboxfeatures & class_logits (-> classif) fdescs = { 'box_features': 'bfeat', 'cbox_features': 'cbfeat', 'clogits': 'clogits' } for ftype, fdesc in fdescs.items(): bfeatures = DataFrame(output[ftype].numpy()) bfeatures.columns = [f'{fdesc}_{i + 1}' for i in bfeatures.columns] bfeatures.index = nuclidxs bfeatures.to_csv(opj(savepath, f'{ftype}.csv'), mode='w' if overwrite else 'a', header=overwrite) # interpretation-friendly features rgb = np.uint8(imgtensor * 255.).transpose(1, 2, 0) stains, _, _ = color_deconvolution_routine(rgb) htx = 255 - stains[..., 0] masks = np.uint8(output['masks'].numpy() > 0.5)[:, 0, :, :] ifeatures = [] for nid in range(n_nuclei): try: fdf = compute_nuclei_features(im_label=masks[nid, ...], im_nuclei=htx) fdf.index = [nuclidxs[nid]] except: fdf = DataFrame(index=[nuclidxs[nid]]) ifeatures.append(fdf) ifeatures = concat(ifeatures, axis=0) ifeatures.to_csv(opj(savepath, f'interp_features.csv'), mode='w' if overwrite else 'a', header=overwrite) # dont forget NUCLID += n_nuclei