Search in sources :

Example 1 with Image

use of bacmman.image.Image in project bacmman by jeanollion.

the class MicrochannelTracker method segmentAndTrack.

/**
 * 1) Segmentation of microchannels depending on the chosen {@link MicrochannelSegmenter segmenter}
 * 2) {@link #track(int, List, TrackLinkEditor)}  tracking of microchannels}
 * 3) {@link #fillGaps(int, List, boolean, SegmentedObjectFactory, TrackLinkEditor)}  gap-filling procedure}
 * 4) Track-Wise Normalization of microchannels width and relative y position
 * @param structureIdx microchannel structure index
 * @param parentTrack microchannel parent track
 * @param trackPreFilters optional track pre-filters to be applied prior to segmentation step
 * @param postFilters  optional post filters to be applied after segmentation and before tracking
 */
@Override
public void segmentAndTrack(int structureIdx, List<SegmentedObject> parentTrack, TrackPreFilterSequence trackPreFilters, PostFilterSequence postFilters, SegmentedObjectFactory factory, TrackLinkEditor editor) {
    if (parentTrack.isEmpty())
        return;
    // segmentation
    final MicrochannelSegmenter.Result[] boundingBoxes = new MicrochannelSegmenter.Result[parentTrack.size()];
    trackPreFilters.filter(structureIdx, parentTrack);
    TrackConfigurable.TrackConfigurer<? super MicrochannelSegmenter> applyToSegmenter = TrackConfigurable.getTrackConfigurer(structureIdx, parentTrack, segmenter.instantiatePlugin());
    Consumer<Integer> exe = idx -> {
        SegmentedObject parent = parentTrack.get(idx);
        MicrochannelSegmenter s = segmenter.instantiatePlugin();
        if (applyToSegmenter != null)
            applyToSegmenter.apply(parent, s);
        boundingBoxes[idx] = s.segment(parent.getPreFilteredImage(structureIdx), structureIdx, parent);
        if (// if not set and call to getChildren() -> DAO will set old children
        boundingBoxes[idx] == null)
            // if not set and call to getChildren() -> DAO will set old children
            factory.setChildObjects(parent, null);
        else
            // else parent.setChildrenObjects(postFilters.filter(boundingBoxes[idx].getObjectPopulation(inputImages[idx], false), structureIdx, parent), structureIdx); // no Y - shift here because the mean shift is added afterwards // TODO if post filter remove objects or modify -> how to link with result object??
            // no Y - shift here because the mean shift is added afterwards
            factory.setChildObjects(parent, boundingBoxes[idx].getObjectPopulation(parent.getPreFilteredImage(structureIdx), false));
    // parent.setPreFilteredImage(null, structureIdx); // save memory
    // TODO perform post-filters at this step and remove the use of boundingBoxes array.. or update the bounding box array by matching each object ...
    };
    ThreadRunner.executeAndThrowErrors(Utils.parallele(IntStream.range(0, parentTrack.size()).mapToObj(i -> i), true), exe);
    Map<SegmentedObject, MicrochannelSegmenter.Result> parentBBMap = new HashMap<>(boundingBoxes.length);
    for (int i = 0; i < boundingBoxes.length; ++i) parentBBMap.put(parentTrack.get(i), boundingBoxes[i]);
    // tracking
    if (debug)
        logger.debug("mc2: {}", Utils.toStringList(parentTrack, p -> "t:" + p.getFrame() + "->" + p.getChildren(structureIdx).count()));
    track(structureIdx, parentTrack, editor);
    fillGaps(structureIdx, parentTrack, allowGaps.getSelected(), factory, editor);
    if (debug)
        logger.debug("mc3: {}", Utils.toStringList(parentTrack, p -> "t:" + p.getFrame() + "->" + p.getChildren(structureIdx).count()));
    // compute mean of Y-shifts & width for each microchannel and modify objects
    Map<SegmentedObject, List<SegmentedObject>> allTracks = SegmentedObjectUtils.getAllTracks(parentTrack, structureIdx);
    if (debug)
        logger.debug("mc4: {}", Utils.toStringList(parentTrack, p -> "t:" + p.getFrame() + "->" + p.getChildren(structureIdx).count()));
    logger.debug("Microchannel tracker: trackHead number: {}", allTracks.size());
    List<SegmentedObject> toRemove = new ArrayList<>();
    for (List<SegmentedObject> track : allTracks.values()) {
        // set shift & width to all objects
        if (track.isEmpty())
            continue;
        List<Integer> shifts = new ArrayList<>(track.size());
        List<Double> widths = new ArrayList<>(track.size());
        for (SegmentedObject o : track) {
            MicrochannelSegmenter.Result r = parentBBMap.get(o.getParent());
            if (o.getIdx() >= r.size()) {
                // object created from gap closing
                if (// for index consitency
                !widths.isEmpty())
                    // for index consitency
                    widths.add(widths.get(widths.size() - 1));
                else
                    widths.add(null);
                if (// for index consitency
                !shifts.isEmpty())
                    // for index consitency
                    shifts.add(shifts.get(shifts.size() - 1));
                else
                    shifts.add(null);
            } else {
                shifts.add(r.yMinShift[o.getIdx()]);
                widths.add((double) r.getXWidth(o.getIdx()));
            }
        }
        // replace null at begining values by following non null value
        int nonNullIdx = 0;
        while (nonNullIdx < shifts.size() && shifts.get(nonNullIdx) == null) ++nonNullIdx;
        int nonNullValue = nonNullIdx < shifts.size() ? shifts.get(nonNullIdx) : 0;
        for (int i = 0; i < nonNullIdx; ++i) shifts.set(i, nonNullValue);
        // if (debug) logger.debug("shifts non null idx: {} values: {}", nonNullIdx, shifts);
        nonNullIdx = 0;
        while (nonNullIdx < widths.size() && widths.get(nonNullIdx) == null) ++nonNullIdx;
        if (nonNullIdx >= widths.size())
            continue;
        for (int i = 0; i < nonNullIdx; ++i) widths.set(i, widths.get(nonNullIdx));
        // if (debug) logger.debug("widths non null idx: {} values: {}", nonNullIdx, widths);
        boolean normWidth = this.normalizeWidths.getSelected();
        boolean normShift = this.normalizeYshift.getSelected();
        // quantile function sorts the values!!
        int shift = !normShift ? -1 : (int) Math.round(ArrayUtil.quantiles(shifts.stream().mapToInt(Integer::intValue).toArray(), yShiftQuantile.getValue().doubleValue())[0]);
        // quantile function sorts the values!!
        int width = !normWidth ? -1 : (int) Math.round(ArrayUtil.quantiles(widths.stream().mapToDouble(Double::doubleValue).toArray(), widthQuantile.getValue().doubleValue())[0]);
        if ((normShift || normWidth) && debug)
            logger.debug("track: {} ymin-shift: {}, width: {} (max: {}, )", track.get(0), shift, width, widths.get(widths.size() - 1));
        // 4) track-wise normalization of width & y-shift
        for (int i = 0; i < track.size(); ++i) {
            SegmentedObject o = track.get(i);
            BoundingBox b = o.getBounds();
            BoundingBox parentBounds = o.getParent().getBounds();
            // shift was not included before
            int offY = b.yMin() + (normShift ? shift : shifts.get(i));
            // if width change -> offset X change
            int offX;
            int currentWidth;
            if (normWidth) {
                currentWidth = width;
                double offXd = b.xMean() - (width - 1d) / 2d;
                double offXdr = offXd - (int) offXd;
                if (offXdr < 0.5)
                    offX = (int) offXd;
                else if (offXdr > 0.5)
                    offX = (int) offXd + 1;
                else {
                    // adjust localy: compare light in both cases //TODO not a good criterion -> biais on the right side
                    MutableBoundingBox bLeft = new MutableBoundingBox((int) offXd, (int) offXd + width - 1, offY, offY + b.sizeY() - 1, b.zMin(), b.zMax());
                    MutableBoundingBox bRight = bLeft.duplicate().translate(1, 0, 0);
                    MutableBoundingBox bLeft2 = bLeft.duplicate().translate(-1, 0, 0);
                    bLeft.contract(parentBounds);
                    bRight.contract(parentBounds);
                    bLeft2.contract(parentBounds);
                    Image r = o.getParent().getRawImage(structureIdx);
                    double valueLeft = ImageOperations.getMeanAndSigmaWithOffset(r, bLeft.getBlankMask(), null, false)[0];
                    double valueLeft2 = ImageOperations.getMeanAndSigmaWithOffset(r, bLeft2.getBlankMask(), null, false)[0];
                    double valueRight = ImageOperations.getMeanAndSigmaWithOffset(r, bRight.getBlankMask(), null, false)[0];
                    if (valueLeft2 > valueRight && valueLeft2 > valueLeft)
                        offX = (int) offXd - 1;
                    else if (valueRight > valueLeft && valueRight > valueLeft2)
                        offX = (int) offXd + 1;
                    else
                        offX = (int) offXd;
                // logger.debug("offX for element: {}, width:{}>{}, left:{}={}, right:{}={} left2:{}={}", o, b, width, bLeft, valueLeft, bRight, valueRight, bLeft2, valueLeft2);
                }
            } else {
                offX = b.xMin();
                currentWidth = b.sizeX();
            }
            if (currentWidth + offX > parentBounds.xMax() || offX < 0) {
                if (debug)
                    logger.debug("remove out of bound track: {}", track.get(0).getTrackHead());
                toRemove.addAll(track);
                break;
            // currentWidth = parentBounds.getxMax()-offX;
            // if (currentWidth<0) logger.error("negative wigth: object:{} parent: {}, current: {}, prev: {}, next:{}", o, o.getParent().getBounds(), o.getBounds(), o.getPrevious().getBounds(), o.getNext().getBounds());
            }
            int height = b.sizeY();
            if (height + offY > parentBounds.yMax())
                height = parentBounds.yMax() - offY;
            BlankMask m = new BlankMask(currentWidth, height, b.sizeZ(), offX, offY, b.zMin(), o.getScaleXY(), o.getScaleZ());
            factory.setRegion(o, new Region(m, o.getIdx() + 1, o.getRegion().is2D()));
        }
    // if (debug) logger.debug("track: {} after norm & shiftY: {}", track.get(0), Utils.toStringList(track, o->o.getBounds()));
    }
    if (debug)
        logger.debug("mc after adjust width: {}", Utils.toStringList(parentTrack, p -> "t:" + p.getFrame() + "->" + p.getChildren(structureIdx).count()));
    if (!toRemove.isEmpty()) {
        Map<SegmentedObject, List<SegmentedObject>> toRemByParent = SegmentedObjectUtils.splitByParent(toRemove);
        for (Entry<SegmentedObject, List<SegmentedObject>> e : toRemByParent.entrySet()) {
            factory.getChildren(e.getKey()).removeAll(e.getValue());
            factory.relabelChildren(e.getKey());
        }
    }
    if (debug)
        logger.debug("mc after remove: {}", Utils.toStringList(parentTrack, p -> "t:" + p.getFrame() + "->" + p.getChildren(structureIdx).count()));
    // relabel by trackHead order of appearance
    HashMapGetCreate<SegmentedObject, Integer> trackHeadIdxMap = new HashMapGetCreate<>(new Function<SegmentedObject, Integer>() {

        int count = -1;

        @Override
        public Integer apply(SegmentedObject key) {
            ++count;
            return count;
        }
    });
    for (SegmentedObject p : parentTrack) {
        List<SegmentedObject> children = factory.getChildren(p);
        Collections.sort(children, ObjectIdxTracker.getComparator(ObjectIdxTracker.IndexingOrder.XYZ));
        for (SegmentedObject c : children) {
            int idx = trackHeadIdxMap.getAndCreateIfNecessary(c.getTrackHead());
            if (idx != c.getIdx())
                factory.setIdx(c, idx);
        }
    }
    if (debug)
        logger.debug("mc end: {}", Utils.toStringList(parentTrack, p -> "t:" + p.getFrame() + "->" + p.getChildren(structureIdx).count()));
    // post-filters are run as track post-filters
    if (!postFilters.isEmpty()) {
        TrackPostFilterSequence tpfs = new TrackPostFilterSequence("");
        for (PostFilter pf : postFilters.get()) tpfs.add(new bacmman.plugins.plugins.track_post_filter.PostFilter(pf).setMergePolicy(bacmman.plugins.plugins.track_post_filter.PostFilter.MERGE_POLICY.ALWAYS_MERGE).setDeleteMethod(bacmman.plugins.plugins.track_post_filter.PostFilter.DELETE_METHOD.PRUNE_TRACK));
        tpfs.filter(structureIdx, parentTrack, factory, editor);
    }
}
Also used : IntStream(java.util.stream.IntStream) java.util(java.util) Utils.parallele(bacmman.utils.Utils.parallele) BlankMask(bacmman.image.BlankMask) MicrochannelPhase2D(bacmman.plugins.plugins.segmenters.MicrochannelPhase2D) bacmman.plugins(bacmman.plugins) Function(java.util.function.Function) HashMapGetCreate(bacmman.utils.HashMapGetCreate) Utils(bacmman.utils.Utils) Pair(bacmman.utils.Pair) Spot(bacmman.processing.matching.trackmate.Spot) bacmman.configuration.parameters(bacmman.configuration.parameters) ThreadRunner(bacmman.utils.ThreadRunner) SimpleBoundingBox(bacmman.image.SimpleBoundingBox) ArrayUtil(bacmman.utils.ArrayUtil) ImageOperations(bacmman.processing.ImageOperations) Point(bacmman.utils.geom.Point) Image(bacmman.image.Image) Collectors(java.util.stream.Collectors) BoundingBox(bacmman.image.BoundingBox) MutableBoundingBox(bacmman.image.MutableBoundingBox) Consumer(java.util.function.Consumer) bacmman.data_structure(bacmman.data_structure) Entry(java.util.Map.Entry) TrackMateInterface(bacmman.processing.matching.TrackMateInterface) bacmman.plugins(bacmman.plugins) Image(bacmman.image.Image) MutableBoundingBox(bacmman.image.MutableBoundingBox) SimpleBoundingBox(bacmman.image.SimpleBoundingBox) BoundingBox(bacmman.image.BoundingBox) MutableBoundingBox(bacmman.image.MutableBoundingBox) BlankMask(bacmman.image.BlankMask) HashMapGetCreate(bacmman.utils.HashMapGetCreate) Point(bacmman.utils.geom.Point)

Example 2 with Image

use of bacmman.image.Image in project bacmman by jeanollion.

the class NestedSpotTracker method track.

/**
 * Mutation tracking within bacteria using <a href='https://imagej.net/TrackMate' target="_top">TrackMate</a>
 * Distance between spots is relative to the nearest bacteria pole (or division point for dividing bacteria)
 * If {@param LQSpots} is true, a first step of removal of low-quality (LQ) spots will be applied: only LQ spots that can be linked (directly or indirectly) to high-quality (HQ) spots are kept, allowing a better selection of true-positives spots of low intensity
 * A global linking with remaining LQ and HQ spots is applied allowing gaps
 * @param structureIdx mutation structure index
 * @param parentTrack parent track containing objects to link at structure {@param structureIdx}
 * @param LQSpots whether objects of structure: {@param structureIdx} contain high- and low-quality spots (unlinkable low quality spots will be removed)
 */
public void track(int structureIdx, List<SegmentedObject> parentTrack, boolean LQSpots, boolean allowSplit, boolean allowMerge, SegmentedObjectFactory factory, TrackLinkEditor editor) {
    // if (true) return;
    int compartmentStructure = this.compartmentStructure.getSelectedIndex();
    // parameter = count only the frames where the spot is missing
    int maxFrameDiff = this.maxGap.getValue().intValue() + 1;
    double spotQualityThreshold = LQSpots ? this.spotQualityThreshold.getValue().doubleValue() : Double.NEGATIVE_INFINITY;
    double maxLinkingDistance = this.maxLinkingDistance.getValue().doubleValue();
    double maxLinkingDistanceGC = this.maxLinkingDistanceGC.getValue().doubleValue();
    double gapPenalty = this.gapPenalty.getValue().doubleValue();
    if (!calibration.getSelected()) {
        double scale = parentTrack.get(0).getScaleXY();
        maxLinkingDistance *= scale;
        maxLinkingDistanceGC *= scale;
        gapPenalty *= scale;
    }
    DistanceComputationParameters distParams = new DistanceComputationParameters().setQualityThreshold(spotQualityThreshold).setGapDistancePenalty(gapPenalty).setAllowGCBetweenLQ(true).setMaxFrameDifference(maxFrameDiff).setProjectionType(projectionType.getSelectedEnum()).setProjOnSameSide(this.projectOnSameSide.getSelected());
    logger.debug("distanceFTF: {}, distance GC: {}, gapP: {}", maxLinkingDistance, maxLinkingDistanceGC, gapPenalty);
    Map<Region, SegmentedObject> mutationMapParentBacteria = Utils.toMapWithNullValues(SegmentedObjectUtils.getAllChildrenAsStream(parentTrack.stream(), structureIdx), e -> e.getRegion(), e -> SegmentedObjectUtils.getContainer(e.getRegion(), e.getParent().getChildren(compartmentStructure), null), false);
    final Map<SegmentedObject, List<Region>> bacteriaMapMutation = mutationMapParentBacteria.keySet().stream().collect(Collectors.groupingBy(m -> mutationMapParentBacteria.get(m)));
    // get all potential spine localizers: for each bacteria with mutation look if there are bacteria with mutations in previous bacteria within gap range
    Set<SegmentedObject> parentWithSpine = new HashSet<>();
    parentWithSpine.addAll(bacteriaMapMutation.keySet());
    bacteriaMapMutation.keySet().forEach(b -> {
        int frameDiff = 1;
        SegmentedObject prev = b.getPrevious();
        while (prev != null && frameDiff < maxFrameDiff && !bacteriaMapMutation.containsKey(prev)) {
            ++frameDiff;
            prev = prev.getPrevious();
        }
        if (prev != null && (frameDiff < maxFrameDiff || bacteriaMapMutation.containsKey(prev))) {
            // add all bacteria between b & prev
            SegmentedObject p = b.getPrevious();
            // for division point computation
            if (b.isTrackHead())
                parentWithSpine.addAll(getDivisionSiblings(b, false));
            while (p != prev) {
                parentWithSpine.add(p);
                // for division point computation
                if (p.isTrackHead())
                    parentWithSpine.addAll(getDivisionSiblings(b, false));
                p = p.getPrevious();
            }
        }
    });
    // Map<SegmentedObject, BacteriaSpineLocalizer> lMap = parallele(parentWithSpine.stream(), true).collect(Collectors.toMap(b->b, b->new BacteriaSpineLocalizer(b.getRegion()))); // spine are long to compute: better performance when computed all at once
    MultipleException me = new MultipleException();
    // spine are long to compute: better performances when computed all at once
    Map<SegmentedObject, BacteriaSpineLocalizer> lMap = Utils.toMapWithNullValues(Utils.parallele(parentWithSpine.stream(), true), b -> b, b -> new BacteriaSpineLocalizer(b.getRegion()), true, me);
    final HashMapGetCreate<SegmentedObject, BacteriaSpineLocalizer> localizerMap = HashMapGetCreate.getRedirectedMap((SegmentedObject s) -> {
        try {
            return new BacteriaSpineLocalizer(s.getRegion());
        } catch (Throwable t) {
            me.addExceptions(new Pair<>(s.toString(), t));
            return null;
        }
    }, HashMapGetCreate.Syncronization.SYNC_ON_KEY);
    localizerMap.putAll(lMap);
    TrackMateInterface<NestedSpot> tmi = new TrackMateInterface<>(new SpotFactory<NestedSpot>() {

        @Override
        public NestedSpot toSpot(Region o, int frame) {
            SegmentedObject b = mutationMapParentBacteria.get(o);
            if (b == null) {
                // me.addExceptions(new Pair<>(parentTrack.stream().filter(p->p.getFrame()==frame).findAny().get()+"-spot#"+o.getLabel(), new RuntimeException("Mutation's parent bacteria not found")));
                return null;
            }
            if (localizerMap.get(b) == null) {
                // me.addExceptions(new Pair<>(b.toString(), new RuntimeException("Mutation's parent bacteria spine could not be computed")));
                return null;
            }
            if (o.getCenter() == null)
                o.setCenter(o.getGeomCenter(false));
            return new NestedSpot(o, b, localizerMap, distParams);
        }

        @Override
        public NestedSpot duplicate(NestedSpot s) {
            return s.duplicate();
        }
    });
    Map<Integer, List<SegmentedObject>> objectsF = SegmentedObjectUtils.getChildrenByFrame(parentTrack, structureIdx);
    long t0 = System.currentTimeMillis();
    tmi.addObjects(objectsF);
    long t1 = System.currentTimeMillis();
    if (LQSpots || logger.isDebugEnabled()) {
        int lQCount = 0;
        for (NestedSpot s : tmi.spotObjectMap.keySet()) if (s.isLowQuality())
            ++lQCount;
        logger.debug("LAP Tracker: {}, spot HQ: {}, #spots LQ: {} (thld: {}), time: {}", parentTrack.get(0), tmi.spotObjectMap.size() - lQCount, lQCount, spotQualityThreshold, t1 - t0);
    }
    if (LQSpots) {
        // sequence to remove LQ spots
        distParams.includeLQ = false;
        // FTF only with HQ
        boolean ok = tmi.processFTF(maxLinkingDistance);
        distParams.includeLQ = true;
        // FTF HQ+LQ
        if (ok)
            ok = tmi.processFTF(maxLinkingDistance);
        distParams.includeLQ = true;
        // GC HQ+LQ (dist param: no gap closing between LQ spots)
        if (ok)
            ok = tmi.processGC(maxLinkingDistanceGC, maxFrameDiff - 1, false, false);
        if (ok) {
            tmi.setTrackLinks(objectsF, editor);
            tmi.resetEdges();
            MutationTrackPostProcessing postProcessor = new MutationTrackPostProcessing(structureIdx, parentTrack, tmi.objectSpotMap, o -> tmi.removeObject(o.getRegion(), o.getFrame()), factory, editor);
            postProcessor.connectShortTracksByDeletingLQSpot(maxLinkingDistanceGC);
            removeUnlinkedLQSpots(parentTrack, structureIdx, tmi, factory);
            objectsF = SegmentedObjectUtils.getChildrenByFrame(parentTrack, structureIdx);
        } else
            return;
    }
    long t2 = System.currentTimeMillis();
    boolean ok = true;
    ok = tmi.processFTF(maxLinkingDistance);
    if (ok)
        ok = tmi.processGC(maxLinkingDistanceGC, maxFrameDiff - 1, allowSplit, allowMerge);
    if (ok && LQSpots) {
        // switchCrossingLinksWithLQBranches(tmi, maxLinkingDistanceGC/Math.sqrt(2), maxLinkingDistanceGC, maxGap); // remove crossing links
        tmi.setTrackLinks(objectsF, editor);
        // TODO : do directly in graph
        MutationTrackPostProcessing postProcessor = new MutationTrackPostProcessing(structureIdx, parentTrack, tmi.objectSpotMap, o -> tmi.removeObject(o.getRegion(), o.getFrame()), factory, editor);
        // 
        postProcessor.connectShortTracksByDeletingLQSpot(maxLinkingDistanceGC);
        // a track cannot start with a LQ spot separated by a gap
        trimLQExtremityWithGaps(tmi, 2, true, true);
    }
    if (ok) {
        objectsF = SegmentedObjectUtils.getChildrenByFrame(parentTrack, structureIdx);
        tmi.setTrackLinks(objectsF, editor);
    }
    if (LQSpots) {
        tmi.resetEdges();
        removeUnlinkedLQSpots(parentTrack, structureIdx, tmi, factory);
    }
    long t3 = System.currentTimeMillis();
    if (factory != null) {
        // relabel
        for (SegmentedObject p : parentTrack) {
            List<SegmentedObject> children = factory.getChildren(p);
            if (children != null) {
                Collections.sort(children, ObjectIdxTracker.getComparator(ObjectIdxTracker.IndexingOrder.YXZ));
                factory.relabelChildren(p);
            }
        }
    }
    logger.debug("Mutation Tracker: {}, total processing time: {}, create spots: {}, remove LQ: {}, link: {}", parentTrack.get(0), t3 - t0, t1 - t0, t2 - t1, t3 - t2);
    // DISPLAY SPINE ON TEST IMAGE THROUGH RIGHT-CLICK
    if (stores != null) {
        BiConsumer<List<SegmentedObject>, Boolean> displayDistance = (l, drawDistances) -> {
            logger.debug("display Spine action");
            if (l.size() == 2 && l.get(0).getStructureIdx() == structureIdx && l.get(1).getStructureIdx() == structureIdx) {
                Collections.sort(l);
                SegmentedObject b1 = mutationMapParentBacteria.get(l.get(0).getRegion());
                if (b1 == null) {
                    Core.userLog("parent bacteria not found for mutation: " + l.get(0));
                    return;
                }
                BacteriaSpineLocalizer bsl1 = localizerMap.get(b1);
                if (bsl1 == null) {
                    Core.userLog("bacteria spine localizer not computable for bacteria: " + b1);
                    return;
                }
                logger.debug("spine1: bact contour: {}, skeleton size: {}, circontour: {}", b1.getRegion().getContour().size(), bsl1.spine.skeleton == null ? "null" : bsl1.spine.skeleton.size(), bsl1.spine.contour == null ? "null" : bsl1.spine.contour.size());
                bsl1.setTestMode(true);
                if (l.get(0).getRegion().getCenter() == null)
                    l.get(0).getRegion().setCenter(l.get(0).getRegion().getGeomCenter(false).translate(l.get(0).getBounds()));
                if (l.get(1).getRegion().getCenter() == null)
                    l.get(1).getRegion().setCenter(l.get(1).getRegion().getGeomCenter(false).translate(l.get(1).getBounds()));
                logger.info("spot: {} center: {} bact coords: {} (other : {})", l.get(0), l.get(0).getRegion().getCenter().duplicate().translateRev(l.get(0).getBounds()), bsl1.getSpineCoord(l.get(0).getRegion().getCenter()));
                SegmentedObject b2 = mutationMapParentBacteria.get(l.get(1).getRegion());
                if (b2 == null) {
                    Core.userLog("parent bacteria not found for mutation: " + l.get(1));
                    return;
                }
                BacteriaSpineLocalizer bsl2 = localizerMap.get(b2);
                bsl2.setTestMode(true);
                if (bsl2 == null) {
                    Core.userLog("bacteria spine localizer not computable for bacteria: " + b2);
                    return;
                }
                logger.info("spot: {} center: {}, bact coords: {} (other : {})", l.get(1), l.get(1).getRegion().getCenter().duplicate().translateRev(l.get(1).getBounds()), bsl2.getSpineCoord(l.get(1).getRegion().getCenter()));
                // draw source with point
                SegmentedObject mc1 = b1.getParent();
                BacteriaSpineCoord coord = bsl1.getSpineCoord(l.get(0).getRegion().getCenter());
                SpineOverlayDrawer drawer = SpineOverlayDrawer.get();
                // draw dest with point
                SegmentedObject mc2 = b2.getParent();
                BacteriaSpineCoord coord2 = bsl2.getSpineCoord(l.get(1).getRegion().getCenter());
                // actual projection
                distParams.includeLQ = true;
                NestedSpot s1 = new NestedSpot(l.get(0).getRegion(), b1, localizerMap, distParams);
                NestedSpot s2 = new NestedSpot(l.get(1).getRegion(), b2, localizerMap, distParams);
                Point proj = project(l.get(0).getRegion().getCenter(), b1, b2, distParams.projectionType, localizerMap, true);
                if (drawer != null) {
                    Object spineDest = drawer.getSpineOverlay(drawer.trimSpine(bsl2.spine, 0.3), mc2.getBounds(), "blue", "yellow", 0.5);
                    drawer.drawPoint(spineDest, mc2.getBounds(), l.get(1).getRegion().getCenter(), "green", 2);
                    drawer.drawPoint(spineDest, mc2.getBounds(), proj, "orange", 2);
                    Object spineSource = drawer.getSpineOverlay(drawer.trimSpine(bsl1.spine, 0.3), mc1.getBounds(), "blue", "yellow", 0.5);
                    drawer.drawPoint(spineSource, mc1.getBounds(), l.get(0).getRegion().getCenter(), "orange", 2);
                    drawer.display("Source", mc1.getRawImage(l.get(0).getStructureIdx()), spineSource);
                    drawer.display("Destination", mc2.getRawImage(l.get(0).getStructureIdx()), spineDest);
                }
                // also add to object attributes
                l.get(0).setAttribute("Curvilinear Coordinate", coord == null ? "could not be computed" : MeasurementExtractor.numberFormater.apply(coord.curvilinearCoord(false)) + "/" + MeasurementExtractor.numberFormater.apply(coord.spineLength()));
                l.get(0).setAttribute("Radial Coordinate", coord == null ? "could not be computed" : MeasurementExtractor.numberFormater.apply(coord.radialCoord(false)) + "/" + MeasurementExtractor.numberFormater.apply(coord.spineRadius()));
                l.get(1).setAttribute("Curvilinear Coordinate", coord2 == null ? "could not be computed" : MeasurementExtractor.numberFormater.apply(coord2.curvilinearCoord(false)) + "/" + MeasurementExtractor.numberFormater.apply(coord2.spineLength()));
                l.get(1).setAttribute("Radial Coordinate", coord2 == null ? "could not be computed" : MeasurementExtractor.numberFormater.apply(coord2.radialCoord(false)) + "/" + MeasurementExtractor.numberFormater.apply(coord2.spineRadius()));
                // log distance
                if (proj != null) {
                    double nDist = Math.sqrt(s1.squareDistanceTo(s2));
                    Core.userLog("Distance " + l.get(0) + "->" + l.get(1) + "=" + proj.dist(l.get(1).getRegion().getCenter()) * l.get(0).getScaleXY() + "µm" + " (with corrections: " + nDist + "µm)");
                    logger.info("Distance {} -> {} = {} µm. Nested Spot distance: {}", l.get(0), l.get(1), proj.dist(l.get(1).getRegion().getCenter()) * l.get(0).getScaleXY(), nDist);
                    if (Double.isInfinite(nDist)) {
                        logger.debug("2 LQ: {}", !distParams.includeLQ && (s1.isLowQuality() || s2.isLowQuality()));
                        logger.debug("max frame diff: {}", s2.frame() - s1.frame() > distParams.maxFrameDiff);
                    }
                } else {
                    Core.userLog("Point could not be projected");
                    logger.info("Point could not be projected");
                }
            /*
                    int verboseZoomFactor  =  3;
                    Image spine1 = bsl1.spine.drawSpine(verboseZoomFactor, drawDistances).setName("Source Spine: "+b1);
                    BacteriaSpineLocalizer.drawPoint(l.get(0).getRegion().getCenter(), spine1, verboseZoomFactor, 1000);
                    spine1.setCalibration(spine1.getScaleXY() * l.get(0).getScaleXY(), 1);
                    Core.showImage(spine1);
                    Image spine2 = bsl2.spine.drawSpine(verboseZoomFactor, drawDistances).setName("Destination Spine: "+b2);
                    BacteriaSpineLocalizer.drawPoint(l.get(1).getRegion().getCenter(), spine2, verboseZoomFactor, 1001);
                    spine2.setCalibration(spine2.getScaleXY() * l.get(0).getScaleXY(), 1);

                    if (proj!=null) {
                        BacteriaSpineLocalizer.drawPoint(proj, spine2, verboseZoomFactor, 1000);
                        logger.info("Dist {} -> {}: {} ({})", l.get(0), l.get(1), proj.dist(l.get(1).getRegion().getCenter()) * l.get(0).getScaleXY(), Math.sqrt(tmi.objectSpotMap.get(l.get(0).getRegion()).squareDistanceTo(tmi.objectSpotMap.get(l.get(1).getRegion()))));
                    } else logger.info("Could not project point");
                    
                    Core.showImage(spine2);
                    */
            }
        };
        parentTrack.forEach((p) -> {
            stores.get(p).addMisc("Display Spine", l -> displayDistance.accept(l, false));
        // stores.get(p).addMisc("Display Spine With Distance", l->displayDistance.accept(l, true));
        });
    }
    if (!me.isEmpty())
        throw me;
}
Also used : java.util(java.util) LoggerFactory(org.slf4j.LoggerFactory) bacmman.plugins(bacmman.plugins) SpineOverlayDrawer(bacmman.processing.bacteria_spine.SpineOverlayDrawer) SegmentedObjectUtils.getDivisionSiblings(bacmman.data_structure.SegmentedObjectUtils.getDivisionSiblings) NestedSpot(bacmman.plugins.plugins.trackers.nested_spot_tracker.NestedSpot) HashMapGetCreate(bacmman.utils.HashMapGetCreate) Utils(bacmman.utils.Utils) DefaultWeightedEdge(org.jgrapht.graph.DefaultWeightedEdge) DistanceComputationParameters(bacmman.plugins.plugins.trackers.nested_spot_tracker.DistanceComputationParameters) MutationTrackPostProcessing(bacmman.plugins.plugins.trackers.nested_spot_tracker.post_processing.MutationTrackPostProcessing) Pair(bacmman.utils.Pair) BacteriaSpineLocalizer(bacmman.processing.bacteria_spine.BacteriaSpineLocalizer) Core(bacmman.core.Core) BiConsumer(java.util.function.BiConsumer) bacmman.configuration.parameters(bacmman.configuration.parameters) Logger(org.slf4j.Logger) MeasurementExtractor(bacmman.measurement.MeasurementExtractor) SpotSegmenter(bacmman.plugins.plugins.segmenters.SpotSegmenter) Point(bacmman.utils.geom.Point) Image(bacmman.image.Image) BacteriaSpineCoord(bacmman.processing.bacteria_spine.BacteriaSpineCoord) BacteriaSpineLocalizer.project(bacmman.processing.bacteria_spine.BacteriaSpineLocalizer.project) Collectors(java.util.stream.Collectors) bacmman.data_structure(bacmman.data_structure) SegmentOnly(bacmman.plugins.plugins.processing_pipeline.SegmentOnly) SpotFactory(bacmman.processing.matching.TrackMateInterface.SpotFactory) TrackMateInterface(bacmman.processing.matching.TrackMateInterface) MultipleException(bacmman.utils.MultipleException) MultipleException(bacmman.utils.MultipleException) DistanceComputationParameters(bacmman.plugins.plugins.trackers.nested_spot_tracker.DistanceComputationParameters) TrackMateInterface(bacmman.processing.matching.TrackMateInterface) Pair(bacmman.utils.Pair) SpineOverlayDrawer(bacmman.processing.bacteria_spine.SpineOverlayDrawer) NestedSpot(bacmman.plugins.plugins.trackers.nested_spot_tracker.NestedSpot) Point(bacmman.utils.geom.Point) Point(bacmman.utils.geom.Point) MutationTrackPostProcessing(bacmman.plugins.plugins.trackers.nested_spot_tracker.post_processing.MutationTrackPostProcessing) BacteriaSpineCoord(bacmman.processing.bacteria_spine.BacteriaSpineCoord) BacteriaSpineLocalizer(bacmman.processing.bacteria_spine.BacteriaSpineLocalizer)

Example 3 with Image

use of bacmman.image.Image in project bacmman by jeanollion.

the class SaturateHistogramHyperfluoBacteria method computeConfigurationData.

@Override
public void computeConfigurationData(int channelIdx, InputImages inputImages) {
    List<Image> allImages = Arrays.asList(InputImages.getImageForChannel(inputImages, channelIdx, true));
    if (allImages.isEmpty()) {
        logger.error("No image");
        return;
    } else
        logger.debug("saturate histo: images: {}", allImages.size());
    long t0 = System.currentTimeMillis();
    Histogram histo = HistogramFactory.getHistogram(() -> Image.stream(allImages).parallel(), HistogramFactory.BIN_SIZE_METHOD.BACKGROUND);
    double[] bckMuStd = new double[2];
    double bckThld = BackgroundFit.backgroundFit(histo, 10, bckMuStd);
    Histogram histoFore = histo.duplicate((int) histo.getIdxFromValue(bckThld) + 1, histo.getData().length);
    double foreThld = histoFore.getQuantiles(0.5)[0];
    double satThld = bckMuStd[0] + (foreThld - bckMuStd[0]) * this.minSignalRatio.getValue().doubleValue();
    double satSignal = 0, totalSignal = 0;
    if (satThld < histo.getMaxValue()) {
        // condition on signal amount
        satSignal = histo.count((int) histo.getIdxFromValue(satThld), histo.getData().length);
        totalSignal = histo.count((int) histo.getIdxFromValue(bckThld), histo.getData().length);
        logger.debug("sat signal proportion: {}, ", satSignal / totalSignal);
        if (maxSignalProportion.getValue().doubleValue() > satSignal / totalSignal) {
            saturateValue = satThld;
        } else {
            saturateValue = histoFore.getQuantiles(1 - maxSignalProportion.getValue().doubleValue())[0];
            satSignal = histo.count((int) histo.getIdxFromValue(saturateValue), histo.getData().length);
            logger.debug("sat value to reach maximal proportion: {}, ", saturateValue);
        }
    }
    long t1 = System.currentTimeMillis();
    configured = true;
    logger.debug("SaturateHistoAuto: {}, bck : {}, thld: {}, fore: {}, saturation thld: {}, saturation proportion: {}, image range: {} computation time {}ms", saturateValue, bckMuStd[0], bckThld, foreThld, satThld, satSignal / totalSignal, new double[] { histo.getMinValue(), histo.getMaxValue() }, t1 - t0);
}
Also used : Histogram(bacmman.image.Histogram) Image(bacmman.image.Image)

Example 4 with Image

use of bacmman.image.Image in project bacmman by jeanollion.

the class BacteriaSpineFactory method getEdtCenter.

private Voxel getEdtCenter(ImageMask mask) {
    Image edt = EDT.transform(mask, true, 1, 1, false);
    Voxel[] max = new Voxel[1];
    ImageMask.loopWithOffset(mask, (x, y, z) -> {
        float edtV = edt.getPixelWithOffset(x, y, z);
        if (max[0] == null || edtV > max[0].value)
            max[0] = new Voxel(x, y, z, edtV);
    });
    return max[0];
}
Also used : Voxel(bacmman.data_structure.Voxel) Image(bacmman.image.Image)

Example 5 with Image

use of bacmman.image.Image in project bacmman by jeanollion.

the class AutoRotationXY method applyTransformation.

@Override
public Image applyTransformation(int channelIdx, int timePoint, Image image) {
    if (Double.isNaN(rotationAngle))
        throw new RuntimeException("Autorotation not configured");
    Image res = ImageTransformation.rotateXY(TypeConverter.toFloat(image, null), rotationAngle, interpolation.getSelectedEnum(), removeIncompleteRowsAndColumns.getSelected());
    if (maintainMaximum.getSelected() && interpolation.getSelectedIndex() > 1) {
        double oldMax = image.getMinAndMax(null)[1];
        SaturateHistogram.saturate(oldMax, oldMax, res);
    }
    return res;
}
Also used : Image(bacmman.image.Image)

Aggregations

Image (bacmman.image.Image)149 Collectors (java.util.stream.Collectors)48 List (java.util.List)47 SegmentedObject (bacmman.data_structure.SegmentedObject)44 LoggerFactory (org.slf4j.LoggerFactory)38 Logger (org.slf4j.Logger)37 bacmman.configuration.parameters (bacmman.configuration.parameters)35 ArrayList (java.util.ArrayList)34 Map (java.util.Map)33 ImageFloat (bacmman.image.ImageFloat)32 ImageMask (bacmman.image.ImageMask)32 Hint (bacmman.plugins.Hint)32 IntStream (java.util.stream.IntStream)29 Function (java.util.function.Function)28 Arrays (java.util.Arrays)27 Core (bacmman.core.Core)26 BoundingBox (bacmman.image.BoundingBox)24 MutableBoundingBox (bacmman.image.MutableBoundingBox)24 Utils (bacmman.utils.Utils)23 RegionPopulation (bacmman.data_structure.RegionPopulation)22