docs: protected boolean estimate( Quadrilateral_F64 cornersPixels ,
  								Quadrilateral_F64 cornersNorm ,
  								Se3_F64 foundFiducialToCamera ) {
  		// put it into a list to simplify algorithms
  		listObs.clear();
  		listObs.add( cornersPixels.a );
  		listObs.add( cornersPixels.b );
  		listObs.add( cornersPixels.c );
  		listObs.add( cornersPixels.d );
  
  		// convert observations into normalized image coordinates which P3P requires
  		points.get(0).observation.set(cornersNorm.a);
  		points.get(1).observation.set(cornersNorm.b);
  		points.get(2).observation.set(cornersNorm.c);
  		points.get(3).observation.set(cornersNorm.d);
  
  		// estimate pose using all permutations
  		bestError = Double.MAX_VALUE;
  		estimateP3P(0);
  		estimateP3P(1);
  		estimateP3P(2);
  		estimateP3P(3);
  
  		if( bestError == Double.MAX_VALUE )
  			return false;
  
  		// refine the best estimate
  		inputP3P.clear();
  		for( int i = 0; i < 4; i++ ) {
  			inputP3P.add( points.get(i) );
  		}
  
  		// got poor or horrible solution the first way, let's try it with EPNP
  		// and see if it does better
  		if( bestError > 2 ) {
  			if (epnp.process(inputP3P, foundEPNP)) {
  				if( foundEPNP.T.z > 0 ) {
  					double error = computeErrors(foundEPNP);
  //					System.out.println("   error EPNP = "+error);
  					if (error < bestError) {
  						bestPose.set(foundEPNP);
  					}
  				}
  			}
  		}
  
  		if( !refine.fitModel(inputP3P,bestPose,foundFiducialToCamera) ) {
  			// us the previous estimate instead
  			foundFiducialToCamera.set(bestPose);
  			return true;
  		}
  
  		return true;
  	}