/**
   * Get standard deviation of the image
   *
   * @param img input image
   * @return sigma
   */
  protected double getStdDev(MTBImage img) {

    int sizeStack = img.getSizeStack();
    int sizeX = img.getSizeX();
    int sizeY = img.getSizeY();

    double val;
    double mu = 0.0;
    double mu2 = 0.0;
    double N = 0.0;
    double sigma;

    for (int i = 0; i < sizeStack; i++) {
      img.setCurrentSliceIndex(i);

      for (int y = 0; y < sizeY; y++) {
        for (int x = 0; x < sizeX; x++) {
          val = img.getValueDouble(x, y);
          mu += val;
          mu2 += val * val;
          N++;
        }
      }
    }

    mu /= N;
    mu2 /= N;
    sigma = Math.sqrt(mu2 - mu * mu);

    return sigma;
  }
  /**
   * Denoise wavelet coefficients using Jeffrey's noninformative prior for a given sigma of noise
   *
   * @param img input image
   * @param sigma sigma of noise
   */
  protected void denoise(MTBImage img, double sigma) {
    int sizeStack = img.getSizeStack();
    int sizeX = img.getSizeX();
    int sizeY = img.getSizeY();

    double s2 = 3.0 * sigma * sigma;
    double val, val2;
    for (int i = 0; i < sizeStack; i++) {
      img.setCurrentSliceIndex(i);

      for (int y = 0; y < sizeY; y++) {
        for (int x = 0; x < sizeX; x++) {
          val = img.getValueDouble(x, y);

          val2 = (val * val - s2);

          if (val2 < 0.0) val2 = 0.0;

          if (val != 0.0) img.putValueDouble(x, y, val2 / val);
          else img.putValueDouble(x, y, 0.0);
        }
      }
    }
    img.setCurrentSliceIndex(0);
  }
  /**
   * @param inImg
   * @param trajectories
   */
  public TrackVisualizer(MTBImage inImg, Vector<Trajectory2D> trajectories) {
    this.inImg = inImg;
    this.trajectories = trajectories;

    this.sizeX = inImg.getSizeX();
    this.sizeY = inImg.getSizeY();
    this.sizeT = inImg.getSizeT();
  }