Ejemplo n.º 1
0
def normalize_pred_keypoints(timepoint,
                             pred_keypoints,
                             downscale=2,
                             image_size=(960, 512)):
    downscale = downscale
    center_tck, width_tck = timepoint.annotations['pose']
    new_width_tck = (AVG_WIDTHS_TCK[0], AVG_WIDTHS_TCK[1] / downscale,
                     AVG_WIDTHS_TCK[2])
    image_shape = (image_size[0] / downscale, image_size[1] / downscale)
    length = spline_geometry.arc_length(center_tck)
    sample_dist = interpolate.spline_interpolate(width_tck, length).max() + 20
    if pred_keypoints is None:
        print("Keypoints do not exist with id: ", pred_id)
        return None
    new_keypoints = {}
    for kp, points in pred_keypoints.items():
        x, y = points
        x_percent = x / length
        new_x = x_percent * image_shape[0]
        new_y = int(image_shape[1] / 2)
        if kp == 'vulva':
            vulvax = int(new_x)
            avg_widths = interpolate.spline_interpolate(
                new_width_tck, image_shape[0])
            if vulvax == len(avg_widths):
                vulvax = vulvax - 1
            vulvay = avg_widths[vulvax]
            if y < 0:
                new_y = (image_shape[1] / 2) - vulvay
            else:
                new_y = (image_shape[1] / 2) + vulvay

        new_keypoints[kp] = (new_x, new_y)

    return new_keypoints
Ejemplo n.º 2
0
def process_centerline_dir(source_dir, microns_per_pixel):
    source_dir = pathlib.Path(source_dir)
    out_dir = source_dir / 'individual_centerlines'
    out_dir.mkdir(exist_ok=True)

    centerline_data = {}
    centerline_data_entries = ['name', 'length']
    
    mask_data = {}
    [mask_data.setdefault(entry,[]) for entry in centerline_data_entries]
    for centerline_image_path in sorted(source_dir.iterdir()):
        if centerline_image_path.suffix[1:] != 'png':
            continue
        aggregate_centerline_image = freeimage.read(centerline_image_path)
        masks = parse_aggregate_centerlines(aggregate_centerline_image)
        for mask_num, mask in enumerate(masks):
            mask_name = centerline_image_path.stem + f'_{mask_num}'
            print(mask_name)
            freeimage.write(mask.astype('uint8')*255, out_dir / (mask_name+'.png'))
            center_tck, _ = worm_spline.pose_from_mask(mask) # Toss the widths
            try:
                length = spline_geometry.arc_length(center_tck) * microns_per_pixel
                mask_data['name'].append(mask_name)
                mask_data['length'].append(length)
            except TypeError:
                print(f'Warning: couldn\'t find centerline for {mask_name} (px location {list(numpy.where(mask))})')

    with (out_dir / 'measurements.txt').open('w+') as measurement_file:
        measurement_file.write('\t'.join(centerline_data_entries)+'\n')
        for data in zip(*[mask_data[entry] for entry in centerline_data_entries]):
            measurement_file.write('\t'.join([str(item) for item in data])+'\n')
Ejemplo n.º 3
0
def renormalize_pred_keypoints(timepoint,
                               pred_keypoints,
                               downscale=2,
                               image_size=(960, 512)):
    downscale = downscale
    center_tck, width_tck = timepoint.annotations['pose']
    image_shape = (image_size[0] / downscale, image_size[1] / downscale)
    length = spline_geometry.arc_length(center_tck)
    sample_dist = interpolate.spline_interpolate(width_tck, length).max() + 20
    width = int(round(sample_dist * 2))
    new_keypoints = {}
    for kp, points in pred_keypoints.items():
        x, y = points
        x_percent = x / image_shape[0]
        new_x = x_percent * length
        if kp is 'vulva':
            vulvax = int(new_x)
            print("vulvax: ", vulvax)

            print("x_percent: ", x_percent)
            avg_widths = interpolate.spline_interpolate(width_tck, length)
            if vulvax == len(avg_widths):
                vulvax = vulvax - 1
            vulvay = avg_widths[vulvax]
            if y < 0:
                new_y = -vulvay
            else:
                new_y = vulvay
        else:
            new_y = 0

        new_keypoints[kp] = (new_x, new_y)

    return new_keypoints
Ejemplo n.º 4
0
def abs_worm_coords_distance_from_edge(lab_image_shape, center_tck, width_tck):
    """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 are the
    distance from the edge of the worm, rather than the distance from the
    centerline, as in abs_worm_coords_in_lab_frame().

    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.
    Returns: (x_coords, y_coords), each of shape lab_image_shape
    """
    left, center, right, widths = spline_geometry.centerline_and_outline(
        center_tck, width_tck)
    num_points = len(left)
    edge_vals = numpy.zeros((num_points, 2), dtype=numpy.float32)
    center_vals = numpy.zeros((num_points, 2), dtype=numpy.float32)
    x_max = spline_geometry.arc_length(center_tck)
    edge_vals[:, 0] = center_vals[:, 0] = numpy.linspace(0, x_max, num_points)
    center_vals[:, 1] = widths
    return draw.gourad_centerline_strip(left,
                                        center,
                                        right,
                                        edge_vals,
                                        center_vals,
                                        edge_vals,
                                        lab_image_shape,
                                        background=numpy.nan)
Ejemplo n.º 5
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)
Ejemplo n.º 6
0
    def get_keypoint_coords(self, i, image_shape):
        annotations = self.timepoint_list[i].annotations
        center_tck, width_tck = annotations['pose']
        keypoints = annotations['keypoints']

        #step 1: get the x,y positions in the new image shape
        length = spline_geometry.arc_length(center_tck)
        sample_dist = interpolate.spline_interpolate(width_tck, length).max()+20
        width = int(round(sample_dist*2))

        xs = numpy.array([keypoints[k][0] for k in ('anterior bulb', 'posterior bulb', 'vulva', 'tail')])
        x_percent = xs/length
        new_xs = x_percent*image_shape[0]

        #get y coordinates
        #put all keypoints except vulva at the midline
        ys = [int(image_shape[1]/2)]*len(new_xs)
        vulvax = int(new_xs[2])
        avg_widths = interpolate.spline_interpolate(self.AVG_WIDTHS_TCK, image_shape[0])
        vulvay = avg_widths[vulvax]
        #widths are wrt the midline, so put vulva on correct side
        if keypoints['vulva'][1] > 0:
            ys[2] = (image_shape[1]/2) + vulvay
        else:
            ys[2] = (image_shape[1]/2) - vulvay

        return new_xs, ys
Ejemplo n.º 7
0
def get_avg_lengths(metadata_list):
    """Get the average lengths of worms 3-7 days old to
    make a unit worm from
    """
    lengths=[]
    for m in metadata_list.values():
        spine_tck=m['spine_tck']
        lengths.append(spline_geometry.arc_length(spine_tck))

    lengths=np.array(lengths)
    lengths_avg=np.mean(lengths, axis=0)
    return lengths_avg
Ejemplo n.º 8
0
def calculate_keypoints(keypoints, center_tck):
    """In order for longitudinal_warp_spline to work we
    need the keypoint positions to be as a ratio of the 
    length of the center_tck.

    Parameters:
        keypoints: dictionary from the annotations file
        center_tck: tck of the centerline of the worm
    """

    length = spline_geometry.arc_length(center_tck)
    x, y = zip(*list(keypoints.values()))
    return x / length
Ejemplo n.º 9
0
def process_spline_file(spline_file, microns_per_pixel):
    spline_file = pathlib.Path(spline_file)
    with spline_file.open('rb') as spline_fp:
        annotations = pickle.load(spline_fp)
    images = sorted(spline_file.parent.glob('*.png'))
    names, lengths = [], []
    for page_annotations, image in zip(annotations, images):
        spline_count = 0
        if page_annotations['MultisplineAnnotation']:
            for spline_tck in page_annotations['MultisplineAnnotation']:
                lengths.append(spline_geometry.arc_length(spline_tck) * microns_per_pixel)
                names.append(image.stem + f'_{spline_count}')
                spline_count += 1
    with (spline_file.parent / (spline_file.stem + '_measurements.txt')).open('w+') as measurement_file:
        measurement_file.write('\t'.join(['Name', 'Length (um)'])+'\n')
        for data in zip(names, lengths):
            measurement_file.write('\t'.join([str(item) for item in data])+'\n')
Ejemplo n.º 10
0
 def measure(self, position_root, timepoint, annotations, before, after):
     center_tck, width_tck = annotations.get(self.pose_annotation,
                                             (None, None))
     measures = {}
     if center_tck is not None:
         if width_tck is None:
             measures['length'] = spline_geometry.arc_length(
                 center_tck) * self.microns_per_pixel
         else:
             measures['projected_area'] = spline_geometry.area(
                 center_tck, width_tck) * self.microns_per_pixel**2
             volume, surface_area = spline_geometry.volume_and_surface_area(
                 center_tck, width_tck)
             measures['volume'] = volume * self.microns_per_pixel**3
             measures[
                 'surface_area'] = surface_area * self.microns_per_pixel**2
             length, max_width = spline_geometry.length_and_max_width(
                 center_tck, width_tck)
             measures['length'] = length * self.microns_per_pixel
             # the "width_tck" is really more like a radius,
             # storing the distance from the centerline to the edge.
             # Double it to generate a real width.
             measures['max_width'] = max_width * 2 * self.microns_per_pixel
         centroid_distances = []
         rmsds = []
         for adjacent in (before, after):
             if adjacent is not None:
                 adj_center_tck, adj_width_tck = adjacent.get(
                     self.pose_annotation, (None, None))
                 if adj_center_tck is not None:
                     centroid_distances.append(
                         spline_geometry.centroid_distance(center_tck,
                                                           adj_center_tck,
                                                           num_points=300))
                     rmsds.append(
                         spline_geometry.rmsd(center_tck,
                                              adj_center_tck,
                                              num_points=300))
         if len(rmsds) > 0:
             measures['centroid_dist'] = numpy.mean(
                 centroid_distances) * self.microns_per_pixel
             measures['rms_dist'] = numpy.mean(
                 rmsds) * self.microns_per_pixel
     return [
         measures.get(feature, numpy.nan) for feature in self.feature_names
     ]
Ejemplo n.º 11
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