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

com.irurueta.ar.sfm.SinglePoint3DTriangulator 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.sfm;

import com.irurueta.geometry.CoordinatesType;
import com.irurueta.geometry.PinholeCamera;
import com.irurueta.geometry.Point2D;
import com.irurueta.geometry.Point3D;
import com.irurueta.geometry.estimators.LockedException;
import com.irurueta.geometry.estimators.NotReadyException;

import java.util.List;

/**
 * Base class to triangulate matched 2D points into a single 3D one by using
 * 2D points correspondences on different views along with the corresponding
 * cameras on each of those views.
 * Subclasses will implement different types of triangulators that can provide
 * either LMSE or weighted solutions using either homogeneous or inhomogeneous
 * systems of equations.
 * Inhomogeneous methods are suitable only for cases where finite points and
 * cameras are being used. If points or cameras are located very far or at
 * infinity, triangulation will fail when using inhomogeneous methods.
 * Homogeneous methods are suitable for any case, however, if points and
 * cameras are close and well defined, inhomogeneous methods might yield better
 * accuracy (although the difference is minimal).
 */
public abstract class SinglePoint3DTriangulator {

    /**
     * Default triangulator type.
     */
    public static final Point3DTriangulatorType DEFAULT_TYPE =
            Point3DTriangulatorType.LMSE_HOMOGENEOUS_TRIANGULATOR;

    /**
     * Minimum required number of views to triangulate 3D points.
     */
    public static final int MIN_REQUIRED_VIEWS = 2;

    /**
     * Matched 2D points. Each point in the list is assumed to be projected by
     * the corresponding camera in the list.
     */
    protected List mPoints2D;

    /**
     * List of cameras associated to the matched 2D point on the same position
     * as the camera on the list.
     */
    protected List mCameras;

    /**
     * Listener to handle events generated by instances of this class.
     */
    protected SinglePoint3DTriangulatorListener mListener;

    /**
     * Indicates whether this instance is locked doing computations.
     */
    protected boolean mLocked;

    /**
     * Constructor.
     */
    protected SinglePoint3DTriangulator() {
    }

    /**
     * Constructor.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  camera for each view where 2D points are represented.
     * @throws IllegalArgumentException if provided lists don't have the same
     *                                  length or their length is less than 2 views, which is the minimum
     *                                  required to compute triangulation.
     */
    protected SinglePoint3DTriangulator(final List points2D,
                                        final List cameras) {
        internalSetPointsAndCameras(points2D, cameras);
    }

    /**
     * Constructor.
     *
     * @param listener listener to notify events generated by instances of this
     *                 class.
     */
    protected SinglePoint3DTriangulator(
            final SinglePoint3DTriangulatorListener listener) {
        mListener = listener;
    }

    /**
     * Constructor.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  cameras for each view where 2D points are represented.
     * @param listener listener to notify events generated by instances of this
     *                 class.
     * @throws IllegalArgumentException if provided lists don't have the same
     *                                  length or their length is less than 2 views, which is the minimum
     *                                  required to compute triangulation.
     */
    protected SinglePoint3DTriangulator(final List points2D,
                                        final List cameras,
                                        final SinglePoint3DTriangulatorListener listener) {
        this(points2D, cameras);
        mListener = listener;
    }

    /**
     * Returns list of matched 2D points on each view. Each point in the list is
     * assumed to be projected by the corresponding camera.
     *
     * @return list of matched 2D points on each view.
     */
    public List getPoints2D() {
        return mPoints2D;
    }

    /**
     * Returns cameras for each view where 2D points are represented.
     *
     * @return cameras for each view where 2D points are represented.
     */
    public List getCameras() {
        return mCameras;
    }

    /**
     * Sets list of matched 2D points for each view and their corresponding
     * cameras used to project them.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  cameras for each view where 2D points are represented.
     * @throws LockedException          if this instance is locked.
     * @throws IllegalArgumentException if provided lists don't have the same
     *                                  length or their length is less than 2 views, which is the minimum
     *                                  required to compute triangulation.
     */
    public void setPointsAndCameras(final List points2D,
                                    final List cameras) throws LockedException {
        if (isLocked()) {
            throw new LockedException();
        }
        internalSetPointsAndCameras(points2D, cameras);
    }

    /**
     * Indicates whether this instance is locked because computations are being
     * done.
     *
     * @return true if instance is locked, false otherwise.
     */
    public boolean isLocked() {
        return mLocked;
    }

    /**
     * Indicates whether this instance is ready to start the triangulation.
     * An instance is ready when both lists of 2D points and cameras are
     * provided, both lists have the same length and at least data for 2 views
     * is provided.
     *
     * @return true if this instance is ready, false otherwise.
     */
    public boolean isReady() {
        return areValidPointsAndCameras(mPoints2D, mCameras);
    }

    /**
     * Returns listener to be notified of events generated by instances of this
     * class.
     *
     * @return listener to be notified of events generated by instances of this
     * class.
     */
    public SinglePoint3DTriangulatorListener getListener() {
        return mListener;
    }

    /**
     * Sets listener to be notified of events generated by instances of this
     * class.
     *
     * @param listener listener to be notified of events generated by instances
     *                 of this class.
     * @throws LockedException if this instance is locked.
     */
    public void setListener(final SinglePoint3DTriangulatorListener listener)
            throws LockedException {
        if (isLocked()) {
            throw new LockedException();
        }

        mListener = listener;
    }

    /**
     * Triangulates provided matched 2D points being projected by each
     * corresponding camera into a single 3D point.
     * At least 2 matched 2D points and their corresponding 2 cameras are
     * required to compute triangulation. If more views are provided, an
     * averaged solution can be found.
     *
     * @return computed triangulated 3D point.
     * @throws LockedException               if this instance is locked.
     * @throws NotReadyException             if lists of points and cameras don't have the
     *                                       same length or less than 2 views are provided.
     * @throws Point3DTriangulationException if triangulation fails for some
     *                                       other reason (i.e. degenerate geometry, numerical instabilities, etc).
     */
    public Point3D triangulate() throws LockedException, NotReadyException,
            Point3DTriangulationException {
        final Point3D result = Point3D.create(
                CoordinatesType.HOMOGENEOUS_COORDINATES);
        triangulate(result);
        return result;
    }

    /**
     * Triangulates provided matched 2D points being projected by each
     * corresponding camera into a single 3D point.
     * At least 2 matched 2D points and their corresponding 2 cameras are
     * required to compute triangulation. If more views are provided, an
     * averaged solution can be found.
     *
     * @param result instance where data for triangulated 3D point is stored.
     * @throws LockedException               if this instance is locked.
     * @throws NotReadyException             if lists of points and cameras don't have the
     *                                       same length or less than 2 views are provided.
     * @throws Point3DTriangulationException if triangulation fails for some
     *                                       other reason (i.e. degenerate geometry, numerical instabilities, etc).
     */
    public void triangulate(final Point3D result) throws LockedException,
            NotReadyException, Point3DTriangulationException {
        if (isLocked()) {
            throw new LockedException();
        }
        if (!isReady()) {
            throw new NotReadyException();
        }

        triangulate(mPoints2D, mCameras, result);
    }

    /**
     * Indicates whether provided points and cameras are valid to start the
     * triangulation.
     * In order to triangulate points, at least two cameras and their
     * corresponding 2 matched 2D points are required.
     * If more views are provided, an averaged solution can be found.
     *
     * @param points2D list of matched points on each view.
     * @param cameras  cameras for each view where 2D points are represented.
     * @return true if data is enough to start triangulation, false otherwise.
     */
    public static boolean areValidPointsAndCameras(final List points2D,
                                                   final List cameras) {
        return points2D != null && cameras != null &&
                points2D.size() == cameras.size() &&
                points2D.size() >= MIN_REQUIRED_VIEWS;
    }

    /**
     * Creates a new 3D point triangulator instance using provided type.
     *
     * @param type a triangulator type.
     * @return a 3D point triangulator instance.
     */
    public static SinglePoint3DTriangulator create(
            final Point3DTriangulatorType type) {
        switch (type) {
            case WEIGHTED_INHOMOGENEOUS_TRIANGULATOR:
                return new WeightedInhomogeneousSinglePoint3DTriangulator();
            case WEIGHTED_HOMOGENEOUS_TRIANGULATOR:
                return new WeightedHomogeneousSinglePoint3DTriangulator();
            case LMSE_INHOMOGENEOUS_TRIANGULATOR:
                return new LMSEInhomogeneousSinglePoint3DTriangulator();
            case LMSE_HOMOGENEOUS_TRIANGULATOR:
            default:
                return new LMSEHomogeneousSinglePoint3DTriangulator();
        }
    }

    /**
     * Creates a new 3D point triangulator instance using provided lists of
     * points and corresponding cameras along with provided type.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  camera for each view where 2D points are represented.
     * @param type     a triangulator type.
     * @return a 3D point triangulator instance.
     * @throws IllegalArgumentException if provided lists don't have the same
     *                                  length or their length is less than 2 views, which is the minimum
     *                                  required to compute triangulation.
     */
    public static SinglePoint3DTriangulator create(
            final List points2D,
            final List cameras,
            final Point3DTriangulatorType type) {
        switch (type) {
            case WEIGHTED_INHOMOGENEOUS_TRIANGULATOR:
                return new WeightedInhomogeneousSinglePoint3DTriangulator(
                        points2D, cameras);
            case WEIGHTED_HOMOGENEOUS_TRIANGULATOR:
                return new WeightedHomogeneousSinglePoint3DTriangulator(
                        points2D, cameras);
            case LMSE_INHOMOGENEOUS_TRIANGULATOR:
                return new LMSEInhomogeneousSinglePoint3DTriangulator(points2D,
                        cameras);
            case LMSE_HOMOGENEOUS_TRIANGULATOR:
            default:
                return new LMSEHomogeneousSinglePoint3DTriangulator(points2D,
                        cameras);
        }
    }

    /**
     * Creates a new 3D point triangulator instance using provided lists of
     * points, weights and corresponding cameras along with provided type.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  camera for each view where 2D points are represented.
     * @param weights  weights assigned to each view.
     * @param type     a triangulator type.
     * @return a 3D point triangulator instance.
     * @throws IllegalArgumentException if provided lists or weights don't have
     *                                  the same length or their length is less than 2 views, which is the
     *                                  minimum required to compute triangulation.
     */
    public static SinglePoint3DTriangulator create(final List points2D,
                                                   final List cameras,
                                                   final double[] weights,
                                                   final Point3DTriangulatorType type) {
        switch (type) {
            case WEIGHTED_INHOMOGENEOUS_TRIANGULATOR:
                return new WeightedInhomogeneousSinglePoint3DTriangulator(
                        points2D, cameras, weights);
            case WEIGHTED_HOMOGENEOUS_TRIANGULATOR:
                return new WeightedHomogeneousSinglePoint3DTriangulator(
                        points2D, cameras, weights);
            case LMSE_INHOMOGENEOUS_TRIANGULATOR:
                return new LMSEInhomogeneousSinglePoint3DTriangulator(points2D,
                        cameras);
            case LMSE_HOMOGENEOUS_TRIANGULATOR:
            default:
                return new LMSEHomogeneousSinglePoint3DTriangulator(points2D,
                        cameras);
        }
    }

    /**
     * Creates a new 3D point triangulator instance using provided listener and
     * type.
     *
     * @param listener listener to notify events generated by instances of this
     *                 class.
     * @param type     a triangulator type.
     * @return a 3D point triangulator instance.
     */
    public static SinglePoint3DTriangulator create(
            final SinglePoint3DTriangulatorListener listener,
            final Point3DTriangulatorType type) {
        switch (type) {
            case WEIGHTED_INHOMOGENEOUS_TRIANGULATOR:
                return new WeightedInhomogeneousSinglePoint3DTriangulator(
                        listener);
            case WEIGHTED_HOMOGENEOUS_TRIANGULATOR:
                return new WeightedHomogeneousSinglePoint3DTriangulator(
                        listener);
            case LMSE_INHOMOGENEOUS_TRIANGULATOR:
                return new LMSEInhomogeneousSinglePoint3DTriangulator(listener);
            case LMSE_HOMOGENEOUS_TRIANGULATOR:
            default:
                return new LMSEHomogeneousSinglePoint3DTriangulator(listener);
        }
    }

    /**
     * Creates a new 3D point triangulator instance using provided lists of
     * points and corresponding cameras, listener and provided type.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  camera for each view where 2D points are represented.
     * @param listener listener to notify events generated by instances of this
     *                 class.
     * @param type     a triangulator type.
     * @return a 3D point triangulator instance.
     * @throws IllegalArgumentException if provided lists don't have the same
     *                                  length or their length is less than 2 views, which is the minimum
     *                                  required to compute triangulation.
     */
    public static SinglePoint3DTriangulator create(final List points2D,
                                                   final List cameras,
                                                   final SinglePoint3DTriangulatorListener listener,
                                                   final Point3DTriangulatorType type) {
        switch (type) {
            case WEIGHTED_INHOMOGENEOUS_TRIANGULATOR:
                return new WeightedInhomogeneousSinglePoint3DTriangulator(
                        points2D, cameras, listener);
            case WEIGHTED_HOMOGENEOUS_TRIANGULATOR:
                return new WeightedHomogeneousSinglePoint3DTriangulator(
                        points2D, cameras, listener);
            case LMSE_INHOMOGENEOUS_TRIANGULATOR:
                return new LMSEInhomogeneousSinglePoint3DTriangulator(points2D,
                        cameras, listener);
            case LMSE_HOMOGENEOUS_TRIANGULATOR:
            default:
                return new LMSEHomogeneousSinglePoint3DTriangulator(points2D,
                        cameras, listener);
        }
    }

    /**
     * Creates a new 3D point triangulator instance using provided lists of
     * points, weights, corresponding cameras, listener and provided type.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  camera for each view where 2D points are represented.
     * @param weights  weights assigned to each view.
     * @param listener listener to notify events generated by instances of this
     *                 class.
     * @param type     a triangulator type.
     * @return a 3D point triangulator instance.
     * @throws IllegalArgumentException if provided lists or weights don't have
     *                                  the same length or their length is less than 2 views, which is the
     *                                  minimum required to compute triangulation.
     */
    public static SinglePoint3DTriangulator create(final List points2D,
                                                   final List cameras,
                                                   final double[] weights,
                                                   final SinglePoint3DTriangulatorListener listener,
                                                   final Point3DTriangulatorType type) {
        switch (type) {
            case WEIGHTED_INHOMOGENEOUS_TRIANGULATOR:
                return new WeightedInhomogeneousSinglePoint3DTriangulator(
                        points2D, cameras, weights, listener);
            case WEIGHTED_HOMOGENEOUS_TRIANGULATOR:
                return new WeightedHomogeneousSinglePoint3DTriangulator(
                        points2D, cameras, weights, listener);
            case LMSE_INHOMOGENEOUS_TRIANGULATOR:
                return new LMSEInhomogeneousSinglePoint3DTriangulator(points2D,
                        cameras, listener);
            case LMSE_HOMOGENEOUS_TRIANGULATOR:
            default:
                return new LMSEHomogeneousSinglePoint3DTriangulator(points2D,
                        cameras, listener);
        }
    }

    /**
     * Creates a new 3D point triangulator instance using default type.
     *
     * @return a 3D point triangulator instance.
     */
    public static SinglePoint3DTriangulator create() {
        return create(DEFAULT_TYPE);
    }

    /**
     * Creates a new 3D point triangulator instance using provided lists of
     * points and corresponding cameras along with default type.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  camera for each view where 2D points are represented.
     * @return a 3D point triangulator instance.
     * @throws IllegalArgumentException if provided lists don't have the same
     *                                  length or their length is less than 2 views, which is the minimum
     *                                  required to compute triangulation.
     */
    public static SinglePoint3DTriangulator create(final List points2D,
                                                   final List cameras) {
        return create(points2D, cameras, DEFAULT_TYPE);
    }

    /**
     * Creates a new 3D point triangulator instance using provided lists of
     * points, weights and corresponding cameras along with default type.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  camera for each view where 2D points are represented.
     * @param weights  weights assigned to each view.
     * @return a 3D point triangulator instance.
     * @throws IllegalArgumentException if provided lists or weights don't have
     *                                  the same length or their length is less than 2 views, which is the
     *                                  minimum required to compute triangulation.
     */
    public static SinglePoint3DTriangulator create(final List points2D,
                                                   final List cameras, double[] weights) {
        return create(points2D, cameras, weights, DEFAULT_TYPE);
    }

    /**
     * Creates a new 3D point triangulator instance using provided listener and
     * default type.
     *
     * @param listener listener to notify events generated by instances of this
     *                 class.
     * @return a 3D point triangulator instance.
     */
    public static SinglePoint3DTriangulator create(
            final SinglePoint3DTriangulatorListener listener) {
        return create(listener, DEFAULT_TYPE);
    }

    /**
     * Creates a new 3D point triangulator instance using provided lists of
     * points and corresponding cameras, listener and default type.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  camera for each view where 2D points are represented.
     * @param listener listener to notify events generated by instances of this
     *                 class.
     * @return a 3D point triangulator instance.
     * @throws IllegalArgumentException if provided lists don't have the same
     *                                  length or their length is less than 2 views, which is the minimum
     *                                  required to compute triangulation.
     */
    public static SinglePoint3DTriangulator create(final List points2D,
                                                   final List cameras,
                                                   final SinglePoint3DTriangulatorListener listener) {
        return create(points2D, cameras, listener, DEFAULT_TYPE);
    }

    /**
     * Creates a new 3D point triangulator instance using provided lists of
     * points, weights, corresponding cameras, listener and default type.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  camera for each view where 2D points are represented.
     * @param weights  weights assigned to each view.
     * @param listener listener to notify events generated by instances of this
     *                 class.
     * @return a 3D point triangulator instance.
     * @throws IllegalArgumentException if provided lists or weights don't have
     *                                  the same length or their length is less than 2 views, which is the
     *                                  minimum required to compute triangulation.
     */
    public static SinglePoint3DTriangulator create(final List points2D,
                                                   final List cameras,
                                                   final double[] weights,
                                                   final SinglePoint3DTriangulatorListener listener) {
        return create(points2D, cameras, weights, listener, DEFAULT_TYPE);
    }

    /**
     * Returns type of triangulator (a combination of homogeneous or
     * inhomogeneous type along with an LMSE or weighted strategy.
     *
     * @return type of triangulator.
     */
    public abstract Point3DTriangulatorType getType();

    /**
     * Internal method to triangulate provided matched 2D points being projected
     * by each corresponding camera into a single 3D point.
     * At least 2 matched 2D points and their corresponding 2 cameras are
     * required to compute triangulation. If more views are provided, an
     * averaged solution is found.
     * This method does not check whether instance is locked or ready.
     *
     * @param points2D matched 2D points. Each point in the list is assumed to
     *                 be projected by the corresponding camera in the list.
     * @param cameras  list of cameras associated to the matched 2D point on the
     *                 same position as the camera on the list.
     * @param result   instance where triangulated 3D point is stored.
     * @throws Point3DTriangulationException if triangulation fails for some
     *                                       other reason (i.e. degenerate geometry, numerical instabilities, etc).
     */
    protected abstract void triangulate(final List points2D,
                                        final List cameras,
                                        final Point3D result)
            throws Point3DTriangulationException;

    /**
     * Internal method to sets list of matched 2D points for each view and their
     * corresponding cameras used to project them.
     * This method does not check whether instance is locked.
     *
     * @param points2D list of matched 2D points on each view. Each point in the
     *                 list is assumed to be projected by the corresponding camera in the list.
     * @param cameras  cameras for each view where 2D points are represented.
     * @throws IllegalArgumentException if provided lists don't have the same
     *                                  length or their length is less than 2 views, which is the minimum
     *                                  required to compute triangulation.
     */
    private void internalSetPointsAndCameras(final List points2D,
                                             final List cameras) {

        if (!areValidPointsAndCameras(points2D, cameras)) {
            throw new IllegalArgumentException();
        }

        mPoints2D = points2D;
        mCameras = cameras;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy