def compare_lineage_trees_to_gt(gt_dir, proposal_dir, lineage_trees):
    import compare_tracking
    from multiprocessing import Pool, cpu_count
    import itertools

    print("Parallelizing over {} cores".format(cpu_count()))
    processing_pool = Pool(cpu_count())

    gt_filenames, proposal_filenames = compare_tracking.get_tracking_filenames(gt_dir, proposal_dir)
    first_timestep = int(os.path.splitext(os.path.basename(gt_filenames[0]))[0])

    timesteps = min(len(gt_filenames), len(proposal_filenames))
    associations = compare_tracking.construct_associations(gt_filenames, proposal_filenames, timesteps)

    filename_pairs = zip(gt_filenames[0:timesteps], proposal_filenames[0:timesteps])
    lineage_tree_traxels = [lt.get_all_traxels() for lt in lineage_trees]

    pb = ProgressBar(0, len(lineage_trees))
    lineage_tree_measures = []
    for measure in processing_pool.imap(compute_traxel_set_measures,
                                        itertools.izip(lineage_tree_traxels,
                                                       itertools.repeat(associations),
                                                       itertools.repeat(filename_pairs),
                                                       itertools.repeat(first_timestep))):
        lineage_tree_measures.append(measure)
        pb.show()

    return lineage_tree_measures
Exemple #2
0
def compare_lineage_trees_to_gt(gt_dir, proposal_dir, lineage_trees):
    import compare_tracking
    from multiprocessing import Pool, cpu_count
    import itertools

    print("Parallelizing over {} cores".format(cpu_count()))
    processing_pool = Pool(cpu_count())

    gt_filenames, proposal_filenames = compare_tracking.get_tracking_filenames(
        gt_dir, proposal_dir)
    first_timestep = int(
        os.path.splitext(os.path.basename(gt_filenames[0]))[0])

    timesteps = min(len(gt_filenames), len(proposal_filenames))
    associations = compare_tracking.construct_associations(
        gt_filenames, proposal_filenames, timesteps)

    filename_pairs = zip(gt_filenames[0:timesteps],
                         proposal_filenames[0:timesteps])
    lineage_tree_traxels = [lt.get_all_traxels() for lt in lineage_trees]

    pb = ProgressBar(0, len(lineage_trees))
    lineage_tree_measures = []
    for measure in processing_pool.imap(
            compute_traxel_set_measures,
            itertools.izip(lineage_tree_traxels,
                           itertools.repeat(associations),
                           itertools.repeat(filename_pairs),
                           itertools.repeat(first_timestep))):
        lineage_tree_measures.append(measure)
        pb.show()

    return lineage_tree_measures
def create_and_link_tracks_and_divisions(track_features_h5, ts, region_features):
    # storage for all tracks and divisions
    tracks = {}
    divisions = {}

    # mapping of traxelID at front and back of track to track_id
    track_starts_with_traxel_id = {}
    track_ends_with_traxel_id = {}

    pb = ProgressBar(0, len(track_features_h5['tracks'].keys()) + len(track_features_h5['divisions'].keys()))
    print("Extracting Tracks and Divisions")

    for track_id in track_features_h5['tracks'].keys():
        pb.show()
        track_id_int = int(track_id)
        t = Track(track_id_int)
        t.extract(track_features_h5)
        t.extract_region_features(ts, region_features)

        # store in container
        tracks[track_id_int] = t
        
        # create mappings
        track_starts_with_traxel_id[t.start_traxel_id] = track_id_int
        track_ends_with_traxel_id[t.end_traxel_id] = track_id_int

    max_length = max([t.length for t in tracks.values()])   
    for t in tracks.values():
        t.features['track_length'] = float(t.length) / max_length

    for division_id in track_features_h5['divisions'].keys():
        pb.show()
        division_id_int = int(division_id)
        d = Division(division_id_int)
        d.extract(track_features_h5)

        # find the tracks that are connected by this division
        # and update information in the tracks
        try:
            d.parent_track_id = track_ends_with_traxel_id[d.parent_traxel_id]
            tracks[d.parent_track_id].end_division_id = division_id_int
        except KeyError as e:
            print("Could not find parent track of division {}: ".format(division_id), e.message)

        for i in [0, 1]:
            try:
                d.children_track_ids[i] = track_starts_with_traxel_id[d.children_traxel_ids[i]]
                tracks[d.children_track_ids[i]].start_division_id = division_id_int
            except KeyError as e:
                print("Could not find child track of division {}: ".format(division_id), e.message)

        # store in container
        divisions[division_id_int] = d
    return tracks, divisions
    def _findOverlaps(self):
        """
        Check which objects are overlapping between the different segmentation hypotheses,
        and store that information in every traxel.
        """
        getLogger().info("Checking for overlapping segmentation hypotheses...")
        t0 = time.time()

        # find exclusion constraints
        if self._useMultiprocessing:
            # use ProcessPoolExecutor, which instanciates as many processes as there CPU cores by default
            ExecutorType = concurrent.futures.ProcessPoolExecutor
            getLogger().info('Parallelizing via multiprocessing on all cores!')
        else:
            ExecutorType = DummyExecutor
            getLogger().info('Running on single core!')

        jobs = []
        progressBar = ProgressBar(stop=self.timeRange[1] - self.timeRange[0])
        progressBar.show(increase=0)

        with ExecutorType() as executor:
            for frame in range(self.timeRange[0], self.timeRange[1]):
                jobs.append(
                    executor.submit(findConflictingHypothesesInSeparateProcess,
                                    frame, self._labelImageFilenames,
                                    self._labelImagePaths,
                                    self._labelImageFrameIdToGlobalId,
                                    self._pluginPaths))
            for job in concurrent.futures.as_completed(jobs):
                progressBar.show()
                frame, overlaps = job.result()
                for objectId, overlapIds in overlaps.iteritems():
                    if self.TraxelsPerFrame[frame][
                            objectId].conflictingTraxelIds is None:
                        self.TraxelsPerFrame[frame][
                            objectId].conflictingTraxelIds = []
                    self.TraxelsPerFrame[frame][
                        objectId].conflictingTraxelIds.extend(overlapIds)

        t1 = time.time()
        getLogger().info("Finding overlaps took {} secs".format(t1 - t0))
    def _findOverlaps(self):
        """
        Check which objects are overlapping between the different segmentation hypotheses,
        and store that information in every traxel.
        """
        getLogger().info("Checking for overlapping segmentation hypotheses...")
        t0 = time.time()

        # find exclusion constraints
        if self._useMultiprocessing:
            # use ProcessPoolExecutor, which instanciates as many processes as there CPU cores by default
            ExecutorType = concurrent.futures.ProcessPoolExecutor
            getLogger().info('Parallelizing via multiprocessing on all cores!')
        else:
            ExecutorType = DummyExecutor
            getLogger().info('Running on single core!')

        jobs = []
        progressBar = ProgressBar(stop=self.timeRange[1] - self.timeRange[0])
        progressBar.show(increase=0)

        with ExecutorType() as executor:
            for frame in range(self.timeRange[0], self.timeRange[1]):
                jobs.append(executor.submit(findConflictingHypothesesInSeparateProcess,
                                            frame,
                                            self._labelImageFilenames,
                                            self._labelImagePaths,
                                            self._labelImageFrameIdToGlobalId,
                                            self._pluginPaths
                ))
            for job in concurrent.futures.as_completed(jobs):
                progressBar.show()
                frame, overlaps = job.result()
                for objectId, overlapIds in overlaps.iteritems():
                    if self.TraxelsPerFrame[frame][objectId].conflictingTraxelIds is None:
                        self.TraxelsPerFrame[frame][objectId].conflictingTraxelIds = []
                    self.TraxelsPerFrame[frame][objectId].conflictingTraxelIds.extend(overlapIds)
        
        t1 = time.time()
        getLogger().info("Finding overlaps took {} secs".format(t1 - t0))
Exemple #6
0
    def convexifyCosts(self, epsilon=0.000001):
        '''
        Convexify all cost vectors in this model (in place!).
        If two values are equal, the specified `epsilon` will be added to make sure the gradient
        does not stay at 0.

        Needed to run the flow solver afterwards
        '''
        if not self.model['settings']['statesShareWeights']:
            raise ValueError(
                'This script can only convexify feature vectors with shared weights!'
            )

        if 'segmentationHypotheses' in self.model:
            segmentationHypotheses = self.model['segmentationHypotheses']
        else:
            segmentationHypotheses = []

        if 'linkingHypotheses' in self.model:
            linkingHypotheses = self.model['linkingHypotheses']
        else:
            linkingHypotheses = []

        if 'divisionHypotheses' in self.model:
            divisionHypotheses = self.model['divisionHypotheses']
        else:
            divisionHypotheses = []

        progressBar = ProgressBar(stop=(len(segmentationHypotheses) +
                                        len(linkingHypotheses) +
                                        len(divisionHypotheses)))
        for seg in segmentationHypotheses:
            for f in [
                    'features', 'appearanceFeatures', 'disappearanceFeatures'
            ]:
                if f in seg:
                    try:
                        seg[f] = convexify(seg[f], epsilon)
                    except:
                        getLogger().warning(
                            "Convexification failed for feature {} of :{}".
                            format(f, seg))
                        exit(0)
            # division features are always convex (2 values defines just a line)
            progressBar.show()

        for link in linkingHypotheses:
            link['features'] = convexify(link['features'], epsilon)
            progressBar.show()

        for division in divisionHypotheses:
            division['features'] = convexify(division['features'], epsilon)
            progressBar.show()
    def convexifyCosts(self, epsilon=0.000001):
        '''
        Convexify all cost vectors in this model (in place!).
        If two values are equal, the specified `epsilon` will be added to make sure the gradient
        does not stay at 0.

        Needed to run the flow solver afterwards
        '''
        if not self.model['settings']['statesShareWeights']:
            raise ValueError('This script can only convexify feature vectors with shared weights!')

        if 'segmentationHypotheses' in self.model:
            segmentationHypotheses = self.model['segmentationHypotheses']
        else:
            segmentationHypotheses = []

        if 'linkingHypotheses' in self.model:
            linkingHypotheses = self.model['linkingHypotheses']
        else:
            linkingHypotheses = []

        if 'divisionHypotheses' in self.model:
            divisionHypotheses = self.model['divisionHypotheses']
        else:
            divisionHypotheses = []

        progressBar = ProgressBar(stop=(len(segmentationHypotheses) + len(linkingHypotheses) + len(divisionHypotheses)))
        for seg in segmentationHypotheses:
            for f in ['features', 'appearanceFeatures', 'disappearanceFeatures']:
                if f in seg:
                    try:
                        seg[f] = convexify(seg[f], epsilon)
                    except:
                        getLogger().warning("Convexification failed for feature {} of :{}".format(f, seg))
                        exit(0)
            # division features are always convex (2 values defines just a line)
            progressBar.show()

        for link in linkingHypotheses:
            link['features'] = convexify(link['features'], epsilon)
            progressBar.show()

        for division in divisionHypotheses:
            division['features'] = convexify(division['features'], epsilon)
            progressBar.show()
Exemple #8
0
def convertLegacyHypothesesGraphToJsonGraph(
        hypothesesGraph, nodeIterator, arcIterator, withTracklets,
        maxNumObjects, numElements, traxelMap, detectionProbabilityFunc,
        transitionProbabilityFunc, boundaryCostMultiplierFunc,
        divisionProbabilityFunc):
    '''
    Build a json representation of this hypotheses graph, by transforming the probabilities for certain
    events (given by the `*ProbabilityFunc`-functions per traxel) into energies. If the given graph
    contained tracklets (`withTracklets`), then also the probabilities over all contained traxels will be
    accumulated for those nodes in the graph.

    The `hypothesesGraph` as well as `nodeIterator` and `arcIterator` are needed as parameters to
    support the legacy pgmlink-style hypotheses graph as well.

    ** Parameters: **

    * `hypothesesGraph`: graph whose nodes and edges we are about to traverse.
    * `nodeIterator`: node iterator
    * `arcIterator`: arc iterator
    * `withTracklets`: whether tracklets are used
    * `maxNumObjects`: the max number of objects per detections
    * `numElements`: number of nodes + number of edges (for progress bar)
    * `traxelMap`: mapping from graph-node to list of traxels (in a tracklet)
    * `detectionProbabilityFunc`: should take a traxel and return its detection probabilities
     ([prob0objects, prob1object,...])
    * `transitionProbabilityFunc`: should take two traxels and return this link's probabilities
     ([prob0objectsInTransition, prob1objectsInTransition,...])
    * `boundaryCostMultiplierFunc`: should take a traxel and a boolean that is true if we are seeking for an appearance cost multiplier, 
      false for disappearance, and return a scalar multiplier between 0 and 1 for the
      appearance/disappearance cost that depends on the traxel's distance to the spacial and time boundary
    * `divisionProbabilityFunc`: should take a traxel and return its division probabilities
     ([probNoDiv, probDiv])
    '''

    getLogger().info("Creating JSON graph from legacy hypotheses graph")
    progressBar = ProgressBar(stop=numElements)
    trackingGraph = hytra.core.jsongraph.JsonTrackingGraph()

    # add all detections to JSON
    for n in nodeIterator:
        if not withTracklets:
            # only one traxel, but make it a list so everything below works the same
            traxels = [traxelMap[n]]
        else:
            traxels = traxelMap[n]

        # accumulate features over all contained traxels
        previousTraxel = None
        detectionFeatures = np.zeros(maxNumObjects + 1)
        for t in traxels:
            detectionFeatures += np.array(negLog(detectionProbabilityFunc(t)))
            if previousTraxel is not None:
                detectionFeatures += np.array(
                    negLog(transitionProbabilityFunc(previousTraxel, t)))
            previousTraxel = t

        detectionFeatures = listify(list(detectionFeatures))

        # division only if probability is big enough
        divisionFeatures = divisionProbabilityFunc(traxels[-1])
        if divisionFeatures is not None:
            divisionFeatures = listify(negLog(divisionFeatures))

        # appearance/disappearance
        appearanceFeatures = listify(
            [0.0] +
            [boundaryCostMultiplierFunc(traxels[0], True)] * maxNumObjects)
        disappearanceFeatures = listify(
            [0.0] +
            [boundaryCostMultiplierFunc(traxels[-1], False)] * maxNumObjects)

        trackingGraph.addDetectionHypothesesFromTracklet(
            traxels,
            detectionFeatures,
            divisionFeatures,
            appearanceFeatures,
            disappearanceFeatures,
            timestep=[traxels[0].Timestep, traxels[-1].Timestep])
        progressBar.show()

    # add all links
    for a in arcIterator:
        if not withTracklets:
            srcTraxel = traxelMap[hypothesesGraph.source(a)]
            destTraxel = traxelMap[hypothesesGraph.target(a)]
        else:
            srcTraxel = traxelMap[hypothesesGraph.source(a)][
                -1]  # src is last of the traxels in source tracklet
            destTraxel = traxelMap[hypothesesGraph.target(a)][
                0]  # dest is first of traxels in destination tracklet
        src = trackingGraph.traxelIdPerTimestepToUniqueIdMap[str(
            srcTraxel.Timestep)][str(srcTraxel.Id)]
        dest = trackingGraph.traxelIdPerTimestepToUniqueIdMap[str(
            destTraxel.Timestep)][str(destTraxel.Id)]

        features = listify(
            negLog(transitionProbabilityFunc(srcTraxel, destTraxel)))
        trackingGraph.addLinkingHypotheses(src, dest, features)
        progressBar.show()

    return trackingGraph
    def fillTraxels(self,
                    usePgmlink=True,
                    ts=None,
                    fs=None,
                    dispyNodeIps=[],
                    turnOffFeatures=[]):
        """
        Compute all the features and predict object count as well as division probabilities.
        Store the resulting information (and all other features) in the given pgmlink::TraxelStore,
        or create a new one if ts=None.

        usePgmlink: boolean whether pgmlink should be used and a pgmlink.TraxelStore and pgmlink.FeatureStore returned
        ts: an initial pgmlink.TraxelStore (only used if usePgmlink=True)
        fs: an initial pgmlink.FeatureStore (only used if usePgmlink=True)

        returns (ts, fs) but only if usePgmlink=True, otherwise it fills self.TraxelsPerFrame
        """
        if usePgmlink:
            import pgmlink
            if ts is None:
                ts = pgmlink.TraxelStore()
                fs = pgmlink.FeatureStore()
            else:
                assert (fs is not None)

        getLogger().info("Extracting features...")
        self._featuresPerFrame = self._extractAllFeatures(
            dispyNodeIps=dispyNodeIps, turnOffFeatures=turnOffFeatures)

        getLogger().info("Creating traxels...")
        progressBar = ProgressBar(stop=len(self._featuresPerFrame))
        progressBar.show(increase=0)

        for frame, features in self._featuresPerFrame.iteritems():
            # predict random forests
            if self._countClassifier is not None:
                objectCountProbabilities = self._countClassifier.predictProbabilities(
                    features=None, featureDict=features)

            if self._divisionClassifier is not None and frame + 1 < self.timeRange[
                    1]:
                divisionProbabilities = self._divisionClassifier.predictProbabilities(
                    features=None, featureDict=features)

            # create traxels for all objects
            for objectId in range(1, features.values()[0].shape[0]):
                # print("Frame {} Object {}".format(frame, objectId))
                pixelSize = features['Count'][objectId]
                if pixelSize == 0 or (self._options.sizeFilter is not None \
                        and (pixelSize < self._options.sizeFilter[0] \
                                     or pixelSize > self._options.sizeFilter[1])):
                    continue

                # create traxel
                if usePgmlink:
                    traxel = pgmlink.Traxel()
                else:
                    traxel = Traxel()
                traxel.Id = objectId
                traxel.Timestep = frame

                # add raw features
                for key, val in features.iteritems():
                    if key == 'id':
                        traxel.idInSegmentation = val[objectId]
                    elif key == 'filename':
                        traxel.segmentationFilename = val[objectId]
                    else:
                        try:
                            if isinstance(
                                    val,
                                    list):  # polygon feature returns a list!
                                featureValues = val[objectId]
                            else:
                                featureValues = val[objectId, ...]
                        except:
                            getLogger().error(
                                "Could not get feature values of {} for key {} from matrix with shape {}"
                                .format(objectId, key, val.shape))
                            raise AssertionError()
                        try:
                            self._setTraxelFeatureArray(
                                traxel, featureValues, key)
                            if key == 'RegionCenter':
                                self._setTraxelFeatureArray(
                                    traxel, featureValues, 'com')
                        except:
                            getLogger().error(
                                "Could not add feature array {} for {}".format(
                                    featureValues, key))
                            raise AssertionError()

                # add random forest predictions
                if self._countClassifier is not None:
                    self._setTraxelFeatureArray(
                        traxel, objectCountProbabilities[objectId, :],
                        self.detectionProbabilityFeatureName)

                if self._divisionClassifier is not None and frame + 1 < self.timeRange[
                        1]:
                    self._setTraxelFeatureArray(
                        traxel, divisionProbabilities[objectId, :],
                        self.divisionProbabilityFeatureName)

                # set other parameters
                traxel.set_x_scale(self.x_scale)
                traxel.set_y_scale(self.y_scale)
                traxel.set_z_scale(self.z_scale)

                if usePgmlink:
                    # add to pgmlink's traxelstore
                    ts.add(fs, traxel)
                else:
                    self.TraxelsPerFrame.setdefault(frame,
                                                    {})[objectId] = traxel
            progressBar.show()

        if usePgmlink:
            return ts, fs
    def _extractAllFeatures(self, dispyNodeIps=[], turnOffFeatures=[]):
        """
        Extract the features of all frames. 

        If a list of IP addresses is given e.g. as `dispyNodeIps = ["104.197.178.206","104.196.46.138"]`, 
        then the computation will be distributed across these nodes. Otherwise, multiprocessing will
        be used if `self._useMultiprocessing=True`, which it is by default.

        If `dispyNodeIps` is an empty list, then the feature extraction will be parallelized via
        multiprocessing.

        **TODO:** fix division feature computation for distributed mode
        """
        import logging
        # configure progress bar
        numSteps = self.timeRange[1] - self.timeRange[0]
        if self._divisionClassifier is not None:
            numSteps *= 2

        t0 = time.time()

        if (len(dispyNodeIps) == 0):
            # no dispy node IDs given, parallelize object feature computation via processes

            if self._useMultiprocessing:
                # use ProcessPoolExecutor, which instanciates as many processes as there CPU cores by default
                ExecutorType = concurrent.futures.ProcessPoolExecutor
                logging.getLogger('Traxelstore').info(
                    'Parallelizing feature extraction via multiprocessing on all cores!'
                )
            else:
                ExecutorType = DummyExecutor
                logging.getLogger('Traxelstore').info(
                    'Running feature extraction on single core!')

            featuresPerFrame = {}
            progressBar = ProgressBar(stop=numSteps)
            progressBar.show(increase=0)

            with ExecutorType() as executor:
                # 1st pass for region features
                jobs = []
                for frame in range(self.timeRange[0], self.timeRange[1]):
                    jobs.append(
                        executor.submit(computeRegionFeaturesOnCloud, frame,
                                        self._options.rawImageFilename,
                                        self._options.rawImagePath,
                                        self._options.rawImageAxes,
                                        self._options.labelImageFilename,
                                        self._options.labelImagePath,
                                        turnOffFeatures, self._pluginPaths))
                for job in concurrent.futures.as_completed(jobs):
                    progressBar.show()
                    frame, feats = job.result()
                    featuresPerFrame[frame] = feats

                # 2nd pass for division features
                if self._divisionClassifier is not None:
                    jobs = []
                    for frame in range(self.timeRange[0],
                                       self.timeRange[1] - 1):
                        jobs.append(
                            executor.submit(
                                computeDivisionFeaturesOnCloud, frame,
                                featuresPerFrame[frame],
                                featuresPerFrame[frame + 1],
                                self._pluginManager.getImageProvider(),
                                self._options.labelImageFilename,
                                self._options.labelImagePath,
                                self.getNumDimensions(),
                                self._divisionFeatureNames))

                    for job in concurrent.futures.as_completed(jobs):
                        progressBar.show()
                        frame, feats = job.result()
                        featuresPerFrame[frame].update(feats)

            # # serialize features??
            # for frame in range(self.timeRange[0], self.timeRange[1]):
            #     featureSerializer.storeFeaturesForFrame(featuresPerFrame[frame], frame)
        else:

            import logging
            logging.getLogger('Traxelstore').warning(
                'Parallelization with dispy is WORK IN PROGRESS!')
            import random
            import dispy
            cluster = dispy.JobCluster(computeRegionFeaturesOnCloud,
                                       nodes=dispyNodeIps,
                                       loglevel=logging.DEBUG,
                                       depends=[self._pluginManager],
                                       secret="teamtracking")

            jobs = []
            for frame in range(self.timeRange[0], self.timeRange[1]):
                job = cluster.submit(
                    frame,
                    self._options.rawImageFilename,
                    self._options.rawImagePath,
                    self._options.rawImageAxes,
                    self._options.labelImageFilename,
                    self._options.labelImagePath,
                    turnOffFeatures,
                    pluginPaths=['/home/carstenhaubold/embryonic/plugins'])
                job.id = frame
                jobs.append(job)

            for job in jobs:
                job()  # wait for job to finish
                print job.exception
                print job.stdout
                print job.stderr
                print job.id

            logging.getLogger('Traxelstore').warning(
                'Using dispy we cannot compute division features yet!')
            # # 2nd pass for division features
            # if self._divisionClassifier is not None:
            #     for frame in range(self.timeRange[0], self.timeRange[1]):
            #         progressBar.show()
            #         featuresPerFrame[frame].update(self._extractDivisionFeaturesForFrame(frame, featuresPerFrame)[1])

        t1 = time.time()
        getLogger().info("Feature computation took {} secs".format(t1 - t0))

        return featuresPerFrame
    def _extractAllFeatures(self, dispyNodeIps=[], turnOffFeatures=[]):
        """
        Extract the features of all frames of all segmentation hypotheses. 
        Feature extraction will be parallelized via multiprocessing.

        WARNING: distributed computation via Dispy is not supported here, so dispyNodeIps must be an empty list!
        """

        # configure progress bar
        numSteps = (self.timeRange[1] - self.timeRange[0]) * len(
            self._labelImageFilenames)
        if self._divisionClassifier is not None:
            numSteps *= 2

        t0 = time.time()

        if self._useMultiprocessing:
            # use ProcessPoolExecutor, which instanciates as many processes as there CPU cores by default
            ExecutorType = concurrent.futures.ProcessPoolExecutor
            logging.getLogger('Traxelstore').info(
                'Parallelizing feature extraction via multiprocessing on all cores!'
            )
        else:
            ExecutorType = DummyExecutor
            logging.getLogger('Traxelstore').info(
                'Running feature extraction on single core!')

        featuresPerFrame = {}
        progressBar = ProgressBar(stop=numSteps)
        progressBar.show(increase=0)

        with ExecutorType() as executor:
            # 1st pass for region features, once per segmentation hypotheses
            for filename, path in zip(self._labelImageFilenames,
                                      self._labelImagePaths):
                jobs = []
                for frame in range(self.timeRange[0], self.timeRange[1]):
                    jobs.append(
                        executor.submit(computeRegionFeaturesOnCloud, frame,
                                        self._options.rawImageFilename,
                                        self._options.rawImagePath,
                                        self._options.rawImageAxes, filename,
                                        path, turnOffFeatures,
                                        self._pluginPaths))
                for job in concurrent.futures.as_completed(jobs):
                    progressBar.show()
                    frame, feats = job.result()
                    self._insertFilenameAndIdToFeatures(feats, filename)
                    if frame not in featuresPerFrame:
                        featuresPerFrame[frame] = feats
                    else:
                        self._mergeFrameFeatures(featuresPerFrame[frame],
                                                 feats)

            # 2nd pass for division features
            # TODO: the division feature manager should also see the child candidates in all segmentation hypotheses
            for filename, path in zip(self._labelImageFilenames,
                                      self._labelImagePaths):
                if self._divisionClassifier is not None:
                    jobs = []
                    for frame in range(self.timeRange[0],
                                       self.timeRange[1] - 1):
                        jobs.append(
                            executor.submit(
                                computeDivisionFeaturesOnCloud, frame,
                                featuresPerFrame[frame],
                                featuresPerFrame[frame + 1],
                                self._pluginManager.getImageProvider(),
                                filename, path, self.getNumDimensions(),
                                self._divisionFeatureNames))

                    for job in concurrent.futures.as_completed(jobs):
                        progressBar.show()
                        frame, feats = job.result()
                        # add division features to the dictionary for the first set, and then merge the new features in
                        if feats.keys()[0] not in featuresPerFrame[frame]:
                            featuresPerFrame[frame].update(feats)
                        else:
                            self._mergeFrameFeatures(featuresPerFrame[frame],
                                                     feats)

        self._storeBackwardMapping(featuresPerFrame)

        t1 = time.time()
        getLogger().info("Feature computation took {} secs".format(t1 - t0))

        return featuresPerFrame
Exemple #12
0
    def insertEnergies(self, maxNumObjects, detectionProbabilityFunc,
                       transitionProbabilityFunc, boundaryCostMultiplierFunc,
                       divisionProbabilityFunc, skipLinksBias):
        '''
        Insert energies for detections, divisions and links into the hypotheses graph, 
        by transforming the probabilities for certain
        events (given by the `*ProbabilityFunc`-functions per traxel) into energies. If the given graph
        contained tracklets (`self.withTracklets is True`), then also the probabilities over all contained traxels will be
        accumulated for those nodes in the graph.

        The energies are stored in the networkx graph under the following attribute names (to match the format for solvers):
        * detection energies: `self._graph.node[n]['features']`
        * division energies: `self._graph.node[n]['divisionFeatures']`
        * appearance energies: `self._graph.node[n]['appearanceFeatures']`
        * disappearance energies: `self._graph.node[n]['disappearanceFeatures']`
        * transition energies: `self._graph.edge[src][dest]['features']`
        * additionally we also store the timestep (range for traxels) per node as `timestep` attribute

        ** Parameters: **

        * `maxNumObjects`: the max number of objects per detections
        * `detectionProbabilityFunc`: should take a traxel and return its detection probabilities
         ([prob0objects, prob1object,...])
        * `transitionProbabilityFunc`: should take two traxels and return this link's probabilities
         ([prob0objectsInTransition, prob1objectsInTransition,...])
        * `boundaryCostMultiplierFunc`: should take a traxel and a boolean that is true if we are seeking for an appearance cost multiplier, 
         false for disappearance, and return a scalar multiplier between 0 and 1 for the
         appearance/disappearance cost that depends on the traxel's distance to the spacial and time boundary
        * `divisionProbabilityFunc`: should take a traxel and return its division probabilities ([probNoDiv, probDiv])
        '''
        numElements = self._graph.number_of_nodes(
        ) + self._graph.number_of_edges()
        progressBar = ProgressBar(stop=numElements)

        # insert detection probabilities for all detections (and some also get a div probability)
        for n in self._graph.nodes_iter():
            if not self.withTracklets:
                # only one traxel, but make it a list so everything below works the same
                traxels = [self._graph.node[n]['traxel']]
            else:
                traxels = self._graph.node[n]['tracklet']

            # accumulate features over all contained traxels
            previousTraxel = None
            detectionFeatures = np.zeros(maxNumObjects + 1)
            for t in traxels:
                detectionFeatures += np.array(
                    negLog(detectionProbabilityFunc(t)))
                if previousTraxel is not None:
                    detectionFeatures += np.array(
                        negLog(transitionProbabilityFunc(previousTraxel, t)))
                previousTraxel = t

            detectionFeatures = listify(list(detectionFeatures))

            # division only if probability is big enough
            divisionFeatures = divisionProbabilityFunc(traxels[-1])
            if divisionFeatures is not None:
                divisionFeatures = listify(negLog(divisionFeatures))

            # appearance/disappearance
            appearanceFeatures = listify(
                [0.0] +
                [boundaryCostMultiplierFunc(traxels[0], True)] * maxNumObjects)
            disappearanceFeatures = listify(
                [0.0] + [boundaryCostMultiplierFunc(traxels[-1], False)] *
                maxNumObjects)

            self._graph.node[n]['features'] = detectionFeatures
            if divisionFeatures is not None:
                self._graph.node[n]['divisionFeatures'] = divisionFeatures
            self._graph.node[n]['appearanceFeatures'] = appearanceFeatures
            self._graph.node[n][
                'disappearanceFeatures'] = disappearanceFeatures
            self._graph.node[n]['timestep'] = [
                traxels[0].Timestep, traxels[-1].Timestep
            ]

            progressBar.show()

        # insert transition probabilities for all links
        for a in self._graph.edges_iter():
            if not self.withTracklets:
                srcTraxel = self._graph.node[self.source(a)]['traxel']
                destTraxel = self._graph.node[self.target(a)]['traxel']
            else:
                srcTraxel = self._graph.node[self.source(a)]['tracklet'][
                    -1]  # src is last of the traxels in source tracklet
                destTraxel = self._graph.node[self.target(a)]['tracklet'][
                    0]  # dest is first of traxels in destination tracklet

            features = listify(
                negLog(transitionProbabilityFunc(srcTraxel, destTraxel)))

            # add feature for additional Frames. Since we do not want these edges to be primarily taken, we add a bias to the edge. Now: hard coded, future: parameter
            frame_gap = destTraxel.Timestep - srcTraxel.Timestep

            # 1. method
            if frame_gap > 1:
                features[1][0] = features[1][0] + skipLinksBias * frame_gap

            # # 2. method
            # # introduce a new energies like: [[6], [15]] -> [[6, 23], [15, 23]] for first links and
            # # [[6], [15]] -> [[23, 6], [23, 15]] for second links, and so on for 3rd order links
            # # !!! this will introduce a new weight in the weight.json file. For the 2nd link, comes in 2nd row and so on.
            # # drawback: did not manage to adjust parameter to get sensible results.
            # for feat in features:
            #     for i in range(frame_gap):
            #         feat.append(23)
            #     if frame_gap > 1:
            #         feat[frame_gap-1], feat[0] = feat[0], feat[frame_gap-1]

            self._graph.edge[a[0]][a[1]]['src'] = self._graph.node[a[0]]['id']
            self._graph.edge[a[0]][a[1]]['dest'] = self._graph.node[a[1]]['id']
            self._graph.edge[a[0]][a[1]]['features'] = features

            progressBar.show()
Exemple #13
0
    def buildFromProbabilityGenerator(self,
                                      probabilityGenerator,
                                      maxNeighborDist=200,
                                      numNearestNeighbors=1,
                                      forwardBackwardCheck=True,
                                      withDivisions=True,
                                      divisionThreshold=0.1,
                                      skipLinks=1):
        """
        Takes a python probabilityGenerator containing traxel features and finds probable links between frames.
        Builds a kdTree with the 'numNearestneighbors' for each frame and adds the nodes. In the same iteration, it adds
        a number of 'skipLinks' between the nodes separated by 'skipLinks' frames.
        """
        assert (probabilityGenerator is not None)
        assert (len(probabilityGenerator.TraxelsPerFrame) > 0)
        assert (skipLinks > 0)

        def checkNodeWhileAddingLinks(frame, obj):
            if (frame, obj) not in self._graph:
                getLogger().warning(
                    "Adding node ({}, {}) when setting up links".format(
                        frame, obj))

        kdTreeFrames = [None] * (skipLinks + 1)
        # len(probabilityGenerator.TraxelsPerFrame.keys()) is NOT an indicator for the total number of frames,
        # because an empty frame does not create a key in the dictionary. E.g. for one frame in the middle of the
        # dataset, we won't access the last one.
        # Idea: take the max key in the dict. Remember, frame numbering starts with 0.
        frameMax = max(probabilityGenerator.TraxelsPerFrame.keys())
        frameMin = min(probabilityGenerator.TraxelsPerFrame.keys())
        numFrames = frameMax - frameMin + 1
        progressBar = ProgressBar(stop=numFrames * skipLinks)
        progressBar.show(0)

        for frame in range(numFrames):
            if frame > 0:
                del kdTreeFrames[0]  # this is the current frame
                if frame + skipLinks < numFrames and frameMin + frame + skipLinks in probabilityGenerator.TraxelsPerFrame.keys(
                ):
                    kdTreeFrames.append(
                        self._buildFrameKdTree(
                            probabilityGenerator.TraxelsPerFrame[frameMin +
                                                                 frame +
                                                                 skipLinks]))
                    self._addNodesForFrame(
                        frameMin + frame + skipLinks,
                        probabilityGenerator.TraxelsPerFrame[frameMin + frame +
                                                             skipLinks])
            else:
                for i in range(0, skipLinks + 1):
                    if frameMin + frame + i in probabilityGenerator.TraxelsPerFrame.keys(
                    ):  # empty frame
                        kdTreeFrames[i] = self._buildFrameKdTree(
                            probabilityGenerator.TraxelsPerFrame[frameMin +
                                                                 frame + i])
                        self._addNodesForFrame(
                            frameMin + frame + i,
                            probabilityGenerator.TraxelsPerFrame[frameMin +
                                                                 frame + i])

            # find forward links
            if frameMin + frame in probabilityGenerator.TraxelsPerFrame.keys(
            ):  # 'frame' could be empty
                for obj, traxel in probabilityGenerator.TraxelsPerFrame[
                        frameMin + frame].iteritems():
                    divisionPreservingNumNearestNeighbors = numNearestNeighbors
                    if divisionPreservingNumNearestNeighbors < 2 \
                            and withDivisions \
                            and self._traxelMightDivide(traxel, divisionThreshold):
                        divisionPreservingNumNearestNeighbors = 2
                    for i in range(1, skipLinks + 1):
                        if frame + i < numFrames and frameMin + frame + i in probabilityGenerator.TraxelsPerFrame.keys(
                        ):
                            neighbors = (self._findNearestNeighbors(
                                kdTreeFrames[i], traxel,
                                divisionPreservingNumNearestNeighbors,
                                maxNeighborDist))
                            # type(neighbors) is list
                            for n in neighbors:
                                checkNodeWhileAddingLinks(
                                    frameMin + frame, obj)
                                checkNodeWhileAddingLinks(
                                    frameMin + frame + i, n)
                                self._graph.add_edge((frameMin + frame, obj),
                                                     (frameMin + frame + i, n))
                                self._graph.edge[frameMin + frame, obj][
                                    frameMin + frame + i,
                                    n]['src'] = self._graph.node[(frameMin +
                                                                  frame,
                                                                  obj)]['id']
                                self._graph.edge[frameMin + frame, obj][
                                    frameMin + frame + i,
                                    n]['dest'] = self._graph.node[(frameMin +
                                                                   frame + i,
                                                                   n)]['id']

            # find backward links
            if forwardBackwardCheck:
                for i in range(1, skipLinks + 1):
                    if frame + i < numFrames:
                        if frameMin + frame + i in probabilityGenerator.TraxelsPerFrame.keys(
                        ):  # empty frame
                            for obj, traxel in probabilityGenerator.TraxelsPerFrame[
                                    frameMin + frame + i].iteritems():
                                if kdTreeFrames[0] is not None:
                                    neighbors = (self._findNearestNeighbors(
                                        kdTreeFrames[0], traxel,
                                        numNearestNeighbors, maxNeighborDist))
                                    for n in neighbors:
                                        checkNodeWhileAddingLinks(
                                            frameMin + frame, n)
                                        checkNodeWhileAddingLinks(
                                            frameMin + frame + i, obj)
                                        self._graph.add_edge(
                                            (frameMin + frame, n),
                                            (frameMin + frame + i, obj))
                                        self._graph.edge[frameMin + frame, n][
                                            frameMin + frame + i,
                                            obj]['src'] = self._graph.node[(
                                                frameMin + frame, n)]['id']
                                        self._graph.edge[frameMin + frame, n][
                                            frameMin + frame + i,
                                            obj]['dest'] = self._graph.node[(
                                                frameMin + frame + i,
                                                obj)]['id']
                    progressBar.show()
        progressBar.show()
            if prev is not None:
                links.append((prev, timestepIdTuple))
            prev = timestepIdTuple

    # group by timestep
    # timesteps = [t for t in traxelIdPerTimestepToUniqueIdMap.keys()]
    # there might be empty frames. We want them as output too.
    timesteps = [str(t).decode("utf-8") for t in range(int(min(traxelIdPerTimestepToUniqueIdMap.keys())) , int(max(traxelIdPerTimestepToUniqueIdMap.keys()))+1 )]
    linksPerTimestep = dict([(t, [(a[1], b[1]) for a, b in links if b[0] == int(t)]) for t in timesteps])
    assert(len(linksPerTimestep['0']) == 0)

    # create output array
    resultVolume = np.zeros((len(timesteps),) + shape, dtype='uint32')
    print("resulting volume shape: {}".format(resultVolume.shape))
    progressBar = ProgressBar(stop=len(timesteps))
    progressBar.show(0)

    # iterate over timesteps and label tracks from front to back in a distinct color
    nextUnusedColor = 1
    lastFrameColorMap = {}
    lastFrameLabelImage = getLabelImageForFrame(args.labelImageFilename, args.labelImagePath, 0, shape)
    for t in range(1,len(timesteps)):
        progressBar.show()
        thisFrameColorMap = {}
        thisFrameLabelImage = getLabelImageForFrame(args.labelImageFilename, args.labelImagePath, t, shape)
        for a, b in linksPerTimestep[str(t)]:
            # propagate color if possible, otherwise assign a new one
            if a in lastFrameColorMap:
                thisFrameColorMap[b] = lastFrameColorMap[a]
            else:
                thisFrameColorMap[b] = nextUnusedColor
def convertLegacyHypothesesGraphToJsonGraph(hypothesesGraph,
                                            nodeIterator,
                                            arcIterator,
                                            withTracklets,
                                            maxNumObjects,
                                            numElements,
                                            traxelMap,
                                            detectionProbabilityFunc,
                                            transitionProbabilityFunc,
                                            boundaryCostMultiplierFunc,
                                            divisionProbabilityFunc):
    '''
    Build a json representation of this hypotheses graph, by transforming the probabilities for certain
    events (given by the `*ProbabilityFunc`-functions per traxel) into energies. If the given graph
    contained tracklets (`withTracklets`), then also the probabilities over all contained traxels will be
    accumulated for those nodes in the graph.

    The `hypothesesGraph` as well as `nodeIterator` and `arcIterator` are needed as parameters to
    support the legacy pgmlink-style hypotheses graph as well.

    ** Parameters: **

    * `hypothesesGraph`: graph whose nodes and edges we are about to traverse.
    * `nodeIterator`: node iterator
    * `arcIterator`: arc iterator
    * `withTracklets`: whether tracklets are used
    * `maxNumObjects`: the max number of objects per detections
    * `numElements`: number of nodes + number of edges (for progress bar)
    * `traxelMap`: mapping from graph-node to list of traxels (in a tracklet)
    * `detectionProbabilityFunc`: should take a traxel and return its detection probabilities
     ([prob0objects, prob1object,...])
    * `transitionProbabilityFunc`: should take two traxels and return this link's probabilities
     ([prob0objectsInTransition, prob1objectsInTransition,...])
    * `boundaryCostMultiplierFunc`: should take a traxel and a boolean that is true if we are seeking for an appearance cost multiplier, 
      false for disappearance, and return a scalar multiplier between 0 and 1 for the
      appearance/disappearance cost that depends on the traxel's distance to the spacial and time boundary
    * `divisionProbabilityFunc`: should take a traxel and return its division probabilities
     ([probNoDiv, probDiv])
    '''

    getLogger().info("Creating JSON graph from legacy hypotheses graph")
    progressBar = ProgressBar(stop=numElements)
    trackingGraph = hytra.core.jsongraph.JsonTrackingGraph()

    # add all detections to JSON
    for n in nodeIterator:
        if not withTracklets:
            # only one traxel, but make it a list so everything below works the same
            traxels = [traxelMap[n]]
        else:
            traxels = traxelMap[n]

        # accumulate features over all contained traxels
        previousTraxel = None
        detectionFeatures = np.zeros(maxNumObjects + 1)
        for t in traxels:
            detectionFeatures += np.array(negLog(detectionProbabilityFunc(t)))
            if previousTraxel is not None:
                detectionFeatures += np.array(negLog(transitionProbabilityFunc(previousTraxel, t)))
            previousTraxel = t

        detectionFeatures = listify(list(detectionFeatures))

        # division only if probability is big enough
        divisionFeatures = divisionProbabilityFunc(traxels[-1])
        if divisionFeatures is not None:
            divisionFeatures = listify(negLog(divisionFeatures))

        # appearance/disappearance
        appearanceFeatures = listify([0.0] + [boundaryCostMultiplierFunc(traxels[0], True)] * maxNumObjects)
        disappearanceFeatures = listify([0.0] + [boundaryCostMultiplierFunc(traxels[-1], False)] * maxNumObjects)

        trackingGraph.addDetectionHypothesesFromTracklet(traxels,
                                                         detectionFeatures,
                                                         divisionFeatures,
                                                         appearanceFeatures,
                                                         disappearanceFeatures,
                                                         timestep=[traxels[0].Timestep, traxels[-1].Timestep])
        progressBar.show()

    # add all links
    for a in arcIterator:
        if not withTracklets:
            srcTraxel = traxelMap[hypothesesGraph.source(a)]
            destTraxel = traxelMap[hypothesesGraph.target(a)]
        else:
            srcTraxel = traxelMap[hypothesesGraph.source(a)][-1]  # src is last of the traxels in source tracklet
            destTraxel = traxelMap[hypothesesGraph.target(a)][0]  # dest is first of traxels in destination tracklet
        src = trackingGraph.traxelIdPerTimestepToUniqueIdMap[str(srcTraxel.Timestep)][str(srcTraxel.Id)]
        dest = trackingGraph.traxelIdPerTimestepToUniqueIdMap[str(destTraxel.Timestep)][str(destTraxel.Id)]

        features = listify(negLog(transitionProbabilityFunc(srcTraxel, destTraxel)))
        trackingGraph.addLinkingHypotheses(src, dest, features)
        progressBar.show()

    return trackingGraph
Exemple #16
0
    def buildFromProbabilityGenerator(self,
                                      probabilityGenerator,
                                      maxNeighborDist=200,
                                      numNearestNeighbors=1,
                                      forwardBackwardCheck=True,
                                      withDivisions=True,
                                      divisionThreshold=0.1):
        """
        Takes a python traxelstore containing traxel features and finds probable links between frames.
        """
        assert (probabilityGenerator is not None)
        assert (len(probabilityGenerator.TraxelsPerFrame) > 0)

        def checkNodeWhileAddingLinks(frame, obj):
            if (frame, obj) not in self._graph:
                getLogger().warning(
                    "Adding node ({}, {}) when setting up links".format(
                        frame, obj))

        kdTreeNextFrame = None
        numFrames = len(probabilityGenerator.TraxelsPerFrame.keys())
        progressBar = ProgressBar(stop=numFrames)
        progressBar.show(0)
        for frame in range(numFrames - 1):
            if frame > 0:
                kdTreeThisFrame = kdTreeNextFrame
            else:
                kdTreeThisFrame = self._buildFrameKdTree(
                    probabilityGenerator.TraxelsPerFrame[frame])
                self._addNodesForFrame(
                    frame, probabilityGenerator.TraxelsPerFrame[frame])

            kdTreeNextFrame = self._buildFrameKdTree(
                probabilityGenerator.TraxelsPerFrame[frame + 1])
            self._addNodesForFrame(
                frame + 1, probabilityGenerator.TraxelsPerFrame[frame + 1])

            # find forward links
            for obj, traxel in probabilityGenerator.TraxelsPerFrame[
                    frame].iteritems():
                divisionPreservingNumNearestNeighbors = numNearestNeighbors
                if divisionPreservingNumNearestNeighbors < 2 \
                        and withDivisions \
                        and self._traxelMightDivide(traxel, divisionThreshold):
                    divisionPreservingNumNearestNeighbors = 2
                neighbors = self._findNearestNeighbors(
                    kdTreeNextFrame, traxel,
                    divisionPreservingNumNearestNeighbors, maxNeighborDist)
                for n in neighbors:
                    checkNodeWhileAddingLinks(frame, obj)
                    checkNodeWhileAddingLinks(frame + 1, n)
                    self._graph.add_edge((frame, obj), (frame + 1, n))
                    self._graph.edge[frame, obj][frame + 1,
                                                 n]['src'] = self._graph.node[(
                                                     frame, obj)]['id']
                    self._graph.edge[frame,
                                     obj][frame + 1,
                                          n]['dest'] = self._graph.node[(
                                              frame + 1, n)]['id']

            # find backward links
            if forwardBackwardCheck:
                for obj, traxel in probabilityGenerator.TraxelsPerFrame[
                        frame + 1].iteritems():
                    neighbors = self._findNearestNeighbors(
                        kdTreeThisFrame, traxel, numNearestNeighbors,
                        maxNeighborDist)
                    for n in neighbors:
                        checkNodeWhileAddingLinks(frame, n)
                        checkNodeWhileAddingLinks(frame + 1, obj)
                        self._graph.add_edge((frame, n), (frame + 1, obj))
                        self._graph.edge[frame,
                                         n][frame + 1,
                                            obj]['src'] = self._graph.node[(
                                                frame, n)]['id']
                        self._graph.edge[frame,
                                         n][frame + 1,
                                            obj]['dest'] = self._graph.node[(
                                                frame + 1, obj)]['id']
            progressBar.show()
        progressBar.show()
Exemple #17
0
    def insertEnergies(self, maxNumObjects, detectionProbabilityFunc,
                       transitionProbabilityFunc, boundaryCostMultiplierFunc,
                       divisionProbabilityFunc):
        '''
        Insert energies for detections, divisions and links into the hypotheses graph, 
        by transforming the probabilities for certain
        events (given by the `*ProbabilityFunc`-functions per traxel) into energies. If the given graph
        contained tracklets (`self.withTracklets is True`), then also the probabilities over all contained traxels will be
        accumulated for those nodes in the graph.

        The energies are stored in the networkx graph under the following attribute names (to match the format for solvers):
        * detection energies: `self._graph.node[n]['features']`
        * division energies: `self._graph.node[n]['divisionFeatures']`
        * appearance energies: `self._graph.node[n]['appearanceFeatures']`
        * disappearance energies: `self._graph.node[n]['disappearanceFeatures']`
        * transition energies: `self._graph.edge[src][dest]['features']`
        * additionally we also store the timestep (range for traxels) per node as `timestep` attribute

        ** Parameters: **

        * `maxNumObjects`: the max number of objects per detections
        * `detectionProbabilityFunc`: should take a traxel and return its detection probabilities
         ([prob0objects, prob1object,...])
        * `transitionProbabilityFunc`: should take two traxels and return this link's probabilities
         ([prob0objectsInTransition, prob1objectsInTransition,...])
        * `boundaryCostMultiplierFunc`: should take a traxel and return a scalar multiplier between 0 and 1 for the
         appearance/disappearance cost that depends on the traxel's distance to the spacial and time boundary
        * `divisionProbabilityFunc`: should take a traxel and return its division probabilities ([probNoDiv, probDiv])
        '''
        numElements = self._graph.number_of_nodes(
        ) + self._graph.number_of_edges()
        progressBar = ProgressBar(stop=numElements)

        # insert detection probabilities for all detections (and some also get a div probability)
        for n in self._graph.nodes_iter():
            if not self.withTracklets:
                # only one traxel, but make it a list so everything below works the same
                traxels = [self._graph.node[n]['traxel']]
            else:
                traxels = self._graph.node[n]['tracklet']

            # accumulate features over all contained traxels
            previousTraxel = None
            detectionFeatures = np.zeros(maxNumObjects + 1)
            for t in traxels:
                detectionFeatures += np.array(
                    negLog(detectionProbabilityFunc(t)))
                if previousTraxel is not None:
                    detectionFeatures += np.array(
                        negLog(transitionProbabilityFunc(previousTraxel, t)))
                previousTraxel = t

            detectionFeatures = listify(list(detectionFeatures))

            # division only if probability is big enough
            divisionFeatures = divisionProbabilityFunc(traxels[-1])
            if divisionFeatures is not None:
                divisionFeatures = listify(negLog(divisionFeatures))

            # appearance/disappearance
            appearanceFeatures = listify(
                [0.0] +
                [boundaryCostMultiplierFunc(traxels[0])] * maxNumObjects)
            disappearanceFeatures = listify(
                [0.0] +
                [boundaryCostMultiplierFunc(traxels[-1])] * maxNumObjects)

            self._graph.node[n]['features'] = detectionFeatures
            if divisionFeatures is not None:
                self._graph.node[n]['divisionFeatures'] = divisionFeatures
            self._graph.node[n]['appearanceFeatures'] = appearanceFeatures
            self._graph.node[n][
                'disappearanceFeatures'] = disappearanceFeatures
            self._graph.node[n]['timestep'] = [
                traxels[0].Timestep, traxels[-1].Timestep
            ]

            progressBar.show()

        # insert transition probabilities for all links
        for a in self._graph.edges_iter():
            if not self.withTracklets:
                srcTraxel = self._graph.node[self.source(a)]['traxel']
                destTraxel = self._graph.node[self.target(a)]['traxel']
            else:
                srcTraxel = self._graph.node[self.source(a)]['tracklet'][
                    -1]  # src is last of the traxels in source tracklet
                destTraxel = self._graph.node[self.target(a)]['tracklet'][
                    0]  # dest is first of traxels in destination tracklet

            features = listify(
                negLog(transitionProbabilityFunc(srcTraxel, destTraxel)))

            self._graph.edge[a[0]][a[1]]['src'] = self._graph.node[a[0]]['id']
            self._graph.edge[a[0]][a[1]]['dest'] = self._graph.node[a[1]]['id']
            self._graph.edge[a[0]][a[1]]['features'] = features

            progressBar.show()
    def findGroundTruthJaccardScoreAndMapping(self, 
                                              hypothesesGraph,
                                              groundTruthSegmentationFilename=None,
                                              groundTruthSegmentationPath=None,
                                              groundTruthTextFilename=None,
                                              groundTruthMinJaccardScore=0.5):
        """
        Find the overlap between all objects in the given segmentations with the groundtruth,
        and store that jaccard score in each traxel's features.

        **Returns** a solution dictionary in our JSON format, which fits to the given hypotheses graph.

        TODO: simplify this method! 
        Currently there are 4 different sets of IDs to reference nodes:
        * the ground truth trackId
        * a corresponding globalId (which is unique within a frame across different segmentation hypotheses)
        * an objectId (which equals the labelId within one segmentation hypotheses)
        * a globally unique UUID as used in the JSON files

        The nodes in the hypotheses graph are indexed by (frame, globalId), the resulting dict must use UUIDs.
        """

        getLogger().info("Computing Jaccard scores w.r.t. GroundTruth ...")
        t0 = time.time()

        # find exclusion constraints
        if self._useMultiprocessing:
            # use ProcessPoolExecutor, which instanciates as many processes as there CPU cores by default
            ExecutorType = concurrent.futures.ProcessPoolExecutor
            getLogger().info('Parallelizing via multiprocessing on all cores!')
        else:
            ExecutorType = DummyExecutor
            getLogger().info('Running on single core!')

        jobs = []
        progressBar = ProgressBar(stop=self.timeRange[1] - self.timeRange[0])
        progressBar.show(increase=0)
        gtFrameIdToGlobalIdsWithScoresMap = {}

        with ExecutorType() as executor:
            for frame in range(self.timeRange[0], self.timeRange[1]):
                jobs.append(executor.submit(computeJaccardScoresOnCloud,
                                            frame,
                                            self._labelImageFilenames,
                                            self._labelImagePaths,
                                            self._labelImageFrameIdToGlobalId,
                                            groundTruthSegmentationFilename,
                                            groundTruthSegmentationPath,
                                            groundTruthMinJaccardScore,
                                            self._pluginPaths
                ))
            for job in concurrent.futures.as_completed(jobs):
                progressBar.show()
                frame, scores, frameGtToGlobalIdMap = job.result()
                for objectId, individualScores in scores.iteritems():
                    self.TraxelsPerFrame[frame][objectId].Features['JaccardScores'] = individualScores
                gtFrameIdToGlobalIdsWithScoresMap.update(frameGtToGlobalIdMap)
        
        t1 = time.time()
        getLogger().info("Finding jaccard scores took {} secs".format(t1 - t0))

        # create JSON result by mapping it to the hypotheses graph
        traxelIdPerTimestepToUniqueIdMap, _ = hypothesesGraph.getMappingsBetweenUUIDsAndTraxels()
        detectionResults = []
        for gtFrameAndId, globalIdsAndScores in gtFrameIdToGlobalIdsWithScoresMap.iteritems():
            detectionResults.append({"id": traxelIdPerTimestepToUniqueIdMap[str(gtFrameAndId[0])][str(globalIdsAndScores[-1][0])], "value":1})
        
        # read tracks from textfile
        with open(groundTruthTextFilename, 'r') as tracksFile:
            lines = tracksFile.readlines()
        tracks = [[int(x) for x in line.strip().split(" ")] for line in lines]

        # order them by track start time and process track by track
        tracks.sort(key=lambda x: x[1])

        linkingResults = []
        descendants = {}
        missingLinks = 0

        def checkLinkExists(gtSrc, gtDest):
            # first check that both GT nodes have been mapped to a hypotheses
            if gtSrc in gtFrameIdToGlobalIdsWithScoresMap:
                src = (gtSrc[0], gtFrameIdToGlobalIdsWithScoresMap[gtSrc][-1][0])
            else:
                getLogger().warning("GT link's source node {} has no match in the segmentation hypotheses".format(gtSrc))
                return False

            if gtDest in gtFrameIdToGlobalIdsWithScoresMap:
                dest = (gtDest[0], gtFrameIdToGlobalIdsWithScoresMap[gtDest][-1][0])
            else:
                getLogger().warning("GT link's destination node {} has no match in the segmentation hypotheses".format(gtDest))
                return False
            
            # then map them to the hypotheses graph
            if not hypothesesGraph.hasNode(src):
                getLogger().warning("Source node of GT link {} was not found in graph".format((gtSrc, gtDest)))
                return False
            if not hypothesesGraph.hasNode(dest):
                getLogger().warning("Destination node of GTlink {} was not found in graph".format((gtSrc, gtDest)))
                return False
            if not hypothesesGraph.hasEdge(src, dest):
                getLogger().warning("Nodes are present, but GT link {} was not found in graph".format((gtSrc, gtDest)))
                return False
            return True

        def gtIdPerFrameToUuid(frame, gtId):
            return traxelIdPerTimestepToUniqueIdMap[str(frame)][str(gtFrameIdToGlobalIdsWithScoresMap[(frame, gtId)][-1][0])]

        # add links of all tracks
        for track in tracks:
            trackId, startFrame, endFrame, parent = track

            if parent != 0:
                descendants.setdefault(parent, []).append((startFrame, trackId))

            # add transitions along track
            for frame in range(startFrame, min(endFrame, self.timeRange[1])):
                if not checkLinkExists((frame, trackId), (frame + 1, trackId)):
                    getLogger().warning("Ignoring GT link from {} to {}".format((frame, trackId), (frame + 1, trackId)))
                    missingLinks += 1
                    continue

                link = {
                    "src":gtIdPerFrameToUuid(frame, trackId),
                    "dest":gtIdPerFrameToUuid(frame + 1, trackId),
                    "value":1
                }
                linkingResults.append(link)

        # construct divisions
        divisionResults = []
        for parent, childrenFrameIds in descendants.iteritems():
            if len(childrenFrameIds) != 2:
                getLogger().warning("Found track {} that had descendants, but not exactly two. Ignoring it".format(parent))
                continue
            if childrenFrameIds[0][0] != childrenFrameIds[1][0]:
                getLogger().warning("Track {} divided, but children are not in same timeframe. Ignoring it".format(parent))
                continue

            # all good, found a proper division. Make sure the mother-daughter-links are available in the hypotheses graph 
            foundAllLinks = True
            divisionFrame = childrenFrameIds[0][0] - 1
            if divisionFrame >= self.timeRange[1]:
                continue
            for i in [0, 1]:
                foundAllLinks = foundAllLinks and checkLinkExists((divisionFrame, parent), (childrenFrameIds[i][0], childrenFrameIds[i][1]))

            if foundAllLinks:
                divisionResults.append({"id": gtIdPerFrameToUuid(divisionFrame, parent), "value": 1})
                for i in [0, 1]:
                    if not checkLinkExists((divisionFrame, parent), (childrenFrameIds[i][0], childrenFrameIds[i][1])):
                        getLogger().warning("Ignoring GT link from {} to {}".format((frame, trackId), (frame + 1, trackId)))
                        continue
                    link = {
                        "src":gtIdPerFrameToUuid(divisionFrame, parent),
                        "dest":gtIdPerFrameToUuid(childrenFrameIds[i][0], childrenFrameIds[i][1]),
                        "value":1
                    }
                    linkingResults.append(link)
            else:
                getLogger().warning("Division of {} ignored, could not find the links to the children, or not all participating GT nodes found a mapping".format(parent))
                missingLinks += 1

        getLogger().info("Ground Truth mapping could not find an equivalent for {} links, {} links projected.".format(missingLinks, len(linkingResults)))

        result = {}
        result['detectionResults'] = detectionResults
        result['linkingResults'] = linkingResults
        result['divisionResults'] = divisionResults
        return result
    def findGroundTruthJaccardScoreAndMapping(
            self,
            hypothesesGraph,
            groundTruthSegmentationFilename=None,
            groundTruthSegmentationPath=None,
            groundTruthTextFilename=None,
            groundTruthMinJaccardScore=0.5):
        """
        Find the overlap between all objects in the given segmentations with the groundtruth,
        and store that jaccard score in each traxel's features.

        **Returns** a solution dictionary in our JSON format, which fits to the given hypotheses graph.

        TODO: simplify this method! 
        Currently there are 4 different sets of IDs to reference nodes:
        * the ground truth trackId
        * a corresponding globalId (which is unique within a frame across different segmentation hypotheses)
        * an objectId (which equals the labelId within one segmentation hypotheses)
        * a globally unique UUID as used in the JSON files

        The nodes in the hypotheses graph are indexed by (frame, globalId), the resulting dict must use UUIDs.
        """

        getLogger().info("Computing Jaccard scores w.r.t. GroundTruth ...")
        t0 = time.time()

        # find exclusion constraints
        if self._useMultiprocessing:
            # use ProcessPoolExecutor, which instanciates as many processes as there CPU cores by default
            ExecutorType = concurrent.futures.ProcessPoolExecutor
            getLogger().info('Parallelizing via multiprocessing on all cores!')
        else:
            ExecutorType = DummyExecutor
            getLogger().info('Running on single core!')

        jobs = []
        progressBar = ProgressBar(stop=self.timeRange[1] - self.timeRange[0])
        progressBar.show(increase=0)
        gtFrameIdToGlobalIdsWithScoresMap = {}

        with ExecutorType() as executor:
            for frame in range(self.timeRange[0], self.timeRange[1]):
                jobs.append(
                    executor.submit(computeJaccardScoresOnCloud, frame,
                                    self._labelImageFilenames,
                                    self._labelImagePaths,
                                    self._labelImageFrameIdToGlobalId,
                                    groundTruthSegmentationFilename,
                                    groundTruthSegmentationPath,
                                    groundTruthMinJaccardScore,
                                    self._pluginPaths))
            for job in concurrent.futures.as_completed(jobs):
                progressBar.show()
                frame, scores, frameGtToGlobalIdMap = job.result()
                for objectId, individualScores in scores.iteritems():
                    self.TraxelsPerFrame[frame][objectId].Features[
                        'JaccardScores'] = individualScores
                gtFrameIdToGlobalIdsWithScoresMap.update(frameGtToGlobalIdMap)

        t1 = time.time()
        getLogger().info("Finding jaccard scores took {} secs".format(t1 - t0))

        # create JSON result by mapping it to the hypotheses graph
        traxelIdPerTimestepToUniqueIdMap, _ = hypothesesGraph.getMappingsBetweenUUIDsAndTraxels(
        )
        detectionResults = []
        for gtFrameAndId, globalIdsAndScores in gtFrameIdToGlobalIdsWithScoresMap.iteritems(
        ):
            detectionResults.append({
                "id":
                traxelIdPerTimestepToUniqueIdMap[str(gtFrameAndId[0])][str(
                    globalIdsAndScores[-1][0])],
                "value":
                1
            })

        # read tracks from textfile
        with open(groundTruthTextFilename, 'r') as tracksFile:
            lines = tracksFile.readlines()
        tracks = [[int(x) for x in line.strip().split(" ")] for line in lines]

        # order them by track start time and process track by track
        tracks.sort(key=lambda x: x[1])

        linkingResults = []
        descendants = {}
        missingLinks = 0

        def checkLinkExists(gtSrc, gtDest):
            # first check that both GT nodes have been mapped to a hypotheses
            if gtSrc in gtFrameIdToGlobalIdsWithScoresMap:
                src = (gtSrc[0],
                       gtFrameIdToGlobalIdsWithScoresMap[gtSrc][-1][0])
            else:
                getLogger().warning(
                    "GT link's source node {} has no match in the segmentation hypotheses"
                    .format(gtSrc))
                return False

            if gtDest in gtFrameIdToGlobalIdsWithScoresMap:
                dest = (gtDest[0],
                        gtFrameIdToGlobalIdsWithScoresMap[gtDest][-1][0])
            else:
                getLogger().warning(
                    "GT link's destination node {} has no match in the segmentation hypotheses"
                    .format(gtDest))
                return False

            # then map them to the hypotheses graph
            if not hypothesesGraph.hasNode(src):
                getLogger().warning(
                    "Source node of GT link {} was not found in graph".format(
                        (gtSrc, gtDest)))
                return False
            if not hypothesesGraph.hasNode(dest):
                getLogger().warning(
                    "Destination node of GTlink {} was not found in graph".
                    format((gtSrc, gtDest)))
                return False
            if not hypothesesGraph.hasEdge(src, dest):
                getLogger().warning(
                    "Nodes are present, but GT link {} was not found in graph".
                    format((gtSrc, gtDest)))
                return False
            return True

        def gtIdPerFrameToUuid(frame, gtId):
            return traxelIdPerTimestepToUniqueIdMap[str(frame)][str(
                gtFrameIdToGlobalIdsWithScoresMap[(frame, gtId)][-1][0])]

        # add links of all tracks
        for track in tracks:
            trackId, startFrame, endFrame, parent = track

            if parent != 0:
                descendants.setdefault(parent, []).append(
                    (startFrame, trackId))

            # add transitions along track
            for frame in range(startFrame, min(endFrame, self.timeRange[1])):
                if not checkLinkExists((frame, trackId), (frame + 1, trackId)):
                    getLogger().warning(
                        "Ignoring GT link from {} to {}".format(
                            (frame, trackId), (frame + 1, trackId)))
                    missingLinks += 1
                    continue

                link = {
                    "src": gtIdPerFrameToUuid(frame, trackId),
                    "dest": gtIdPerFrameToUuid(frame + 1, trackId),
                    "value": 1
                }
                linkingResults.append(link)

        # construct divisions
        divisionResults = []
        for parent, childrenFrameIds in descendants.iteritems():
            if len(childrenFrameIds) != 2:
                getLogger().warning(
                    "Found track {} that had descendants, but not exactly two. Ignoring it"
                    .format(parent))
                continue
            if childrenFrameIds[0][0] != childrenFrameIds[1][0]:
                getLogger().warning(
                    "Track {} divided, but children are not in same timeframe. Ignoring it"
                    .format(parent))
                continue

            # all good, found a proper division. Make sure the mother-daughter-links are available in the hypotheses graph
            foundAllLinks = True
            divisionFrame = childrenFrameIds[0][0] - 1
            if divisionFrame >= self.timeRange[1]:
                continue
            for i in [0, 1]:
                foundAllLinks = foundAllLinks and checkLinkExists(
                    (divisionFrame, parent),
                    (childrenFrameIds[i][0], childrenFrameIds[i][1]))

            if foundAllLinks:
                divisionResults.append({
                    "id":
                    gtIdPerFrameToUuid(divisionFrame, parent),
                    "value":
                    1
                })
                for i in [0, 1]:
                    if not checkLinkExists(
                        (divisionFrame, parent),
                        (childrenFrameIds[i][0], childrenFrameIds[i][1])):
                        getLogger().warning(
                            "Ignoring GT link from {} to {}".format(
                                (frame, trackId), (frame + 1, trackId)))
                        continue
                    link = {
                        "src":
                        gtIdPerFrameToUuid(divisionFrame, parent),
                        "dest":
                        gtIdPerFrameToUuid(childrenFrameIds[i][0],
                                           childrenFrameIds[i][1]),
                        "value":
                        1
                    }
                    linkingResults.append(link)
            else:
                getLogger().warning(
                    "Division of {} ignored, could not find the links to the children, or not all participating GT nodes found a mapping"
                    .format(parent))
                missingLinks += 1

        getLogger().info(
            "Ground Truth mapping could not find an equivalent for {} links, {} links projected."
            .format(missingLinks, len(linkingResults)))

        result = {}
        result['detectionResults'] = detectionResults
        result['linkingResults'] = linkingResults
        result['divisionResults'] = divisionResults
        return result
    def _extractAllFeatures(self, dispyNodeIps=[], turnOffFeatures=[]):
        """
        Extract the features of all frames of all segmentation hypotheses. 
        Feature extraction will be parallelized via multiprocessing.

        WARNING: distributed computation via Dispy is not supported here, so dispyNodeIps must be an empty list!
        """

        # configure progress bar
        numSteps = (self.timeRange[1] - self.timeRange[0]) * len(self._labelImageFilenames)
        if self._divisionClassifier is not None:
            numSteps *= 2

        t0 = time.time()

        if self._useMultiprocessing:
            # use ProcessPoolExecutor, which instanciates as many processes as there CPU cores by default
            ExecutorType = concurrent.futures.ProcessPoolExecutor
            logging.getLogger('Traxelstore').info('Parallelizing feature extraction via multiprocessing on all cores!')
        else:
            ExecutorType = DummyExecutor
            logging.getLogger('Traxelstore').info('Running feature extraction on single core!')

        featuresPerFrame = {}
        progressBar = ProgressBar(stop=numSteps)
        progressBar.show(increase=0)

        with ExecutorType() as executor:
            # 1st pass for region features, once per segmentation hypotheses
            for filename, path in zip(self._labelImageFilenames, self._labelImagePaths):
                jobs = []
                for frame in range(self.timeRange[0], self.timeRange[1]):
                    jobs.append(executor.submit(computeRegionFeaturesOnCloud,
                                                frame,
                                                self._options.rawImageFilename, 
                                                self._options.rawImagePath,
                                                self._options.rawImageAxes,
                                                filename,
                                                path,
                                                turnOffFeatures,
                                                self._pluginPaths
                    ))
                for job in concurrent.futures.as_completed(jobs):
                    progressBar.show()
                    frame, feats = job.result()
                    self._insertFilenameAndIdToFeatures(feats, filename)
                    if frame not in featuresPerFrame:
                        featuresPerFrame[frame] = feats
                    else:
                        self._mergeFrameFeatures(featuresPerFrame[frame], feats)

            # 2nd pass for division features
            # TODO: the division feature manager should also see the child candidates in all segmentation hypotheses
            for filename, path in zip(self._labelImageFilenames, self._labelImagePaths):
                if self._divisionClassifier is not None:
                    jobs = []
                    for frame in range(self.timeRange[0], self.timeRange[1] - 1):
                        jobs.append(executor.submit(computeDivisionFeaturesOnCloud,
                                                    frame,
                                                    featuresPerFrame[frame],
                                                    featuresPerFrame[frame + 1],
                                                    self._pluginManager.getImageProvider(),
                                                    filename,
                                                    path,
                                                    self.getNumDimensions(),
                                                    self._divisionFeatureNames
                        ))

                    for job in concurrent.futures.as_completed(jobs):
                        progressBar.show()
                        frame, feats = job.result()
                        # add division features to the dictionary for the first set, and then merge the new features in
                        if feats.keys()[0] not in featuresPerFrame[frame]:
                            featuresPerFrame[frame].update(feats)
                        else:
                            self._mergeFrameFeatures(featuresPerFrame[frame], feats)

        self._storeBackwardMapping(featuresPerFrame)

        t1 = time.time()
        getLogger().info("Feature computation took {} secs".format(t1 - t0))
        
        return featuresPerFrame
Exemple #21
0
    def getPredictedCount(uuid):
        segHyps = model['segmentationHypotheses']
        for i, s in enumerate(segHyps):
            if s['id'] == uuid:
                break
        if i == len(segHyps) and s['id'] != uuid:
            raise InvalidArgumentException

        feats = segHyps[i]['features']
        feats = np.array(feats)
        return np.argmin(feats)

    objectCounts = {}
    print("Extracting GT mergers...")
    progressBar = ProgressBar(stop=num_frames)
    progressBar.show(0)
    duplicates = 0
    # handle all frames by remapping their indices
    for frame in range(0, num_frames):
        # find moves, but only store in temporary list because
        # we don't know the number of cells in that move yet
        moves = get_frame_dataset(frame, "Moves", args)
        for src, dest in moves:
            if src == 0 or dest == 0:
                continue

            assert (str(src)
                    in traxelIdPerTimestepToUniqueIdMap[str(frame - 1)])
            assert (str(dest) in traxelIdPerTimestepToUniqueIdMap[str(frame)])
            s = traxelIdPerTimestepToUniqueIdMap[str(frame - 1)][str(src)]
            t = traxelIdPerTimestepToUniqueIdMap[str(frame)][str(dest)]
    def buildFromProbabilityGenerator(self, probabilityGenerator, maxNeighborDist=200, numNearestNeighbors=1,
                                      forwardBackwardCheck=True, withDivisions=True, divisionThreshold=0.1, skipLinks=1):
        """
        Takes a python probabilityGenerator containing traxel features and finds probable links between frames.
        Builds a kdTree with the 'numNearestneighbors' for each frame and adds the nodes. In the same iteration, it adds
        a number of 'skipLinks' between the nodes separated by 'skipLinks' frames.
        """
        assert (probabilityGenerator is not None)
        assert (len(probabilityGenerator.TraxelsPerFrame) > 0)
        assert (skipLinks > 0)

        def checkNodeWhileAddingLinks(frame, obj):
            if (frame, obj) not in self._graph:
                getLogger().warning("Adding node ({}, {}) when setting up links".format(frame, obj))

        kdTreeFrames = [None]*(skipLinks + 1)
        # len(probabilityGenerator.TraxelsPerFrame.keys()) is NOT an indicator for the total number of frames,
        # because an empty frame does not create a key in the dictionary. E.g. for one frame in the middle of the
        # dataset, we won't access the last one.
        # Idea: take the max key in the dict. Remember, frame numbering starts with 0.
        frameMax = max(probabilityGenerator.TraxelsPerFrame.keys())
        frameMin = min(probabilityGenerator.TraxelsPerFrame.keys())
        numFrames = frameMax - frameMin + 1
        progressBar = ProgressBar(stop=numFrames*skipLinks)
        progressBar.show(0)
        
        for frame in range(numFrames):
            if frame > 0:
                del kdTreeFrames[0] # this is the current frame
                if frame + skipLinks < numFrames and frameMin + frame + skipLinks in probabilityGenerator.TraxelsPerFrame.keys():
                    kdTreeFrames.append(self._buildFrameKdTree(probabilityGenerator.TraxelsPerFrame[frameMin + frame + skipLinks]))
                    self._addNodesForFrame(frameMin + frame + skipLinks, probabilityGenerator.TraxelsPerFrame[frameMin + frame + skipLinks])
            else:
                for i in range(0, skipLinks+1):
                    if frameMin + frame + i in probabilityGenerator.TraxelsPerFrame.keys(): # empty frame
                        kdTreeFrames[i] = self._buildFrameKdTree(probabilityGenerator.TraxelsPerFrame[frameMin + frame + i])
                        self._addNodesForFrame(frameMin + frame + i, probabilityGenerator.TraxelsPerFrame[frameMin + frame + i])

            # find forward links
            if frameMin + frame in probabilityGenerator.TraxelsPerFrame.keys(): # 'frame' could be empty
                for obj, traxel in probabilityGenerator.TraxelsPerFrame[frameMin + frame].iteritems():
                    divisionPreservingNumNearestNeighbors = numNearestNeighbors
                    if divisionPreservingNumNearestNeighbors < 2 \
                            and withDivisions \
                            and self._traxelMightDivide(traxel, divisionThreshold):
                        divisionPreservingNumNearestNeighbors = 2
                    for i in range(1, skipLinks+1):
                        if frame + i < numFrames and frameMin + frame + i in probabilityGenerator.TraxelsPerFrame.keys():
                            neighbors = (self._findNearestNeighbors(kdTreeFrames[i],
                                                               traxel,
                                                               divisionPreservingNumNearestNeighbors,
                                                               maxNeighborDist))
                            # type(neighbors) is list
                            for n in neighbors:
                                checkNodeWhileAddingLinks(frameMin + frame, obj)
                                checkNodeWhileAddingLinks(frameMin + frame + i, n)
                                self._graph.add_edge((frameMin + frame, obj), (frameMin + frame + i, n))
                                self._graph.edge[frameMin + frame, obj][frameMin + frame + i, n]['src'] = self._graph.node[(frameMin + frame, obj)]['id']
                                self._graph.edge[frameMin + frame, obj][frameMin + frame + i, n]['dest'] = self._graph.node[(frameMin + frame + i, n)]['id']

            # find backward links
            if forwardBackwardCheck:
                for i in range(1, skipLinks+1):
                    if frame + i < numFrames:
                        if frameMin + frame + i in probabilityGenerator.TraxelsPerFrame.keys(): # empty frame
                            for obj, traxel in probabilityGenerator.TraxelsPerFrame[frameMin + frame + i].iteritems():
                                if kdTreeFrames[0] is not None:
                                    neighbors = (self._findNearestNeighbors(kdTreeFrames[0],
                                                                       traxel,
                                                                       numNearestNeighbors,
                                                                       maxNeighborDist))
                                    for n in neighbors:
                                        checkNodeWhileAddingLinks(frameMin + frame, n)
                                        checkNodeWhileAddingLinks(frameMin + frame + i, obj)
                                        self._graph.add_edge((frameMin + frame, n), (frameMin + frame + i, obj))
                                        self._graph.edge[frameMin + frame, n][frameMin + frame + i, obj]['src'] = self._graph.node[(frameMin + frame, n)]['id']
                                        self._graph.edge[frameMin + frame, n][frameMin + frame + i, obj]['dest'] = self._graph.node[(frameMin + frame + i, obj)]['id']
                    progressBar.show()
        progressBar.show()
    def insertEnergies(self,
                       maxNumObjects,
                       detectionProbabilityFunc,
                       transitionProbabilityFunc,
                       boundaryCostMultiplierFunc,
                       divisionProbabilityFunc,
                       skipLinksBias):
        '''
        Insert energies for detections, divisions and links into the hypotheses graph, 
        by transforming the probabilities for certain
        events (given by the `*ProbabilityFunc`-functions per traxel) into energies. If the given graph
        contained tracklets (`self.withTracklets is True`), then also the probabilities over all contained traxels will be
        accumulated for those nodes in the graph.

        The energies are stored in the networkx graph under the following attribute names (to match the format for solvers):
        * detection energies: `self._graph.node[n]['features']`
        * division energies: `self._graph.node[n]['divisionFeatures']`
        * appearance energies: `self._graph.node[n]['appearanceFeatures']`
        * disappearance energies: `self._graph.node[n]['disappearanceFeatures']`
        * transition energies: `self._graph.edge[src][dest]['features']`
        * additionally we also store the timestep (range for traxels) per node as `timestep` attribute

        ** Parameters: **

        * `maxNumObjects`: the max number of objects per detections
        * `detectionProbabilityFunc`: should take a traxel and return its detection probabilities
         ([prob0objects, prob1object,...])
        * `transitionProbabilityFunc`: should take two traxels and return this link's probabilities
         ([prob0objectsInTransition, prob1objectsInTransition,...])
        * `boundaryCostMultiplierFunc`: should take a traxel and a boolean that is true if we are seeking for an appearance cost multiplier, 
         false for disappearance, and return a scalar multiplier between 0 and 1 for the
         appearance/disappearance cost that depends on the traxel's distance to the spacial and time boundary
        * `divisionProbabilityFunc`: should take a traxel and return its division probabilities ([probNoDiv, probDiv])
        '''
        numElements = self._graph.number_of_nodes() + self._graph.number_of_edges()
        progressBar = ProgressBar(stop=numElements)

        # insert detection probabilities for all detections (and some also get a div probability)
        for n in self._graph.nodes_iter():
            if not self.withTracklets:
                # only one traxel, but make it a list so everything below works the same
                traxels = [self._graph.node[n]['traxel']]
            else:
                traxels = self._graph.node[n]['tracklet']

            # accumulate features over all contained traxels
            previousTraxel = None
            detectionFeatures = np.zeros(maxNumObjects + 1)
            for t in traxels:
                detectionFeatures += np.array(negLog(detectionProbabilityFunc(t)))
                if previousTraxel is not None:
                    detectionFeatures += np.array(negLog(transitionProbabilityFunc(previousTraxel, t)))
                previousTraxel = t

            detectionFeatures = listify(list(detectionFeatures))

            # division only if probability is big enough
            divisionFeatures = divisionProbabilityFunc(traxels[-1])
            if divisionFeatures is not None:
                divisionFeatures = listify(negLog(divisionFeatures))

            # appearance/disappearance
            appearanceFeatures = listify([0.0] + [boundaryCostMultiplierFunc(traxels[0], True)] * maxNumObjects)
            disappearanceFeatures = listify([0.0] + [boundaryCostMultiplierFunc(traxels[-1], False)] * maxNumObjects)

            self._graph.node[n]['features'] = detectionFeatures
            if divisionFeatures is not None:
                self._graph.node[n]['divisionFeatures'] = divisionFeatures
            self._graph.node[n]['appearanceFeatures'] = appearanceFeatures
            self._graph.node[n]['disappearanceFeatures'] = disappearanceFeatures
            self._graph.node[n]['timestep'] = [traxels[0].Timestep, traxels[-1].Timestep]

            progressBar.show()

        # insert transition probabilities for all links
        for a in self._graph.edges_iter():
            if not self.withTracklets:
                srcTraxel = self._graph.node[self.source(a)]['traxel']
                destTraxel = self._graph.node[self.target(a)]['traxel']
            else:
                srcTraxel = self._graph.node[self.source(a)]['tracklet'][-1]  # src is last of the traxels in source tracklet
                destTraxel = self._graph.node[self.target(a)]['tracklet'][0]  # dest is first of traxels in destination tracklet

            features = listify(negLog(transitionProbabilityFunc(srcTraxel, destTraxel)))

            # add feature for additional Frames. Since we do not want these edges to be primarily taken, we add a bias to the edge. Now: hard coded, future: parameter
            frame_gap = destTraxel.Timestep - srcTraxel.Timestep

            # 1. method
            if frame_gap > 1:
                features[1][0] = features[1][0] + skipLinksBias*frame_gap

            # # 2. method
            # # introduce a new energies like: [[6], [15]] -> [[6, 23], [15, 23]] for first links and
            # # [[6], [15]] -> [[23, 6], [23, 15]] for second links, and so on for 3rd order links
            # # !!! this will introduce a new weight in the weight.json file. For the 2nd link, comes in 2nd row and so on.
            # # drawback: did not manage to adjust parameter to get sensible results.
            # for feat in features:
            #     for i in range(frame_gap):
            #         feat.append(23)
            #     if frame_gap > 1:
            #         feat[frame_gap-1], feat[0] = feat[0], feat[frame_gap-1]


            self._graph.edge[a[0]][a[1]]['src'] = self._graph.node[a[0]]['id']
            self._graph.edge[a[0]][a[1]]['dest'] = self._graph.node[a[1]]['id']
            self._graph.edge[a[0]][a[1]]['features'] = features

            progressBar.show()
Exemple #24
0
def create_and_link_tracks_and_divisions(track_features_h5, ts,
                                         region_features):
    # storage for all tracks and divisions
    tracks = {}
    divisions = {}

    # mapping of traxelID at front and back of track to track_id
    track_starts_with_traxel_id = {}
    track_ends_with_traxel_id = {}

    pb = ProgressBar(
        0,
        len(track_features_h5['tracks'].keys()) +
        len(track_features_h5['divisions'].keys()))
    print("Extracting Tracks and Divisions")

    for track_id in track_features_h5['tracks'].keys():
        pb.show()
        track_id_int = int(track_id)
        t = Track(track_id_int)
        t.extract(track_features_h5)
        t.extract_region_features(ts, region_features)

        # store in container
        tracks[track_id_int] = t

        # create mappings
        track_starts_with_traxel_id[t.start_traxel_id] = track_id_int
        track_ends_with_traxel_id[t.end_traxel_id] = track_id_int

    max_length = max([t.length for t in tracks.values()])
    for t in tracks.values():
        t.features['track_length'] = float(t.length) / max_length

    for division_id in track_features_h5['divisions'].keys():
        pb.show()
        division_id_int = int(division_id)
        d = Division(division_id_int)
        d.extract(track_features_h5)

        # find the tracks that are connected by this division
        # and update information in the tracks
        try:
            d.parent_track_id = track_ends_with_traxel_id[d.parent_traxel_id]
            tracks[d.parent_track_id].end_division_id = division_id_int
        except KeyError as e:
            print(
                "Could not find parent track of division {}: ".format(
                    division_id), e.message)

        for i in [0, 1]:
            try:
                d.children_track_ids[i] = track_starts_with_traxel_id[
                    d.children_traxel_ids[i]]
                tracks[d.children_track_ids[
                    i]].start_division_id = division_id_int
            except KeyError as e:
                print(
                    "Could not find child track of division {}: ".format(
                        division_id), e.message)

        # store in container
        divisions[division_id_int] = d
    return tracks, divisions