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

com.irurueta.ar.calibration.CameraCalibratorSample Maven / Gradle / Ivy

There is a newer version: 1.3.0
Show newest version
/*
 * Copyright (C) 2015 Alberto Irurueta Carro ([email protected])
 *
 * 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 com.irurueta.ar.calibration;

import com.irurueta.algebra.AlgebraException;
import com.irurueta.ar.calibration.estimators.CameraPoseEstimator;
import com.irurueta.geometry.*;
import com.irurueta.geometry.estimators.LockedException;
import com.irurueta.geometry.estimators.NotReadyException;
import com.irurueta.geometry.estimators.PointCorrespondenceProjectiveTransformation2DRobustEstimator;
import com.irurueta.numerical.robust.RobustEstimatorException;
import com.irurueta.numerical.robust.RobustEstimatorMethod;

import java.util.List;

/**
 * Contains data obtained from a single picture using the camera.
 * Several samples can be used to calibrate the camera. The more samples are
 * used, typically the better the results.
 */
public class CameraCalibratorSample {
    /**
     * Minimum number of sampled markers that must be provided to estimate
     * an homography.
     */
    public static final int MIN_REQUIRED_SAMPLED_MARKERS = 4;

    /**
     * Pattern used for camera calibration. Each pattern contains a unique
     * combination of 2D points that must be sampled using the camera to be
     * calibrated.
     */
    private Pattern2D mPattern;

    /**
     * Contains the sampled markers taken from a single picture using the
     * camera.
     */
    private List mSampledMarkers;

    /**
     * Contains the sampled markers of the pattern but accounting for the
     * distortion effect introduced by the camera lens.
     */
    private List mUndistortedMarkers;

    /**
     * Quality scores of sampled markers. These can be used during
     * homography estimation if a robust estimation method such as PROSAC or
     * PROMedS is used.
     */
    private double[] mSampledMarkersQualityScores;

    /**
     * 2D homography estimated from the sampled pattern points respect to
     * the ideal ones using a single picture.
     */
    private Transformation2D mHomography;

    /**
     * Estimated camera rotation. This contains the amount of rotation
     * respect to the plane formed by the pattern markers. This is obtained
     * once the IAC of the camera is estimated.
     */
    private Rotation3D mRotation;

    /**
     * Estimated camera center. This determines the amount of translation
     * of the camera respect to the plane formed by the pattern markers. This
     * is obtained once the IAC of the camera is estimated.
     */
    private Point3D mCameraCenter;

    /**
     * Estimated camera. Estimated pinhole camera taking into account
     * estimated intrinsic parameters and amount of rotation and translation
     * respect to the plane formed by the pattern markers, but without
     * taking into account any radial distortion introduced by the lens.
     */
    private PinholeCamera mCamera;

    /**
     * Constructor.
     */
    public CameraCalibratorSample() {
    }

    /**
     * Constructor.
     *
     * @param sampledMarkers sampled markers of the pattern taken from a
     *                       single picture using the camera.
     * @throws IllegalArgumentException if provided number of sampled
     *                                  markers is smaller than the required minimum (4) to estimate an
     *                                  homography.
     */
    public CameraCalibratorSample(final List sampledMarkers) {
        setSampledMarkers(sampledMarkers);
    }

    /**
     * Constructor.
     *
     * @param sampledMarkers              sampled markers of the pattern taken from a
     *                                    single picture using the camera.
     * @param sampledMarkersQualityScores quality scores associated to
     *                                    each provided point for each sampled marker. The higher the value the
     *                                    better the quality assigned to that point.
     * @throws IllegalArgumentException if size of sampled markers or
     *                                  quality scores is smaller than the required minimum (4) to estimate
     *                                  an homography, or if their sizes do not match.
     */
    public CameraCalibratorSample(final List sampledMarkers,
                                  final double[] sampledMarkersQualityScores) {
        if (sampledMarkers.size() != sampledMarkersQualityScores.length) {
            throw new IllegalArgumentException();
        }

        setSampledMarkers(sampledMarkers);
        setSampledMarkersQualityScores(sampledMarkersQualityScores);
    }

    /**
     * Constructor.
     *
     * @param pattern        2D pattern to use for calibration.
     * @param sampledMarkers sampled markers of the pattern taken from a
     *                       single picture using the camera.
     * @throws IllegalArgumentException if provided number of sampled
     *                                  markers is smaller than the required minimum (4) to estimate an
     *                                  homography.
     */
    public CameraCalibratorSample(final Pattern2D pattern,
                                  final List sampledMarkers) {
        mPattern = pattern;
        setSampledMarkers(sampledMarkers);
    }

    /**
     * Constructor.
     *
     * @param pattern                     2D pattern to use for calibration.
     * @param sampledMarkers              sampled markers of the pattern taken from a
     *                                    single picture using the camera.
     * @param sampledMarkersQualityScores quality scores associated to
     *                                    each provided point for each sampled marker. The higher the value the
     *                                    better the quality assigned to that point.
     * @throws IllegalArgumentException if size of sampled markers or
     *                                  quality scores is smaller than the required minimum (4) to estimate
     *                                  an homography, or if their sizes do not match.
     */
    public CameraCalibratorSample(final Pattern2D pattern,
                                  final List sampledMarkers, double[] sampledMarkersQualityScores) {
        if (sampledMarkers.size() != sampledMarkersQualityScores.length) {
            throw new IllegalArgumentException();
        }

        mPattern = pattern;
        setSampledMarkers(sampledMarkers);
        setSampledMarkersQualityScores(sampledMarkersQualityScores);
    }

    /**
     * Returns pattern used for camera calibration. Each pattern contain a
     * unique combination of 2D points that must be sampled using the camera to
     * be calibrated.
     *
     * @return pattern used for camera calibration.
     */
    public Pattern2D getPattern() {
        return mPattern;
    }

    /**
     * Sets pattern used for camera calibration. Each pattern contains a unique
     * combination of 2D points that must be sampled using the camera to be
     * calibrated.
     *
     * @param pattern pattern used for camera calibration.
     */
    public void setPattern(final Pattern2D pattern) {
        mPattern = pattern;
    }

    /**
     * Obtains sampled markers of the pattern taken from a single picture
     * using the camera.
     *
     * @return sampled markers of the pattern.
     */
    public List getSampledMarkers() {
        return mSampledMarkers;
    }

    /**
     * Sets sampled markers of the pattern taken from a single picture
     * using the camera.
     *
     * @param sampledMarkers sampled markers of the pattern.
     * @throws IllegalArgumentException if provided number of sampled
     *                                  markers is smaller than the required minimum (4) to estimate an
     *                                  homography.
     */
    public final void setSampledMarkers(final List sampledMarkers) {
        if (sampledMarkers.size() < MIN_REQUIRED_SAMPLED_MARKERS) {
            throw new IllegalArgumentException();
        }

        mSampledMarkers = sampledMarkers;
    }

    /**
     * Returns quality scores of sampled markers. The higher the quality
     * score value the better the quality assigned to the associated 2D
     * point of a sampled marker.
     * Quality scores are only used if a robust estimation method such as
     * PROSAC or PROMedS is used for homography estimation
     *
     * @return quality scores of sampled markers.
     */
    public double[] getSampledMarkersQualityScores() {
        return mSampledMarkersQualityScores;
    }

    /**
     * Sets quality scores of sampled markers. The higher the quality score
     * value the better the quality assigned to the associated 2D point of
     * a sampled marker.
     * Quality scores are only used if a robust estimation method such as
     * PROSAC or PROMedS is used for homography estimation.
     *
     * @param sampledMarkersQualityScores quality scores of sampled markers.
     * @throws IllegalArgumentException if provided number of quality scores
     *                                  is smaller than the required minimum (4) to estimate an homography.
     */
    public final void setSampledMarkersQualityScores(
            final double[] sampledMarkersQualityScores) {
        if (sampledMarkersQualityScores.length < MIN_REQUIRED_SAMPLED_MARKERS) {
            throw new IllegalArgumentException();
        }

        mSampledMarkersQualityScores = sampledMarkersQualityScores;
    }

    /**
     * Computes quality scores of sampled markers by taking into account
     * distance to radial distortion center.
     * Typically the farther a sample is to the radial distortion, the more
     * likely it is to be distorted, and hence, the less reliable will be.
     *
     * @param sampledMarkers         sampled markers of the pattern.
     * @param radialDistortionCenter location where radial distortion center
     *                               is assumed to be. If null, it is assumed that center is at origin
     *                               of coordinates (i.e. center of image if principal point is also at
     *                               center of image).
     * @return quality scores of sampled markers.
     */
    public static double[] computeSampledMarkersQualityScores(
            final List sampledMarkers,
            final Point2D radialDistortionCenter) {

        final Point2D center = radialDistortionCenter != null ?
                radialDistortionCenter : new InhomogeneousPoint2D(0.0, 0.0);

        final double[] qualityScores = new double[sampledMarkers.size()];

        int counter = 0;
        double distance;
        double qualityScore;
        for (final Point2D sampledMarker : sampledMarkers) {
            distance = sampledMarker.distanceTo(center);
            qualityScore = 1.0 / (1.0 + distance);

            qualityScores[counter] = qualityScore;
            counter++;
        }

        return qualityScores;
    }

    /**
     * Computes quality scores of sampled markers by taking into account
     * distance to radial distortion center, which is assumed to be at
     * origin of coordinates (i.e. center of image if principal point is
     * also at center of image).
     *
     * @param sampledMarkers sampled markers of the pattern.
     * @return quality scores of sampled markers.
     */
    public static double[] computeSampledMarkersQualityScores(
            final List sampledMarkers) {
        return computeSampledMarkersQualityScores(sampledMarkers, null);
    }

    /**
     * Contains the sampled markers of the pattern but accounting for the
     * distortion effect introduced by the camera lens, so that coordinates
     * are undistorted and follow a pure pinhole camera model.
     * Coordinates of undistorted markers might change during camera
     * calibration while the radial distortion parameters are refined.
     *
     * @return sampled markers of the pattern accounting for lens radial
     * distortion.
     */
    protected List getUndistortedMarkers() {
        return mUndistortedMarkers;
    }

    /**
     * Sets sampled markers of the pattern but accounting for the distortion
     * effect introduced by the camera lens, so that coordinates are
     * undistorted and follow a pure pinhole camera model.
     * This method is for internal purposes only and it is called while
     * the camera radial distortion parameters are being computed.
     *
     * @param undistortedMarkers sampled markers of the pattern accounting
     *                           for lens radial distortion.
     */
    protected void setUndistortedMarkers(final List undistortedMarkers) {
        mUndistortedMarkers = undistortedMarkers;
    }

    /**
     * Returns 2D homography estimated from the sampled pattern points
     * respect to the ideal ones using a single picture.
     *
     * @return homography of the sampled pattern points respect to the ideal
     * ones.
     */
    public Transformation2D getHomography() {
        return mHomography;
    }

    /**
     * Sets 2D homography estimated from the sampled pattern points
     * respect to the ideal ones using a single picture.
     * This method is for internal purposes only and it is called while
     * the IAC is being estimated.
     *
     * @param homography homography to be set.
     */
    protected void setHomography(final Transformation2D homography) {
        mHomography = homography;
    }

    /**
     * Returns estimated camera rotation for this sample. This contains
     * the amount of rotation respect to the plane formed by the pattern
     * markers for the picture associated to this sample. This is obtained
     * once the IAC of the camera is estimated.
     *
     * @return estimated camera rotation for this sample.
     */
    public Rotation3D getRotation() {
        return mRotation;
    }

    /**
     * Sets estimated camera rotation for this sample. This contains
     * the amount of rotation respect to the plane formed by the pattern
     * markers for the picture associated to this sample. This is obtained
     * once the IAC of the camera is estimated.
     * This method is for internal purposes only and might only be called
     * if camera rotation is required during radial distortion estimation,
     * or if rotation is requested for some other purpose.
     *
     * @param rotation camera rotation for this sample.
     */
    protected void setRotation(final Rotation3D rotation) {
        mRotation = rotation;
    }

    /**
     * Returns estimated camera center. This determines the amount of
     * translation of the camera respect to the plane formed by the pattern
     * markers. This is obtained once the IAC of the camera is estimated.
     *
     * @return estimated camera center.
     */
    public Point3D getCameraCenter() {
        return mCameraCenter;
    }

    /**
     * Sets estimated camera center. This determines the amount of translation
     * of the camera respect to the plane formed by the pattern markers. This is
     * obtained once the IAC of the camera is estimated.
     *
     * @param cameraCenter estimated camera center.
     */
    protected void setCameraCenter(final Point3D cameraCenter) {
        mCameraCenter = cameraCenter;
    }

    /**
     * Returns estimated camera. Estimated pinhole camera taking into
     * account estimated intrinsic parameters and amount of rotation and
     * translation respect to the plane formed by the pattern markers, but
     * without taking into account any radial distortion introduced by the
     * lens.
     *
     * @return estimated camera.
     */
    public PinholeCamera getCamera() {
        return mCamera;
    }

    /**
     * Sets estimated camera taking into account estimated intrinsic
     * parameters, amount of rotation and translation respect to the plane
     * formed by the pattern markers, but without taking into account any
     * radial distortion introduced by the lens.
     * This method is for internal purposes only and might only be called if
     * camera is required during radial distortion estimation, or if camera
     * is requested for some other purpose.
     *
     * @param camera estimated camera.
     */
    protected void setCamera(final PinholeCamera camera) {
        mCamera = camera;
    }

    /**
     * Estimates homography of sampled points respect to the ideal pattern
     * points. Undistorted sampled taking into account radial distortion
     * will be taken into account whenever possible.
     *
     * @param estimator           a robust estimator for the homography. If will only
     *                            be used if more than 4 markers are provided.
     * @param idealPatternMarkers ideal marker coordinates of the pattern.
     *                            This contains measures expressed in meters so that camera can be
     *                            calibrated against real measures.
     * @return an homography.
     * @throws LockedException           if robust estimator is locked because
     *                                   computations are already in progress.
     * @throws NotReadyException         if provided data to compute homography is
     *                                   not enough or it is invalid.
     * @throws RobustEstimatorException  if robust estimation of homography
     *                                   failed. This typically happens when not enough inliers are found or
     *                                   configuration of points to estimate homography is degenerate.
     * @throws CoincidentPointsException if configuration of points to
     *                                   estimate homography is degenerate.
     */
    protected Transformation2D estimateHomography(
            final PointCorrespondenceProjectiveTransformation2DRobustEstimator estimator,
            final List idealPatternMarkers) throws LockedException,
            NotReadyException, RobustEstimatorException,
            CoincidentPointsException {

        final List markers = mUndistortedMarkers != null ?
                mUndistortedMarkers : mSampledMarkers;

        if (markers.size() < MIN_REQUIRED_SAMPLED_MARKERS) {
            throw new NotReadyException();
        }
        if (markers.size() != idealPatternMarkers.size()) {
            throw new NotReadyException();
        }

        if (markers.size() == MIN_REQUIRED_SAMPLED_MARKERS) {
            // use non robust projective transformation estimation since it
            // is faster and will produce the same result as a robust
            // estimator
            return new ProjectiveTransformation2D(
                    idealPatternMarkers.get(0), idealPatternMarkers.get(1),
                    idealPatternMarkers.get(2), idealPatternMarkers.get(3),
                    markers.get(0), markers.get(1), markers.get(2),
                    markers.get(3));
        } else {
            // use robust projective transformation estimation
            estimator.setPoints(idealPatternMarkers, markers);
            if (estimator.getMethod() == RobustEstimatorMethod.PROSAC ||
                    estimator.getMethod() == RobustEstimatorMethod.PROMedS) {
                if (mSampledMarkersQualityScores == null) {
                    // attempt to estimate quality scores based on distance of
                    // samples to origin of coordinates (i.e. image center)
                    mSampledMarkersQualityScores =
                            computeSampledMarkersQualityScores(markers);
                }
                estimator.setQualityScores(mSampledMarkersQualityScores);
            }

            return estimator.estimate();
        }
    }

    /**
     * Computes camera pose using estimated homography and provided intrinsic
     * pinhole camera parameters that have been estimated so far.
     *
     * @param intrinsic intrinsic pinhole camera parameters.
     * @throws CalibrationException if something fails.
     */
    protected void computeCameraPose(final PinholeCameraIntrinsicParameters intrinsic)
            throws CalibrationException {
        try {
            // reset previous values
            mRotation = null;
            mCameraCenter = null;
            mCamera = null;

            final CameraPoseEstimator estimator = new CameraPoseEstimator();
            estimator.estimate(intrinsic, mHomography);

            mRotation = estimator.getRotation();
            mCameraCenter = estimator.getCameraCenter();
            mCamera = estimator.getCamera();

        } catch (final AlgebraException | GeometryException e) {
            throw new CalibrationException(e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy