/*
* 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.GeoTestingOps;
import boofcv.struct.calib.CameraPinholeRadial;
import boofcv.struct.calib.StereoParameters;
import boofcv.struct.sfm.Stereo2D3D;
import georegression.geometry.ConvertRotation3D_F64;
import georegression.struct.EulerType;
import georegression.struct.point.Point2D_F64;
import georegression.struct.point.Point3D_F64;
import georegression.struct.se.Se3_F64;
import georegression.transform.se.SePointOps_F64;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* @author Peter Abeles
*/
public class CommonStereoMotionNPoint {
protected Random rand = new Random(234);
// the true motion
protected Se3_F64 worldToLeft;
protected Se3_F64 leftToRight;
protected Se3_F64 worldToRight;
// list of points in world reference frame
protected List<Point3D_F64> worldPts;
// list of points is camera reference frame
protected List<Point3D_F64> cameraLeftPts;
protected List<Point3D_F64> cameraRightPts;
// list of point pairs
protected List<Stereo2D3D> pointPose;
protected StereoParameters param;
public CommonStereoMotionNPoint() {
leftToRight = new Se3_F64();
ConvertRotation3D_F64.eulerToMatrix(EulerType.XYZ,0.01,-0.001,0.005,leftToRight.getR());
leftToRight.getT().set(-0.1,0.02,-0.03);
param = new StereoParameters();
param.rightToLeft = leftToRight.invert(null);
param.left = new CameraPinholeRadial(400,500,0.1,160,120,320,240).fsetRadial(0, 0);
param.right = new CameraPinholeRadial(380,505,0.05,165,115,320,240).fsetRadial(0,0);
worldToLeft = new Se3_F64();
ConvertRotation3D_F64.eulerToMatrix(EulerType.XYZ,0.01, 0.04, -0.05, worldToLeft.getR());
worldToLeft.getT().set(0.1,-0.1,0.2);
worldToRight = worldToLeft.concat(leftToRight,null);
}
protected void generateScene(int N, Se3_F64 worldToLeft, boolean planar) {
if( worldToLeft == null ) {
this.worldToLeft = worldToLeft = new Se3_F64();
ConvertRotation3D_F64.eulerToMatrix(EulerType.XYZ,0.1, 1, -0.2, worldToLeft.getR());
worldToLeft.getT().set(-0.3,0.4,1);
} else {
this.worldToLeft = worldToLeft;
}
// randomly generate points in space
if( planar ) {
worldPts = createRandomPlane(rand, 3, N);
} else {
worldPts = GeoTestingOps.randomPoints_F64(-1, 1, -1, 1, 2, 3, N, rand);
}
cameraLeftPts = new ArrayList<>();
cameraRightPts = new ArrayList<>();
// transform points into second camera's reference frame
pointPose = new ArrayList<>();
for(Point3D_F64 p1 : worldPts ) {
Point3D_F64 leftPt = SePointOps_F64.transform(worldToLeft, p1, null);
Point3D_F64 rightPt = SePointOps_F64.transform(leftToRight, leftPt, null);
Point2D_F64 leftObs = new Point2D_F64(leftPt.x/leftPt.z,leftPt.y/leftPt.z);
Point2D_F64 rightObs = new Point2D_F64(rightPt.x/rightPt.z,rightPt.y/rightPt.z);
pointPose.add( new Stereo2D3D(leftObs,rightObs,p1));
cameraLeftPts.add(leftPt);
cameraRightPts.add(rightPt);
}
}
public void addNoise( double sigma ) {
for( Stereo2D3D o : pointPose ) {
o.leftObs.x += rand.nextGaussian()*sigma;
o.leftObs.y += rand.nextGaussian()*sigma;
o.rightObs.x += rand.nextGaussian()*sigma;
o.rightObs.y += rand.nextGaussian()*sigma;
}
}
/**
* Creates a set of random points along the (X,Y) plane
*/
public static List<Point3D_F64> createRandomPlane( Random rand , double d , int N )
{
List<Point3D_F64> ret = new ArrayList<>();
for( int i = 0; i < N; i++ ) {
double x = (rand.nextDouble()-0.5)*2;
double y = (rand.nextDouble()-0.5)*2;
ret.add( new Point3D_F64(x,y,d));
}
return ret;
}
}