summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStéphane Lenclud <github@lenclud.com>2019-04-15 13:03:23 +0200
committerStéphane Lenclud <github@lenclud.com>2019-04-24 18:46:12 +0200
commit5e2f6182f41d7c027f58b110bc8c6e539a50ac2c (patch)
tree641fea105a557b34eac09f07d4ab6c92f50242e7
parent6ca96478ea4d8e6ba71ebf41a1f7d904f2c3df5d (diff)
Easy Tracker: Improved solver managements of data structures.
-rw-r--r--tracker-easy/tracker-easy.cpp151
-rw-r--r--tracker-easy/tracker-easy.h17
2 files changed, 74 insertions, 94 deletions
diff --git a/tracker-easy/tracker-easy.cpp b/tracker-easy/tracker-easy.cpp
index d5bccc6b..8bae883a 100644
--- a/tracker-easy/tracker-easy.cpp
+++ b/tracker-easy/tracker-easy.cpp
@@ -45,6 +45,8 @@ namespace EasyTracker
connect(&s.fov, value_::value_changed<int>(), this, &Tracker::set_fov, Qt::DirectConnection);
set_fov(s.fov);
+
+ CreateModelFromSettings();
}
Tracker::~Tracker()
@@ -60,33 +62,7 @@ namespace EasyTracker
}
- // Compute Euler angles from ratation matrix
- cv::Vec3f EulerAngles(cv::Mat &R)
- {
-
- float sy = sqrt(R.at<double>(0, 0) * R.at<double>(0, 0) + R.at<double>(1, 0) * R.at<double>(1, 0));
-
- bool singular = sy < 1e-6; // If
-
- float x, y, z;
- if (!singular)
- {
- x = atan2(R.at<double>(2, 1), R.at<double>(2, 2));
- y = atan2(-R.at<double>(2, 0), sy);
- z = atan2(R.at<double>(1, 0), R.at<double>(0, 0));
- }
- else
- {
- x = atan2(-R.at<double>(1, 2), R.at<double>(1, 1));
- y = atan2(-R.at<double>(2, 0), sy);
- z = 0;
- }
-
- // Convert to degrees
- return cv::Vec3f(x * 180 / CV_PI, y * 180 / CV_PI, z * 180 / CV_PI);
- }
-
-
+ // Compute Euler angles from rotation matrix
void getEulerAngles(cv::Mat &rotCamerMatrix, cv::Vec3d &eulerAngles)
{
@@ -106,6 +82,44 @@ namespace EasyTracker
eulerAngles);
}
+ ///
+ void Tracker::CreateModelFromSettings()
+ {
+ // Construct the points defining the object we want to detect based on settings.
+ // We are converting them from millimeters to centimeters.
+ // TODO: Need to support clip too. That's cap only for now.
+ // s.active_model_panel != PointModel::Clip
+ iModel.clear();
+ iModel.push_back(cv::Point3f(s.cap_x / 10.0, s.cap_z / 10.0, -s.cap_y / 10.0)); // Right
+ iModel.push_back(cv::Point3f(-s.cap_x / 10.0, s.cap_z / 10.0, -s.cap_y / 10.0)); // Left
+ iModel.push_back(cv::Point3f(0, 0, 0)); // Top
+ }
+
+ ///
+ void Tracker::CreateCameraIntrinsicsMatrices()
+ {
+ // Create our camera matrix
+ iCameraMatrix.create(3, 3, CV_64FC1);
+ iCameraMatrix.setTo(cv::Scalar(0));
+ iCameraMatrix.at<double>(0, 0) = iCameraInfo.focalLengthX;
+ iCameraMatrix.at<double>(1, 1) = iCameraInfo.focalLengthY;
+ iCameraMatrix.at<double>(0, 2) = iCameraInfo.principalPointX;
+ iCameraMatrix.at<double>(1, 2) = iCameraInfo.principalPointY;
+ iCameraMatrix.at<double>(2, 2) = 1;
+
+ // Create distortion cooefficients
+ iDistCoeffsMatrix = cv::Mat::zeros(8, 1, CV_64FC1);
+ // As per OpenCV docs they should be thus: k1, k2, p1, p2, k3, k4, k5, k6
+ iDistCoeffsMatrix.at<double>(0, 0) = 0; // Radial first order
+ iDistCoeffsMatrix.at<double>(1, 0) = iCameraInfo.radialDistortionSecondOrder; // Radial second order
+ iDistCoeffsMatrix.at<double>(2, 0) = 0; // Tangential first order
+ iDistCoeffsMatrix.at<double>(3, 0) = 0; // Tangential second order
+ iDistCoeffsMatrix.at<double>(4, 0) = 0; // Radial third order
+ iDistCoeffsMatrix.at<double>(5, 0) = iCameraInfo.radialDistortionFourthOrder; // Radial fourth order
+ iDistCoeffsMatrix.at<double>(6, 0) = 0; // Radial fith order
+ iDistCoeffsMatrix.at<double>(7, 0) = iCameraInfo.radialDistortionSixthOrder; // Radial sixth order
+ }
+
void Tracker::run()
{
@@ -139,8 +153,7 @@ namespace EasyTracker
}
iPoints.clear();
- iPointExtractor.ExtractPoints(iMatFrame, (preview_visible ? &iPreview.iFrameRgb : nullptr), iPoints);
- point_count.store(iPoints.size(), std::memory_order_relaxed);
+ iPointExtractor.ExtractPoints(iMatFrame, (preview_visible ? &iPreview.iFrameRgb : nullptr), iPoints);
const bool success = iPoints.size() >= KPointCount;
@@ -154,22 +167,11 @@ namespace EasyTracker
ever_success.store(true, std::memory_order_relaxed);
// Solve P3P problem with OpenCV
-
- // Construct the points defining the object we want to detect based on settings.
- // We are converting them from millimeters to centimeters.
- // TODO: Need to support clip too. That's cap only for now.
- // s.active_model_panel != PointModel::Clip
-
- std::vector<cv::Point3f> objectPoints;
- objectPoints.push_back(cv::Point3f(s.cap_x / 10.0, s.cap_z / 10.0, -s.cap_y / 10.0)); // Right
- objectPoints.push_back(cv::Point3f(-s.cap_x / 10.0, s.cap_z / 10.0, -s.cap_y / 10.0)); // Left
- objectPoints.push_back(cv::Point3f(0, 0, 0)); // Top
-
+
//Bitmap origin is top left
- std::vector<cv::Point2f> trackedPoints;
- // Stuff bitmap point in there making sure they match the order of the object point
+ iTrackedPoints.clear();
+ // Tracked points must match the order of the object model points.
// Find top most point, that's the one with min Y as we assume our guy's head is not up side down
-
int minY = std::numeric_limits<int>::max();
for (int i = 0; i < 3; i++)
{
@@ -207,52 +209,24 @@ namespace EasyTracker
}
//
- trackedPoints.push_back(iPoints[rightPointIndex]);
- trackedPoints.push_back(iPoints[leftPointIndex]);
- trackedPoints.push_back(iPoints[topPointIndex]);
-
- dbgout << "Object: " << objectPoints << "\n";
- dbgout << "Points: " << trackedPoints << "\n";
-
-
- // Create our camera matrix
- // TODO: Just do that once, use data member instead
- // Double or Float?
- cv::Mat cameraMatrix;
- cameraMatrix.create(3, 3, CV_64FC1);
- cameraMatrix.setTo(cv::Scalar(0));
- cameraMatrix.at<double>(0, 0) = iCameraInfo.focalLengthX;
- cameraMatrix.at<double>(1, 1) = iCameraInfo.focalLengthY;
- cameraMatrix.at<double>(0, 2) = iCameraInfo.principalPointX;
- cameraMatrix.at<double>(1, 2) = iCameraInfo.principalPointY;
- cameraMatrix.at<double>(2, 2) = 1;
-
- // Create distortion cooefficients
- cv::Mat distCoeffs = cv::Mat::zeros(8, 1, CV_64FC1);
- // As per OpenCV docs they should be thus: k1, k2, p1, p2, k3, k4, k5, k6
- distCoeffs.at<double>(0, 0) = 0; // Radial first order
- distCoeffs.at<double>(1, 0) = iCameraInfo.radialDistortionSecondOrder; // Radial second order
- distCoeffs.at<double>(2, 0) = 0; // Tangential first order
- distCoeffs.at<double>(3, 0) = 0; // Tangential second order
- distCoeffs.at<double>(4, 0) = 0; // Radial third order
- distCoeffs.at<double>(5, 0) = iCameraInfo.radialDistortionFourthOrder; // Radial fourth order
- distCoeffs.at<double>(6, 0) = 0; // Radial fith order
- distCoeffs.at<double>(7, 0) = iCameraInfo.radialDistortionSixthOrder; // Radial sixth order
-
- // Define our solution arrays
- // They will receive up to 4 solutions for our P3P problem
-
-
- // TODO: try SOLVEPNP_AP3P too
+ iTrackedPoints.push_back(iPoints[rightPointIndex]);
+ iTrackedPoints.push_back(iPoints[leftPointIndex]);
+ iTrackedPoints.push_back(iPoints[topPointIndex]);
+
+ dbgout << "Object: " << iModel << "\n";
+ dbgout << "Points: " << iTrackedPoints << "\n";
+
+
+ // TODO: try SOLVEPNP_AP3P too, make it a settings option?
iAngles.clear();
iBestSolutionIndex = -1;
- int solutionCount = cv::solveP3P(objectPoints, trackedPoints, cameraMatrix, distCoeffs, iRotations, iTranslations, cv::SOLVEPNP_P3P);
+ int solutionCount = cv::solveP3P(iModel, iTrackedPoints, iCameraMatrix, iDistCoeffsMatrix, iRotations, iTranslations, cv::SOLVEPNP_P3P);
if (solutionCount > 0)
{
dbgout << "Solution count: " << solutionCount << "\n";
int minPitch = std::numeric_limits<int>::max();
- // Find the solution we want
+ // Find the solution we want amongst all possible ones
for (int i = 0; i < solutionCount; i++)
{
dbgout << "Translation:\n";
@@ -270,19 +244,17 @@ namespace EasyTracker
int absolutePitch = std::abs(angles[0]);
if (minPitch > absolutePitch)
{
+ // The solution with pitch closest to zero is the one we want
minPitch = absolutePitch;
iBestSolutionIndex = i;
}
- //cv::Vec3f angles=EulerAngles(quaternion);
dbgout << angles;
dbgout << "\n";
}
dbgout << "\n";
-
}
-
}
// Send solution data back to main thread
@@ -347,7 +319,10 @@ namespace EasyTracker
iCameraInfo.width = s.cam_res_x;
iCameraInfo.height = s.cam_res_y;
- return camera->start(iCameraInfo);
+ bool res = camera->start(iCameraInfo);
+ // We got new our camera intrinsics, create corresponding matrices
+ CreateCameraIntrinsicsMatrices();
+ return res;
}
void Tracker::set_fov(int value)
@@ -398,9 +373,5 @@ namespace EasyTracker
return false;
}
- int Tracker::get_n_points()
- {
- return (int)point_count.load(std::memory_order_relaxed);
- }
}
diff --git a/tracker-easy/tracker-easy.h b/tracker-easy/tracker-easy.h
index 8b771c67..00e24811 100644
--- a/tracker-easy/tracker-easy.h
+++ b/tracker-easy/tracker-easy.h
@@ -37,6 +37,7 @@ namespace EasyTracker
struct Tracker : QThread, ITracker
{
+ public:
friend class Dialog;
explicit Tracker();
@@ -44,10 +45,11 @@ namespace EasyTracker
module_status start_tracker(QFrame* parent_window) override;
void data(double* data) override;
bool center() override;
-
- int get_n_points();
-
+
private:
+ void CreateModelFromSettings();
+ void CreateCameraIntrinsicsMatrices();
+
void run() override;
bool maybe_reopen_camera();
@@ -73,10 +75,17 @@ namespace EasyTracker
cv::Mat iMatFrame;
Preview iPreview;
- std::atomic<unsigned> point_count{ 0 };
std::atomic<bool> ever_success = false;
mutable QMutex center_lock, data_lock;
+ // Vertices defining the model we are tracking
+ std::vector<cv::Point3f> iModel;
+ // Bitmap points corresponding to model vertices
+ std::vector<cv::Point2f> iTrackedPoints;
+ // Intrinsics camera matrix
+ cv::Mat iCameraMatrix;
+ // Intrinsics distortion coefficients as a matrix
+ cv::Mat iDistCoeffsMatrix;
// Translation solutions
std::vector<cv::Mat> iTranslations;
// Rotation solutions