def main(args): args = CLIArgumentParser(xml_file).parse_args(args) total_start_time = time.time() print('\n>> CLI Parameters ...\n') print(args) if not os.path.isfile(args.inputImageFile): raise IOError('Input image file does not exist.') if len(args.reference_mu_lab) != 3: raise ValueError('Reference Mean LAB should be a 3 element vector.') if len(args.reference_std_lab) != 3: raise ValueError('Reference Stddev LAB should be a 3 element vector.') if len(args.analysis_roi) != 4: raise ValueError('Analysis ROI must be a vector of 4 elements.') if np.all(np.array(args.analysis_roi) == -1): process_whole_image = True else: process_whole_image = False # # Initiate Dask client # print('\n>> Creating Dask client ...\n') start_time = time.time() c = cli_utils.create_dask_client(args) print(c) dask_setup_time = time.time() - start_time print('Dask setup time = {}'.format( cli_utils.disp_time_hms(dask_setup_time))) # # Read Input Image # print('\n>> Reading input image ... \n') ts = large_image.getTileSource(args.inputImageFile) ts_metadata = ts.getMetadata() print(json.dumps(ts_metadata, indent=2)) is_wsi = ts_metadata['magnification'] is not None # # Compute tissue/foreground mask at low-res for whole slide images # if is_wsi and process_whole_image: print('\n>> Computing tissue/foreground mask at low-res ...\n') start_time = time.time() im_fgnd_mask_lres, fgnd_seg_scale = \ cli_utils.segment_wsi_foreground_at_low_res(ts) fgnd_time = time.time() - start_time print('low-res foreground mask computation time = {}'.format( cli_utils.disp_time_hms(fgnd_time))) # # Compute foreground fraction of tiles in parallel using Dask # tile_fgnd_frac_list = [1.0] it_kwargs = { 'tile_size': {'width': args.analysis_tile_size}, 'scale': {'magnification': args.analysis_mag}, } if not process_whole_image: it_kwargs['region'] = { 'left': args.analysis_roi[0], 'top': args.analysis_roi[1], 'width': args.analysis_roi[2], 'height': args.analysis_roi[3], 'units': 'base_pixels' } if is_wsi: print('\n>> Computing foreground fraction of all tiles ...\n') start_time = time.time() num_tiles = ts.getSingleTile(**it_kwargs)['iterator_range']['position'] print('Number of tiles = {}'.format(num_tiles)) if process_whole_image: tile_fgnd_frac_list = htk_utils.compute_tile_foreground_fraction( args.inputImageFile, im_fgnd_mask_lres, fgnd_seg_scale, **it_kwargs ) else: tile_fgnd_frac_list = np.full(num_tiles, 1.0) num_fgnd_tiles = np.count_nonzero( tile_fgnd_frac_list >= args.min_fgnd_frac) percent_fgnd_tiles = 100.0 * num_fgnd_tiles / num_tiles fgnd_frac_comp_time = time.time() - start_time print('Number of foreground tiles = {0:d} ({1:2f}%%)'.format( num_fgnd_tiles, percent_fgnd_tiles)) print('Tile foreground fraction computation time = {}'.format( cli_utils.disp_time_hms(fgnd_frac_comp_time))) # # Compute reinhard stats for color normalization # src_mu_lab = None src_sigma_lab = None if is_wsi and process_whole_image: print('\n>> Computing reinhard color normalization stats ...\n') start_time = time.time() src_mu_lab, src_sigma_lab = htk_cnorm.reinhard_stats( args.inputImageFile, 0.01, magnification=args.analysis_mag) rstats_time = time.time() - start_time print('Reinhard stats computation time = {}'.format( cli_utils.disp_time_hms(rstats_time))) # # Detect nuclei in parallel using Dask # print('\n>> Detecting nuclei ...\n') start_time = time.time() tile_nuclei_list = [] for tile in ts.tileIterator(**it_kwargs): tile_position = tile['tile_position']['position'] if is_wsi and tile_fgnd_frac_list[tile_position] <= args.min_fgnd_frac: continue # detect nuclei cur_nuclei_list = dask.delayed(detect_tile_nuclei)( args.inputImageFile, tile_position, args, it_kwargs, src_mu_lab, src_sigma_lab ) # append result to list tile_nuclei_list.append(cur_nuclei_list) tile_nuclei_list = dask.delayed(tile_nuclei_list).compute() nuclei_list = list(itertools.chain.from_iterable(tile_nuclei_list)) nuclei_detection_time = time.time() - start_time print('Number of nuclei = {}'.format(len(nuclei_list))) print('Nuclei detection time = {}'.format( cli_utils.disp_time_hms(nuclei_detection_time))) # # Write annotation file # print('\n>> Writing annotation file ...\n') annot_fname = os.path.splitext( os.path.basename(args.outputNucleiAnnotationFile))[0] annotation = { "name": annot_fname + '-nuclei-' + args.nuclei_annotation_format, "elements": nuclei_list } with open(args.outputNucleiAnnotationFile, 'w') as annotation_file: json.dump(annotation, annotation_file, indent=2, sort_keys=False) total_time_taken = time.time() - total_start_time print('Total analysis time = {}'.format( cli_utils.disp_time_hms(total_time_taken)))
import os import pprint from ctk_cli import CLIArgumentParser import sys def main(args): print('>> parsed arguments') pprint.pprint(vars(args)) if __name__ == '__main__': if len(sys.argv) == 2: if sys.argv[1] == '--json': json_spec_file = os.path.splitext(sys.argv[0])[0] + '.json' with open(json_spec_file) as f: print(f.read()) sys.exit(0) if sys.argv[1] == '--yaml': yaml_spec_file = os.path.splitext(sys.argv[0])[0] + '.yaml' with open(yaml_spec_file) as f: print(f.read()) sys.exit(0) main(CLIArgumentParser().parse_args())
import histomicstk.preprocessing.color_normalization as htk_cnorm import histomicstk.preprocessing.color_deconvolution as htk_cdeconv import histomicstk.utils as htk_utils import large_image from ctk_cli import CLIArgumentParser import logging logging.basicConfig(level=logging.CRITICAL) from ..cli_common import utils as cli_utils # noqa xml_file = os.path.join(os.path.dirname(__file__), 'NucleiDetection.xml') default_args = CLIArgumentParser(xml_file).parse_args(['a', 'b']) def detect_nuclei(im_tile, tile_info=None, args=None, src_mu_lab=None, src_sigma_lab=None): args = args or default_args # perform color normalization im_nmzd = htk_cnorm.reinhard(im_tile, args.reference_mu_lab, args.reference_std_lab, src_mu=src_mu_lab, src_sigma=src_sigma_lab) # perform color decovolution w = cli_utils.get_stain_matrix(args)