Example #1
0
def run_lap(img0, img1, labels0, labels1, DISPLACEMENT=30, MASSTHRES=0.2):
    '''Linear assignment problem for mammalian cells.
    Cost matrix is simply the distance.
    costDie and costBorn are variables changing over frame. Update it through holder.

    Args:
    DISPLACEMENT (int): The maximum distance (in pixel)
    MASSTHRES (float):  The maximum difference of total intensity changes.
                        0.2 means it allows for 20% total intensity changes.
    '''
    labels = -labels1.copy()
    rps0 = regionprops(labels0, img0)
    rps1 = regionprops(labels1, img1)

    if not rps0 or not rps1:
        return labels0, labels

    dist = cdist([i.centroid for i in rps0], [i.centroid for i in rps1])
    massdiff = calc_massdiff(rps0, rps1)
    '''search radius is now simply set by maximum displacement possible.
    In the future, I might add data-driven approach mentioned in LAP paper (supple pg.7)'''
    dist[dist >
         DISPLACEMENT] = np.Inf  # assign a large cost for unlikely a pair
    # dist[abs(massdiff) > MASSTHRES] = np.Inf
    cost = dist
    if cost.shape[0] == 0 or cost.shape[1] == 0:
        return labels0, labels

    # Define initial costBorn and costDie in the first frame
    if not hasattr(holder, 'cost_born') or not hasattr(holder, 'cost_die'):
        holder.cost_born = np.percentile(cost[~np.isinf(cost)], 80)
        holder.cost_die = np.percentile(cost[~np.isinf(cost)], 80)
    # try:
    binary_cost = call_lap(cost, holder.cost_die, holder.cost_born)
    # The first assignment of np.Inf is to reduce calculation of linear assignment.
    # This part will make sure that cells outside of these range do not get connected.
    binary_cost[(np.abs(massdiff) > MASSTHRES)] = False
    binary_cost[(dist > DISPLACEMENT)] = False

    gp, gc = np.where(binary_cost)
    idx0, idx1 = list(gp), list(gc)

    for i0, i1 in zip(idx0, idx1):
        labels[labels1 == rps1[i1].label] = rps0[i0].label
        labels0[labels0 == rps0[i0].label] = -rps0[i0].label

    # update cost
    linked_dist = [dist[i0, i1] for i0, i1 in zip(idx0, idx1)]
    if linked_dist:
        cost = np.max(linked_dist) * 1.05
        if cost != 0:  # solver freezes if cost is 0
            holder.cost_born, holder.cost_die = cost, cost
    return labels0, labels
Example #2
0
def caller(inputs_list, inputs_labels_list, output, primary, secondary):
    make_dirs(dirname(abspath(output)))

    inputs_list = [inputs_list, ] if isinstance(inputs_list[0], str) else inputs_list
    inputs_labels_list = [inputs_labels_list, ] if isinstance(inputs_labels_list[0], str) else inputs_labels_list

    obj_names = [basename(dirname(i[0])) for i in inputs_labels_list] if primary is None else primary
    ch_names = [basename(dirname(i[0])) for i in inputs_list] if secondary is None else secondary

    store = []
    for inputs, ch in zip(inputs_list, ch_names):
        for inputs_labels, obj in zip(inputs_labels_list, obj_names):
            logger.info("Channel {0}: {1} applied...".format(ch, obj))
            for frame, (path, pathl) in enumerate(zip(inputs, inputs_labels)):
                img, labels = imread(path), lbread(pathl, nonneg=False)
                cells = regionprops(labels, img)
                if (labels < 0).any():
                    cells = add_parent(cells, labels)
                [setattr(cell, 'frame', frame) for cell in cells]
                cells = [Cell(cell) for cell in cells]
                store.append(cells)

            logger.info("\tmaking dataframe...")
            df = multi_index([i for ii in store for i in ii], obj, ch)
            if exists(join(output, 'df.csv')):
                ex_df = pd.read_csv(join(output, 'df.csv'), index_col=['object', 'ch', 'prop', 'frame'])
                ex_df.columns = pd.to_numeric(ex_df.columns)
                ex_df = ex_df.astype(np.float32)
                df = pd.concat([df, ex_df])
            df.to_csv(join(output, 'df.csv'))
    larr = df2larr(df)
    larr.save(join(output, 'df.npz'))
    logger.info("\tdf.npz saved.")
Example #3
0
def caller(inputs, inputs_labels, output, functions, params):
    make_dirs(output)

    # Make cells. cells are a list of regionproperties or subclasses.
    logger.info('Postprocess.\tcollecting cells...')
    store = []
    for frame, (path, pathl) in enumerate(zip(inputs, inputs_labels)):
        img, labels = imread(path), lbread(pathl)
        cells = regionprops(labels, img)
        cells = [Cell(cell) for cell in cells]
        for cell in cells:
            cell.frame = frame
            if frame > 0:
                all_labels = [i.label for i in store[frame - 1]]
                if cell.label in all_labels:
                    store[frame - 1][all_labels.index(cell.label)].nxt = cell
        store.append(cells)
    cells = [i for j in store for i in j]

    # Each function receives cells (regionprops) and finally return labels generated by cells.label
    for function, param in zip(functions, params):
        logger.info('\trunning {0}'.format(function))
        func = getattr(postprocess_operation, function)
        cells = func(cells, **param)

    logger.info('\tsaving images...')
    for frame, (path, pathl) in enumerate(zip(inputs, inputs_labels)):
        labels = cells2labels(cells, frame, lbread(pathl))
        imsave(labels, output, path, dtype=np.int16)
Example #4
0
def nn_closer(img0, img1, labels0, labels1, DISPLACEMENT=30, MASSTHRES=0.25):
    labels = -labels1.copy()
    rps0 = regionprops(labels0, img0)
    rps1 = regionprops(labels1, img1)

    if not rps0 or not rps1:
        return labels0, labels

    dist = cdist([i.centroid for i in rps0], [i.centroid for i in rps1])
    massdiff = calc_massdiff(rps0, rps1)
    binary_cost = (dist < DISPLACEMENT) * (abs(massdiff) < MASSTHRES)
    binary_cost = pick_closer_cost(binary_cost, dist)
    binary_cost = pick_closer_cost(binary_cost.T, dist.T).T
    idx1, idx0 = find_one_to_one_assign(binary_cost)
    for i0, i1 in zip(idx0, idx1):
        labels[labels1 == rps1[i1].label] = rps0[i0].label
        labels0[labels0 == rps0[i0].label] = -rps0[i0].label
    return labels0, labels
Example #5
0
def caller(inputs_list, inputs_labels_list, output, primary, secondary):
    make_dirs(dirname(abspath(output)))

    inputs_list = [
        inputs_list,
    ] if isinstance(inputs_list[0], str) else inputs_list
    inputs_labels_list = [
        inputs_labels_list,
    ] if isinstance(inputs_labels_list[0], str) else inputs_labels_list

    obj_names = [basename(dirname(i[0]))
                 for i in inputs_labels_list] if primary is None else primary
    ch_names = [basename(dirname(i[0]))
                for i in inputs_list] if secondary is None else secondary

    for inputs, ch in zip(inputs_list, ch_names):
        for inputs_labels, obj in zip(inputs_labels_list, obj_names):
            logger.info("Channel {0}: {1} applied...".format(ch, obj))
            arr = np.ones((MAX_NUMCELL, len(PROP_SAVE), len(inputs)),
                          np.float32) * np.nan
            for frame, (path, pathl) in enumerate(zip(inputs, inputs_labels)):
                img, labels = imread(path), lbread(pathl, nonneg=False)
                cells = regionprops(labels, img)
                if (labels < 0).any():
                    cells = add_parent(cells, labels)
                [setattr(cell, 'frame', frame) for cell in cells]
                cells = [Cell(cell) for cell in cells]
                tarr = _cells2array(cells)
                index = tarr[:, 1].astype(np.int32)
                arr[index, :, frame] = tarr

            logger.info("\tmaking dataframe...")
            cellids = np.where(~np.isnan(arr[:, 0, :]).all(axis=1))[0]
            marr = np.zeros((len(cellids), arr.shape[1], arr.shape[2]))
            for pn, i in enumerate(cellids):
                marr[pn] = arr[i]
            sarr = np.swapaxes(marr, 0, 2)
            narr = sarr.reshape((sarr.shape[0] * sarr.shape[1], sarr.shape[2]),
                                order='F')
            index = pd.MultiIndex.from_product(
                [obj, ch, PROP_SAVE, range(arr.shape[-1])],
                names=['object', 'ch', 'prop', 'frame'])
            df = pd.DataFrame(narr, index=index, columns=cellids)

            if exists(join(output, FILE_NAME + '.csv')):
                ex_df = pd.read_csv(
                    join(output, FILE_NAME + '.csv'),
                    index_col=['object', 'ch', 'prop', 'frame'])
                ex_df.columns = pd.to_numeric(ex_df.columns)
                ex_df = ex_df.astype(np.float32)
                df = pd.concat([df, ex_df])
            df.to_csv(join(output, FILE_NAME + '.csv'))
    larr = df2larr(df)
    larr.save(join(output, FILE_NAME + '.npz'))
    logger.info("\t" + FILE_NAME + ".npz saved.")
Example #6
0
def nearest_neighbor(img0,
                     img1,
                     labels0,
                     labels1,
                     DISPLACEMENT=20,
                     MASSTHRES=0.2):
    """
    labels0 and labels1: the positive values for non-tracked objects and the negative values for tracked objects.
    """
    labels = -labels1.copy()
    rps0 = regionprops(labels0, img0)
    rps1 = regionprops(labels1, img1)
    if not rps0 or not rps1:
        return labels0, labels
    dist = cdist([i.centroid for i in rps0], [i.centroid for i in rps1])
    massdiff = calc_massdiff(rps0, rps1)
    binary_cost = (dist < DISPLACEMENT) * (abs(massdiff) < MASSTHRES)
    idx1, idx0 = find_one_to_one_assign(binary_cost)
    for i0, i1 in zip(idx0, idx1):
        labels[labels1 == rps1[i1].label] = rps0[i0].label
        labels0[labels0 == rps0[i0].label] = -rps0[i0].label
    return labels0, labels
Example #7
0
    def _wd(labels0, labels, img0, img1):
        labels1 = -labels.copy()
        rps0 = regionprops(labels0, img0)

        from subdetect_operation import watershed_divide  # DO NOT MOVE IT
        from utils.track_utils import _find_match
        untracked_labels = labels1.copy()
        untracked_labels[untracked_labels < 0] = 0
        wshed_labels = watershed_divide(untracked_labels,
                                        regmax=REGMAX,
                                        min_size=MIN_SIZE)
        wshed_labels = label(wshed_labels)

        store = regionprops(wshed_labels, img1)
        good_cells = _find_match(rps0, store, DISPLACEMENT, MASSTHRES)
        for gc in good_cells:  # needed to reuse _update_labels_neck_cut
            gccrds = gc.coords[0]
            gc.raw_label = labels1[gccrds[0], gccrds[1]]
        labels0, labels = _update_labels_neck_cut(labels0, labels1, good_cells)
        labels0, labels = nn_closer(img0, img1, labels0, -labels, DISPLACEMENT,
                                    MASSTHRES)
        return labels0, labels, good_cells
Example #8
0
def track_neck_cut(img0,
                   img1,
                   labels0,
                   labels1,
                   DISPLACEMENT=10,
                   MASSTHRES=0.2,
                   EDGELEN=5,
                   THRES_ANGLE=180,
                   WSLIMIT=False,
                   SMALL_RAD=3,
                   CANDS_LIMIT=300):
    """
    Adaptive segmentation by using tracking informaiton.
    Separate two objects by making a cut at the deflection. For each points on the outline,
    it will make a triangle separated by EDGELEN and calculates the angle facing inside of concave.

    The majority of cells need to be tracked before the this method to calculate LARGE_RAD and SMALL_RAD.

    EDGELEN (int):      A length of edges of triangle on the nuclear perimeter.
    THRES_ANGLE (int):  Define the neck points if a triangle has more than this angle.
    STEPLIM (int):      points of neck needs to be separated by at least STEPLIM in parimeters.
    WSLIMIT (bool):     Limit search points to ones overlapped with watershed transformed images. Set it True if calculation is slow.

    SMALL_RAD (int or None): The smallest radius of candidate objects. If you have many cells, set it to None will infer the radius from previous frame.
    CANDS_LIMIT(int): use lower if slow. limit a number of searches.

    """
    labels0, labels = nn_closer(img0, img1, labels0, labels1, DISPLACEMENT,
                                MASSTHRES)
    labels1 = -labels.copy()

    if SMALL_RAD is None and not hasattr(holder, 'SMALL_RAD'):
        tracked_area = [i.area for i in regionprops(labels)]
        holder.SMALL_RAD = np.sqrt(np.percentile(tracked_area, 5) / np.pi)
    elif SMALL_RAD is not None:
        holder.SMALL_RAD = SMALL_RAD
    SMALL_RAD = holder.SMALL_RAD

    rps0 = regionprops(labels0, img0)
    unique_labels = np.unique(labels1)

    if WSLIMIT:
        wlines = wshed_raw(labels1 > 0, img1)
    else:
        wlines = np.ones(labels1.shape, np.bool)

    store = []
    coords_store = []
    for label_id in unique_labels:
        if label_id == 0:
            continue
        cc = CellCutter(labels1 == label_id,
                        img1,
                        wlines,
                        small_rad=SMALL_RAD,
                        EDGELEN=EDGELEN,
                        THRES=THRES_ANGLE,
                        CANDS_LIMIT=CANDS_LIMIT)
        cc.prepare_coords_set()
        candidates = cc.search_cut_candidates(cc.bw.copy(),
                                              cc.coords_set[:CANDS_LIMIT])
        for c in candidates:
            c.raw_label = label_id
        store.append(candidates)
        coords_store.append(cc.coords_set)

    coords_store = [i for i in coords_store if i]
    # Attempt a first cut.
    good_cells = _find_best_neck_cut(rps0, store, DISPLACEMENT, MASSTHRES)
    labels0, labels = _update_labels_neck_cut(labels0, labels1, good_cells)
    labels0, labels = nn_closer(img0, img1, labels0, -labels, DISPLACEMENT,
                                MASSTHRES)
    # iteration from here.
    while good_cells:
        rps0 = regionprops(labels0, img0)
        labels1 = -labels.copy()
        rps0 = regionprops(labels0, img0)
        unique_labels = np.unique(labels1)

        store = []
        for label_id in unique_labels:
            if label_id == 0:
                continue
            bw = labels1 == label_id
            coords_set = [
                i for i in coords_store if bw[i[0][0][0], i[0][0][1]]
            ]
            if not coords_set:
                continue
            coords_set = coords_set[0]
            candidates = cc.search_cut_candidates(bw, coords_set)
            for c in candidates:
                c.raw_label = label_id
            store.append(candidates)
            coords_store.append(coords_set)
        good_cells = _find_best_neck_cut(rps0, store, DISPLACEMENT, MASSTHRES)
        labels0, labels = _update_labels_neck_cut(labels0, labels1, good_cells)
        labels0, labels = nn_closer(img0, img1, labels0, -labels, DISPLACEMENT,
                                    MASSTHRES)
    return labels0, labels