@Test
  public void incorrectInput() {
    init(30, false);

    // compute true essential matrix
    DenseMatrix64F E = MultiViewOps.createEssential(worldToCamera.getR(), worldToCamera.getT());

    // create an alternative incorrect matrix
    Vector3D_F64 T = worldToCamera.getT().copy();
    T.x += 0.1;
    DenseMatrix64F Emod = MultiViewOps.createEssential(worldToCamera.getR(), T);

    ModelFitter<DenseMatrix64F, AssociatedPair> alg = createAlgorithm();

    // compute and compare results
    assertTrue(alg.fitModel(pairs, Emod, found));

    // normalize to allow comparison
    CommonOps.divide(E.get(2, 2), E);
    CommonOps.divide(Emod.get(2, 2), Emod);
    CommonOps.divide(found.get(2, 2), found);

    double error0 = 0;
    double error1 = 0;

    // very crude error metric
    for (int i = 0; i < 9; i++) {
      error0 += Math.abs(Emod.data[i] - E.data[i]);
      error1 += Math.abs(found.data[i] - E.data[i]);
    }

    //		System.out.println("error "+error1+"   other "+error0);
    assertTrue(error1 < error0);
  }
  /** H0 = H*M P=[M|m] from canonical camera */
  private SimpleMatrix computeHZero(DenseMatrix64F F, Point3D_F64 e2, SimpleMatrix H) {

    Vector3D_F64 v = new Vector3D_F64(.1, 0.5, .2);

    // need to make sure M is not singular for this technique to work
    SimpleMatrix P = SimpleMatrix.wrap(MultiViewOps.canonicalCamera(F, e2, v, 1));

    SimpleMatrix M = P.extractMatrix(0, 3, 0, 3);

    return H.mult(M);
  }
  @Test
  public void perfectInput() {
    init(30, false);

    // compute true essential matrix
    DenseMatrix64F E = MultiViewOps.createEssential(worldToCamera.getR(), worldToCamera.getT());

    ModelFitter<DenseMatrix64F, AssociatedPair> alg = createAlgorithm();

    // give it the perfect matrix and see if it screwed it up
    assertTrue(alg.fitModel(pairs, E, found));

    // normalize so that they are the same
    CommonOps.divide(E.get(2, 2), E);
    CommonOps.divide(found.get(2, 2), found);

    assertTrue(MatrixFeatures.isEquals(E, found, 1e-8));
  }
  /**
   * Compute rectification transforms for the stereo pair given a fundamental matrix and its
   * observations.
   *
   * @param F Fundamental matrix
   * @param observations Observations used to compute F
   * @param width Width of first image.
   * @param height Height of first image.
   */
  public void process(DenseMatrix64F F, List<AssociatedPair> observations, int width, int height) {

    int centerX = width / 2;
    int centerY = height / 2;

    MultiViewOps.extractEpipoles(F, epipole1, epipole2);
    checkEpipoleInside(width, height);

    // compute the transform H which will send epipole2 to infinity
    SimpleMatrix R = rotateEpipole(epipole2, centerX, centerY);
    SimpleMatrix T = translateToOrigin(centerX, centerY);
    SimpleMatrix G = computeG(epipole2, centerX, centerY);

    SimpleMatrix H = G.mult(R).mult(T);

    // Find the two matching transforms
    SimpleMatrix Hzero = computeHZero(F, epipole2, H);

    SimpleMatrix Ha = computeAffineH(observations, H.getMatrix(), Hzero.getMatrix());

    rect1.set(Ha.mult(Hzero).getMatrix());
    rect2.set(H.getMatrix());
  }