/* * 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.struct.calib; /** * <p>Camera model for omnidirectional single viewpoint sensors [1]. Designed to work with parabolic, * hyperbolic, wide-angle, and spherical sensors. The FOV that this model can describe is dependent * on the mirror parameter ξ. See [1] for details, but for example ξ=0 is a pinhole camera, * ξ=1 can describe fisheye cameras, but a value larger than 1 is limited to 180 degrees due to * multiple points on the unit sphere intersecting the same projection line. This is the same model as * {@link CameraPinholeRadial} except that there is a change in reference frame which allows it to model wider FOV.</p> * * Forward Projection * <ol> * <li>Given a 3D point X=(x,y,z) in camera (mirror) coordinates</li> * <li>Project onto unit sphere X<sub>s</sub>=X/||X||</li> * <li>Change reference frame X'=(x',y',z') = (x<sub>s</sub>,y<sub>s</sub>,z<sub>s</sub> + ξ)</li> * <li>Compute normalized image coordinates (u,v)=(x'/z', y'/z')</li> * <li>Apply radial and tangential distortion (see below)</li> * <li>Convert into pixels p = K*distort([u;v])</li> * </ol> * * <pre> * Camera Projection * [ fx skew cx ] * K = [ 0 fy cy ] * [ 0 0 1 ] * </pre> * * <p> * Radial and Tangential Distortion:<br> * x<sub>d</sub> = x<sub>n</sub> + x<sub>n</sub>[k<sub>1</sub> r<sup>2</sup> + ... + k<sub>n</sub> r<sup>2n</sup>]<br> * dx<sub>u</sub> = [ 2t<sub>1</sub> u v + t<sub>2</sub>(r<sup>2</sup> + 2u<sup>2</sup>)] <br> * dx<sub>v</sub> = [ t<sub>1</sub>(r<sup>2</sup> + 2v<sup>2</sup>) + 2 t<sub>2</sub> u v]<br> * <br> * r<sup>2</sup> = u<sup>2</sup> + v<sup>2</sup><br> * where x<sub>d</sub> is the distorted normalized image coordinates, x<sub>n</sub>=(u,v) is * undistorted normalized image coordinates. * </p> * * <p>NOTE: The only difference from [1] is that skew is used instead of fx*alpha.</p> * <p> * [1] Christopher Mei, and Patrick Rives. "Single view point omnidirectional camera calibration * from planar grids." ICRA 2007. * </p> * @author Peter Abeles */ public class CameraUniversalOmni extends CameraPinhole { /** Mirror offset distance. ξ */ public double mirrorOffset; /** radial distortion parameters: k<sub>1</sub>,...,k<sub>n</sub> */ public double radial[]; /** tangential distortion parameters */ public double t1, t2; /** * Constructor for specifying number of radial distortion * * @param numRadial Number of radial distortion parameters */ public CameraUniversalOmni( int numRadial ) { this.radial = new double[ numRadial ]; } /** * Copy constructor * @param original Model which is to be copied */ public CameraUniversalOmni( CameraUniversalOmni original ) { set(original); } public CameraUniversalOmni fsetMirror( double mirrorOffset ) { this.mirrorOffset = mirrorOffset; return this; } public CameraUniversalOmni fsetRadial(double ...radial ) { this.radial = radial.clone(); return this; } public CameraUniversalOmni fsetTangental(double t1 , double t2) { this.t1 = t1; this.t2 = t2; return this; } /** * Assigns this model to be identical to the passed in model * @param original Model which is to be copied */ public void set( CameraUniversalOmni original ) { super.set(original); this.mirrorOffset = original.mirrorOffset; if( radial.length != original.radial.length ) radial = new double[ original.radial.length ]; System.arraycopy(original.radial,0,radial,0,radial.length); this.t1 = original.t1; this.t2 = original.t2; } public double[] getRadial() { return radial; } public void setRadial(double[] radial) { this.radial = radial; } public double getT1() { return t1; } public void setT1(double t1) { this.t1 = t1; } public double getT2() { return t2; } public void setT2(double t2) { this.t2 = t2; } public double getMirrorOffset() { return mirrorOffset; } public void setMirrorOffset(double mirrorOffset) { this.mirrorOffset = mirrorOffset; } }