예제 #1
0
 /**
  * Overrides Step getBounds method.
  *
  * @param trackerPanel the tracker panel drawing the step
  * @return the bounding rectangle
  */
 public Rectangle getBounds(TrackerPanel trackerPanel) {
   Rectangle bounds = getMark(trackerPanel).getBounds(false);
   Rectangle layoutRect = layoutBounds.get(trackerPanel);
   if (layoutRect != null) {
     bounds.add(layoutRect);
   }
   return bounds;
 }
예제 #2
0
 /**
  * Finds the Interactive located at the specified pixel position.
  *
  * @param panel the drawing panel
  * @param xpix the x pixel position
  * @param ypix the y pixel position
  * @return the TPoint that is hit, or null
  */
 public Interactive findInteractive(DrawingPanel panel, int xpix, int ypix) {
   boolean highlighted = (track.trackerPanel.getFrameNumber() == getFrameNumber());
   AutoTracker autoTracker = track.trackerPanel.getAutoTracker();
   TrackerPanel trackerPanel = (TrackerPanel) panel;
   setHitRectCenter(xpix, ypix);
   for (int i = 0; i < points.length; i++) {
     if (points[i] == null || Double.isNaN(points[i].getX())) continue;
     if (hitRect.contains(points[i].getScreenPosition(trackerPanel))) {
       if (highlighted && autoTracker.isDrawingKeyFrameFor(track, i)) return null;
       return points[i];
     }
   }
   return null;
 }
예제 #3
0
  /**
   * Overrides Step getMark method.
   *
   * @param trackerPanel the tracker panel
   * @return the mark
   */
  protected Mark getMark(TrackerPanel trackerPanel) {
    Mark mark = marks.get(trackerPanel);
    TPoint selection = null;
    if (mark == null) {
      selection = trackerPanel.getSelectedPoint();
      Point p = null; // draws this step as "selected" shape if not null
      valid = true; // true if step is not NaN
      for (int n = 0; n < points.length; n++) {
        if (!valid) continue;
        // determine if point is valid (ie not NaN)
        valid = valid && !Double.isNaN(points[n].getX()) && !Double.isNaN(points[n].getY());
        screenPoints[n] = points[n].getScreenPosition(trackerPanel);
        // step is "selected" if trackerPanel selectedPoint is position or selectedSteps contains
        // this step
        if (valid && (selection == points[n] || trackerPanel.selectedSteps.contains(this))) {
          p = screenPoints[n];
        }
      }
      if (p == null) {
        if (footprint instanceof PositionVectorFootprint) {
          twoPoints[0] = screenPoints[0];
          twoPoints[1] = trackerPanel.getSnapPoint().getScreenPosition(trackerPanel);
          mark = footprint.getMark(twoPoints);
        } else mark = footprint.getMark(screenPoints);
      } else {
        transform.setToTranslation(p.x, p.y);
        int scale = FontSizer.getIntegerFactor();
        if (scale > 1) {
          transform.scale(scale, scale);
        }
        final Color color = footprint.getColor();
        final Shape selectedShape = transform.createTransformedShape(selectionShape);
        mark =
            new Mark() {
              public void draw(Graphics2D g, boolean highlighted) {
                g.setRenderingHint(
                    RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                Paint gpaint = g.getPaint();
                g.setPaint(color);
                g.fill(selectedShape);
                g.setPaint(gpaint);
              }

              public Rectangle getBounds(boolean highlighted) {
                return selectedShape.getBounds();
              }
            };
      }
      final Mark theMark = mark;
      mark =
          new Mark() {
            public void draw(Graphics2D g, boolean highlighted) {
              if (!valid) {
                return;
              }
              theMark.draw(g, highlighted);
            }

            public Rectangle getBounds(boolean highlighted) {
              return theMark.getBounds(highlighted);
            }
          };
      marks.put(trackerPanel, mark);
      // get new text layout
      String s = ""; // $NON-NLS-1$
      VideoClip clip = trackerPanel.getPlayer().getVideoClip();
      if (clip.getStepCount() != 1) {
        s += clip.frameToStep(getFrameNumber());
      }
      if (s.length() == 0) s = " "; // $NON-NLS-1$
      TextLayout layout = new TextLayout(s, textLayoutFont, frc);
      textLayouts.put(trackerPanel, layout);
      // get layout position (bottom left corner of text)
      p = getLayoutPosition(trackerPanel);
      Rectangle bounds = layoutBounds.get(trackerPanel);
      if (bounds == null) {
        bounds = new Rectangle();
        layoutBounds.put(trackerPanel, bounds);
      }
      Rectangle2D rect = layout.getBounds();
      // set bounds (top left corner and size)
      bounds.setRect(p.x, p.y - rect.getHeight(), rect.getWidth(), rect.getHeight());
    }
    return mark;
  }
예제 #4
0
 /**
  * Centers the hit testing rectangle on the specified screen point.
  *
  * @param xpix the x pixel position
  * @param ypix the y pixel position
  */
 protected void setHitRectCenter(int xpix, int ypix) {
   hitRect.setLocation(xpix - hitRect.width / 2, ypix - hitRect.height / 2);
 }
  /**
   * Gets the template location at which the best match occurs in a rectangle and along a line. May
   * return null.
   *
   * @param target the image to search
   * @param searchRect the rectangle to search within the target image
   * @param x0 the x-component of a point on the line
   * @param y0 the y-component of a point on the line
   * @param slope the slope of the line
   * @param spread the spread of the line (line width = 1+2*spread)
   * @return the optimized template location of the best match, if any
   */
  public TPoint getMatchLocation(
      BufferedImage target, Rectangle searchRect, double x0, double y0, double theta, int spread) {
    wTarget = target.getWidth();
    hTarget = target.getHeight();
    // determine insets needed to accommodate template
    int left = wTemplate / 2, right = left;
    if (wTemplate % 2 > 0) right++;
    int top = hTemplate / 2, bottom = top;
    if (hTemplate % 2 > 0) bottom++;

    // trim search rectangle if necessary
    searchRect.x = Math.max(left, Math.min(wTarget - right, searchRect.x));
    searchRect.y = Math.max(top, Math.min(hTarget - bottom, searchRect.y));
    searchRect.width = Math.min(wTarget - searchRect.x - right, searchRect.width);
    searchRect.height = Math.min(hTarget - searchRect.y - bottom, searchRect.height);
    if (searchRect.width <= 0 || searchRect.height <= 0) {
      peakHeight = Double.NaN;
      peakWidth = Double.NaN;
      return null;
    }
    // set up test pixels to search (rectangle plus template)
    int xMin = Math.max(0, searchRect.x - left);
    int xMax = Math.min(wTarget, searchRect.x + searchRect.width + right);
    int yMin = Math.max(0, searchRect.y - top);
    int yMax = Math.min(hTarget, searchRect.y + searchRect.height + bottom);
    wTest = xMax - xMin;
    hTest = yMax - yMin;
    if (target.getType() != BufferedImage.TYPE_INT_RGB) {
      BufferedImage image = new BufferedImage(wTarget, hTarget, BufferedImage.TYPE_INT_RGB);
      image.createGraphics().drawImage(target, 0, 0, null);
      target = image;
    }
    targetPixels = new int[wTest * hTest];
    target.getRaster().getDataElements(xMin, yMin, wTest, hTest, targetPixels);
    // get the points to search along the line
    ArrayList<Point2D> searchPts = getSearchPoints(searchRect, x0, y0, theta);
    if (searchPts == null) {
      peakHeight = Double.NaN;
      peakWidth = Double.NaN;
      return null;
    }
    // collect differences in a map as they are measured
    HashMap<Point2D, Double> diffs = new HashMap<Point2D, Double>();
    // find the point with the minimum difference from template
    double matchDiff = largeNumber; // larger than typical differences
    int xMatch = 0, yMatch = 0;
    double avgDiff = 0;
    Point2D matchPt = null;
    for (Point2D pt : searchPts) {
      int x = (int) pt.getX();
      int y = (int) pt.getY();
      double diff = getDifferenceAtTestPoint(x, y);
      diffs.put(pt, diff);
      avgDiff += diff;
      if (diff < matchDiff) {
        matchDiff = diff;
        xMatch = x;
        yMatch = y;
        matchPt = pt;
      }
    }
    avgDiff /= searchPts.size();
    peakHeight = avgDiff / matchDiff - 1;
    peakWidth = Double.NaN;
    double dl = 0;
    int matchIndex = searchPts.indexOf(matchPt);

    // if match is not exact, fit a Gaussian and find peak
    if (!Double.isInfinite(peakHeight) && matchIndex > 0 && matchIndex < searchPts.size() - 1) {
      // fill data arrays
      Point2D pt = searchPts.get(matchIndex - 1);
      double diff = diffs.get(pt);
      xValues[0] = -pt.distance(matchPt);
      yValues[0] = avgDiff / diff - 1;
      xValues[1] = 0;
      yValues[1] = peakHeight;
      pt = searchPts.get(matchIndex + 1);
      diff = diffs.get(pt);
      xValues[2] = pt.distance(matchPt);
      yValues[2] = avgDiff / diff - 1;

      // determine approximate offset (dl) and width (w) values
      double pull = -xValues[0] / (yValues[1] - yValues[0]);
      double push = xValues[2] / (yValues[1] - yValues[2]);
      if (Double.isNaN(pull)) pull = LARGE_NUMBER;
      if (Double.isNaN(push)) push = LARGE_NUMBER;
      dl = 0.3 * (xValues[2] - xValues[0]) * (push - pull) / (push + pull);
      double ratio = dl > 0 ? peakHeight / yValues[0] : peakHeight / yValues[2];
      double w = dl > 0 ? dl - xValues[0] : dl - xValues[2];
      w = w * w / Math.log(ratio);

      // set parameters and fit to x data
      dataset.clear();
      dataset.append(xValues, yValues);
      double rmsDev = 1;
      for (int k = 0; k < 3; k++) {
        double c = k == 0 ? w : k == 1 ? w / 3 : w * 3;
        f.setParameterValue(0, peakHeight);
        f.setParameterValue(1, dl);
        f.setParameterValue(2, c);
        rmsDev = fitter.fit(f);
        if (rmsDev < 0.01) { // fitter succeeded (3-point fit should be exact)	
          dl = f.getParameterValue(1);
          peakWidth = f.getParameterValue(2);
          break;
        }
      }
    }
    double dx = dl * Math.cos(theta);
    double dy = dl * Math.sin(theta);
    double xImage = xMatch + searchRect.x - left - trimLeft + dx;
    double yImage = yMatch + searchRect.y - top - trimTop + dy;
    return new TPoint(xImage, yImage);
  }
  /**
   * Gets the template location at which the best match occurs in a rectangle. May return null.
   *
   * @param target the image to search
   * @param searchRect the rectangle to search within the target image
   * @return the optimized template location at which the best match, if any, is found
   */
  public TPoint getMatchLocation(BufferedImage target, Rectangle searchRect) {
    wTarget = target.getWidth();
    hTarget = target.getHeight();
    // determine insets needed to accommodate template
    int left = wTemplate / 2, right = left;
    if (wTemplate % 2 > 0) right++;
    int top = hTemplate / 2, bottom = top;
    if (hTemplate % 2 > 0) bottom++;
    // trim search rectangle if necessary
    searchRect.x = Math.max(left, Math.min(wTarget - right, searchRect.x));
    searchRect.y = Math.max(top, Math.min(hTarget - bottom, searchRect.y));
    searchRect.width = Math.min(wTarget - searchRect.x - right, searchRect.width);
    searchRect.height = Math.min(hTarget - searchRect.y - bottom, searchRect.height);
    if (searchRect.width <= 0 || searchRect.height <= 0) {
      peakHeight = Double.NaN;
      peakWidth = Double.NaN;
      return null;
    }
    // set up test pixels to search (rectangle plus template)
    int xMin = Math.max(0, searchRect.x - left);
    int xMax = Math.min(wTarget, searchRect.x + searchRect.width + right);
    int yMin = Math.max(0, searchRect.y - top);
    int yMax = Math.min(hTarget, searchRect.y + searchRect.height + bottom);
    wTest = xMax - xMin;
    hTest = yMax - yMin;
    if (target.getType() != BufferedImage.TYPE_INT_RGB) {
      BufferedImage image = new BufferedImage(wTarget, hTarget, BufferedImage.TYPE_INT_RGB);
      image.createGraphics().drawImage(target, 0, 0, null);
      target = image;
    }
    targetPixels = new int[wTest * hTest];
    target.getRaster().getDataElements(xMin, yMin, wTest, hTest, targetPixels);
    // find the rectangle point with the minimum difference
    double matchDiff = largeNumber; // larger than typical differences
    int xMatch = 0, yMatch = 0;
    double avgDiff = 0;
    for (int x = 0; x <= searchRect.width; x++) {
      for (int y = 0; y <= searchRect.height; y++) {
        double diff = getDifferenceAtTestPoint(x, y);
        avgDiff += diff;
        if (diff < matchDiff) {
          matchDiff = diff;
          xMatch = x;
          yMatch = y;
        }
      }
    }
    avgDiff /= (searchRect.width * searchRect.height);
    peakHeight = avgDiff / matchDiff - 1;
    peakWidth = Double.NaN;
    double dx = 0, dy = 0;
    // if match is not exact, fit a Gaussian and find peak
    if (!Double.isInfinite(peakHeight)) {
      // fill data arrays
      xValues[1] = yValues[1] = peakHeight;
      for (int i = -1; i < 2; i++) {
        if (i == 0) continue;
        double diff = getDifferenceAtTestPoint(xMatch + i, yMatch);
        xValues[i + 1] = avgDiff / diff - 1;
        diff = getDifferenceAtTestPoint(xMatch, yMatch + i);
        yValues[i + 1] = avgDiff / diff - 1;
      }
      // estimate peakHeight = peak of gaussian
      // estimate offset dx of gaussian
      double pull = 1 / (xValues[1] - xValues[0]);
      double push = 1 / (xValues[1] - xValues[2]);
      if (Double.isNaN(pull)) pull = LARGE_NUMBER;
      if (Double.isNaN(push)) push = LARGE_NUMBER;
      dx = 0.6 * (push - pull) / (push + pull);
      // estimate width wx of gaussian
      double ratio = dx > 0 ? peakHeight / xValues[0] : peakHeight / xValues[2];
      double wx = dx > 0 ? dx + 1 : dx - 1;
      wx = wx * wx / Math.log(ratio);
      // estimate offset dy of gaussian
      pull = 1 / (yValues[1] - yValues[0]);
      push = 1 / (yValues[1] - yValues[2]);
      if (Double.isNaN(pull)) pull = LARGE_NUMBER;
      if (Double.isNaN(push)) push = LARGE_NUMBER;
      dy = 0.6 * (push - pull) / (push + pull);
      // estimate width wy of gaussian
      ratio = dy > 0 ? peakHeight / yValues[0] : peakHeight / yValues[2];
      double wy = dy > 0 ? dy + 1 : dy - 1;
      wy = wy * wy / Math.log(ratio);

      // set x parameters and fit to x data
      dataset.clear();
      dataset.append(pixelOffsets, xValues);
      double rmsDev = 1;
      for (int k = 0; k < 3; k++) {
        double c = k == 0 ? wx : k == 1 ? wx / 3 : wx * 3;
        f.setParameterValue(0, peakHeight);
        f.setParameterValue(1, dx);
        f.setParameterValue(2, c);
        rmsDev = fitter.fit(f);
        if (rmsDev < 0.01) { // fitter succeeded (3-point fit should be exact)	
          dx = f.getParameterValue(1);
          peakWidth = f.getParameterValue(2);
          break;
        }
      }
      if (!Double.isNaN(peakWidth)) {
        // set y parameters and fit to y data
        dataset.clear();
        dataset.append(pixelOffsets, yValues);
        for (int k = 0; k < 3; k++) {
          double c = k == 0 ? wy : k == 1 ? wy / 3 : wy * 3;
          f.setParameterValue(0, peakHeight);
          f.setParameterValue(1, dx);
          f.setParameterValue(2, c);
          rmsDev = fitter.fit(f);
          if (rmsDev < 0.01) { // fitter succeeded (3-point fit should be exact)	
            dy = f.getParameterValue(1);
            peakWidth = (peakWidth + f.getParameterValue(2)) / 2;
            break;
          }
        }
        if (rmsDev > 0.01) peakWidth = Double.NaN;
      }
    }
    double xImage = xMatch + searchRect.x - left - trimLeft + dx;
    double yImage = yMatch + searchRect.y - top - trimTop + dy;
    return new TPoint(xImage, yImage);
  }