All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boofcv.abst.calib.CalibrateStereoPlanar Maven / Gradle / Ivy

/*
 * Copyright (c) 2011-2015, 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.abst.calib;

import boofcv.alg.geo.calibration.Zhang99ParamAll;
import boofcv.struct.calib.IntrinsicParameters;
import boofcv.struct.calib.StereoParameters;
import boofcv.struct.image.ImageFloat32;
import georegression.fitting.se.FitSpecialEuclideanOps_F64;
import georegression.geometry.RotationMatrixGenerator;
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;

/**
 * 

* Given a sequence of observations from a stereo camera compute the intrinsic calibration * of each camera and the extrinsic calibration between the two cameras. A Planar calibration * grid is used, which must be completely visible in all images. *

* *

* Calibration is performed by first independently determining the intrinsic parameters of each camera as well as * their extrinsic parameters relative to the calibration grid. Then the extrinsic parameters between the two cameras * is found by creating two point clouds composed of the calibration points in each camera's view. Then the rigid * body motion is found which transforms one point cloud into the other. *

* *

* See comments in {@link CalibrateMonoPlanar} about when the y-axis should be inverted. *

* * @author Peter Abeles */ public class CalibrateStereoPlanar { // transform from world to camera in each view List viewLeft = new ArrayList(); List viewRight = new ArrayList(); // calibrates the left and right camera image CalibrateMonoPlanar calibLeft; CalibrateMonoPlanar calibRight; List layout; /** * Configures stereo calibration * * @param detector Target detection algorithm. */ public CalibrateStereoPlanar(PlanarCalibrationDetector detector) { calibLeft = new CalibrateMonoPlanar(detector); calibRight = new CalibrateMonoPlanar(detector); layout = detector.getLayout(); } /** * Puts the class into its initial state. */ public void reset() { viewLeft.clear(); viewRight.clear(); calibLeft.reset(); calibRight.reset(); } /** * Specify calibration assumptions. * * @param assumeZeroSkew If true zero skew is assumed. * @param numRadialParam Number of radial parameters * @param includeTangential If true it will estimate tangential distortion parameters. */ public void configure( boolean assumeZeroSkew , int numRadialParam , boolean includeTangential ) { calibLeft.configure(assumeZeroSkew,numRadialParam,includeTangential); calibRight.configure(assumeZeroSkew,numRadialParam,includeTangential); } /** * Adds a pair of images that observed the same target. * * @param left Image of left target. * @param right Image of right target. */ public boolean addPair( ImageFloat32 left , ImageFloat32 right ) { if( !calibLeft.addImage(left) ) return false; if( !calibRight.addImage(right ) ) { calibLeft.removeLatestImage(); return false; } return true; } /** * Compute stereo calibration parameters * * @return Stereo calibration parameters */ public StereoParameters process() { // calibrate left and right cameras IntrinsicParameters leftParam = calibrateMono(calibLeft,viewLeft); IntrinsicParameters rightParam = calibrateMono(calibRight,viewRight); // fit motion from right to left Se3_F64 rightToLeft = computeRightToLeft(); return new StereoParameters(leftParam,rightParam,rightToLeft); } /** * Compute intrinsic calibration for one of the cameras */ private IntrinsicParameters calibrateMono( CalibrateMonoPlanar calib , List location ) { IntrinsicParameters intrinsic = calib.process(); Zhang99ParamAll zhangParam = calib.getZhangParam(); for( Zhang99ParamAll.View v : zhangParam.views ) { Se3_F64 pose = new Se3_F64(); RotationMatrixGenerator.rodriguesToMatrix(v.rotation,pose.getR()); pose.getT().set(v.T); location.add(pose); } return intrinsic; } /** * Creates two 3D point clouds for the left and right camera using the known calibration points and camera * calibration. Then find the optimal rigid body transform going from the right to left views. * * @return Transform from right to left view. */ private Se3_F64 computeRightToLeft() { // location of points in the world coordinate system List points2D = layout; List points3D = new ArrayList(); for( Point2D_F64 p : points2D ) { points3D.add( new Point3D_F64(p.x,p.y,0)); } // create point cloud in each view List left = new ArrayList(); List right = new ArrayList(); for( int i = 0; i < viewLeft.size(); i++ ) { Se3_F64 worldToLeft = viewLeft.get(i); Se3_F64 worldToRight = viewRight.get(i); // These points can really be arbitrary and don't have to be target points for( Point3D_F64 p : points3D ) { Point3D_F64 l = SePointOps_F64.transform(worldToLeft, p, null); Point3D_F64 r = SePointOps_F64.transform(worldToRight, p, null); left.add(l); right.add(r); } } // find the transform from right to left cameras return FitSpecialEuclideanOps_F64.fitPoints3D(right,left); } public CalibrateMonoPlanar getCalibLeft() { return calibLeft; } public CalibrateMonoPlanar getCalibRight() { return calibRight; } public void printStatistics() { System.out.println("********** LEFT ************"); calibLeft.printStatistics(); System.out.println("********** RIGHT ************"); calibRight.printStatistics(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy