/* * Copyright (c) 2011-2016, Peter Abeles. All Rights Reserved. * * This file is part of BoofCV (http://boofcv.org). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package boofcv.alg.geo.pose; import boofcv.alg.geo.PerspectiveOps; import boofcv.struct.calib.StereoParameters; import boofcv.struct.sfm.Stereo2D3D; import georegression.struct.point.Point2D_F64; import georegression.struct.point.Point3D_F64; import georegression.struct.se.Se3_F64; import org.ejml.data.DenseMatrix64F; import org.junit.Test; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * @author Peter Abeles */ public class TestPnPStereoDistanceReprojectionSq extends CommonStereoMotionNPoint{ @Test public void checkErrorSingle() { // Point location in world frame Point3D_F64 X = new Point3D_F64(0.1,-0.04,2.3); DenseMatrix64F K_left = PerspectiveOps.calibrationMatrix(param.left,null); DenseMatrix64F K_right = PerspectiveOps.calibrationMatrix(param.right,null); // errors double deltaX0 = 0.1; double deltaY0 = -0.2; double deltaX1 = -0.3; double deltaY1 = 0.05; // create a noisy observed Point2D_F64 obsLeft = PerspectiveOps.renderPixel(worldToLeft, K_left, X); obsLeft.x += deltaX0; obsLeft.y += deltaY0; Point2D_F64 obsRight = PerspectiveOps.renderPixel(worldToRight, K_right, X); obsRight.x += deltaX1; obsRight.y += deltaY1; // convert to normalized image coordinates PerspectiveOps.convertPixelToNorm(K_left,obsLeft,obsLeft); PerspectiveOps.convertPixelToNorm(K_right,obsRight,obsRight); PnPStereoDistanceReprojectionSq alg = new PnPStereoDistanceReprojectionSq(); alg.setStereoParameters(param); alg.setModel(worldToLeft); double found = alg.computeDistance(new Stereo2D3D(obsLeft,obsRight,X)); double expected = deltaX0*deltaX0 + deltaY0*deltaY0 + deltaX1*deltaX1 + deltaY1*deltaY1; assertEquals(expected,found,1e-8); } /** * Have the observation be behind the left camera but not the right */ @Test public void checkBehindCamera_Left() { checkBehind(-0.1,-0.05); } /** * Have the observation be behind the right camera but not the left */ @Test public void checkBehindCamera_Right() { checkBehind(0.1,0.05); } public void checkBehind( double Tz , double Pz ) { // Point location in world frame Point3D_F64 X = new Point3D_F64(0.1,-0.04,Pz); DenseMatrix64F K_left = PerspectiveOps.calibrationMatrix(param.left,null); DenseMatrix64F K_right = PerspectiveOps.calibrationMatrix(param.right,null); // create a noisy observed Point2D_F64 obsLeft = PerspectiveOps.renderPixel(worldToLeft, K_left, X); Point2D_F64 obsRight = PerspectiveOps.renderPixel(worldToRight, K_right, X); // convert to normalized image coordinates PerspectiveOps.convertPixelToNorm(K_left,obsLeft,obsLeft); PerspectiveOps.convertPixelToNorm(K_right,obsRight,obsRight); PnPStereoDistanceReprojectionSq alg = new PnPStereoDistanceReprojectionSq(); StereoParameters param = new StereoParameters(this.param.left,this.param.right,new Se3_F64()); param.rightToLeft.getT().set(0.1,0,Tz); alg.setStereoParameters(param); alg.setModel(new Se3_F64()); double found = alg.computeDistance(new Stereo2D3D(obsLeft,obsRight,X)); assertTrue(Double.MAX_VALUE == found); } @Test public void checkErrorArray() { DenseMatrix64F K_left = PerspectiveOps.calibrationMatrix(param.left,null); DenseMatrix64F K_right = PerspectiveOps.calibrationMatrix(param.right,null); PnPStereoDistanceReprojectionSq alg = new PnPStereoDistanceReprojectionSq(); alg.setStereoParameters(param); alg.setModel(worldToLeft); int N = 10; double expected[] = new double[N*4]; List<Stereo2D3D> obs = new ArrayList<>(); for( int i = 0; i < N; i++ ) { // Point location in world frame Point3D_F64 X = new Point3D_F64(rand.nextGaussian(),rand.nextGaussian(),2.3); // create a noisy observed Point2D_F64 obsLeft = PerspectiveOps.renderPixel(worldToLeft, K_left, X); obsLeft.x += rand.nextGaussian()*0.05; obsLeft.y += rand.nextGaussian()*0.05; Point2D_F64 obsRight = PerspectiveOps.renderPixel(worldToRight, K_right, X); obsRight.x += rand.nextGaussian()*0.05; obsRight.y += rand.nextGaussian()*0.05; // convert to normalized image coordinates PerspectiveOps.convertPixelToNorm(K_left,obsLeft,obsLeft); PerspectiveOps.convertPixelToNorm(K_right,obsRight,obsRight); Stereo2D3D p = new Stereo2D3D(obsLeft,obsRight,X); expected[i] = alg.computeDistance(p); obs.add( p ); } double found[] = new double[ N ]; alg.computeDistance(obs,found); for( int i = 0; i < N; i++ ) assertEquals(expected[i],found[i],1e-8); } }