Beispiel #1
0
def suppfig_metrics(test_root, save_root, save_figure=False):
    """ cyto performance measured with AJI and boundary precision """
    ntest = len(glob(os.path.join(test_root, '*_img.tif')))
    test_data = [io.imread(os.path.join(test_root, '%03d_img.tif'%i)) for i in range(ntest)]
    test_labels = [io.imread(os.path.join(test_root, '%03d_masks.tif'%i)) for i in range(ntest)]
    
    masks = []
    aji = []
    model_type = 'cyto'
    masks.append(np.load(os.path.join(save_root, 'cellpose_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'maskrcnn_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'stardist_%s_masks.npy'%model_type), allow_pickle=True))
    #masks.append(np.load(os.path.join(save_root, 'unet3_residual_on_style_on_concatenation_off_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'unet3_residual_off_style_off_concatenation_on_%s_masks.npy'%model_type), allow_pickle=True))
    
    for j in range(len(masks)):
        aji.append(metrics.aggregated_jaccard_index(test_labels, masks[j]))
        fsc.append(metrics.aggregated_jaccard_index(test_labels, masks[j]))


    for m,model_type in enumerate(model_types):
        masks[m].append(np.load(os.path.join(save_root, 'cellpose_%s_masks.npy'%model_type), allow_pickle=True))
        masks[m].append(np.load(os.path.join(save_root, 'maskrcnn_%s_masks.npy'%model_type), allow_pickle=True))
        masks[m].append(np.load(os.path.join(save_root, 'stardist_%s_masks.npy'%model_type), allow_pickle=True))
        #masks[m].append(np.load(os.path.join(save_root, 'unet3_residual_on_style_on_concatenation_off_%s_masks.npy'%model_type), allow_pickle=True))
        masks[m].append(np.load(os.path.join(save_root, 'unet3_residual_off_style_off_concatenation_on_%s_masks.npy'%model_type), allow_pickle=True))
        masks[m].append(np.load(os.path.join(save_root, 'unet2_residual_off_style_off_concatenation_on_%s_masks.npy'%model_type), allow_pickle=True))
        
        for j in range(len(masks[m])):
            aps[m].append(metrics.average_precision(test_labels, masks[m][j], 
                                                    threshold=thresholds)[0])
Beispiel #2
0
def test_unets(model_root, test_root, save_root, model_type='cyto'):
    """ test trained unets """
    device = mx.gpu()
    ntest = len(glob(os.path.join(test_root, '*_img.tif')))
    if model_type[:4] == 'cyto':
        channels = [2, 1]
    else:
        channels = [0, 0]

    concatenation = [1, 1, 0]
    residual_on = [0, 0, 1]
    style_on = [0, 0, 1]
    nclasses = [3, 2, 3]
    sstr = ['off', 'on']

    aps = np.zeros((len(concatenation), ntest, len(thresholds)))

    test_data = [
        io.imread(os.path.join(test_root, '%03d_img.tif' % i))
        for i in range(ntest)
    ]
    test_labels = [
        io.imread(os.path.join(test_root, '%03d_masks.tif' % i))
        for i in range(ntest)
    ]

    if model_type != 'cyto_sp':
        dat = np.load(os.path.join(test_root, 'predicted_diams.npy'),
                      allow_pickle=True).item()
        if model_type == 'cyto':
            rescale = 30. / dat['predicted_diams']
        else:
            rescale = 17. / dat['predicted_diams']
    else:
        rescale = np.ones(len(test_data))

    for k in range(1):  #len(concatenation)):
        pretrained_models = get_pretrained_models(model_root, 1, nclasses[k],
                                                  residual_on[k], style_on[k],
                                                  concatenation[k])
        print(pretrained_models)
        model = models.UnetModel(device=device,
                                 pretrained_model=pretrained_models)

        masks = model.eval(test_data,
                           channels=channels,
                           rescale=rescale,
                           net_avg=True)[0]
        ap = metrics.average_precision(test_labels,
                                       masks,
                                       threshold=thresholds)[0]
        print(ap[:, [0, 5, 8]].mean(axis=0))
        aps[k] = ap
        np.save(
            os.path.join(
                save_root,
                'unet%d_residual_%s_style_%s_concatenation_%s_%s_masks.npy' %
                (nclasses[k], sstr[residual_on[k]], sstr[style_on[k]],
                 sstr[concatenation[k]], model_type)), masks)
Beispiel #3
0
def train_unets(data_root):
    """ train unets with 3 or 2 classes and different architectures (12 networks total) """
    # can also run on command line for GPU cluster
    # python -m cellpose --train --use_gpu --dir images_cyto/train/ --test_dir images_cyto/test/ --img_filter _img --pretrained_model None --chan 2 --chan2 1 --unet "$1" --nclasses "$2" --learning_rate "$3" --residual_on "$4" --style_on "$5" --concatenation "$6"
    device = mx.gpu()
    ntest = len(glob(os.path.join(data_root, 'test/*_img.tif')))
    ntrain = len(glob(os.path.join(data_root, 'train/*_img.tif')))
    channels = [2, 1]

    concatenation = [1, 1, 0]
    residual_on = [0, 0, 1]
    style_on = [0, 0, 1]
    nclasses = [3, 2, 3]

    # load images
    train_root = os.path.join(data_root, 'train/')
    train_data = [
        io.imread(os.path.join(train_root, '%03d_img.tif' % i))
        for i in range(ntrain)
    ]
    train_labels = [
        io.imread(os.path.join(train_root, '%03d_masks.tif' % i))
        for i in range(ntrain)
    ]

    test_root = os.path.join(data_root, 'test/')
    test_data = [
        io.imread(os.path.join(test_root, '%03d_img.tif' % i))
        for i in range(ntest)
    ]
    test_labels = [
        io.imread(os.path.join(test_root, '%03d_masks.tif' % i))
        for i in range(ntest)
    ]

    # train networks
    for k in range(len(concatenation)):
        # 4 nets for each
        for l in range(4):
            model = models.UnetModel(device=device,
                                     pretrained_model=None,
                                     diam_mean=30,
                                     residual_on=residual_on[k],
                                     style_on=style_on[k],
                                     concatenation=concatenation[k],
                                     nclasses=nclasses[k])
            model.train(train_data,
                        train_labels,
                        test_data,
                        test_labels,
                        channels=channels,
                        rescale=True,
                        save_path=train_root)
Beispiel #4
0
def test_cellpose_kfold_aug(data_root, save_root):
    """ test trained cellpose networks on all cyto images """
    device = mx.gpu()
    ntest = 68
    concatenation = [0]
    residual_on = [1]
    style_on = [1]
    channels = [2, 1]

    aps = np.zeros((9, 68, len(thresholds)))

    for j in range(9):
        train_root = os.path.join(data_root, 'train%d/' % j)
        model_root = os.path.join(train_root, 'models/')

        test_root = os.path.join(data_root, 'test%d/' % j)
        test_data = [
            io.imread(os.path.join(test_root, '%03d_img.tif' % i))
            for i in range(ntest)
        ]
        test_labels = [
            io.imread(os.path.join(test_root, '%03d_masks.tif' % i))
            for i in range(ntest)
        ]

        k = 0

        pretrained_models = get_pretrained_models(model_root, 0, 3,
                                                  residual_on[k], style_on[k],
                                                  concatenation[k])
        print(pretrained_models)

        cp_model = models.CellposeModel(device=device,
                                        pretrained_model=pretrained_models)

        dat = np.load(test_root + 'predicted_diams.npy',
                      allow_pickle=True).item()
        rescale = 30. / dat['predicted_diams']

        masks = cp_model.eval(test_data,
                              channels=channels,
                              rescale=rescale,
                              net_avg=True,
                              augment=True)[0]
        ap = metrics.average_precision(test_labels,
                                       masks,
                                       threshold=thresholds)[0]
        print(ap[:, [0, 5, 8]].mean(axis=0))
        aps[j] = ap

    return aps
Beispiel #5
0
def compare_masks(data_dir, image_names, runtype, model_type):
    """
    Helper function to check if outputs given by a test are exactly the same
    as the ground truth outputs.
    """
    data_dir_2D = data_dir.joinpath('2D')
    data_dir_3D = data_dir.joinpath('3D')
    for image_name in image_names:
        check = False
        if '2D' in runtype and '2D' in image_name:
            image_file = str(data_dir_2D.joinpath(image_name))
            name = os.path.splitext(image_file)[0]
            output_test = name + '_cp_masks.png'
            output_true = name + '_%s_masks.png' % model_type
            check = True
        elif '3D' in runtype and '3D' in image_name:
            image_file = str(data_dir_3D.joinpath(image_name))
            name = os.path.splitext(image_file)[0]
            output_test = name + '_cp_masks.tif'
            output_true = name + '_%s_masks.tif' % model_type
            check = True

        if check:
            if os.path.exists(output_test):
                print('checking output %s' % output_test)
                masks_test = io.imread(output_test)
                masks_true = io.imread(output_true)

                ap = metrics.average_precision(masks_true, masks_test)[0]
                print('average precision of [%0.3f %0.3f %0.3f]' %
                      (ap[0], ap[1], ap[2]))
                ap_precision = np.allclose(ap,
                                           np.ones(3),
                                           rtol=r_tol,
                                           atol=a_tol)

                matching_pix = np.logical_and(masks_test > 0,
                                              masks_true > 0).mean()
                all_pix = (masks_test > 0).mean()
                pix_precision = np.allclose(all_pix,
                                            matching_pix,
                                            rtol=r_tol,
                                            atol=a_tol)

                assert all([ap_precision, pix_precision])
            else:
                print('ERROR: no output file of name %s found' % output_test)
                assert False
Beispiel #6
0
 def LoadMultiple(self, event):
     wcd = 'Images (*.jpg,*.png,*.bmp,*.tif)|*.jpg;*.png;*.bmp;*.tif'
     dlg = wx.FileDialog(self, "Load files", "", "", wcd, wx.FD_MULTIPLE)
     if dlg.ShowModal() == wx.ID_OK:
         print('OK loaded')
         files = dlg.GetPaths()
         print(files)
         print('Number of files: ', len(files))
         imgs = [io.imread(f) for f in files]
         type = os.path.splitext(files[0])[1]
         self.channels = [self.channel, 0]
         modeltype = ('cyto', 'nuclei')[self.model]
         model = models.Cellpose(gpu=False, model_type=modeltype)
         masks, flows, styles, diams = model.eval(
             imgs,
             diameter=None,
             flow_threshold=self.number1,
             cellprob_threshold=self.number3,
             channels=self.channels)
         io.masks_flows_to_seg(imgs, masks, flows, diams, files,
                               self.channels)
         for f in files:
             npy = f.replace(type, '_seg.npy')
             data, maxkey = get_labels(npy)
             dir = npy.replace('_seg.npy', '_map.csv')
             np.savetxt(dir, data, delimiter=",")
             if self.centerShow:
                 centers = np.asarray(get_centers(data, maxkey))
                 dir = npy.replace('_seg.npy', '_center.csv')
                 np.savetxt(dir, centers, delimiter=",")
             os.remove(npy)
Beispiel #7
0
def test_timing(test_root, save_root):
    itest = 14
    test_data = io.imread(os.path.join(test_root, '%03d_img.tif' % itest))
    dat = np.load(os.path.join(test_root, 'predicted_diams.npy'),
                  allow_pickle=True).item()
    rescale = 30. / dat['predicted_diams'][itest]
    Ly, Lx = test_data.shape[1:]
    test_data = cv2.resize(np.transpose(test_data, (1, 2, 0)),
                           (int(Lx * rescale), int(Ly * rescale)))

    devices = [mx.gpu(), mx.cpu()]
    bsize = [256, 512, 1024]
    t100 = np.zeros((2, 3, 2))
    for d, device in enumerate(devices):
        model = models.CellposeModel(device=device, pretrained_model=None)
        for j in range(3):
            if j == 2:
                test_data = np.tile(test_data, (2, 2, 1))
            img = test_data[:bsize[j], :bsize[j]]
            imgs = [img for i in range(100)]
            for k in [0, 1]:
                tic = time.time()
                masks = model.eval(imgs,
                                   channels=[2, 1],
                                   rescale=1.0,
                                   net_avg=k)[0]
                print(masks[0].max())
                t100[d, j, k] = time.time() - tic
                print(t100[d, j, k])
def main(argv):
    parser = ParserCreator.createArgumentParser("./predict.yml")
    if len(argv) == 1:
        parser.print_help(sys.stderr)
        sys.exit(1)
    args = parser.parse_args(argv[1:])
    print(args)
    model = models.Cellpose(gpu=args.gpu, model_type=args.modelType)
    files = [
        os.path.join(args.dataPath, image)
        for image in os.listdir(args.dataPath)
        if (image.lower().endswith(".tif") or image.lower().endswith(".jpg")
            or image.lower().endswith(".png"))
        and not image.lower().endswith("_cp_masks.png")
    ]
    channels = [[args.segChannel, args.nucleiChannel]] * len(files)
    diameter = args.diameter
    if diameter == 0:
        diameter = None
    for channel, filename in zip(channels, files):
        img = io.imread(filename)
        masks, flows, styles, diams = model.eval(img,
                                                 diameter=diameter,
                                                 channels=channel)
        newFilename = filename.split(".")[0] + "_c" + str(
            args.segChannel) + "." + filename.split(".")[1]
        io.save_to_png(img, masks, flows, newFilename)
Beispiel #9
0
def test_cyto2_to_seg(data_dir, image_names):
    clear_output(data_dir, image_names)
    image_names = ['rgb_2D.png', 'rgb_2D_tif.tif']
    file_names = [str(data_dir.joinpath('2D').joinpath(image_name)) for image_name in image_names]
    imgs = [io.imread(file_name) for file_name in file_names]
    model_type = 'cyto2'
    model = models.Cellpose(model_type=model_type)
    channels = [2,1]
    masks, flows, styles, diams = model.eval(imgs, diameter=30, channels=channels, net_avg=False)
    io.masks_flows_to_seg(imgs, masks, flows, diams, file_names)
Beispiel #10
0
def test_class_3D(data_dir, image_names):
    clear_output(data_dir, image_names)
    img = io.imread(str(data_dir.joinpath('3D').joinpath('rgb_3D.tif')))
    model_types = ['nuclei']
    chan = [1]
    chan2 = [0]
    for m,model_type in enumerate(model_types):
        model = models.Cellpose(model_type='nuclei')
        masks = model.eval(img, do_3D=True, diameter=25, channels=[chan[m],chan2[m]], net_avg=False)[0]
        io.imsave(str(data_dir.joinpath('3D').joinpath('rgb_3D_cp_masks.tif')), masks)
        compare_masks(data_dir, ['rgb_3D.tif'], '3D', model_type)
        clear_output(data_dir, image_names)
Beispiel #11
0
def size_distributions(data_root, save_root):
    """ size distributions for all images """
    ntest = 68
    sz_dist = np.zeros((9, ntest))

    for j in range(9):
        test_root = os.path.join(data_root, 'test%d/' % j)
        test_labels = [
            io.imread(os.path.join(test_root, '%03d_masks.tif' % i))
            for i in range(ntest)
        ]
        sz_dist[j] = np.array(
            [utils.size_distribution(lbl) for lbl in test_labels])
    np.save(os.path.join(save_root, 'size_distribution.npy'), sz_dist)
    return sz_dist
Beispiel #12
0
def test_class_2D(data_dir, image_names):
    clear_output(data_dir, image_names)
    img = io.imread(str(data_dir.joinpath('2D').joinpath('rgb_2D.png')))
    model_types = ['nuclei']
    chan = [1]
    chan2 = [0]
    for m,model_type in enumerate(model_types):
        model = models.Cellpose(model_type=model_type)
        masks, flows, _, _ = model.eval(img, diameter=0, channels=[chan[m],chan2[m]], net_avg=False)
        io.imsave(str(data_dir.joinpath('2D').joinpath('rgb_2D_cp_masks.png')), masks)
        compare_masks(data_dir, ['rgb_2D.png'], '2D', model_type)
        clear_output(data_dir, image_names)
        if MATPLOTLIB:
            fig = plt.figure(figsize=(8,3))
            plot.show_segmentation(fig, img, masks, flows[0], channels=[chan[m],chan2[m]])
Beispiel #13
0
    def ClickFind(self, event):
        #segmentation
        modeltype = ('cyto', 'nuclei')[self.model]
        print(modeltype)
        model = models.Cellpose(gpu=False, model_type=modeltype)
        self.channels = [self.channel, 0]
        if self.regionShow:
            image = self.pilImg2
            pathname = self.pilImg1fullpath.replace(self.pilImg1type,
                                                    '_cropped.tif')
            image.save(pathname)
            self.nppilImg1 = io.imread(pathname)
        else:
            self.nppilImg1 = io.imread(self.pilImg1fullpath)
        print(self.number1, self.number3)
        self.masks, self.flows, styles, self.diams = model.eval(
            self.nppilImg1,
            diameter=None,
            flow_threshold=self.number1,
            cellprob_threshold=self.number3,
            channels=self.channels)
        io.masks_flows_to_seg(self.nppilImg1, self.masks, self.flows,
                              self.diams, self.pilImg1fullpath, self.channels)
        dir = self.pilImg1fullpath.replace(self.pilImg1type, '_seg.npy')

        self.data, self.maxkey = get_labels(dir, region=None)
        self.m_height.SetLabel(
            str(self.maxkey) + '  (avg. Diameter in pixels: ' +
            str(round(self.diams)) + ')')
        os.remove(dir)
        if self.centerShow:
            self.centers = get_centers(self.data, self.maxkey)
        newbox = wx.MessageDialog(None, 'Results succesfully saved', 'Notice',
                                  wx.OK)
        answer = newbox.ShowModal()
        newbox.Destroy()
Beispiel #14
0
def test_cellpose(test_root,
                  save_root,
                  pretrained_models,
                  diam_file=None,
                  model_type='cyto'):
    """ test single cellpose net or 4 nets averaged """
    device = mx.gpu()
    ntest = len(glob(os.path.join(test_root, '*_img.tif')))
    if model_type[:4] != 'nuclei':
        channels = [2, 1]
    else:
        channels = [0, 0]

    test_data = [
        io.imread(os.path.join(test_root, '%03d_img.tif' % i))
        for i in range(ntest)
    ]

    # saved diameters
    if model_type != 'cyto_sp':
        if diam_file is None:
            dat = np.load(os.path.join(test_root, 'predicted_diams.npy'),
                          allow_pickle=True).item()
        else:
            dat = np.load(diam_file, allow_pickle=True).item()
        if model_type == 'cyto':
            rescale = 30. / dat['predicted_diams']
        else:
            rescale = 17. / dat['predicted_diams']
    else:
        rescale = np.ones(len(test_data))

    model = models.CellposeModel(device=device,
                                 pretrained_model=pretrained_models)
    masks = model.eval(test_data, channels=channels, rescale=rescale)[0]

    np.save(os.path.join(save_root, 'cellpose_%s_masks.npy' % model_type),
            masks)
def segment_obj_indiv(path_scan,
                      obj_name,
                      str_channel,
                      img_ext,
                      new_size,
                      model_type,
                      diameter,
                      net_avg,
                      resample,
                      path_save,
                      input_subfolder=None,
                      callback_log=None,
                      callback_status=None,
                      callback_progress=None):
    """ Will recursively search folder for images to be analyzed!

    Parameters
    ----------
    path_scan : [type]
        [description]
    str_nuclei : [type]
        [description]
    img_ext : [type]
        [description]
    diameter : [type]
        [description]
    model_type : [type]
        [description]
    path_save : pathlib object or string
        Path to save results,
        - If Pathlib object, then this absolute path is used.
        - If 'string' a replacement operation on the provided name of the data path will be applied (see create_output_path).
    input_subfolder : str
        Name of subfolder that contains results. If specified ONLY files in this folder will be processed.
    callback_log : [type], optional
        [description], by default None
    callback_status : [type], optional
        [description], by default None
    callback_progress : [type], optional
        [description], by default None

    Returns
    -------
    [type]
        [description]
    """

    # Print all input parameters
    par_dict = locals()
    par_dict = clean_par_dict(par_dict)
    log_message(f"Function (segment_obj_indiv) called with: {str(par_dict)} ",
                callback_fun=callback_log)

    # Configurations
    config = {
        'model_type': model_type,
        'diameter': diameter,
        'net_avg': net_avg,
        'resample': resample
    }

    channels = [0, 1]

    # Use provided absolute user-path to save images.
    if isinstance(path_save, pathlib.PurePath):
        path_save_results = path_save
        if not path_save_results.is_dir():
            path_save_results.mkdir(parents=True)

    else:
        path_save_str_replace = path_save

    if not path_scan.is_dir():
        log_message(f'Path {path_scan} does not exist.',
                    callback_fun=callback_log)
        return

    # Search for file to be analyzed
    log_message(f'\nLoading images and segment them on the fly',
                callback_fun=callback_log)
    files_proc = []
    for path_img in path_scan.rglob(f'*{str_channel}*{img_ext}'):
        if input_subfolder:
            if path_img.parts[-2] == input_subfolder:
                files_proc.append(path_img)
        else:
            files_proc.append(path_img)
    n_imgs = len(files_proc)

    if n_imgs == 0:
        log_message(f'NO IMAGES FOUND. Check your settings.',
                    callback_fun=callback_log)
        return

    # Process files
    for idx, path_img in enumerate(files_proc):
        imgs = []
        files = []
        sizes_orginal = []

        log_message(f'Segmenting image : {path_img.name}',
                    callback_fun=callback_log)

        if callback_status:
            callback_status(f'Segmenting image : {path_img.name}')

        if callback_progress:
            progress = float((idx + 1) / n_imgs)
            callback_progress(progress)

        # Read images
        img = io.imread(str(path_img))
        if img.ndim != 2:
            log_message(
                f'\nERROR\n  Input image has to be 2D. Current image is {img.ndim}D',
                callback_fun=callback_log)
            continue

        # IMPORTANT: CV2 resize is defined as (width, height)
        print('>>> process file')
        print(f'input file (size): {img.shape}')

        sizes_orginal.append(img.shape)

        # Resize
        if new_size:

            # New size can also be defined as a scalar factor
            if len(new_size) == 1:
                scale_factor = new_size[0]
                img_size = img.shape
                new_size = tuple(int(ti / scale_factor) for ti in img_size)

            # IMPORTANT: CV2 resize is defined as (width, height)
            dsize = (new_size[1], new_size[0])
            img = cv2.resize(img, dsize)

        print(f'resized file (size): {img.shape}')

        # For object segmentation
        img_zeros = np.zeros(img.shape)
        img_3d_dpi = np.dstack([img_zeros, img_zeros, img])
        imgs.append(img_3d_dpi)
        files.append(path_img)

        # >>> Call function for prediction
        data = {
            'imgs': imgs,
            'file_names': files,
            'channels': channels,
            'obj_name': obj_name,
            'sizes_orginal': sizes_orginal,
            'new_size': new_size
        }

        # Create new output path if specified
        if not isinstance(path_save, pathlib.PurePath):
            path_save_results = create_output_path(path_img.parent,
                                                   path_save_str_replace,
                                                   subfolder='',
                                                   create_path=True)
            path_save_settings = path_save_results

        cellpose_predict(data,
                         config,
                         path_save=path_save_results,
                         callback_log=callback_log)

    # Save settings
    if len(imgs) > 0:
        fp = open(
            str(path_save_results / f'segmentation_settings__{obj_name}.json'),
            "w")
        json.dump(par_dict, fp, indent=4, sort_keys=True)
        fp.close()

    log_message(f'\n BATCH SEGMENTATION finished', callback_fun=callback_log)
Beispiel #16
0
def getVoronoiStyle(seg_file,max_voro_area,voro_imfile,voro_imfile_2,voro_outfile,voro_transfile):
    temp = np.asarray(np.load(seg_file,allow_pickle=True)).item()
    masks = temp['masks']

    im = np.zeros_like(np.array(masks))

    fro = pd.DataFrame(measure.regionprops_table(masks, properties=['label','centroid']))


    points_mask = np.array(fro[['centroid-0','centroid-1']].to_numpy())

    vor = Voronoi(points_mask)

    my_dpi=im.shape[1]

    plt.rcParams['figure.dpi'] = my_dpi
    plt.rcParams['figure.figsize'] = ( im.shape[0]/my_dpi,im.shape[1]/my_dpi)
    fig = plt.figure();

    for simplex in vor.ridge_vertices:
        simplex = np.asarray(simplex)
        if np.all(simplex >= 0):
            plt.plot(vor.vertices[simplex, 0], vor.vertices[simplex, 1], 'k-',c='black',linewidth=.2)

    center = points_mask.mean(axis=0)
    for pointidx, simplex in zip(vor.ridge_points, vor.ridge_vertices):
        simplex = np.asarray(simplex)
        if np.any(simplex < 0):
            i = simplex[simplex >= 0][0] # finite end Voronoi vertex
            t = points_mask[pointidx[0]] - points_mask[pointidx[1]]  # tangent
            t = t / np.linalg.norm(t)
            n = np.array([-t[1], t[0]]) # normal
            midpoint = points_mask[pointidx].mean(axis=0)
            far_point = vor.vertices[i] + np.sign(np.dot(midpoint - center, n)) * n * 100
            plt.plot([vor.vertices[i,0], far_point[0]],
                     [vor.vertices[i,1], far_point[1]], 'k-',c='black',linewidth=.2)

    plt.xlim([0, im.shape[0]]); plt.ylim([0,im.shape[1]])
    plt.axis('off')
    fig.tight_layout(pad=0)
    plt.savefig(voro_imfile, dpi=my_dpi, #bbox_inches='tight',#dpi=my_dpi,
                transparent=False, pad_inches=0,facecolor='white')
    plt.close()
    im2 = io.imread(voro_imfile)
    voro = (im2[:,:,0])
    voro = voro[1:-1, 1:-1]
    voro = np.pad(voro, pad_width=1, mode='constant')
    distance = ndi.distance_transform_edt(voro)
    coords = peak_local_max(distance, footprint=np.ones((1, 1)), labels=voro)
    mask = np.zeros(distance.shape, dtype=bool)
    mask[tuple(coords.T)] = True
    markers, _ = ndi.label(mask)
    labels = segmentation.watershed(-distance, markers, mask=voro)
    labels = morphology.remove_small_objects(labels, min_size=40, connectivity=1, in_place=False)
    labels = morphology.dilation(labels, morphology.square(3))
    segmasks = masks
    segmasks = morphology.dilation(segmasks,morphology.square(3))

    sizeOfSegs = pd.DataFrame(measure.regionprops_table(labels, properties=['label','area']))
    bigMasks = np.array(sizeOfSegs[sizeOfSegs['area']>=max_voro_area]['label'])
    newVorMask = np.copy(labels)[::-1,:]
    for bMI in range(len(bigMasks)):
        print("progress:"+str(bMI)+'/'+str(len(bigMasks)))
        chckMtx = (labels == bigMasks[bMI])[::-1,:]

        for i in range(len(points_mask)):
            confirm = points_mask[i]
            print(points_mask[i])
            print("---")

        tmp_cellpose_mask = (morphology.dilation((segmasks == int(fro[(fro['centroid-0']==confirm[0])&(fro['centroid-1']==confirm[1])]['label'])).T,morphology.disk(11))).astype(int)
        tmp_voronoi_mask = 2*chckMtx.astype(int)
        tmp_join = segmentation.join_segmentations(tmp_cellpose_mask,tmp_voronoi_mask)
        tmp_join = (tmp_join == np.max(tmp_join))

        newVorMask[newVorMask == bigMasks[bMI]] = 0
        newVorMask[tmp_join] = bigMasks[bMI]

    np.save(voro_outfile, newVorMask.T, allow_pickle=True, fix_imports=True)
    io.imsave(voro_imfile_2, segmentation.find_boundaries(newVorMask).T)

    oldAssign = pd.DataFrame(measure.regionprops_table(masks, properties=['label','centroid']))
    newAssign = pd.DataFrame(measure.regionprops_table(newVorMask, properties=['label','centroid']))

    Clps2Voro = pd.DataFrame()

    for nlab in range(newAssign.shape[0]):
        tmpMtx = (newVorMask == newAssign['label'][nlab])
        for olab in range(oldAssign.shape[0]):
            if (tmpMtx[int(np.round(oldAssign['centroid-1'][olab])),int(np.round(oldAssign['centroid-0'][olab]))]):
                Clps2Voro = Clps2Voro.append(pd.DataFrame([newAssign['label'][nlab], oldAssign['label'][olab]]).T)

    Clps2Voro = Clps2Voro.rename(columns={0: "voro_label", 1: "clps_label"})
    Clps2Voro = Clps2Voro.reset_index(drop=True)
    Clps2Voro.to_csv(voro_transfile)
Beispiel #17
0
def main():

    parser = argparse.ArgumentParser(description='cellpose parameters')
    parser.add_argument('--check_mkl',
                        action='store_true',
                        help='check if mkl working')
    parser.add_argument(
        '--mkldnn',
        action='store_true',
        help='for mxnet, force MXNET_SUBGRAPH_BACKEND = "MKLDNN"')
    parser.add_argument('--train',
                        action='store_true',
                        help='train network using images in dir')
    parser.add_argument('--dir',
                        required=False,
                        default=[],
                        type=str,
                        help='folder containing data to run or train on')
    parser.add_argument('--look_one_level_down', action='store_true', help='')
    parser.add_argument('--mxnet', action='store_true', help='use mxnet')
    parser.add_argument('--img_filter',
                        required=False,
                        default=[],
                        type=str,
                        help='end string for images to run on')
    parser.add_argument('--use_gpu',
                        action='store_true',
                        help='use gpu if mxnet with cuda installed')
    parser.add_argument(
        '--fast_mode',
        action='store_true',
        help="make code run faster by turning off 4 network averaging")
    parser.add_argument(
        '--resample',
        action='store_true',
        help=
        "run dynamics on full image (slower for images with large diameters)")
    parser.add_argument(
        '--no_interp',
        action='store_true',
        help='do not interpolate when running dynamics (was default)')
    # settings for running cellpose
    parser.add_argument(
        '--do_3D',
        action='store_true',
        help='process images as 3D stacks of images (nplanes x nchan x Ly x Lx'
    )
    parser.add_argument('--pretrained_model',
                        required=False,
                        default='cyto',
                        type=str,
                        help='model to use')
    parser.add_argument(
        '--chan',
        required=False,
        default=0,
        type=int,
        help='channel to segment; 0: GRAY, 1: RED, 2: GREEN, 3: BLUE')
    parser.add_argument(
        '--chan2',
        required=False,
        default=0,
        type=int,
        help=
        'nuclear channel (if cyto, optional); 0: NONE, 1: RED, 2: GREEN, 3: BLUE'
    )
    parser.add_argument('--invert',
                        required=False,
                        action='store_true',
                        help='invert grayscale channel')
    parser.add_argument(
        '--all_channels',
        action='store_true',
        help=
        'use all channels in image if using own model and images with special channels'
    )
    parser.add_argument(
        '--diameter',
        required=False,
        default=30.,
        type=float,
        help='cell diameter, if 0 cellpose will estimate for each image')
    parser.add_argument(
        '--stitch_threshold',
        required=False,
        default=0.0,
        type=float,
        help=
        'compute masks in 2D then stitch together masks with IoU>0.9 across planes'
    )
    parser.add_argument(
        '--flow_threshold',
        required=False,
        default=0.4,
        type=float,
        help='flow error threshold, 0 turns off this optional QC step')
    parser.add_argument('--cellprob_threshold',
                        required=False,
                        default=0.0,
                        type=float,
                        help='cell probability threshold, centered at 0.0')
    parser.add_argument('--save_png',
                        action='store_true',
                        help='save masks as png')
    parser.add_argument('--save_outlines',
                        action='store_true',
                        help='save outlines as text file for ImageJ')
    parser.add_argument('--save_tif',
                        action='store_true',
                        help='save masks as tif')
    parser.add_argument('--no_npy',
                        action='store_true',
                        help='suppress saving of npy')
    parser.add_argument(
        '--channel_axis',
        required=False,
        default=None,
        type=int,
        help='axis of image which corresponds to image channels')
    parser.add_argument('--z_axis',
                        required=False,
                        default=None,
                        type=int,
                        help='axis of image which corresponds to Z dimension')
    parser.add_argument('--exclude_on_edges',
                        action='store_true',
                        help='discard masks which touch edges of image')
    parser.add_argument(
        '--unet',
        required=False,
        default=0,
        type=int,
        help='run standard unet instead of cellpose flow output')
    parser.add_argument(
        '--nclasses',
        required=False,
        default=3,
        type=int,
        help='if running unet, choose 2 or 3, otherwise not used')

    # settings for training
    parser.add_argument('--train_size',
                        action='store_true',
                        help='train size network at end of training')
    parser.add_argument('--mask_filter',
                        required=False,
                        default='_masks',
                        type=str,
                        help='end string for masks to run on')
    parser.add_argument('--test_dir',
                        required=False,
                        default=[],
                        type=str,
                        help='folder containing test data (optional)')
    parser.add_argument('--learning_rate',
                        required=False,
                        default=0.2,
                        type=float,
                        help='learning rate')
    parser.add_argument('--n_epochs',
                        required=False,
                        default=500,
                        type=int,
                        help='number of epochs')
    parser.add_argument('--batch_size',
                        required=False,
                        default=8,
                        type=int,
                        help='batch size')
    parser.add_argument('--residual_on',
                        required=False,
                        default=1,
                        type=int,
                        help='use residual connections')
    parser.add_argument('--style_on',
                        required=False,
                        default=1,
                        type=int,
                        help='use style vector')
    parser.add_argument(
        '--concatenation',
        required=False,
        default=0,
        type=int,
        help=
        'concatenate downsampled layers with upsampled layers (off by default which means they are added)'
    )

    args = parser.parse_args()

    if args.check_mkl:
        mkl_enabled = models.check_mkl((not args.mxnet))
    else:
        mkl_enabled = True

    if not args.train and (mkl_enabled and args.mkldnn):
        os.environ["MXNET_SUBGRAPH_BACKEND"] = "MKLDNN"
    else:
        os.environ["MXNET_SUBGRAPH_BACKEND"] = ""

    if len(args.dir) == 0:
        if not GUI_ENABLED:
            logger.critical('ERROR: %s' % GUI_ERROR)
            if GUI_IMPORT:
                logger.critical(
                    'GUI FAILED: GUI dependencies may not be installed, to install, run'
                )
                logger.critical('     pip install cellpose[gui]')
        else:
            gui.run()

    else:
        use_gpu = False
        channels = [args.chan, args.chan2]

        # find images
        if len(args.img_filter) > 0:
            imf = args.img_filter
        else:
            imf = None

        device, gpu = models.assign_device((not args.mxnet), args.use_gpu)

        if not args.train and not args.train_size:
            tic = time.time()
            if not (args.pretrained_model == 'cyto' or args.pretrained_model
                    == 'nuclei' or args.pretrained_model == 'cyto2'):
                cpmodel_path = args.pretrained_model
                if not os.path.exists(cpmodel_path):
                    logger.warning(
                        'model path does not exist, using cyto model')
                    args.pretrained_model = 'cyto'

            image_names = io.get_image_files(
                args.dir,
                args.mask_filter,
                imf=imf,
                look_one_level_down=args.look_one_level_down)
            nimg = len(image_names)

            cstr0 = ['GRAY', 'RED', 'GREEN', 'BLUE']
            cstr1 = ['NONE', 'RED', 'GREEN', 'BLUE']
            logger.info(
                '>>>> running cellpose on %d images using chan_to_seg %s and chan (opt) %s'
                % (nimg, cstr0[channels[0]], cstr1[channels[1]]))

            if args.pretrained_model == 'cyto' or args.pretrained_model == 'nuclei' or args.pretrained_model == 'cyto2':
                if args.mxnet and args.pretrained_model == 'cyto2':
                    logger.warning(
                        'cyto2 model not available in mxnet, using cyto model')
                    args.pretrained_model = 'cyto'
                model = models.Cellpose(gpu=gpu,
                                        device=device,
                                        model_type=args.pretrained_model,
                                        torch=(not args.mxnet))
            else:
                if args.all_channels:
                    channels = None
                model = models.CellposeModel(gpu=gpu,
                                             device=device,
                                             pretrained_model=cpmodel_path,
                                             torch=(not args.mxnet))

            if args.diameter == 0:
                if args.pretrained_model == 'cyto' or args.pretrained_model == 'nuclei' or args.pretrained_model == 'cyto2':
                    diameter = None
                    logger.info('>>>> estimating diameter for each image')
                else:
                    logger.info(
                        '>>>> using user-specified model, no auto-diameter estimation available'
                    )
                    diameter = model.diam_mean
            else:
                diameter = args.diameter
                logger.info('>>>> using diameter %0.2f for all images' %
                            diameter)

            tqdm_out = utils.TqdmToLogger(logger, level=logging.INFO)
            for image_name in tqdm(image_names, file=tqdm_out):
                image = io.imread(image_name)
                out = model.eval(image,
                                 channels=channels,
                                 diameter=diameter,
                                 do_3D=args.do_3D,
                                 net_avg=(not args.fast_mode),
                                 augment=False,
                                 resample=args.resample,
                                 flow_threshold=args.flow_threshold,
                                 cellprob_threshold=args.cellprob_threshold,
                                 invert=args.invert,
                                 batch_size=args.batch_size,
                                 interp=(not args.no_interp),
                                 channel_axis=args.channel_axis,
                                 z_axis=args.z_axis)
                masks, flows = out[:2]
                if len(out) > 3:
                    diams = out[-1]
                else:
                    diams = diameter
                if args.exclude_on_edges:
                    masks = utils.remove_edge_masks(masks)
                if not args.no_npy:
                    io.masks_flows_to_seg(image, masks, flows, diams,
                                          image_name, channels)
                if args.save_png or args.save_tif or args.save_outlines:
                    io.save_masks(image,
                                  masks,
                                  flows,
                                  image_name,
                                  png=args.save_png,
                                  tif=args.save_tif,
                                  outlines=args.save_outlines)
            logger.info('>>>> completed in %0.3f sec' % (time.time() - tic))
        else:
            if args.pretrained_model == 'cyto' or args.pretrained_model == 'nuclei' or args.pretrained_model == 'cyto2':
                if args.mxnet and args.pretrained_model == 'cyto2':
                    logger.warning(
                        'cyto2 model not available in mxnet, using cyto model')
                    args.pretrained_model = 'cyto'
                cpmodel_path = models.model_path(args.pretrained_model, 0,
                                                 not args.mxnet)
                if args.pretrained_model == 'cyto':
                    szmean = 30.
                else:
                    szmean = 17.
            else:
                cpmodel_path = os.fspath(args.pretrained_model)
                szmean = 30.

            test_dir = None if len(args.test_dir) == 0 else args.test_dir
            output = io.load_train_test_data(args.dir, test_dir, imf,
                                             args.mask_filter, args.unet,
                                             args.look_one_level_down)
            images, labels, image_names, test_images, test_labels, image_names_test = output

            # training with all channels
            if args.all_channels:
                img = images[0]
                if img.ndim == 3:
                    nchan = min(img.shape)
                elif img.ndim == 2:
                    nchan = 1
                channels = None
            else:
                nchan = 2

            # model path
            if not os.path.exists(cpmodel_path):
                if not args.train:
                    error_message = 'ERROR: model path missing or incorrect - cannot train size model'
                    logger.critical(error_message)
                    raise ValueError(error_message)
                cpmodel_path = False
                logger.info('>>>> training from scratch')
                if args.diameter == 0:
                    rescale = False
                    logger.info(
                        '>>>> median diameter set to 0 => no rescaling during training'
                    )
                else:
                    rescale = True
                    szmean = args.diameter
            else:
                rescale = True
                args.diameter = szmean
                logger.info('>>>> pretrained model %s is being used' %
                            cpmodel_path)
                args.residual_on = 1
                args.style_on = 1
                args.concatenation = 0
            if rescale and args.train:
                logger.info(
                    '>>>> during training rescaling images to fixed diameter of %0.1f pixels'
                    % args.diameter)

            # initialize model
            if args.unet:
                model = core.UnetModel(device=device,
                                       pretrained_model=cpmodel_path,
                                       diam_mean=szmean,
                                       residual_on=args.residual_on,
                                       style_on=args.style_on,
                                       concatenation=args.concatenation,
                                       nclasses=args.nclasses,
                                       nchan=nchan)
            else:
                model = models.CellposeModel(device=device,
                                             torch=(not args.mxnet),
                                             pretrained_model=cpmodel_path,
                                             diam_mean=szmean,
                                             residual_on=args.residual_on,
                                             style_on=args.style_on,
                                             concatenation=args.concatenation,
                                             nchan=nchan)

            # train segmentation model
            if args.train:
                cpmodel_path = model.train(images,
                                           labels,
                                           train_files=image_names,
                                           test_data=test_images,
                                           test_labels=test_labels,
                                           test_files=image_names_test,
                                           learning_rate=args.learning_rate,
                                           channels=channels,
                                           save_path=os.path.realpath(
                                               args.dir),
                                           rescale=rescale,
                                           n_epochs=args.n_epochs,
                                           batch_size=args.batch_size)
                model.pretrained_model = cpmodel_path
                logger.info('>>>> model trained and saved to %s' %
                            cpmodel_path)

            # train size model
            if args.train_size:
                sz_model = models.SizeModel(cp_model=model, device=device)
                sz_model.train(images,
                               labels,
                               test_images,
                               test_labels,
                               channels=channels,
                               batch_size=args.batch_size)
                if test_images is not None:
                    predicted_diams, diams_style = sz_model.eval(
                        test_images, channels=channels)
                    if test_labels[0].ndim > 2:
                        tlabels = [lbl[0] for lbl in test_labels]
                    else:
                        tlabels = test_labels
                    ccs = np.corrcoef(
                        diams_style,
                        np.array([utils.diameters(lbl)[0]
                                  for lbl in tlabels]))[0, 1]
                    cc = np.corrcoef(
                        predicted_diams,
                        np.array([utils.diameters(lbl)[0]
                                  for lbl in tlabels]))[0, 1]
                    logger.info(
                        'style test correlation: %0.4f; final test correlation: %0.4f'
                        % (ccs, cc))
                    np.save(
                        os.path.join(
                            args.test_dir, '%s_predicted_diams.npy' %
                            os.path.split(cpmodel_path)[1]), {
                                'predicted_diams': predicted_diams,
                                'diams_style': diams_style
                            })
Beispiel #18
0
def main():
    parser = argparse.ArgumentParser(description='cellpose parameters')

    # settings for CPU vs GPU
    hardware_args = parser.add_argument_group("hardware arguments")
    hardware_args.add_argument(
        '--use_gpu',
        action='store_true',
        help='use gpu if torch or mxnet with cuda installed')
    hardware_args.add_argument('--check_mkl',
                               action='store_true',
                               help='check if mkl working')
    hardware_args.add_argument(
        '--mkldnn',
        action='store_true',
        help='for mxnet, force MXNET_SUBGRAPH_BACKEND = "MKLDNN"')

    # settings for locating and formatting images
    input_img_args = parser.add_argument_group("input image arguments")
    input_img_args.add_argument(
        '--dir',
        default=[],
        type=str,
        help='folder containing data to run or train on.')
    input_img_args.add_argument(
        '--look_one_level_down',
        action='store_true',
        help='run processing on all subdirectories of current folder')
    input_img_args.add_argument('--mxnet',
                                action='store_true',
                                help='use mxnet')
    input_img_args.add_argument('--img_filter',
                                default=[],
                                type=str,
                                help='end string for images to run on')
    input_img_args.add_argument(
        '--channel_axis',
        default=None,
        type=int,
        help='axis of image which corresponds to image channels')
    input_img_args.add_argument(
        '--z_axis',
        default=None,
        type=int,
        help='axis of image which corresponds to Z dimension')
    input_img_args.add_argument(
        '--chan',
        default=0,
        type=int,
        help=
        'channel to segment; 0: GRAY, 1: RED, 2: GREEN, 3: BLUE. Default: %(default)s'
    )
    input_img_args.add_argument(
        '--chan2',
        default=0,
        type=int,
        help=
        'nuclear channel (if cyto, optional); 0: NONE, 1: RED, 2: GREEN, 3: BLUE. Default: %(default)s'
    )
    input_img_args.add_argument('--invert',
                                action='store_true',
                                help='invert grayscale channel')
    input_img_args.add_argument(
        '--all_channels',
        action='store_true',
        help=
        'use all channels in image if using own model and images with special channels'
    )

    # model settings
    model_args = parser.add_argument_group("model arguments")
    parser.add_argument('--pretrained_model',
                        required=False,
                        default='cyto',
                        type=str,
                        help='model to use')
    parser.add_argument(
        '--unet',
        required=False,
        default=0,
        type=int,
        help='run standard unet instead of cellpose flow output')
    model_args.add_argument(
        '--nclasses',
        default=3,
        type=int,
        help=
        'if running unet, choose 2 or 3; if training omni, choose 4; standard Cellpose uses 3'
    )

    # algorithm settings
    algorithm_args = parser.add_argument_group("algorithm arguments")
    parser.add_argument('--omni',
                        action='store_true',
                        help='Omnipose algorithm (disabled by default)')
    parser.add_argument(
        '--cluster',
        action='store_true',
        help=
        'DBSCAN clustering. Reduces oversegmentation of thin features (disabled by default).'
    )
    parser.add_argument(
        '--fast_mode',
        action='store_true',
        help=
        'make code run faster by turning off 4 network averaging and resampling'
    )
    parser.add_argument(
        '--no_resample',
        action='store_true',
        help=
        "disable dynamics on full image (makes algorithm faster for images with large diameters)"
    )
    parser.add_argument('--no_net_avg',
                        action='store_true',
                        help='make code run faster by only running 1 network')
    parser.add_argument(
        '--no_interp',
        action='store_true',
        help='do not interpolate when running dynamics (was default)')
    parser.add_argument(
        '--do_3D',
        action='store_true',
        help='process images as 3D stacks of images (nplanes x nchan x Ly x Lx'
    )
    parser.add_argument(
        '--diameter',
        required=False,
        default=30.,
        type=float,
        help='cell diameter, if 0 cellpose will estimate for each image')
    parser.add_argument(
        '--stitch_threshold',
        required=False,
        default=0.0,
        type=float,
        help=
        'compute masks in 2D then stitch together masks with IoU>0.9 across planes'
    )

    algorithm_args.add_argument(
        '--flow_threshold',
        default=0.4,
        type=float,
        help=
        'flow error threshold, 0 turns off this optional QC step. Default: %(default)s'
    )
    algorithm_args.add_argument(
        '--mask_threshold',
        default=0,
        type=float,
        help=
        'mask threshold, default is 0, decrease to find more and larger masks')

    parser.add_argument('--anisotropy',
                        required=False,
                        default=1.0,
                        type=float,
                        help='anisotropy of volume in 3D')
    parser.add_argument(
        '--diam_threshold',
        required=False,
        default=12.0,
        type=float,
        help=
        'cell diameter threshold for upscaling before mask rescontruction, default 12.'
    )
    parser.add_argument('--exclude_on_edges',
                        action='store_true',
                        help='discard masks which touch edges of image')

    # output settings
    output_args = parser.add_argument_group("output arguments")
    output_args.add_argument(
        '--save_png',
        action='store_true',
        help='save masks as png and outlines as text file for ImageJ')
    output_args.add_argument(
        '--save_tif',
        action='store_true',
        help='save masks as tif and outlines as text file for ImageJ')
    output_args.add_argument('--no_npy',
                             action='store_true',
                             help='suppress saving of npy')
    output_args.add_argument(
        '--savedir',
        default=None,
        type=str,
        help=
        'folder to which segmentation results will be saved (defaults to input image directory)'
    )
    output_args.add_argument(
        '--dir_above',
        action='store_true',
        help=
        'save output folders adjacent to image folder instead of inside it (off by default)'
    )
    output_args.add_argument(
        '--in_folders',
        action='store_true',
        help='flag to save output in folders (off by default)')
    output_args.add_argument(
        '--save_flows',
        action='store_true',
        help=
        'whether or not to save RGB images of flows when masks are saved (disabled by default)'
    )
    output_args.add_argument(
        '--save_outlines',
        action='store_true',
        help=
        'whether or not to save RGB outline images when masks are saved (disabled by default)'
    )
    output_args.add_argument(
        '--save_ncolor',
        action='store_true',
        help=
        'whether or not to save minimal "n-color" masks (disabled by default')
    output_args.add_argument(
        '--save_txt',
        action='store_true',
        help='flag to enable txt outlines for ImageJ (disabled by default)')

    # training settings
    training_args = parser.add_argument_group("training arguments")
    training_args.add_argument('--train',
                               action='store_true',
                               help='train network using images in dir')
    training_args.add_argument('--train_size',
                               action='store_true',
                               help='train size network at end of training')
    training_args.add_argument(
        '--mask_filter',
        default='_masks',
        type=str,
        help='end string for masks to run on. Default: %(default)s')
    training_args.add_argument('--test_dir',
                               default=[],
                               type=str,
                               help='folder containing test data (optional)')
    training_args.add_argument('--learning_rate',
                               default=0.2,
                               type=float,
                               help='learning rate. Default: %(default)s')
    training_args.add_argument('--n_epochs',
                               default=500,
                               type=int,
                               help='number of epochs. Default: %(default)s')
    training_args.add_argument('--batch_size',
                               default=8,
                               type=int,
                               help='batch size. Default: %(default)s')
    training_args.add_argument(
        '--min_train_masks',
        default=5,
        type=int,
        help=
        'minimum number of masks a training image must have to be used. Default: %(default)s'
    )
    training_args.add_argument('--residual_on',
                               default=1,
                               type=int,
                               help='use residual connections')
    training_args.add_argument('--style_on',
                               default=1,
                               type=int,
                               help='use style vector')
    training_args.add_argument(
        '--concatenation',
        default=0,
        type=int,
        help=
        'concatenate downsampled layers with upsampled layers (off by default which means they are added)'
    )
    training_args.add_argument(
        '--save_every',
        default=100,
        type=int,
        help='number of epochs to skip between saves. Default: %(default)s')
    training_args.add_argument(
        '--save_each',
        action='store_true',
        help=
        'save the model under a different filename per --save_every epoch for later comparsion'
    )

    # misc settings
    parser.add_argument(
        '--verbose',
        action='store_true',
        help=
        'flag to output extra information (e.g. diameter metrics) for debugging and fine-tuning parameters'
    )
    parser.add_argument(
        '--testing',
        action='store_true',
        help=
        'flag to suppress CLI user confirmation for saving output; for test scripts'
    )

    args = parser.parse_args()

    # handle mxnet option
    if args.check_mkl:
        mkl_enabled = models.check_mkl((not args.mxnet))
    else:
        mkl_enabled = True

    if not args.train and (mkl_enabled and args.mkldnn):
        os.environ["MXNET_SUBGRAPH_BACKEND"] = "MKLDNN"
    else:
        os.environ["MXNET_SUBGRAPH_BACKEND"] = ""

    if len(args.dir) == 0:
        if not GUI_ENABLED:
            print('GUI ERROR: %s' % GUI_ERROR)
            if GUI_IMPORT:
                print(
                    'GUI FAILED: GUI dependencies may not be installed, to install, run'
                )
                print('     pip install cellpose[gui]')
        else:
            gui.run()

    else:
        if args.verbose:
            from .io import logger_setup
            logger, log_file = logger_setup()
        else:
            print(
                '>>>> !NEW LOGGING SETUP! To see cellpose progress, set --verbose'
            )
            print('No --verbose => no progress or info printed')
            logger = logging.getLogger(__name__)

        use_gpu = False
        channels = [args.chan, args.chan2]

        # find images
        if len(args.img_filter) > 0:
            imf = args.img_filter
        else:
            imf = None

        # Check with user if they REALLY mean to run without saving anything
        if not (args.train or args.train_size):
            saving_something = args.save_png or args.save_tif or args.save_flows or args.save_ncolor or args.save_txt

        device, gpu = models.assign_device((not args.mxnet), args.use_gpu)

        #define available model names, right now we have three broad categories
        model_names = [
            'cyto', 'nuclei', 'bact', 'cyto2', 'bact_omni', 'cyto2_omni'
        ]
        builtin_model = np.any(
            [args.pretrained_model == s for s in model_names])
        cytoplasmic = 'cyto' in args.pretrained_model
        nuclear = 'nuclei' in args.pretrained_model
        bacterial = 'bact' in args.pretrained_model

        # force omni on for those models, but don't toggle it off if manually specified
        if 'omni' in args.pretrained_model:
            args.omni = True

        if args.cluster and 'sklearn' not in sys.modules:
            print('>>>> DBSCAN clustering requires scikit-learn.')
            confirm = confirm_prompt('Install scikit-learn?')
            if confirm:
                install('scikit-learn')
            else:
                print(
                    '>>>> scikit-learn not installed. DBSCAN clustering will be automatically disabled.'
                )

        omni = check_omni(
            args.omni
        )  # repeat the above check but factor it for use elsewhere
        if args.omni:
            print(
                '>>>> Omnipose enabled. See https://raw.githubusercontent.com/MouseLand/cellpose/master/cellpose/omnipose/license.txt for licensing details.'
            )

        if not args.train and not args.train_size:
            tic = time.time()
            if not builtin_model:
                cpmodel_path = args.pretrained_model
                if not os.path.exists(cpmodel_path):
                    logger.warning(
                        'model path does not exist, using cyto model')
                    args.pretrained_model = 'cyto'
                else:
                    logger.info(f'>>> running model {cpmodel_path}')

            image_names = io.get_image_files(
                args.dir,
                args.mask_filter,
                imf=imf,
                look_one_level_down=args.look_one_level_down)
            nimg = len(image_names)

            cstr0 = ['GRAY', 'RED', 'GREEN', 'BLUE']
            cstr1 = ['NONE', 'RED', 'GREEN', 'BLUE']
            logger.info(
                '>>>> running cellpose on %d images using chan_to_seg %s and chan (opt) %s'
                % (nimg, cstr0[channels[0]], cstr1[channels[1]]))
            if args.omni:
                logger.info(f'>>>> omni is ON, cluster is {args.cluster}')

            # handle built-in model exceptions; bacterial ones get no size model
            if builtin_model:
                if args.mxnet:
                    if args.pretrained_model == 'cyto2':
                        logger.warning(
                            'cyto2 model not available in mxnet, using cyto model'
                        )
                        args.pretrained_model = 'cyto'
                    if bacterial:
                        logger.warning(
                            'bacterial models not available in mxnet, using pytorch'
                        )
                        args.mxnet = False
                if not bacterial:
                    model = models.Cellpose(gpu=gpu,
                                            device=device,
                                            model_type=args.pretrained_model,
                                            torch=(not args.mxnet),
                                            omni=args.omni,
                                            net_avg=(not args.fast_mode
                                                     and not args.no_net_avg))
                else:
                    cpmodel_path = models.model_path(args.pretrained_model, 0,
                                                     True)
                    model = models.CellposeModel(gpu=gpu,
                                                 device=device,
                                                 pretrained_model=cpmodel_path,
                                                 torch=True,
                                                 nclasses=args.nclasses,
                                                 omni=args.omni,
                                                 net_avg=False)
            else:
                if args.all_channels:
                    channels = None
                model = models.CellposeModel(gpu=gpu,
                                             device=device,
                                             pretrained_model=cpmodel_path,
                                             torch=True,
                                             nclasses=args.nclasses,
                                             omni=args.omni,
                                             net_avg=False)

            # omni changes not implemented for mxnet. Full parity for cpu/gpu in pytorch.
            if args.omni and args.mxnet:
                logger.info('>>>> omni only implemented in pytorch.')
                confirm = confirm_prompt('Continue with omni set to false?')
                if not confirm:
                    exit()
                else:
                    logger.info('>>>> omni set to false.')
                    args.omni = False

            # For now, omni version is not compatible with 3D. WIP.
            if args.omni and args.do_3D:
                logger.info(
                    '>>>> omni not yet compatible with 3D segmentation.')
                confirm = confirm_prompt('Continue with omni set to false?')
                if not confirm:
                    exit()
                else:
                    logger.info('>>>> omni set to false.')
                    args.omni = False

            # omni model needs 4 classes. Would prefer a more elegant way to automaticaly update the flow fields
            # instead of users deleting them manually - a check on the number of channels, maybe, or just use
            # the yes/no prompt to ask the user if they want their flow fields in the given directory to be deleted.
            # would also need the look_one_level_down optionally toggled...
            if args.omni and args.train:
                logger.info('>>>> Training omni model. Setting nclasses to 4.')
                logger.info(
                    '>>>> Make sure your flow fields are deleted and re-computed.'
                )
                args.nclasses = 4

            # handle diameters
            if args.diameter == 0:
                if builtin_model:
                    diameter = None
                    logger.info('>>>> estimating diameter for each image')
                else:
                    logger.info(
                        '>>>> using user-specified model, no auto-diameter estimation available'
                    )
                    diameter = model.diam_mean
            else:
                diameter = args.diameter
                logger.info('>>>> using diameter %0.2f for all images' %
                            diameter)

            tqdm_out = utils.TqdmToLogger(logger, level=logging.INFO)

            for image_name in tqdm(image_names, file=tqdm_out):
                image = io.imread(image_name)
                out = model.eval(image,
                                 channels=channels,
                                 diameter=diameter,
                                 do_3D=args.do_3D,
                                 net_avg=(not args.fast_mode
                                          and not args.no_net_avg),
                                 augment=False,
                                 resample=(not args.no_resample
                                           and not args.fast_mode),
                                 flow_threshold=args.flow_threshold,
                                 mask_threshold=args.mask_threshold,
                                 diam_threshold=args.diam_threshold,
                                 invert=args.invert,
                                 batch_size=args.batch_size,
                                 interp=(not args.no_interp),
                                 cluster=args.cluster,
                                 channel_axis=args.channel_axis,
                                 z_axis=args.z_axis,
                                 omni=args.omni,
                                 anisotropy=args.anisotropy,
                                 verbose=args.verbose,
                                 model_loaded=True)
                masks, flows = out[:2]
                if len(out) > 3:
                    diams = out[-1]
                else:
                    diams = diameter
                if args.exclude_on_edges:
                    masks = utils.remove_edge_masks(masks)
                if not args.no_npy:
                    io.masks_flows_to_seg(image, masks, flows, diams,
                                          image_name, channels)
                if saving_something:
                    io.save_masks(image,
                                  masks,
                                  flows,
                                  image_name,
                                  png=args.save_png,
                                  tif=args.save_tif,
                                  save_flows=args.save_flows,
                                  save_outlines=args.save_outlines,
                                  save_ncolor=args.save_ncolor,
                                  dir_above=args.dir_above,
                                  savedir=args.savedir,
                                  save_txt=args.save_txt,
                                  in_folders=args.in_folders)
            logger.info('>>>> completed in %0.3f sec' % (time.time() - tic))
        else:
            if builtin_model:
                if args.mxnet and args.pretrained_model == 'cyto2':
                    logger.warning(
                        'cyto2 model not available in mxnet, using cyto model')
                    args.pretrained_model = 'cyto'
                cpmodel_path = models.model_path(args.pretrained_model, 0,
                                                 not args.mxnet)
                if cytoplasmic:
                    szmean = 30.
                elif nuclear:
                    szmean = 17.
                elif bacterial:
                    szmean = 0.  #bacterial models are not rescaled
            else:
                cpmodel_path = os.fspath(args.pretrained_model)
                szmean = 30.

            test_dir = None if len(args.test_dir) == 0 else args.test_dir
            output = io.load_train_test_data(args.dir, test_dir, imf,
                                             args.mask_filter, args.unet,
                                             args.look_one_level_down)
            images, labels, image_names, test_images, test_labels, image_names_test = output

            # training with all channels
            if args.all_channels:
                img = images[0]
                if img.ndim == 3:
                    nchan = min(img.shape)
                elif img.ndim == 2:
                    nchan = 1
                channels = None
            else:
                nchan = 2

            # model path
            if not os.path.exists(cpmodel_path):
                if not args.train:
                    error_message = 'ERROR: model path missing or incorrect - cannot train size model'
                    logger.critical(error_message)
                    raise ValueError(error_message)
                cpmodel_path = False
                logger.info('>>>> training from scratch')
                if args.diameter == 0:
                    rescale = False
                    logger.info(
                        '>>>> median diameter set to 0 => no rescaling during training'
                    )
                else:
                    rescale = True
                    szmean = args.diameter
            else:
                rescale = True
                args.diameter = szmean
                logger.info('>>>> pretrained model %s is being used' %
                            cpmodel_path)
                args.residual_on = 1
                args.style_on = 1
                args.concatenation = 0
            if rescale and args.train:
                logger.info(
                    '>>>> during training rescaling images to fixed diameter of %0.1f pixels'
                    % args.diameter)

            # initialize model
            if args.unet:
                model = core.UnetModel(device=device,
                                       pretrained_model=cpmodel_path,
                                       diam_mean=szmean,
                                       residual_on=args.residual_on,
                                       style_on=args.style_on,
                                       concatenation=args.concatenation,
                                       nclasses=args.nclasses,
                                       nchan=nchan)
            else:
                model = models.CellposeModel(device=device,
                                             torch=(not args.mxnet),
                                             pretrained_model=cpmodel_path,
                                             diam_mean=szmean,
                                             residual_on=args.residual_on,
                                             style_on=args.style_on,
                                             concatenation=args.concatenation,
                                             nclasses=args.nclasses,
                                             nchan=nchan,
                                             omni=args.omni)

            # train segmentation model
            if args.train:
                cpmodel_path = model.train(
                    images,
                    labels,
                    train_files=image_names,
                    test_data=test_images,
                    test_labels=test_labels,
                    test_files=image_names_test,
                    learning_rate=args.learning_rate,
                    channels=channels,
                    save_path=os.path.realpath(args.dir),
                    save_every=args.save_every,
                    save_each=args.save_each,
                    rescale=rescale,
                    n_epochs=args.n_epochs,
                    batch_size=args.batch_size,
                    min_train_masks=args.min_train_masks,
                    omni=args.omni)
                model.pretrained_model = cpmodel_path
                logger.info('>>>> model trained and saved to %s' %
                            cpmodel_path)

            # train size model
            if args.train_size:
                sz_model = models.SizeModel(cp_model=model, device=device)
                sz_model.train(images,
                               labels,
                               test_images,
                               test_labels,
                               channels=channels,
                               batch_size=args.batch_size)
                if test_images is not None:
                    predicted_diams, diams_style = sz_model.eval(
                        test_images, channels=channels)
                    if test_labels[0].ndim > 2:
                        tlabels = [lbl[0] for lbl in test_labels]
                    else:
                        tlabels = test_labels
                    ccs = np.corrcoef(
                        diams_style,
                        np.array([utils.diameters(lbl)[0]
                                  for lbl in tlabels]))[0, 1]
                    cc = np.corrcoef(
                        predicted_diams,
                        np.array([utils.diameters(lbl)[0]
                                  for lbl in tlabels]))[0, 1]
                    logger.info(
                        'style test correlation: %0.4f; final test correlation: %0.4f'
                        % (ccs, cc))
                    np.save(
                        os.path.join(
                            args.test_dir, '%s_predicted_diams.npy' %
                            os.path.split(cpmodel_path)[1]), {
                                'predicted_diams': predicted_diams,
                                'diams_style': diams_style
                            })
Beispiel #19
0
def nuclei(test_root, save_root, save_figure=False):
    """ nuclei performance, suppfig """
    ntest = len(glob(os.path.join(test_root, '*_img.tif')))
    test_data = [io.imread(os.path.join(test_root, '%03d_img.tif'%i)) for i in range(ntest)]
    test_labels = [io.imread(os.path.join(test_root, '%03d_masks.tif'%i)) for i in range(ntest)]
    
    masks = []
    aps = []
    model_type = 'nuclei'
    masks.append(np.load(os.path.join(save_root, 'cellpose_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'maskrcnn_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'stardist_%s_masks.npy'%model_type), allow_pickle=True))
    #masks.append(np.load(os.path.join(save_root, 'unet3_residual_on_style_on_concatenation_off_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'unet3_residual_off_style_off_concatenation_on_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'unet2_residual_off_style_off_concatenation_on_%s_masks.npy'%model_type), allow_pickle=True))
    
    for j in range(len(masks)):
        aps.append(metrics.average_precision(test_labels, masks[j], 
                                                threshold=thresholds)[0])

    ltrf = 10
    rc('font', **{'size': 6})

    fig = plt.figure(figsize=(6.85/2,3.85),facecolor='w',frameon=True, dpi=300)

    mdl = ['cellpose', 'mask r-cnn', 'stardist',  'unet3', 'unet2']
    col ='mgcyr'


    iimg = 25
    for j in range(3):
        ax = plt.subplot(3,2,2*(1+j)-1)

        img = test_data[iimg][1]
        img = np.stack((img, img, img), axis=2)
        plt.imshow(np.clip(img[:,:,:], 0, 255))

        outpix1 = utils.outlines_list(masks[j][iimg])
        outpix = utils.outlines_list(test_labels[iimg])
        for out in outpix:  
            plt.plot(out[:,0],  out[:,1],  color='y', lw=.5)
        for out in outpix1:
            plt.plot(out[:,0], out[:,1], '--', color='r', lw=.5)

        plt.title(mdl[j], color=col[j], loc = 'left')    
        plt.text(.5, 1.05, '[email protected]=%.2f'%aps[j][iimg,0], transform=ax.transAxes, fontsize=6)

        plt.axis('off')

        if j==0:
            plt.text(-.1, 1.2, 'b', fontsize = ltrf, transform=ax.transAxes)

    ax=fig.add_axes([.65, .3 ,.33,.4])
    for j in range(len(mdl)):
        ax.plot(thresholds, aps[j].mean(axis=0), color=col[j], lw=1.)
        #print(aps[0][j][:11].mean(axis=0)[0])
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    ax.set_ylim([0, 1])
    ax.set_xlim([0.5, 1])
    ax.set_ylabel('average precision')
    ax.set_xlabel('IoU matching threshold')
    for j in range(len(mdl)):
        ax.text(.05, .32 - .075*j, mdl[j], color=col[j], fontsize=6, transform=ax.transAxes)
    ax.text(-.4, 1., 'c', fontsize = ltrf, transform=ax.transAxes)
    if save_figure:
        os.makedirs(os.path.join(save_root, 'figs'), exist_ok=True)
        fig.savefig(os.path.join(save_root, 'figs/suppfig_perf2d_nuclei.pdf'), bbox_inches='tight')
    return masks, aps
Beispiel #20
0
def cyto(test_root, save_root, save_figure=False):
    """ cyto performance, main fig 2 """
    ntest = len(glob(os.path.join(test_root, '*_img.tif')))
    test_data = [io.imread(os.path.join(test_root, '%03d_img.tif'%i)) for i in range(ntest)]
    test_labels = [io.imread(os.path.join(test_root, '%03d_masks.tif'%i)) for i in range(ntest)]
    
    masks = [[], []]
    aps = [[], []]
    model_types = ['cyto_sp', 'cyto']
    for m,model_type in enumerate(model_types):
        masks[m].append(np.load(os.path.join(save_root, 'cellpose_%s_masks.npy'%model_type), allow_pickle=True))
        masks[m].append(np.load(os.path.join(save_root, 'maskrcnn_%s_masks.npy'%model_type), allow_pickle=True))
        masks[m].append(np.load(os.path.join(save_root, 'stardist_%s_masks.npy'%model_type), allow_pickle=True))
        #masks[m].append(np.load(os.path.join(save_root, 'unet3_residual_on_style_on_concatenation_off_%s_masks.npy'%model_type), allow_pickle=True))
        masks[m].append(np.load(os.path.join(save_root, 'unet3_residual_off_style_off_concatenation_on_%s_masks.npy'%model_type), allow_pickle=True))
        masks[m].append(np.load(os.path.join(save_root, 'unet2_residual_off_style_off_concatenation_on_%s_masks.npy'%model_type), allow_pickle=True))
        
        for j in range(len(masks[m])):
            aps[m].append(metrics.average_precision(test_labels, masks[m][j], 
                                                    threshold=thresholds)[0])

    ltrf = 10
    rc('font', **{'size': 6})

    fig = plt.figure(figsize=(6.85,3.75/2 * 3),facecolor='w',frameon=True, dpi=300)

    mdl = ['cellpose', 'mask r-cnn', 'stardist',  'unet3', 'unet2']
    col ='mgcyr'

    iimg = 1
    for j in range(3):
        ax = plt.subplot(3,4,2+j)

        img = test_data[1][1]
        img = np.stack((np.zeros_like(img), img, test_data[iimg][0]), axis=2)
        plt.imshow(np.clip(img[:,75:-75,:], 0, 255))

        outpix1 = utils.outlines_list(masks[0][j][iimg][:,75:-75])
        outpix = utils.outlines_list(test_labels[iimg][:,75:-75])
        for out in outpix:  
            plt.plot(out[:,0],  out[:,1],  color='y', lw=.5)
        for out in outpix1:
            plt.plot(out[:,0], out[:,1], '--', color='r', lw=.5)

        plt.title(mdl[j], color=col[j], loc = 'left')    
        plt.text(.5, 1.05, '[email protected]=%.2f'%aps[0][j][iimg,0], transform=ax.transAxes, fontsize=7)

        plt.arrow(305, 110, 7, 7, color='w', head_width = 5)
        plt.arrow(255, 325, -10, 0, color='w', head_width = 5)
        plt.arrow(155, 250, 10, 0, color='w', head_width = 5)
        plt.arrow(315, 50, 0, -10, color='w', head_width = 5)
        plt.arrow(100, 220, -7, -7, color='w', head_width = 5)

        plt.axis('off')

        if j==0:
            plt.text(.0, 1.2, 'specialist model / specialized data', fontsize = 7, style='italic', transform=ax.transAxes)
            plt.text(-.1, 1.2, 'b', fontsize = ltrf, transform=ax.transAxes)

    iimg = 16
    for j in range(3):
        ax = plt.subplot(3,4,6+j)

        img = test_data[iimg][1]
        img = np.stack((img, img, img), axis=2)
        plt.imshow(np.clip(img[:,:,:], 0, 255))

        outpix1 = utils.outlines_list(masks[1][j][iimg][:,:])    
        outpix = utils.outlines_list(test_labels[iimg])
        for out in outpix:
            plt.plot(out[:,0],  out[:,1],  color='y', lw=.5)
        for out in outpix1:
            plt.plot(out[:,0], out[:,1], '--', color='r', lw=.5)

        plt.title(mdl[j], color=col[j], loc = 'left', fontsize=7)    
        plt.text(.5, 1.1, '[email protected]=%.2f'%aps[1][j][iimg,0], transform=ax.transAxes, fontsize=6)
        plt.axis('off')

        if j==0:
            plt.text(.0, 1.3, 'generalist model / generalized data', fontsize = 7, style='italic', transform=ax.transAxes)
            plt.text(-.1, 1.3, 'c', fontsize = ltrf, transform=ax.transAxes)



    titles = ['specialist model / \n specialized data', 'specialist model /\n generalized data', 
            'generalist model / \n specialized data', 'generalist model /\n generalized data']

    inds = [np.arange(0,11,1,int), np.arange(11,ntest,1,int)]
    for t in range(4):
        ax = fig.add_axes([0.1+.22*t,0.1,0.17,0.25])
        for j in range(len(mdl)):
            ap = aps[t//2][j][inds[t%2]].mean(axis=0)
            #print(titles[t], mdl[j], ap[0])
            ax.plot(thresholds, ap, color=col[j])
            #print(aps[0][j][:11].mean(axis=0)[0])
            if t==2:
                print(mdl[j], aps[t//2][j].mean(axis=0)[0])
        ax.spines['right'].set_visible(False)
        ax.spines['top'].set_visible(False)
        ax.set_ylim([0, 1])
        ax.set_xlim([0.5, 1])
        if t==0:
            plt.ylabel('average precision')
        ax.set_xlabel('IoU matching threshold')
        ax.text(0, 1.05, titles[t], fontsize = 7, ha='left', transform=ax.transAxes)

        ax.text(-.25, 1.15, string.ascii_lowercase[t+3], fontsize = 10, transform=ax.transAxes)

        if t==0:
            for j in range(len(mdl)):
                ax.text(.05, .4 - .075*j, mdl[j], color=col[j], fontsize=6, transform=ax.transAxes)

    ax = fig.add_axes([.05,.37,.25,.65])
    img = io.imread(os.path.join(save_root, 'figs/training_schematic_final.PNG'))
    ax.imshow(img)
    ax.axis('off')
    ax.text(0, 1.09, 'a', fontsize = ltrf, transform=ax.transAxes)

    if save_figure:
        os.makedirs(os.path.join(save_root, 'figs'), exist_ok=True)
        fig.savefig(os.path.join(save_root, 'figs/fig_perf2d_cyto.pdf'), bbox_inches='tight')
Beispiel #21
0
def suppfig_cellpose_params(test_root, save_root, save_figure=False):
    ap_cellpose_all = np.load(os.path.join(save_root, 'ap_cellpose_all.npy'))

    rc('font', **{'size': 6})
    fig=plt.figure(figsize=(3,1.5), facecolor='w',frameon=True, dpi=300)
    colors = [c for c in plt.get_cmap('Dark2').colors]

    ap_compare = ap_cellpose_all[:,0,:,0].flatten()
    netstr = ['style off', 'residual off', 'concatenation on', 'unet architecture', 'one net']

    bmax = 0.15
    dbin = 0.02
    for i in range(4):#ap_cellpose_all.shape[1]-1):
        ax = fig.add_axes([0.1+i*0.5, 0.1, 0.38, 0.75])
        if i<5:
            apt = ap_cellpose_all[:,i+1,:,0].flatten()
        else:
            apt = ap_cellpose_all[:,5:,:,0].mean(axis=1).flatten()
        diffs = apt - ap_compare
        ax.text(-.1, 1.1, netstr[i], transform=ax.transAxes , fontsize=7) 
        hb = ax.hist(np.clip(diffs, -1*bmax+dbin/2, bmax-dbin/2), bins=np.arange(-bmax, bmax+dbin, dbin), 
                    color=colors[i])
        max_counts = hb[0].max()*1.05
        dm = np.mean(diffs)
        p = stats.wilcoxon(diffs).pvalue
        print(p)
        nstars = np.array([p<0.05, p<0.01, p<0.001]).sum()
        ax.scatter(dm, max_counts*1.025, marker='v', color=colors[i], s=10)
        ax.text(dm, max_counts*1.1, '%0.3f'%dm+'*'*nstars, ha='center', fontsize=6)
        ax.set_xlabel('difference in average precision')
        if i==0:
            ax.set_ylabel('# of test images')
        ax.text(-.3, 1.1, string.ascii_lowercase[i], transform=ax.transAxes, fontsize=11)
        ax.spines['right'].set_visible(False)
        ax.spines['top'].set_visible(False)
        ax.set_xlim([-bmax, bmax])
        #ax.set_xticks(np.arange(-0.3,0.4,0.1))
        ax.set_ylim([0, max_counts*1.25])

    # performance without specialized images
    ntest = len(glob(os.path.join(test_root, '*_img.tif')))
    test_data = [io.imread(os.path.join(test_root, '%03d_img.tif'%i)) for i in range(ntest)]
    test_labels = [io.imread(os.path.join(test_root, '%03d_masks.tif'%i)) for i in range(ntest)]
    masks = []
    aps = []
    model_type = 'cyto'
    masks.append(np.load(os.path.join(save_root, 'cellpose_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'cellpose_%s_wo_sp_masks.npy'%model_type), allow_pickle=True))
    for j in range(len(masks)):
        aps.append(metrics.average_precision(test_labels, masks[j], 
                                             threshold=thresholds)[0])

    i=4
    ax = fig.add_axes([0.1+i*0.5, 0.1, 0.38, 0.75])
    inds = [np.arange(11,ntest,1,int)]
    sstr = ['cellpose', 'cellpose w/o\nspecialized']
    ls = ['-']
    col = ['m', [0.3, 0, 0.3]]
    for t in range(len(inds)):
        for j in range(len(masks)):
            ax.plot(thresholds, aps[j][inds[t]].mean(axis=0), color=col[j], ls=ls[t])
            if t==0:
                ax.text(1., 0.7-j*0.18, sstr[j], color=col[j], ha='right')
            #print(aps[0][j][:11].mean(axis=0)[0])
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    ax.set_ylim([0, 1])
    ax.set_xlim([0.5, 1])
    ax.set_ylabel('average precision')
    ax.set_xlabel('IoU matching threshold')
    ax.text(-.1, 1., 'remove specialized images\n       from training set', transform=ax.transAxes , fontsize=7) 
    ax.text(-.3, 1.1, string.ascii_lowercase[i], transform=ax.transAxes, fontsize=11)

    if save_figure:
        os.makedirs(os.path.join(save_root, 'figs'), exist_ok=True)
        fig.savefig(os.path.join(save_root, 'figs/suppfig_cellpose_params.pdf'), 
                    bbox_inches='tight')
Beispiel #22
0
def train_cellpose_nets(data_root):
    """ train networks on 9-folds of data (180 networks total) ... ~1 week on one GPU """
    # can also run on command line for GPU cluster
    # python -m cellpose --train --use_gpu --dir images_cyto/train"$7"/ --test_dir images_cyto/test"$7"/ --img_filter _img --pretrained_model None --chan 2 --chan2 1 --unet "$1" --nclasses "$2" --learning_rate "$3" --residual_on "$4" --style_on "$5" --concatenation "$6"
    device = mx.gpu()
    ntest = 68
    ntrain = 540
    concatenation = [0, 0, 0, 1, 1]
    residual_on = [1, 1, 0, 1, 0]
    style_on = [1, 0, 1, 1, 0]
    channels = [2, 1]

    for j in range(9):
        # load images
        train_root = os.path.join(data_root, 'train%d/' % j)
        train_data = [
            io.imread(os.path.join(train_root, '%03d_img.tif' % i))
            for i in range(ntrain)
        ]
        train_labels = [
            io.imread(os.path.join(train_root, '%03d_masks.tif' % i))
            for i in range(ntrain)
        ]
        train_flow_labels = [
            io.imread(os.path.join(train_root, '%03d_img_flows.tif' % i))
            for i in range(ntrain)
        ]
        train_labels = [
            np.concatenate(
                (train_labels[i][np.newaxis, :, :], train_flow_labels), axis=0)
            for i in range(ntrain)
        ]
        test_root = os.path.join(data_root, 'test%d/' % j)
        test_data = [
            io.imread(os.path.join(test_root, '%03d_img.tif' % i))
            for i in range(ntest)
        ]
        test_labels = [
            io.imread(os.path.join(test_root, '%03d_masks.tif' % i))
            for i in range(ntest)
        ]
        test_flow_labels = [
            io.imread(os.path.join(test_root, '%03d_img_flows.tif' % i))
            for i in range(ntest)
        ]
        test_labels = [
            np.concatenate(
                (test_labels[i][np.newaxis, :, :], test_flow_labels), axis=0)
            for i in range(ntest)
        ]

        # train networks
        for k in range(len(concatenation)):
            # 4 nets for each
            for l in range(4):
                model = models.CellposeModel(device=device,
                                             pretrained_model=None,
                                             diam_mean=30,
                                             residual_on=residual_on[k],
                                             style_on=style_on[k],
                                             concatenation=concatenation[k])
                model.train(images,
                            labels,
                            test_data=test_images,
                            test_labels=test_labels,
                            channels=channels,
                            rescale=True,
                            save_path=train_root)

                # train size network on default network once
                if k == 0 and l == 0:
                    sz_model = models.SizeModel(model, device=device)
                    sz_model.train(train_data,
                                   train_labels,
                                   test_data,
                                   test_labels,
                                   channels=channels)

                    predicted_diams, diams_style = sz_model.eval(
                        test_data, channels=channels)
                    tlabels = [lbl[0] for lbl in test_labels]
                    ccs = np.corrcoef(
                        diams_style,
                        np.array([utils.diameters(lbl)[0]
                                  for lbl in tlabels]))[0, 1]
                    cc = np.corrcoef(
                        predicted_diams,
                        np.array([utils.diameters(lbl)[0]
                                  for lbl in tlabels]))[0, 1]
                    print(
                        'style test correlation: %0.4f; final test correlation: %0.4f'
                        % (ccs, cc))
                    np.save(
                        os.path.join(test_root, 'predicted_diams.npy'), {
                            'predicted_diams': predicted_diams,
                            'diams_style': diams_style
                        })
Beispiel #23
0
def suppfig_metrics(test_root, save_root, save_figure=False):
    """ boundary / aji metrics """
    ntest = len(glob(os.path.join(test_root, '*_img.tif')))
    test_data = [io.imread(os.path.join(test_root, '%03d_img.tif'%i)) for i in range(ntest)]
    test_labels = [io.imread(os.path.join(test_root, '%03d_masks.tif'%i)) for i in range(ntest)]
    
    masks = []
    bscores = []
    ajis = []
    model_type = 'cyto'
    
    masks.append(np.load(os.path.join(save_root, 'cellpose_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'maskrcnn_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'stardist_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'unet3_residual_off_style_off_concatenation_on_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'unet2_residual_off_style_off_concatenation_on_%s_masks.npy'%model_type), allow_pickle=True))
        
    scales = np.arange(0.025, 0.275, 0.025)
    for j in range(len(masks)):
        bscores.append(metrics.boundary_scores(test_labels, masks[j], scales))
        ajis.append(metrics.aggregated_jaccard_index(test_labels, masks[j]))

    ltrf = 10
    rc('font', **{'size': 6})

    fig = plt.figure(figsize=(6.85,3.85),facecolor='w',frameon=True, dpi=300)

    mdl = ['cellpose', 'mask r-cnn', 'stardist',  'unet3', 'unet2']
    col ='mgcyr'

    titles = ['boundary precision', 'boundary recall', 'boundary F-score', 'aggregated jaccard index']


    s=0
    ttr = ['specialized data', 'generalized data']
    ii = [0,2,1,3]
    inds = [np.arange(0,11,1,int), np.arange(11,ntest,1,int)]
    for t in range(len(inds)):
        for k in range(4):
            ax = fig.add_axes([0.1+.22*k,0.66-t*0.5,0.14,0.28])
            ax.spines['right'].set_visible(False)
            ax.spines['top'].set_visible(False)
            if k<3:
                for j in range(len(mdl)):
                    ax.plot(scales*30, bscores[j][k][:,inds[t]].mean(axis=1), color=col[j])
                ax.set_ylim([0.25, 1])
                ax.set_ylabel(titles[k])
                ax.set_xlabel('boundary width (pixels)')
                if k==0:
                    ax.text(-0.2, 1.1, ttr[t], fontsize = 7, ha='left', transform=ax.transAxes)
                    
            else:
                for j in range(len(mdl)):
                    ax.bar(j, ajis[j][inds[t]].mean(), color=col[j])
                    ax.errorbar(j, ajis[j][inds[t]].mean(), 
                            ajis[j][inds[t]].std()/ len(inds[t])**0.5, color='k')
                ax.text(-0.2, 1.1, ttr[t], fontsize = 7, ha='left', transform=ax.transAxes)
                ax.set_ylabel(titles[k])
                ax.set_xticks(np.arange(0,len(mdl)))
                plt.xticks(rotation=90)
                ax.set_xticklabels(mdl) 
                ax.set_ylim([0,1])
                
            #ax.set_xlim([0.5, 1])
            if k==0 or k==3:
                ax.text(-.4, 1.1, string.ascii_lowercase[ii[s]], fontsize = ltrf, transform=ax.transAxes)
                s+=1
            if t==0 and k==0:
                for j in range(len(mdl)):
                    ax.text(.5, .5 - .075*j, mdl[j], color=col[j], fontsize=6, transform=ax.transAxes)


    if save_figure:
        os.makedirs(os.path.join(save_root, 'figs'), exist_ok=True)
        fig.savefig(os.path.join(save_root, 'figs/suppfig_metrics.pdf'), bbox_inches='tight')
def segment_cells_nuclei_indiv(path_scan,
                               str_channels,
                               img_ext,
                               new_size,
                               model_types,
                               diameters,
                               net_avg,
                               resample,
                               path_save,
                               input_subfolder=None,
                               callback_log=None,
                               callback_status=None,
                               callback_progress=None):
    """[summary] segment cells and nuclei in bulk, e.g. first all images are loaded and then segmented. 
    TODO: specify parameters
    Parameters
    ----------
    path_scan : [type]
        [description]
    strings : [type]
        [description]
    img_ext : [type]
        [description]
    new_size : tuple
        Defines resizing of image. If two elements, new size of image. If one element, resizing factor. 
        If emtpy, no resizing.
    sizes : [type]
        [description]
    models : [type]
        [description]
    path_save : pathlin object or string
        Path to save results,
        - If Pathlib object, then this absolute path is used.
        - If 'string' a replacement operation on the provided name of the data path will be applied (see create_output_path).
          And results will be stored in subfolder 'segmentation-input'
    callback_log : [type], optional
        [description], by default None
    callback_status : [type], optional
        [description], by default None
    callback_progress : [type], optional
        [description], by default None
    """

    par_dict = locals()
    par_dict = clean_par_dict(par_dict)
    log_message(f"Function (segment_obj_indiv) called with: {str(par_dict)} ",
                callback_fun=callback_log)

    # Get parameters
    (str_cyto, str_nuclei) = str_channels
    (diameter_cells, diameter_nuclei) = diameters
    (model_type_cells, model_type_nuclei) = model_types

    # Use provided absolute user-path to save images.
    if isinstance(path_save, pathlib.PurePath):
        path_save_results = path_save
        if not path_save_results.is_dir():
            path_save_results.mkdir(parents=True)

    else:
        path_save_str_replace = path_save

    # Configurations
    config_nuclei = {
        'model_type': model_type_nuclei,
        'diameter': diameter_nuclei,
        'net_avg': net_avg,
        'resample': resample
    }

    config_cyto = {
        'model_type': model_type_cells,
        'diameter': diameter_cells,
        'net_avg': net_avg,
        'resample': resample
    }

    channels_cyto = [1, 3]
    channels_nuclei = [0, 1]

    # Loop over data
    log_message(f'\nLoading image pairs and segment them on the fly',
                callback_fun=callback_log)

    if not path_scan.is_dir():
        log_message(f'Path {path_scan} does not exist.',
                    callback_fun=callback_log)
        return

    # Search for file to be analyzed
    log_message(f'\nLoading images and segment them on the fly',
                callback_fun=callback_log)
    files_proc = []
    for path_img in path_scan.rglob(f'*{str_cyto}*{img_ext}'):
        if input_subfolder:
            if path_img.parts[-2] == input_subfolder:
                files_proc.append(path_img)
        else:
            files_proc.append(path_img)
    n_imgs = len(files_proc)

    if n_imgs == 0:
        log_message(f'NO IMAGES FOUND. Check your settings.',
                    callback_fun=callback_log)
        return

    # Process files
    for idx, path_cyto in enumerate(files_proc):
        imgs_cyto = []
        imgs_nuclei = []
        files_cyto = []
        files_nuclei = []
        sizes_orginal = []

        log_message(f'Segmenting image : {path_cyto.name}',
                    callback_fun=callback_log)

        if callback_status:
            callback_status(f'Segmenting image : {path_cyto.name}')

        if callback_progress:
            progress = float((idx + 1) / n_imgs)
            callback_progress(progress)

        # DAPI image: existing?
        path_nuclei = Path(str(path_cyto).replace(str_cyto, str_nuclei))
        if not path_nuclei.is_file():
            log_message(f'DAPI image not found : {path_nuclei}',
                        callback_fun=callback_log)
            continue

        # Read images
        img_cyto = io.imread(str(path_cyto))
        if img_cyto.ndim != 2:
            log_message(
                f'\nERROR\n  Input image of cell has to be 2D. Current image is {img_cyto.ndim}D',
                callback_fun=callback_log)
            continue

        img_nuclei = io.imread(str(path_nuclei))
        if img_nuclei.ndim != 2:
            log_message(
                f'\nERROR\n  Input image of cell has to be 2D. Current image is {img_nuclei.ndim}D',
                callback_fun=callback_log)
            continue

        # Resize image before CellPose if specified
        sizes_orginal.append(img_cyto.shape)

        # Resize
        if new_size:

            # New size can also be defined as a scalar factor
            if len(new_size) == 1:
                scale_factor = new_size[0]
                img_size = img_cyto.shape
                new_size = tuple(int(ti / scale_factor) for ti in img_size)

            # IMPORTANT: CV2 resize is defined as (width, height)
            dsize = (new_size[1], new_size[0])
            img_cyto = cv2.resize(img_cyto, dsize)
            img_nuclei = cv2.resize(img_nuclei, dsize)

        img_zeros = np.zeros(img_cyto.shape)

        # For cell segmentation
        img_3d = np.dstack([img_cyto, img_zeros, img_nuclei])
        imgs_cyto.append(img_3d)
        files_cyto.append(path_cyto)

        # For nuclei segmentation
        img_3d_dpi = np.dstack([img_zeros, img_zeros, img_nuclei])
        imgs_nuclei.append(img_3d_dpi)
        files_nuclei.append(path_nuclei)

        # Create new output path if specified
        if not isinstance(path_save, pathlib.PurePath):
            path_save_results = create_output_path(path_cyto.parent,
                                                   path_save_str_replace,
                                                   subfolder='',
                                                   create_path=True)
            path_save_settings = path_save_results

        # >>> Call function for prediction of cell
        data_cyto = {
            'imgs': imgs_cyto,
            'file_names': files_cyto,
            'sizes_orginal': sizes_orginal,
            'new_size': new_size,
            'channels': channels_cyto,
            'obj_name': 'cells'
        }

        cellpose_predict(data_cyto,
                         config_cyto,
                         path_save=path_save_results,
                         callback_log=callback_log)

        # >>> Call function for prediction of nuclei
        data_nuclei = {
            'imgs': imgs_nuclei,
            'file_names': files_nuclei,
            'channels': channels_nuclei,
            'obj_name': 'nuclei',
            'sizes_orginal': sizes_orginal,
            'new_size': new_size
        }

        cellpose_predict(data_nuclei,
                         config_nuclei,
                         path_save=path_save_results,
                         callback_log=callback_log)

    # Save settings
    if len(imgs_cyto) > 0:
        fp = open(
            str(path_save_results /
                'segmentation_settings__cells_nuclei.json'), "w")
        json.dump(par_dict, fp, indent=4, sort_keys=True)
        fp.close()

    log_message(f'\n BATCH SEGMENTATION finished', callback_fun=callback_log)
Beispiel #25
0
def mask_stats(test_root, save_root, save_figure=False):
    """ cyto performance broken down """
    ntest = len(glob(os.path.join(test_root, '*_img.tif')))
    test_data = [io.imread(os.path.join(test_root, '%03d_img.tif'%i)) for i in range(ntest)]
    test_labels = [io.imread(os.path.join(test_root, '%03d_masks.tif'%i)) for i in range(ntest)]
    
    masks = []
    aps = []
    model_type = 'cyto'
    
    masks.append(np.load(os.path.join(save_root, 'cellpose_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'maskrcnn_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'stardist_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'unet3_residual_off_style_off_concatenation_on_%s_masks.npy'%model_type), allow_pickle=True))
    masks.append(np.load(os.path.join(save_root, 'unet2_residual_off_style_off_concatenation_on_%s_masks.npy'%model_type), allow_pickle=True))
        
    for j in range(len(masks)):
        aps.append(metrics.average_precision(test_labels, masks[j], 
                                             threshold=thresholds)[0])

    # compute shape measure + bin it
    convexities = np.zeros(0)
    maskinds = np.zeros(0, 'int')
    for i in range(len(test_labels)):
        _,solidity, _ = utils.get_mask_stats(test_labels[i])
        convexities = np.append(convexities, solidity)
        maskinds = np.append(maskinds, i*np.ones(len(solidity), 'int'))
        if i==10:
            ispec = len(convexities)
    bins = np.array([np.percentile(convexities, ip) for ip in np.linspace(0,100,4)])
    digi = np.digitize(np.clip(convexities.copy(),bins[0]+.01, bins[-1]-0.01), 
                        bins=bins) - 1
    
    # compute IoU in shape bins
    nbins = 3
    iou_threshold = 0.5
    ioub = np.zeros((len(masks), nbins))
    ioub_exc = np.zeros((len(masks), nbins))
    ioub_ste = np.zeros((len(masks), nbins))    
    for j in range(len(masks)):
        iouall=np.zeros(0)
        for i in range(len(test_labels)):
            iou = metrics._intersection_over_union(test_labels[i], masks[j][i])[1:,1:]
            n_min = min(iou.shape[0], iou.shape[1])
            costs = -(iou >= 0.5).astype(float) - iou / (2*n_min)
            true_ind, pred_ind = linear_sum_assignment(costs)
            iout = np.zeros(test_labels[i].max())
            iout[true_ind] = iou[true_ind,pred_ind]
            iouall = np.append(iouall, iout)

        for d in np.unique(digi):
            iou_d = iouall[ispec:][digi[ispec:]==d]
            ioub_exc[j,d] = (iou_d<=iou_threshold).mean()
            iou_d = iou_d[iou_d > iou_threshold]
            ioub[j,d] = iou_d.mean()
            ioub_ste[j,d] = iou_d.std() / (digi==d).sum()
        
    ltrf = 10
    rc('font', **{'size': 6})

    fig = plt.figure(figsize=(6.85,3.85),facecolor='w',frameon=True, dpi=300)

    mdl = ['cellpose', 'mask r-cnn', 'stardist',  'unet3', 'unet2']
    col ='mgcyr'

    titles = ['Cells : fluorescent', 'Cells : nonfluorescent', 
              'Cell membranes', 'Microscopy : other', 'Non-microscopy']

    
    s=0
    inds = [np.arange(11,28,1,int), np.arange(28,33,1,int), 
            np.arange(33,42,1,int), np.arange(42,55,1,int),
            np.arange(55,ntest,1,int)]
    for t in range(len(inds)):
        ax = fig.add_axes([0.1+.22*t,0.66,0.14,0.28])
        for j in range(len(mdl)):
            ax.plot(thresholds, aps[j][inds[t]].mean(axis=0), color=col[j])
            #print(aps[0][j][:11].mean(axis=0)[0])
        ax.spines['right'].set_visible(False)
        ax.spines['top'].set_visible(False)
        ax.set_ylim([0, 1])
        ax.set_xlim([0.5, 1])
        if t==0:
            plt.ylabel('average precision')
        ax.set_xlabel('IoU matching threshold')
        ax.text(-0.2, 1.1, titles[t], fontsize = 7, ha='left', transform=ax.transAxes)
        if t==0:
            ax.text(-.4, 1.1, string.ascii_lowercase[s], fontsize = 10, transform=ax.transAxes)
            s+=1
            for j in range(len(mdl)):
                ax.text(.5, .9 - .075*j, mdl[j], color=col[j], fontsize=6, transform=ax.transAxes)

    # size figs
    # size dist for all images
    sz_dist = np.load(os.path.join(save_root, 'size_distribution.npy'))
    # ap for all images
    aps=np.load(os.path.join(save_root, 'ap_cellpose_all.npy'))
    # example low-high masks
    d=np.load(os.path.join(save_root, 'example_size_masks.npy'), allow_pickle=True).item()
    msks = d['masks']
    imgs = d['imgs']
    inds = d['inds']
    szs = sz_dist.flatten()
    ap5 = aps[:,0,:,0].flatten()
    r,p = stats.pearsonr(szs, ap5)
    print(r,p)
    xb = np.linspace(0,1,3)
    bs = [300, 200]
    for j in range(2):
        ax = fig.add_axes([.07, .2-0.3*(j), 0.14,0.28])
        #inds = np.nonzero(np.logical_and(sz_dist[0,:]>xb[j], sz_dist[0,:]<xb[j+1]))[0]
        ic = inds[j]
        maski = plot.mask_overlay(imgs[j], msks[j])
        patch = plot.interesting_patch(msks[j], bsize=bs[j])
        ax.imshow(maski[np.ix_(patch[0], patch[1])])
        
        ax.axis('off')
        if j==0:
            ax.text(0.1, 1.05, 'low homogeneity', transform=ax.transAxes)
            ax.text(-.15,1.25,string.ascii_lowercase[s],transform=ax.transAxes, fontsize=10)
            ax.text(-.0,1.25,'within-image size variability',transform=ax.transAxes, fontsize=7)

            s+=1
        else:
            ax.text(0.1, 1.05, 'high homogeneity', transform=ax.transAxes)
            
    ax = fig.add_axes([0.285, 0.04, 0.18,0.4])
    ax.scatter(szs, ap5, s=0.5)
    slope, intercept = stats.linregress(szs, ap5)[:2]
    lp = szs*slope + intercept
    ax.plot(szs, lp, color='k', lw=1)
    ax.scatter(szs[inds], ap5[inds], s=40, color='r', marker='+', lw=1)
    ax.set_ylabel('AP @ IoU>0.5')
    ax.set_xlabel('homogeneity of mask areas\n(25th / 75th percentile)')
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    ax.text(1.05, 0.63, 'r=%0.2f,\np=%0.3f'%(r, p), ha='right', 
                    transform=ax.transAxes, fontsize=6)
    #ax.text(-.25,1.1,string.ascii_lowercase[s],transform=ax.transAxes, fontsize=10)
    #ax.set_title('Within-image size variability')

    sstr = ['low', 'medium', 'high']
    print(s)
    for k in range(3):
        ic = np.nonzero(np.logical_and(convexities<bins[k+1], convexities>bins[k]))[0]
        np.random.seed(20)
        inds = np.random.permutation(len(ic))
        for l in range(24):
            ax = fig.add_axes([0.51+0.035*(l%8), 0.44-(3.3*k+l//8)*0.06, 0.03, 0.05])
            imask = ic[inds[l]]
            im = maskinds[imask]
            imask -= np.nonzero(maskinds==im)[0][0]
            slices = find_objects(test_labels[im]==(imask+1))
            ax.imshow(test_labels[im][slices[0]]==(imask+1), vmin=0, vmax=1, cmap='gray_r')
            ax.axis('off')
            if l==0:
                ax.text(0.1, 1.3,'%s'%(sstr[k]), ha='left', transform=ax.transAxes)
                if k==0:
                    ax.text(-0.5, 2, string.ascii_lowercase[s], transform=ax.transAxes, fontsize=10)
                    s+=1    
                    ax.text(0.1, 2, 'convexity distributions', transform=ax.transAxes, fontsize=7)

    dx=0.44
    pbins = np.arange(0,3)
    ax = fig.add_axes([0.42+dx, 0.04,.11,.4])
    for j in range(len(masks)):
        ax.plot(pbins+0.04*j, ioub_exc[j], color=col[j], lw=1)
        ax.scatter(pbins+0.04*j, ioub_exc[j], color=col[j], s=5)
        #if k==1 and s==0:
        #    ax.text(0.7,.95-0.06*(4-j), mdl[j], transform=ax.transAxes, color=col[j])
    ax.set_xticks([0,1,2])
    ax.set_xticklabels(['low', 'medium' , 'high'])
    ax.set_ylabel('miss rate')
    ax.set_xlabel('mask convexity')
    ax.text(.7, 1.1, 'IoU threshold = 0.5', transform=ax.transAxes)
    ax.set_ylim([0,1.])
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)  
    #ax.set_title('generalized data', fontsize=7)
    ax.text(-.5, 1.1, string.ascii_lowercase[s], transform=ax.transAxes, fontsize=10)
    s+=1
    
    ax = fig.add_axes([0.6+dx, 0.04, .11,.4])
    for j in range(len(masks)):
        ax.errorbar(pbins+0.04*j, ioub[j], ioub_ste[j],#np.abs(ioubi[k,j] - ioubi_ste[k,j].T), 
                    color=col[j], lw=1)
        ax.scatter(pbins+0.04*j, ioub[j], s=5, color=col[j])
        
    ax.set_ylim([0.4, 1.0])
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    ax.set_ylabel('average IoU of true positives')
    ax.set_xlabel('mask convexity')
    ax.set_xticks([0,1,2])
    ax.set_xticklabels(['low', 'medium' , 'high'])


    if save_figure:
        os.makedirs(os.path.join(save_root, 'figs'), exist_ok=True)
        fig.savefig(os.path.join(save_root, 'figs/fig_stats.pdf'), bbox_inches='tight')
Beispiel #26
0
def folder_prepare_prediction(path_process,
                              channel_ident,
                              img_ext,
                              path_save,
                              projection_type,
                              subfolder=None,
                              search_recursive=False,
                              callback_log=None,
                              callback_status=None,
                              callback_progress=None):
    """[summary]

    Parameters
    ----------
    path_process : [type]
        [description]
    channel_ident : str
        [description]
    img_ext : str
        Image extension
    path_save : pathlin object or string
        Path to save results,
        - If Pathlib object, then this absolute path is used.
        - If 'string' a replacement operation on the provided name of the data path will be applied (see create_output_path).
          And results will be stored in subfolder 'segmentation-input'
    projection_type : [type]
        [description]
    subfolder: str
        subfolder where data should be stored. Will only be used when string replacement for path is used. 
    search_recursive : bool
        Recursively search folder, default: false.
    callback_log : [type], optional
        [description], by default None
    callback_status : [type], optional
        [description], by default None
    callback_progress : [type], optional
        [description], by default None
    """

    # Print all input parameters
    log_message(f"Function (segment_obj_indiv) called with: {str(locals())} ",
                callback_fun=callback_log)

    # Use provided absolute user-path to save images.
    if isinstance(path_save, pathlib.PurePath):
        path_save_results = path_save
        if not path_save_results.is_dir():
            path_save_results.mkdir(parents=True)
        path_save_settings = path_save_results

    else:
        path_save_str_replace = path_save

    # How to look for files
    files_proc = []
    if search_recursive:
        for path_img in path_process.rglob(f'*{channel_ident}*{img_ext}'):
            files_proc.append(path_img)
    else:
        for path_img in path_process.glob(f'*{channel_ident}*{img_ext}'):
            files_proc.append(path_img)

    # Process files
    n_files = len(files_proc)
    for idx, file_proc in enumerate(files_proc):

        log_message(f'\n>>> Processing file: {file_proc}',
                    callback_fun=callback_status)

        if callback_progress:
            progress = float((idx + 1) / n_files)
            callback_progress(progress)

        name_base = file_proc.stem

        # Create new output path if specified
        if not isinstance(path_save, pathlib.PurePath):
            path_save_results = create_output_path(file_proc.parent,
                                                   path_save_str_replace,
                                                   subfolder=subfolder,
                                                   create_path=True)
            log_message(f'Results will be save here : {path_save_results}',
                        callback_fun=callback_status)
            path_save_settings = path_save_results

        # Create subfolder when processing individual images
        if projection_type == 'indiv':
            path_save_indiv = path_save_results / name_base

            if not path_save_indiv.is_dir():
                path_save_indiv.mkdir(parents=True)
                path_save_settings = path_save_indiv

        # Open image
        print(file_proc)
        img = imread(str(file_proc))

        img_properties = {
            "file_process": str(file_proc),
            "img_name": file_proc.name,
            "img_path": str(file_proc.parent),
            "channel_ident": channel_ident,
            "projection_type": projection_type
        }

        name_json = path_save_settings / f'img-prop__{name_base}.json'
        with open(name_json, 'w') as fp:
            json.dump(img_properties, fp, sort_keys=True, indent=4)

        # Process depending specified option
        if projection_type == 'indiv':

            for i in range(img.shape[0]):
                name_save = path_save_indiv / f'{name_base}_Z{str(i+1).zfill(3)}.png'

                if name_save.is_file():
                    log_message(
                        f'File already exists. Will be overwritten {name_save}',
                        callback_fun=callback_log)
                imsave(str(name_save), img[i, :, :])

        else:

            if projection_type == 'mean':
                img_proj = img.mean(axis=0)

            elif projection_type == 'max':
                img_proj = img.max(axis=0)

            name_save = path_save_results / f'{name_base}.png'

            if name_save.is_file():
                log_message(
                    f'File already exists. Will be overwritten {name_save}',
                    callback_fun=callback_log)
            imsave(str(name_save), img_proj.astype('uint16'))