Пример #1
0
def worm_frame_mask(width_tck, image_shape, num_spline_points=None, antialias=False, zoom=1):
    """Use a centerline and width spline to draw a worm mask image in the worm frame of reference.

    Parameters:
        width_tck: width splines defining worm outline
        image_shape: shape of the output mask
        num_spline_points: number of points to evaluate the worm outline along
            (more points = smoother mask). By default, ~1 point/pixel will be
            used, which is more than enough.
        antialias: if False, return a mask with only values 0 and 255. If True,
            edges will be smoothed for better appearance. This is slightly slower,
            and unnecessary when just using the mask to select pixels of interest.
        zoom: zoom-value to use (for matching output of to_worm_frame with zooming.)

    Returns: mask image with dtype=numpy.uint8 in range [0, 255]. To obtain a
        True/False-valued mask from a uint8 mask (regardless of antialiasing):
            bool_mask = uint8_mask > 255
    """
    worm_length = image_shape[0]
    if num_spline_points is None:
        num_spline_points = worm_length
    widths = interpolate.spline_interpolate(width_tck, num_points=num_spline_points)
    widths *= zoom
    x_vals = numpy.linspace(0, worm_length, num_spline_points)
    centerline_y = image_shape[1] / 2
    top = numpy.transpose([x_vals, centerline_y - widths])
    bottom = numpy.transpose([x_vals, centerline_y + widths])[::-1]
    path = celiagg.Path()
    path.lines(numpy.concatenate([top, bottom]))
    return draw.draw_mask(image_shape, path, antialias)
Пример #2
0
def worm_image_coords_in_lab_frame(lab_image_shape, worm_image_shape, center_tck, width_tck,
        standard_width=None, zoom=1, reflect_centerline=False):
    """Produce a map in the lab frame noting the coordinates of each worm pixel in the
        frame of reference of an image as generated by to_worm_frame().

    The output coordinates are relative to a worm frame-of-reference image, as
    produced by to_worm_frame(). All parameters must be the same as those passed
    to to_worm_frame() for the coordinate transform to be correct. In particular,
    if a standard_width and/or a zoom factor were used to produce the image,
    those values must be used here as well.

    Areas outside of the worm will be nan.

    Parameters:
        lab_image_shape: shape of output image in lab frame
        worm_image_shape: shape of worm image in which the coordinates are defined
        center_tck: centerline spline of the worm in the lab frame.
        width_tck: spline width profile of the worm.
        standard_width: a width spline specifying the "standardized" width
            profile for the output image.
        zoom: zoom factor.
        reflect_centerline: reflect worm coordinates over the centerline
    Returns: (x_coords, y_coords), each of shape lab_image_shape
    """
    triangle_strip = spline_geometry.triangle_strip(center_tck, width_tck)
    wtck = width_tck if standard_width is None else standard_width
    widths = interpolate.spline_interpolate(wtck, num_points=len(triangle_strip)//2)
    right = worm_image_shape[1]/2 - widths*zoom # worm_image_shape[1]/2 is the position of the centerline
    left = worm_image_shape[1]/2 + widths*zoom # worm_image_shape[1]/2 is the position of the centerline
    return _worm_coords(lab_image_shape, triangle_strip, x_max=worm_image_shape[0], right=right, left=left, reflect_centerline=reflect_centerline)
Пример #3
0
def abs_worm_coords_in_lab_frame(lab_image_shape,
                                 center_tck,
                                 width_tck,
                                 reflect_centerline=False):
    """Produce a map of the pixel-wise worm coordinates in the lab frame.

    Output x-coords run from 0 to the length of the worm, and y-coords from
    -width (right side) to width, which varies along the worm.
    Areas outside of the worm will be nan.

    Parameters:
        lab_image_shape: shape of output image in lab frame
        center_tck: centerline spline of the worm in the lab frame.
        width_tck: spline width profile of the worm.
        reflect_centerline: reflect worm coordinates over the centerline
    Returns: (x_coords, y_coords), each of shape lab_image_shape
    """
    triangle_strip = spline_geometry.triangle_strip(center_tck, width_tck)
    x_max = spline_geometry.arc_length(center_tck)
    widths = interpolate.spline_interpolate(width_tck,
                                            num_points=len(triangle_strip) //
                                            2)
    return _worm_coords(lab_image_shape,
                        triangle_strip,
                        x_max,
                        right=-widths,
                        left=widths,
                        reflect_centerline=reflect_centerline)
Пример #4
0
def to_worm_frame(images, center_tck, width_tck=None, width_margin=20, sample_distance=None,
        standard_length=None, standard_width=None, zoom=1, reflect_centerline=False,
        order=3, dtype=None, **kwargs):
    """Transform images from the lab reference frame to the worm reference frame.

    The width of the output image is defined by the center_tck, which defines
    the length of the worm and thus the width of the image. The height of the
    image can be specified either directly by the sample_distance parameter,
    or can be computed from a width_tck that defines the location of the sides
    of the worm (a fixed width_margin is added so that the image extends a bit
    past the worm).

    The size and shape of the output worm can be standardized to a "unit worm"
    by use of the "standard_length" and "standard_width" parameters; see below.

    Parameters:
        images: single numpy array, or list/tuple/3d array of multiple images to
            be transformed.
        center_tck: centerline spline defining the pose of the worm in the lab
            frame.
        width_tck: width spline defining the distance from centerline to worm
            edges. Optional; uses are as follows: (1) if sample_distance is not
            specified, a width_tck must be specified in order to calculate the
            output image height; (2) if standard_width is specified, a width_tck
            must also be specified to define the transform from this worm's
            width profile to the standardized width profile.
        width_margin: if sample_distance is not specified, width_margin is used
            to define the distance (in image pixels) that the output image will
            extend past the edge of the worm (at its widest). If a zoom is
            specified, note that the margin pixels will be zoomed too.
        sample_distance: number of pixels to sample in each direction
            perpendicular to the centerline. The height of the output image is
            int(round(2 * sample_distance * zoom)).
        standard_length: if not specified, the width of the output image is
            int(round(arc_length)*zoom), where arc_length is the path integral
            along center_tck (i.e. the length from beginning to end). If
            standard_length is specified, then the length of the output image is
            int(round(standard_length*zoom)). The full length of the worm will
            be compressed or expanded as necessary to bring it to the specified
            standard_length.
        standard_width: a width spline specifying the "standardized" width
            profile for the output image. If specified, the actual width profile
            must also be provided as width_tck. In this case, the output image
            will be compressed/expanded perpendicular to the centerline as needed
            to make the actual widths conform to the standard width profile.
        zoom: zoom factor, can be any real number > 0.
        reflect_centerline: reflect worm over its centerline.
        order: image interpolation order (0 = nearest neighbor, 1 = linear,
            3 = cubic). Cubic is best, but slowest.
        dtype: if None, use dtype of input images for output. Otherwise, use
            the specified dtype.
        kwargs: additional keyword arguments to pass to ndimage.map_coordinates.

    Returns: single image or list of images (depending on whether the input is a
        single image or list/tuple/3d array).
    """

    assert width_tck is not None or sample_distance is not None
    if standard_width is not None:
        assert width_tck is not None

    if standard_length is None:
        length = spline_geometry.arc_length(center_tck)
    else:
        length = standard_length
    x_samples = int(round(length * zoom))

    if sample_distance is None:
        wtck = standard_width if standard_width is not None else width_tck
        sample_distance = interpolate.spline_interpolate(wtck, num_points=x_samples).max() + width_margin
    y_samples = int(round(2 * sample_distance * zoom))

    # basic plan:
    # 1) get the centerline and the perpendiculars to it.
    # 2) define positions along each perpendicular at which to sample the input images.
    # (This is the "offset_distances" variable).

    x = numpy.arange(x_samples, dtype=float) + 0.5 # want to sample at pixel centers, not edges
    y = numpy.ones_like(x) * (y_samples / 2)
    worm_frame_centerline = numpy.transpose([x, y])
    centerline, perpendiculars, spline_y = _lab_centerline_and_perps(worm_frame_centerline, (x_samples, y_samples),
        center_tck, width_tck, standard_width, zoom)
    # if the far edges of the top and bottom pixels are sample_distance from the centerline,
    # figure out the position of the *centers* of the top and bottom of the pixels.
    # i.e. correct for fencepost error
    sample_max = sample_distance * (y_samples - 1) / y_samples
    offsets = numpy.linspace(-sample_max, sample_max, y_samples) # distances along each perpendicular across the width of the sample swath
    offset_distances = numpy.multiply.outer(perpendiculars.T, offsets) # shape = (2, x_samples, y_samples)
    centerline = centerline.T[:, :, numpy.newaxis] # from shape = (x_samples, 2) to shape = (2, x_samples, 1)
    if reflect_centerline:
        offset_distances *= -1
    sample_coordinates = centerline + offset_distances # shape = (2, x_samples, y_samples)

    unpack_list = False
    if isinstance(images, numpy.ndarray):
        if images.ndim == 3:
            images = list(images)
        else:
            unpack_list = True
            images = [images]
    # subtract half-pixel offset because map_coordinates treats (0,0) as the middle
    # of the top-left pixel, not the far corner of that pixel.
    worm_frame = [ndimage.map_coordinates(image, sample_coordinates - _HALF_PX_OFFSET.reshape(2, 1, 1),
        order=order, output=dtype, **kwargs) for image in images]
    if unpack_list:
        worm_frame = worm_frame[0]
    return worm_frame