Source code for mycelyso.highlevel.pixelframe

# -*- coding: utf-8 -*-
"""
The pixelframe module contains the PixelFrame class, a representation of one time lapse frame
at the binary mask/pixel level.
"""

import numpy as np

from skimage.measure import label

from ..processing.pixelgraphs import \
    where2d, get_connectivity_map, get_neighborhood_map, is_edge, is_end, is_junction, \
    get_next_neighbor, get_inverse_neighbor_shift, get_all_neighbor_nums


[docs]class PixelFrame(object): """ A PixelFrame represents the pixel graph of one (skeletonized) image stack frame. """ def __init__(self, image, timepoint=0.0, calibration=1.0): """ Initializes the PixelFrame :param image: Input image (skeletonized) :param timepoint: Experiment time (in seconds) :param calibration: Pixel size (in µm) """ self.timepoint = timepoint self.calibration = calibration # binary image of skeleton, 0 and 1s (forced bool cast) self.image = (image > 0).astype(np.uint8) self.marker = label(image) self.graph_lengths = np.bincount(self.marker.ravel()) self.graph_count = self.graph_lengths.shape[0] self.connectivity = get_connectivity_map(image) self.neighborhood_map = get_neighborhood_map(image) self.junctions_map = is_junction(self.connectivity) self.endpoints_map = is_end(self.connectivity) self.junctions = where2d(self.junctions_map) self.endpoints = where2d(self.endpoints_map) self.pathlets = [] self.create_graph()
[docs] def create_graph(self): """ Creates the graph from the pixel skeleton. :return: """ conn = self.connectivity nm = self.neighborhood_map.copy() todo = [[nm[y, x], y, x] for y, x in self.endpoints] pathlets = [] while len(todo) > 0: n, y, x = todo.pop() if nm[y, x] < n: continue points = [[y, x]] while True: ys, xs = get_next_neighbor(n) nm[y, x] -= n last_n = n y, x = y + ys, x + xs if not (-1 < y < nm.shape[0] and -1 < x < nm.shape[1]): # there was a strange case where the algorithm wanted to jump outside of the image y, x = y - ys, x - xs break points.append([y, x]) inverse = get_inverse_neighbor_shift(last_n) if inverse < nm[y, x]: nm[y, x] -= inverse n = nm[y, x] if not is_edge(conn[y, x]): break if n == 0: break points = np.array(points) if is_junction(conn[y, x]): if nm[y, x] > 0: for n in get_all_neighbor_nums(nm[y, x]): todo.insert(0, [n, y, x]) pathlets.append(points) self.pathlets = pathlets