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);
}
}
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;
}
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);
}
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];
}
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;
}
Aggregations