Commit 705ad212 authored by jlaura's avatar jlaura
Browse files

Merge pull request #126 from jlaura/master

Merging Dev into Master for Release 0.1.0
parents 0d85cd16 bd6f9493
Loading
Loading
Loading
Loading
+11 −6
Original line number Diff line number Diff line
@@ -33,11 +33,15 @@ install:

  # Install the non-conda packages if required, requirements.txt duplicates are ignored
  - conda install -c https://conda.anaconda.org/jlaura opencv3=3.0.0
  - conda install -c menpo cyvlfeat
  - conda config --add channels conda-forge
  - conda install runipy
  - conda install -c https://conda.anaconda.org/conda-forge gdal h5py
  - pip install -r requirements.txt
  - pip install coverage
  # Development installation
  - conda install nose coverage
  - pip install coveralls
  - python runipynbs.py

script:
  - nosetests --with-coverage --cover-package=autocnet
@@ -48,15 +52,16 @@ after_success:
notifications:
  webhooks:
    urls:
      - https://webhooks.gitter.im/e/6cbe4b65fff6764ed80f
 #     - https://webhooks.gitter.im/e/6cbe4b65fff6764ed80f
    on_success: always  
    on_failure: always  
    on_start: never     
  email:
      recipients:
          - kberry@usgs.gov
          - dmlytle@usgs.gov
          - jwbacker@usgs.gov
          - krodriguez@usgs.gov
#          - kberry@usgs.gov
#          - dmlytle@usgs.gov
#          - jwbacker@usgs.gov
#          - krodriguez@usgs.gov
      on_success: always
      on_failure: always
      
+0 −0

File moved.

+165 −0
Original line number Diff line number Diff line
import numpy as np
import cv2


def compute_epipoles(f):
    """
    Compute the epipole and epipolar prime

    Parameters
    ----------
    f : ndarray
        (3,3) fundamental matrix or autocnet Fundamental Matrix object

    Returns
    -------
    e : ndarray
        (3,1) epipole

    e1 : ndarray
         (3,3) epipolar prime matrix
    """
    u, _, _ = np.linalg.svd(f)
    e = u[:, -1]
    e1 = np.array([[0, -e[2], e[1]],
                   [e[2], 0, -e[0]],
                   [-e[1], e[0], 0]])

    return e, e1


def idealized_camera():
    """
    Create an idealized camera transformation matrix

    Returns
    -------
     : ndarray
       (3,4) with diagonal 1
    """
    return np.eye(3, 4)


def estimated_camera_from_f(f):
    """
    Estimate a camera matrix using a fundamental matrix.


    Parameters
    ----------
    f : ndarray
        (3,3) fundamental matrix or autocnet Fundamental Matrix object

    Returns
    -------
    p1 : ndarray
         Estimated camera matrix
    """

    e, e1 = compute_epipoles(f)
    p1 = np.empty((3, 4))
    p1[:, :3] = e1.dot(f)
    p1[:, 3] = e

    return p1


def triangulate(pt, pt1, p, p1):
    """
    Given two sets of homogeneous coordinates and two camera matrices,
    triangulate the 3D coordinates.  The image correspondences are
    assumed to be implicitly ordered.

    References
    ----------
    .. [Hartley2003]

    Parameters
    ----------
    pt : ndarray
         (n, 3) array of homogeneous correspondences

    pt1 : ndarray
          (n, 3) array of homogeneous correspondences

    p : ndarray
        (3, 4) camera matrix

    p1 : ndarray
         (3, 4) camera matrix

    Returns
    -------
    coords : ndarray
             (4, n) projection matrix

    """
    pt = np.asarray(pt)
    pt1 = np.asarray(pt1)

    # Transpose for the openCV call if needed
    if pt.shape[0] != 3:
        pt = pt.T
    if pt1.shape[0] != 3:
        pt1 = pt1.T

    X = cv2.triangulatePoints(p, p1, pt[:2], pt1[:2])

    # Homogenize
    X /= X[3]

    return X


def projection_error(p1, p, pt, pt1):
    """
    Based on Hartley and Zisserman p.285 this function triangulates
    image correspondences and computes the reprojection error
    by back-projecting the points into the image.

    References
    ----------
    .. [Hartley2003]

    Parameters
    -----------
    p1 : ndarray
         (3,4) camera matrix

    p : ndarray
        (3,4) idealized camera matrix in the form np.eye(3,4)

    pt : dataframe or ndarray
         of homogeneous coordinates in the form (x_{i}, y_{i}, 1)

    pt1 : dataframe or ndarray
          of homogeneous coordinates in the form (x_{i}, y_{i}, 1)

    Returns
    -------
    residuals : ndarray
                (n, 1) residuals for each correspondence

    cumulative_error : float
                       sum of the residuals


    """
    if p1.shape != (3,4):
        p1 = p1.reshape(3,4)

    # Triangulate the correspondences
    xw_est = triangulate(pt, pt1, p, p1)

    # Back project and homogenize
    xhat = np.dot(p, xw_est)
    xhat /= xhat[2]
    x2hat = np.dot(p1, xw_est)
    x2hat /= x2hat[2]

    # Compute residuals
    dist = (pt.T - xhat)**2 + (pt1.T - x2hat)**2
    residuals = np.sum(dist, axis=0)
    reproj_error = np.sum(dist)

    return residuals, reproj_error
+66 −0
Original line number Diff line number Diff line
import os
import sys
import unittest

import numpy as np

sys.path.append(os.path.abspath('..'))

from .. import camera


class TestCamera(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.f = np.array([[3.27429392e-07, 8.31555374e-06, -1.37175583e-05],
                          [2.33349759e-07, 5.99315297e-07,  1.15196332e-01],
                          [-4.78065797e-03, -1.21448858e-01, 1.00000000e+00]])

    def test_compute_epipoles(self):
        e, e1 = camera.compute_epipoles(self.f)
        np.testing.assert_array_almost_equal(e, np.array([9.99999885e-01, -4.75272787e-04, 6.84672384e-05]))

        np.testing.assert_array_almost_equal(e1, np.array([[0.00000000e+00,  -6.84672384e-05,  -4.75272787e-04],
                                                    [6.84672384e-05,   0.00000000e+00,  -9.99999885e-01],
                                                    [4.75272787e-04,   9.99999885e-01,   0.00000000e+00]]))

    def test_idealized_camera(self):
        np.testing.assert_array_equal(np.eye(3,4), camera.idealized_camera())

    def test_estimated_camera_from_f(self):
        p1 = camera.estimated_camera_from_f(self.f)
        np.testing.assert_array_almost_equal(p1, np.array([[2.27210066e-06, 5.77212964e-05, -4.83159962e-04, 9.99999885e-01],
                                                    [4.78065745e-03,   1.21448845e-01,  -9.99999886e-01, -4.75272787e-04],
                                                    [2.33505351e-07,   6.03267385e-07,   1.15196312e-01, 6.84672384e-05]]))

    def test_triangulation_and_reprojection_error(self):
        p = np.eye(3,4)
        p1 = np.array([[2.27210066e-06, 5.77212964e-05, -4.83159962e-04, 9.99999885e-01],
                       [4.78065745e-03,   1.21448845e-01,  -9.99999886e-01, -4.75272787e-04],
                       [2.33505351e-07,   6.03267385e-07,   1.15196312e-01, 6.84672384e-05]])

        coords1 = np.array([[260.12573242, 6.37760448, 1.],
                            [539.05926514, 7.0553031 , 1.],
                            [465.07751465, 16.02966881, 1.],
                            [46.39139938, 16.96884346, 1.],
                            [456.28939819, 23.12134743, 1.]])

        coords2 = np.array([[707.23968506, 8.2479744, 1.],
                            [971.61566162, 18.7211895, 1.],
                            [905.67974854, 25.06698608, 1.],
                            [487.46420288, 11.28651524, 1.],
                            [897.73425293, 32.06435013, 1.]])

        truth = np.array([[3.03655751, 4.49076221, 4.17705934, 0.7984432 , 4.13673958],
                          [0.07447866, 0.05871216, 0.14393111, 0.29223435, 0.20962208],
                          [0.01167342, 0.00833074, 0.00898143, 0.01721084, 0.00906604],
                          [1., 1., 1., 1., 1. ]])

        c = camera.triangulate(coords1, coords2, p, p1)
        np.testing.assert_array_almost_equal(c, truth)

        truth = np.array([  3.09866357e-02, 2.60295132e-01,
                            8.12871690e-02, 5.57281224e-01,   4.72226586e-04])
        residuals, reproj_error = camera.projection_error(p1, p, coords1, coords2)
        np.testing.assert_array_almost_equal(residuals, truth)
 No newline at end of file
Loading