/** * This method exists for the following reason: * * <p>The segmenter receives at each frame a cropped image to operate on, depending on the user * specifying a ROI. It therefore returns spots whose coordinates are with respect to the top-left * corner of the ROI, not of the original image. * * <p>This method modifies the given spots to put them back in the image coordinate system. * Additionally, is a non-square ROI was specified (e.g. a polygon), it prunes the spots that are * not within the polygon of the ROI. * * @param spotsThisFrame the spot list to inspect * @param settings the {@link Settings} object that will be used to retrieve the image ROI and * cropping information * @return a list of spot. Depending on the presence of a polygon ROI, it might be a new, pruned * list. Or not. */ protected List<Spot> translateAndPruneSpots( final List<Spot> spotsThisFrame, final Settings settings) { // Get Roi final Polygon polygon; if (null == settings.imp || null == settings.imp.getRoi()) { polygon = null; } else { polygon = settings.imp.getRoi().getPolygon(); } // Put them back in the right referential final float[] calibration = settings.getCalibration(); TMUtils.translateSpots( spotsThisFrame, settings.xstart * calibration[0], settings.ystart * calibration[1], settings.zstart * calibration[2]); List<Spot> prunedSpots; // Prune if outside of ROI if (null != polygon) { prunedSpots = new ArrayList<Spot>(); for (Spot spot : spotsThisFrame) { if (polygon.contains( spot.getFeature(Spot.POSITION_X) / calibration[0], spot.getFeature(Spot.POSITION_Y) / calibration[1])) prunedSpots.add(spot); } } else { prunedSpots = spotsThisFrame; } return prunedSpots; }
/** * @return the image string of the given spot, based on the raw images contained in the given * model. For performance, the image at target frame is stored for subsequent calls of this * method. So it is a good idea to group calls to this method for spots that belong to the * same frame. */ @SuppressWarnings({"rawtypes", "unchecked"}) public String getImageString(final Spot spot) { final Integer frame = spot.getFeature(TrackmateConstants.FRAME).intValue(); if (null == frame) return ""; if (frame == previousFrame) { // Keep the same image than in memory } else { final ImgPlus img = TMUtils.rawWraps(settings.imp); int targetChannel = 0; if (settings != null && settings.detectorSettings != null) { // Try to extract it from detector settings target channel final Map<String, Object> ds = settings.detectorSettings; final Object obj = ds.get(KEY_TARGET_CHANNEL); if (null != obj && obj instanceof Integer) { targetChannel = ((Integer) obj) - 1; } } // TODO: be more flexible about that final ImgPlus<?> imgCT = HyperSliceImgPlus.fixTimeAxis( HyperSliceImgPlus.fixChannelAxis(img, targetChannel), frame); grabber = new SpotIconGrabber(imgCT); previousFrame = frame; } return grabber.getImageString(spot); }
/** * Returns the set of track IDs managed by this model, ordered by track names (alpha-numerically * sorted). * * @param visibleOnly if <code>true</code>, only visible track IDs will be returned. * @return a new set of track IDs. */ public Set<Integer> trackIDs(final boolean visibleOnly) { final Set<Integer> ids = TMUtils.sortByValue(names, AlphanumComparator.instance).keySet(); if (!visibleOnly) { return ids; } else { final Set<Integer> vids = new LinkedHashSet<Integer>(ids.size()); for (final Integer id : ids) { if (visibility.get(id)) { vids.add(id); } } return vids; } }
private void buildFrameContent( final SpotCollection spots, final Integer frame, final double radiusRatio, final FeatureColorGenerator<Spot> spotColorGenerator) { final Map<Spot, Point4d> centers = new HashMap<Spot, Point4d>(spots.getNSpots(frame, false)); final Map<Spot, Color4f> colors = new HashMap<Spot, Color4f>(spots.getNSpots(frame, false)); final double[] coords = new double[3]; for (final Iterator<Spot> it = spots.iterator(frame, false); it.hasNext(); ) { final Spot spot = it.next(); TMUtils.localize(spot, coords); final Double radius = spot.getFeature(Spot.RADIUS); final double[] pos = new double[] {coords[0], coords[1], coords[2], radius * radiusRatio}; centers.put(spot, new Point4d(pos)); final Color4f col = new Color4f(spotColorGenerator.color(spot)); col.w = 0f; colors.put(spot, col); } final SpotGroupNode<Spot> blobGroup = new SpotGroupNode<Spot>(centers, colors); final ContentInstant contentThisFrame = new ContentInstant("Spots_frame_" + frame); try { contentThisFrame.display(blobGroup); } catch (final BadTransformException bte) { System.err.println( "Bad content for frame " + frame + ". Generated an exception:\n" + bte.getLocalizedMessage() + "\nContent was:\n" + blobGroup.toString()); } // Set visibility: if (spots.getNSpots(frame, true) > 0) { blobGroup.setVisible(spots.iterable(frame, true)); } contentAllFrames.put(frame, contentThisFrame); blobs.put(frame, blobGroup); }
public static void main(final String[] args) { final int N_BLOBS = 20; final double RADIUS = 5; // µm final Random RAN = new Random(); final double WIDTH = 100; // µm final double HEIGHT = 100; // µm final double DEPTH = 50; // µm final double[] CALIBRATION = new double[] {0.5f, 0.5f, 1}; final AxisType[] AXES = new AxisType[] {Axes.X, Axes.Y, Axes.Z}; // Create 3D image final Img<UnsignedByteType> source = new ArrayImgFactory<UnsignedByteType>() .create( new int[] { (int) (WIDTH / CALIBRATION[0]), (int) (HEIGHT / CALIBRATION[1]), (int) (DEPTH / CALIBRATION[2]) }, new UnsignedByteType()); final ImgPlus<UnsignedByteType> img = new ImgPlus<UnsignedByteType>(source, "Test", AXES, CALIBRATION); // Random blobs final double[] radiuses = new double[N_BLOBS]; final ArrayList<double[]> centers = new ArrayList<double[]>(N_BLOBS); final int[] intensities = new int[N_BLOBS]; double x, y, z; for (int i = 0; i < N_BLOBS; i++) { radiuses[i] = RADIUS + RAN.nextGaussian(); x = WIDTH * RAN.nextFloat(); y = HEIGHT * RAN.nextFloat(); z = DEPTH * RAN.nextFloat(); centers.add(i, new double[] {x, y, z}); intensities[i] = RAN.nextInt(100) + 100; } // Put the blobs in the image for (int i = 0; i < N_BLOBS; i++) { final Spot tmpSpot = new Spot(centers.get(i)[0], centers.get(i)[1], centers.get(i)[2], radiuses[i], -1d); tmpSpot.putFeature(Spot.RADIUS, radiuses[i]); final SpotNeighborhood<UnsignedByteType> sphere = new SpotNeighborhood<UnsignedByteType>(tmpSpot, img); for (final UnsignedByteType pixel : sphere) { pixel.set(intensities[i]); } } // Instantiate detector final LogDetector<UnsignedByteType> detector = new LogDetector<UnsignedByteType>( img, img, TMUtils.getSpatialCalibration(img), RADIUS, 0, true, false); // Segment final long start = System.currentTimeMillis(); if (!detector.checkInput() || !detector.process()) { System.out.println(detector.getErrorMessage()); return; } final Collection<Spot> spots = detector.getResult(); final long end = System.currentTimeMillis(); // Display image ImageJFunctions.show(img); // Display results final int spot_found = spots.size(); System.out.println("Segmentation took " + (end - start) + " ms."); System.out.println("Found " + spot_found + " blobs.\n"); Point3d p1, p2; double dist, min_dist; int best_index = 0; double[] best_match; final ArrayList<Spot> spot_list = new ArrayList<Spot>(spots); Spot best_spot = null; final double[] coords = new double[3]; final String[] posFeats = Spot.POSITION_FEATURES; while (!spot_list.isEmpty() && !centers.isEmpty()) { min_dist = Float.POSITIVE_INFINITY; for (final Spot s : spot_list) { int index = 0; for (final String pf : posFeats) { coords[index++] = s.getFeature(pf).doubleValue(); } p1 = new Point3d(coords); for (int j = 0; j < centers.size(); j++) { p2 = new Point3d(centers.get(j)); dist = p1.distance(p2); if (dist < min_dist) { min_dist = dist; best_index = j; best_spot = s; } } } spot_list.remove(best_spot); best_match = centers.remove(best_index); int index = 0; for (final String pf : posFeats) { coords[index++] = best_spot.getFeature(pf).doubleValue(); } System.out.println("Blob coordinates: " + Util.printCoordinates(coords)); System.out.println( String.format( " Best matching center at distance %.1f with coords: " + Util.printCoordinates(best_match), min_dist)); } System.out.println(); System.out.println("Unmatched centers:"); for (int i = 0; i < centers.size(); i++) System.out.println("Center " + i + " at position: " + Util.printCoordinates(centers.get(i))); }
@Override public void modelChanged(final ModelChangeEvent event) { if (DEBUG) { System.out.println( "[SpotDisplayer3D: modelChanged() called with event ID: " + event.getEventID()); System.out.println(event); } switch (event.getEventID()) { case ModelChangeEvent.SPOTS_COMPUTED: makeSpotContent(); break; case ModelChangeEvent.SPOTS_FILTERED: for (final int frame : blobs.keySet()) { final SpotGroupNode<Spot> frameBlobs = blobs.get(frame); for (final Iterator<Spot> it = model.getSpots().iterator(frame, false); it.hasNext(); ) { final Spot spot = it.next(); final boolean visible = spot.getFeature(SpotCollection.VISIBLITY).compareTo(SpotCollection.ZERO) > 0; frameBlobs.setVisible(spot, visible); } } break; case ModelChangeEvent.TRACKS_COMPUTED: trackContent = makeTrackContent(); universe.removeContent(TRACK_CONTENT_NAME); universe.addContent(trackContent); break; case ModelChangeEvent.TRACKS_VISIBILITY_CHANGED: updateTrackColors(); trackNode.setTrackVisible(model.getTrackModel().trackIDs(true)); break; case ModelChangeEvent.MODEL_MODIFIED: { /* * Deal with spots first. */ // Useful fields. @SuppressWarnings("unchecked") final FeatureColorGenerator<Spot> spotColorGenerator = (FeatureColorGenerator<Spot>) displaySettings.get(KEY_SPOT_COLORING); final double radiusRatio = (Double) displaySettings.get(KEY_SPOT_RADIUS_RATIO); // Iterate each spot of the event. final Set<Spot> spotsModified = event.getSpots(); for (final Spot spot : spotsModified) { final int spotFlag = event.getSpotFlag(spot); final int frame = spot.getFeature(Spot.FRAME).intValue(); final SpotGroupNode<Spot> spotGroupNode = blobs.get(frame); switch (spotFlag) { case ModelChangeEvent.FLAG_SPOT_REMOVED: spotGroupNode.remove(spot); break; case ModelChangeEvent.FLAG_SPOT_ADDED: { // Sphere location and radius final double[] coords = new double[3]; TMUtils.localize(spot, coords); final Double radius = spot.getFeature(Spot.RADIUS); final double[] pos = new double[] {coords[0], coords[1], coords[2], radius * radiusRatio}; final Point4d center = new Point4d(pos); // Sphere color final Color4f color = new Color4f(spotColorGenerator.color(spot)); color.w = 0; // Do we have an empty frame? if (null == spotGroupNode) { /* * We then just give up. I dig really hard on an elegant * way to add a new ContentInstant for a missing frame, * but found no satisfying way. There is no good way to * add spots to an empty frame. The way I found is very * similar to closing the 3D viewer and re-opening it, * therefore I let the user do it. * * So because of this, the SpotDisplayer3D is only a * partial ModelListener. */ System.err.println( "[SpotDisplayer3D] The TrackMate 3D viewer cannot deal with adding a spot to an empty frame."); } else { spotGroupNode.add(spot, center, color); } break; } case ModelChangeEvent.FLAG_SPOT_FRAME_CHANGED: { // Where did it belonged? Integer targetFrame = -1; for (final Integer f : blobs.keySet()) { if (blobs.get(f).centers.containsKey(spot)) { targetFrame = f; break; } } if (targetFrame < 0) { System.err.println( "[SpotDisplayer3D] Could not find the frame spot " + spot + " belongs to."); return; } blobs.get(targetFrame).remove(spot); // Sphere location and radius final double[] coords = new double[3]; TMUtils.localize(spot, coords); final Double radius = spot.getFeature(Spot.RADIUS); final double[] pos = new double[] {coords[0], coords[1], coords[2], radius * radiusRatio}; final Point4d center = new Point4d(pos); // Sphere color final Color4f color = new Color4f(spotColorGenerator.color(spot)); color.w = 0; if (null == spotGroupNode) { /* * We then just give up. See above. */ System.err.println( "[SpotDisplayer3D] The TrackMate 3D viewer cannot deal with moving a spot to an empty frame."); } else { spotGroupNode.add(spot, center, color); } break; } case ModelChangeEvent.FLAG_SPOT_MODIFIED: { if (null != spotGroupNode) { spotGroupNode.remove(spot); // Sphere location and radius final double[] coords = new double[3]; TMUtils.localize(spot, coords); final Double radius = spot.getFeature(Spot.RADIUS); final double[] pos = new double[] {coords[0], coords[1], coords[2], radius * radiusRatio}; final Point4d center = new Point4d(pos); // Sphere color final Color4f color = new Color4f(spotColorGenerator.color(spot)); color.w = 0; spotGroupNode.add(spot, center, color); } break; } default: { System.err.println("[SpotDisplayer3D] Unknown spot flag ID: " + spotFlag); } } } /* * Deal with edges */ for (final DefaultWeightedEdge edge : event.getEdges()) { final int edgeFlag = event.getEdgeFlag(edge); switch (edgeFlag) { case ModelChangeEvent.FLAG_EDGE_ADDED: case ModelChangeEvent.FLAG_EDGE_MODIFIED: case ModelChangeEvent.FLAG_EDGE_REMOVED: { if (null == trackNode) { trackContent = makeTrackContent(); universe.removeContent(TRACK_CONTENT_NAME); universe.addContent(trackContent); } else { trackNode.makeMeshes(); updateTrackColors(); } break; } default: { System.err.println("[SpotDisplayer3D] Unknown edge flag ID: " + edgeFlag); } } } break; } default: { System.err.println("[SpotDisplayer3D] Unknown event ID: " + event.getEventID()); } } }