Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,19 @@ public enum SolvePnPMethod
/// </summary>
P3P = 2,

/// <summary>
/// **Broken implementation. Using this flag will fallback to EPnP**.
/// Joel A. Hesch and Stergios I. Roumeliotis. "A Direct Least-Squares (DLS) Method for PnP"
/// </summary>
DLS = 3,

/// <summary>
/// **Broken implementation. Using this flag will fallback to EPnP.**
/// Method is based on the paper of A.Penate-Sanchez, J.Andrade-Cetto, F.Moreno-Noguer.
/// "Exhaustive Linearization for Robust Camera Pose and Focal Length Estimation"
/// </summary>
UPNP = 4,

/// <summary>
/// Method is based on the paper of T. Ke, S. Roumeliotis
/// "An Efficient Algebraic Solution to the Perspective-Three-Point Problem"
/// In this case the function requires exactly four object and image points.
/// </summary>
AP3P = 5,
AP3P = 3,

/// <summary>
/// Method is based on the paper of T. Collins and A. Bartoli.
/// "Infinitesimal Plane-Based Pose Estimation".
/// This method requires coplanar object points.
/// </summary>
IPPE = 6,
IPPE = 4,

/// <summary>
/// Method is based on the paper of Toby Collins and Adrien Bartoli.
Expand All @@ -63,46 +50,11 @@ public enum SolvePnPMethod
/// - point 2: [squareLength / 2, -squareLength / 2, 0]
/// - point 3: [-squareLength / 2, -squareLength / 2, 0]
/// </summary>
IPPE_SQUARE = 7,
IPPESquare = 5,

/// <summary>
/// Method is based on the paper "A Consistently Fast and Globally Optimal Solution to the
/// Perspective-n-Point Problem" by G. Terzakis and M. Lourakis. It requires 3 or more points.
/// </summary>
SQPNP = 8,
}

/// <summary>
/// Obsolete: Use SolvePnPMethod instead. This enum is kept for backward compatibility.
/// </summary>
[Obsolete("Use SolvePnPMethod instead", true)]
public enum SolvePnPFlags
{
/// <summary>
/// Iterative method is based on Levenberg-Marquardt optimization.
/// In this case the function finds such a pose that minimizes reprojection error,
/// that is the sum of squared distances between the observed projections imagePoints and the projected (using projectPoints() ) objectPoints .
/// </summary>
Iterative = 0,

/// <summary>
/// Method has been introduced by F.Moreno-Noguer, V.Lepetit and P.Fua in the paper “EPnP: Efficient Perspective-n-Point Camera Pose Estimation”.
/// </summary>
EPNP = 1,

/// <summary>
/// Method is based on the paper of X.S. Gao, X.-R. Hou, J. Tang, H.-F. Chang“Complete Solution Classification for
/// the Perspective-Three-Point Problem”. In this case the function requires exactly four object and image points.
/// </summary>
P3P = 2,

/// <summary>
/// Joel A. Hesch and Stergios I. Roumeliotis. "A Direct Least-Squares (DLS) Method for PnP"
/// </summary>
DLS = 3,

/// <summary>
/// A.Penate-Sanchez, J.Andrade-Cetto, F.Moreno-Noguer. "Exhaustive Linearization for Robust Camera Pose and Focal Length Estimation"
/// </summary>
UPNP = 4,
SQPNP = 6,
}
73 changes: 73 additions & 0 deletions test/OpenCvSharp.Tests/calib3d/Calib3dTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,79 @@ public void SolvePnPTestByArray(bool useExtrinsicGuess)
Cv2.SolvePnP(objPts, imgPts, cameraMatrix, dist, ref rvec, ref tvec, useExtrinsicGuess: useExtrinsicGuess);
}

[Theory]
[InlineData(SolvePnPMethod.P3P)]
[InlineData(SolvePnPMethod.AP3P)]
[InlineData(SolvePnPMethod.IPPE)]
[InlineData(SolvePnPMethod.SQPNP)]
public void SolvePnPTestByArrayMethods(SolvePnPMethod method)
{
var rvec = new double[] { 3, 0, 0 };
var tvec = new double[] { 0, 0, 10 };
var cameraMatrix = new double[,]
{
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 }
};
var dist = new double[] { 0, 0, 0, 0, 0 };

var objPts = new[]
{
new Point3f(0,0,1),
new Point3f(1,0,1),
new Point3f(0,1,1),
new Point3f(1,1,1)
};

Cv2.ProjectPoints(objPts, rvec, tvec, cameraMatrix, dist, out var imgPts, out _);

Cv2.SolvePnP(objPts, imgPts, cameraMatrix, dist, ref rvec, ref tvec, flags: method);

// Verify the recovered pose actually reprojects onto imgPts (rather than just "didn't throw"):
// a stale/misdirected enum value can silently dispatch to a different native solver that
// still runs to completion without throwing, but produces a wrong pose.
Cv2.ProjectPoints(objPts, rvec, tvec, cameraMatrix, dist, out var reprojected, out _);
for (var i = 0; i < imgPts.Length; i++)
{
Assert.Equal(imgPts[i].X, reprojected[i].X, 3);
Assert.Equal(imgPts[i].Y, reprojected[i].Y, 3);
}
}

[Fact]
public void SolvePnPTestByArrayIPPESquare()
{
var rvec = new double[] { 3, 0, 0 };
var tvec = new double[] { 0, 0, 10 };
var cameraMatrix = new double[,]
{
{ 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 }
};
var dist = new double[] { 0, 0, 0, 0, 0 };

var objPts = new[]
{
new Point3f(-0.5f, 0.5f, 0),
new Point3f(0.5f, 0.5f, 0),
new Point3f(0.5f, -0.5f, 0),
new Point3f(-0.5f, -0.5f, 0)
};

Cv2.ProjectPoints(objPts, rvec, tvec, cameraMatrix, dist, out var imgPts, out _);

Cv2.SolvePnP(objPts, imgPts, cameraMatrix, dist, ref rvec, ref tvec, flags: SolvePnPMethod.IPPESquare);

Cv2.ProjectPoints(objPts, rvec, tvec, cameraMatrix, dist, out var reprojected, out _);
for (var i = 0; i < imgPts.Length; i++)
{
Assert.Equal(imgPts[i].X, reprojected[i].X, 3);
Assert.Equal(imgPts[i].Y, reprojected[i].Y, 3);
}
}

[Fact]
public void SolvePnPTestByMat()
{
Expand Down
Loading