Beispiel #1
0
def refine_worm(image, initial_area, candidate_edges):
    # find strong worm edges (roughly equivalent to the edges found by find_initial_worm,
    # which are in candidate_edges): smooth the image, do canny edge-finding, and
    # then keep only those edges near candidate_edges
    smooth_image = restoration.denoise_tv_bregman(image, 140).astype(numpy.float32)
    smoothed, gradient, sobel = canny.prepare_canny(smooth_image, 8, initial_area)
    local_maxima = canny.canny_local_maxima(gradient, sobel)
    candidate_edge_region = ndimage.binary_dilation(candidate_edges, iterations=4)
    strong_edges = local_maxima & candidate_edge_region

    # Now threshold the image to find dark blobs as our initial worm region
    # First, find areas in the initial region unlikely to be worm pixels
    mean, std = mcd.robust_mean_std(smooth_image[initial_area][::4], 0.85)
    non_worm = (smooth_image > mean - std) & initial_area
    # now fit a smoothly varying polynomial to the non-worm pixels in the initial
    # region of interest, and subtract that from the actual image to generate
    # an image with a flat illumination field
    background = polyfit.fit_polynomial(smooth_image, mask=non_worm, degree=2)
    minus_bg = smooth_image - background
    # now recalculate a threshold from the background-subtracted pixels
    mean, std = mcd.robust_mean_std(minus_bg[initial_area][::4], 0.85)
    initial_worm = (minus_bg < mean - std) & initial_area
    # Add any pixels near the strong edges to our candidate worm position
    initial_worm |= ndimage.binary_dilation(strong_edges, iterations=3)
    initial_worm = mask.fill_small_radius_holes(initial_worm, 5)

    # Now grow/shrink the initial_worm region so that as many of the strong
    # edges from the canny filter are in contact with the region edges as possible.
    ac = active_contour.EdgeClaimingAdvection(initial_worm, strong_edges,
        max_region_mask=initial_area)
    stopper = active_contour.StoppingCondition(ac, max_iterations=100)
    while stopper.should_continue():
        ac.advect(iters=1)
        ac.smooth(iters=1, depth=2)
    worm_mask = mask.fill_small_radius_holes(ac.mask, 7)

    # Now, get edges from the image at a finer scale
    smoothed, gradient, sobel = canny.prepare_canny(smooth_image, 0.3, initial_area)
    local_maxima = canny.canny_local_maxima(gradient, sobel)
    strong_sum = strong_edges.sum()
    highp = 100 * (1 - 1.5*strong_sum/local_maxima.sum())
    lowp = max(100 * (1 - 3*strong_sum/local_maxima.sum()), 0)
    low_worm, high_worm = numpy.percentile(gradient[local_maxima], [lowp, highp])
    fine_edges = canny.canny_hysteresis(local_maxima, gradient, low_worm, high_worm)

    # Expand out the identified worm area to include any of these finer edges
    closed_edges = ndimage.binary_closing(fine_edges, structure=S)
    worm = ndimage.binary_propagation(worm_mask, mask=worm_mask|closed_edges, structure=S)
    worm = ndimage.binary_closing(worm, structure=S, iterations=2)
    worm = mask.fill_small_radius_holes(worm, 5)
    worm = ndimage.binary_opening(worm)
    worm = mask.get_largest_object(worm)
    # Last, smooth the shape a bit to reduce sharp corners, but not too much to
    # sand off the tail
    ac = active_contour.CurvatureMorphology(worm, max_region_mask=initial_area)
    ac.smooth(depth=2, iters=2)
    return strong_edges, ac.mask
def measure_fluorescence(image, worm_mask, well_mask=None):
    if well_mask is not None:
        restricted_mask = ndimage.binary_erosion(well_mask, iterations=15)
        background = polyfit.fit_polynomial(image[::4,::4], mask=restricted_mask[::4,::4], degree=2).astype(numpy.float32)
        background = ndimage.zoom(background, 4)
        background /= background[well_mask].mean()
        background[background <= 0.01] = 1 # we're going to divide by background, so prevent div/0 errors
        image = image.astype(numpy.float32) / background
        image[~well_mask] = 0

    worm_pixels = image[worm_mask]
    low_px_mean, low_px_std = mcd.robust_mean_std(worm_pixels[worm_pixels < worm_pixels.mean()], 0.5)
    expression_thresh = low_px_mean + 2.5*low_px_std
    high_expression_thresh = low_px_mean + 6*low_px_std
    fluo_px = worm_pixels[worm_pixels > expression_thresh]
    high_fluo_px = worm_pixels[worm_pixels > high_expression_thresh]

    area = worm_mask.sum()
    integrated = worm_pixels.sum()
    median, percentile95 = numpy.percentile(worm_pixels, [50, 95])
    expression_area = fluo_px.size
    expression_area_fraction = expression_area / area
    expression_mean = fluo_px.mean()
    high_expression_area = high_fluo_px.size
    high_expression_area_fraction = high_expression_area / area
    high_expression_mean = high_fluo_px.mean()
    high_expression_integrated = high_fluo_px.sum()

    expression_mask = (image > expression_thresh) & worm_mask
    high_expression_mask = (image > high_expression_thresh) & worm_mask

    return data_row(area, integrated, median, percentile95,
     expression_area, expression_area_fraction, expression_mean,
     high_expression_area, high_expression_area_fraction,
     high_expression_mean, high_expression_integrated), (image, background, expression_mask, high_expression_mask)
def measure_gfp_fluorescence(fluorescent_image, worm_mask):
    '''Given an image, measure the gfp flourescence
    TODO: Do we need a worm_frame? Figure out how to add columns to the tsv files
    '''
    worm_pixels = fluorescent_image[worm_mask].copy()

    #Get interesting statistics out
    low_px_mean, low_px_std = mcd.robust_mean_std(
        worm_pixels[worm_pixels < worm_pixels.mean()], 0.5)
    expression_thresh = low_px_mean + 2.5 * low_px_std
    high_expression_thresh = low_px_mean + 6 * low_px_std
    fluo_px = worm_pixels[worm_pixels > expression_thresh]
    high_fluo_px = worm_pixels[worm_pixels > high_expression_thresh]
    area = worm_mask.sum()
    integrated = worm_pixels.sum()
    median, percentile95 = np.percentile(worm_pixels, [50, 95])
    expression_area = fluo_px.size
    expression_area_fraction = expression_area / area
    expression_mean = fluo_px.mean()
    high_expression_area = high_fluo_px.size
    high_expression_area_fraction = high_expression_area / area
    high_expression_mean = high_fluo_px.mean()
    high_expression_integrated = high_fluo_px.sum()
    expression_mask = (fluorescent_image > expression_thresh) & worm_mask
    high_expression_mask = (fluorescent_image >
                            high_expression_thresh) & worm_mask

    #create dictionary to store the statistics/measurements

    gfp_data = {
        'warped_integrated_gfp': integrated,
        'warped_median_gfp': median,
        'warped_percentile95_gfp': percentile95,
        'warped_expression_area_gfp': expression_area,
        'warped_expression_areafraction_gfp': expression_area_fraction,
        'warped_expression_mean_gfp': expression_mean,
        'warped_high_expression_area_gfp': high_expression_area,
        'warped_high_expression_area_fraction_gfp':
        high_expression_area_fraction,
        'warped_high_expression_mean_gfp': high_expression_mean,
        'warped_high_expression_integrated_gfp': high_expression_integrated,
        'warped_total_size': np.sum(worm_mask)
    }

    #Generate nice looking pictures to save
    expression_area_mask = np.zeros(worm_mask.shape).astype('bool')
    high_expression_area_mask = np.zeros(worm_mask.shape).astype('bool')
    percentile95_mask = np.zeros(worm_mask.shape).astype('bool')

    expression_area_mask[fluorescent_image > expression_thresh] = True
    expression_area_mask[np.invert(worm_mask)] = False
    high_expression_area_mask[
        fluorescent_image > high_expression_thresh] = True
    high_expression_area_mask[np.invert(worm_mask)] = False
    percentile95_mask[fluorescent_image > percentile95] = True
    percentile95_mask[np.invert(worm_mask)] = False

    colored_areas = extractFeatures.color_features(
        [expression_area_mask, high_expression_area_mask, percentile95_mask])
    return (gfp_data, colored_areas)
Beispiel #4
0
def get_vignette_mask(image):
    """Convert a well-exposed image (ideally a brightfield image with ~uniform
    intensity) into a mask delimiting the image region from the dark,
    vignetted borders of the image.

    Returns: vignette_mask, which is True in the image regions.

    """
    likely_vignette_pixels = image[image < numpy.percentile(image, 40)]
    mean, std = mcd.robust_mean_std(likely_vignette_pixels, 0.5)
    vignette_threshold = mean + 150 * std
    vignette_mask = image > vignette_threshold
    vignette_mask = ndimage.binary_fill_holes(vignette_mask)
    return vignette_mask
Beispiel #5
0
def subregion_measures(image, mask):
    """Measure region properties of a masked image, defining several sub-regions
    relevant to fluorescence images.

    Three sub-regions will be defined:
        expression: the region of a fluorescence image where there is
            apparent fluorescent protein expression (2.5 standard deviations
            above the background distribution of low-valued pixels in the
            masked region)
        high_expression: the region of apparent intense fluorescence (6 standard
            deviations above background)
        over_99: the region including the top 1% of pixels by intensity.

    Parameters:
        image, mask: numpy.ndarrays of same shape.

    Returns: data, region_masks
        data:
            [sum, mean, median, percentile_95, percentile_99,
            expression_sum, expression_mean, expression_median,
            expression_area_fraction,
            high_expression_sum, high_expression_mean, high_expression_median,
            high_expression_area_fraction,
            over_99_sum, over_99_mean, over_99_median]
            where the 'area_fraction' measurements represent the fraction of the
            mask area encompassed by the expression and high_expression areas.
        region_masks: [expression_mask, high_expression_mask, over_99_mask]
            where each is a mask defining the sub-region of the mask.
    """
    if mask.dtype != bool:
        mask = mask > 0
    pixels = image[mask]
    mask_measures = region_measures(pixels)
    mean = mask_measures[1]
    area = pixels.sum()
    low_mean, low_std = mcd.robust_mean_std(pixels[pixels < mean], 0.5)
    expression_mask = (image > (low_mean + 2.5 * low_std)) & mask
    expression_measures = region_measures(image[expression_mask])[:3]
    expression_area_fraction = expression_mask.sum() / area
    expression_measures.append(expression_area_fraction)
    high_expression_mask = (image > (low_mean + 6 * low_std)) & mask
    high_expression_measures = region_measures(image[high_expression_mask])[:3]
    high_expression_area_fraction = high_expression_mask.sum() / area
    high_expression_measures.append(high_expression_area_fraction)
    percentile_99 = mask_measures[-1]
    over_99_mask = (image > percentile_99) & mask
    over_99_measures = region_measures(image[over_99_mask])[:3]
    data = mask_measures + expression_measures + high_expression_measures + over_99_measures
    region_masks = [expression_mask, high_expression_mask, over_99_mask]
    return data, region_masks
def get_rough_mask(image):
    """Take an image with light wells and dark inter-well regions and construct
    a mask with 'True' values in all pixels belonging to a well and 'False' values
    elsewhere."""
    # take every 3rd pixel in each direction and then flatten to a 1D array.
    image_sample = image[::3, ::3].flatten()
    # use that subsample to estimate the mean and variance of the background pixels
    mean, std = mcd.robust_mean_std(image_sample, subset_fraction=0.5)
    # find the non-background pixels
    well_mask = image > (mean + 12*std)
    well_mask = ndimage.binary_fill_holes(well_mask)
    well_mask = mask.remove_small_radius_objects(well_mask, max_radius=10)
    well_mask = mask.remove_edge_objects(well_mask)
    return well_mask
Beispiel #7
0
def get_vignette_mask(image, percent_vignetted=5):
    """Convert a well-exposed image (ideally a brightfield image with ~uniform
    intensity) into a mask delimiting the image region from the dark,
    vignetted borders of the image.

    percent_vignetted: percent (0-100) of pixels estimated to be in the vignetted region.
        35% is a good estimate for images with a full circular vignette
        (e.g. 0.7x optocoupler); 5% is reasonable for images with only small
        vignetted areas (e.g. 1x optocoupler).

    Returns: vignette_mask, which is True in the image regions.
    """
    bright_pixels = image[image > numpy.percentile(image[::4,::4], 1.5*percent_vignetted)]
    mean, std = mcd.robust_mean_std(bright_pixels[::10], 0.85)
    vignette_threshold = mean - 5 * std
    vignette_mask = image > vignette_threshold
    vignette_mask = ndimage.binary_closing(vignette_mask)
    vignette_mask = ndimage.binary_fill_holes(vignette_mask)
    vignette_mask = ndimage.binary_opening(vignette_mask, iterations=15)
    return vignette_mask
Beispiel #8
0
def get_vignette_mask(image, percent_vignetted=5):
    """Convert a well-exposed image (ideally a brightfield image with ~uniform
    intensity) into a mask delimiting the image region from the dark,
    vignetted borders of the image.

    percent_vignetted: percent (0-100) of pixels estimated to be in the vignetted region.
        35% is a good estimate for images with a full circular vignette
        (e.g. 0.7x optocoupler); 5% is reasonable for images with only small
        vignetted areas (e.g. 1x optocoupler).

    Returns: vignette_mask, which is True in the image regions.
    """
    bright_pixels = image[image > numpy.percentile(image[::4,::4], 1.5*percent_vignetted)]
    mean, std = mcd.robust_mean_std(bright_pixels[::10], 0.85)
    vignette_threshold = mean - 5 * std
    vignette_mask = image > vignette_threshold
    vignette_mask = ndimage.binary_closing(vignette_mask)
    vignette_mask = ndimage.binary_fill_holes(vignette_mask)
    vignette_mask = ndimage.binary_opening(vignette_mask, iterations=15)
    return vignette_mask
def measure_gfp_fluorescence(fluorescent_image,
                             worm_mask,
                             measurement_name=None):
    """Measure specific GFP fluorescent things for a particular GFP image
    and return a dictionary of the measurements

    Parameters:
        flourescent_image: numpy array of the flourescent image
        worm_mask: numpy array of the mask
        measurement_name: string of the descriptor that you want the columns to have
            i.e. if you were measuring gfp in the head then you might put measurement_name = 'head'
            and then in the output your dictionary will have keys such as 'integrated_gfp_head' 
            instead of 'integrated_gfp'. This makes it easier to input into elegant right away and
            not overwrite any other previously made measurements

    Returns:
        gfp_measurements: dictionary of measurements and their values
            NOTE: currently gfp_measurements has set things to look for, but maybe
            in the future we can have this take functions to study.
    """
    worm_pixels = fluorescent_image[worm_mask].copy()

    low_px_mean, low_px_std = mcd.robust_mean_std(
        worm_pixels[worm_pixels < worm_pixels.mean()], 0.5)
    expression_thresh = low_px_mean + 2.5 * low_px_std
    high_expression_thresh = low_px_mean + 6 * low_px_std
    fluo_px = worm_pixels[worm_pixels > expression_thresh]
    high_fluo_px = worm_pixels[worm_pixels > high_expression_thresh]
    area = worm_mask.sum()
    integrated = worm_pixels.sum()
    median, percentile95 = np.percentile(worm_pixels, [50, 95])
    expression_area = fluo_px.size
    expression_area_fraction = expression_area / area
    expression_mean = fluo_px.mean()
    high_expression_area = high_fluo_px.size
    high_expression_area_fraction = high_expression_area / area
    high_expression_mean = high_fluo_px.mean()
    high_expression_integrated = high_fluo_px.sum()
    expression_mask = (fluorescent_image > expression_thresh) & worm_mask
    high_expression_mask = (fluorescent_image >
                            high_expression_thresh) & worm_mask
    length = worm_mask.shape[0]

    gfp_measurements = {
        'integrated_gfp': integrated,
        'median_gfp': median,
        'percentile95_gfp': percentile95,
        'expressionarea_gfp': expression_area,
        'expressionareafraction_gfp': expression_area_fraction,
        'expressionmean_gfp': expression_mean,
        'highexpressionarea_gfp': high_expression_area,
        'highexpressionareafraction_gfp': high_expression_area_fraction,
        'highexpressionmean_gfp': high_expression_mean,
        'highexpressionintegrated_gfp': high_expression_integrated,
        'area': area,
        'length': length
    }

    if measurement_name is not None:
        for key in sorted(gfp_measurements.keys()):
            gfp_measurements[key + "_" +
                             measurement_name] = gfp_measurements.pop(key)

    expression_area_mask = np.zeros(worm_mask.shape).astype('bool')
    high_expression_area_mask = np.zeros(worm_mask.shape).astype('bool')
    percentile95_mask = np.zeros(worm_mask.shape).astype('bool')

    expression_area_mask[fluorescent_image > expression_thresh] = True
    expression_area_mask[np.invert(worm_mask)] = False
    high_expression_area_mask[
        fluorescent_image > high_expression_thresh] = True
    high_expression_area_mask[np.invert(worm_mask)] = False
    percentile95_mask[fluorescent_image > percentile95] = True
    percentile95_mask[np.invert(worm_mask)] = False

    #colored_areas = extractFeatures.color_features([expression_area_mask,high_expression_area_mask,percentile95_mask])
    return gfp_measurements