Exemple #1
0
  /**
   * 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());
        }
    }
  }