This source file includes following definitions.
- main
- help
- initKalmanFilter
- updateKalmanFilter
- fillMeasurements
#include <iostream>
#include <time.h>
#include <opencv2/core/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/video/tracking.hpp>
#include "Mesh.h"
#include "Model.h"
#include "PnPProblem.h"
#include "RobustMatcher.h"
#include "ModelRegistration.h"
#include "Utils.h"
using namespace cv;
using namespace std;
string tutorial_path = "../../samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/";
string video_read_path = tutorial_path + "Data/box.mp4";
string yml_read_path = tutorial_path + "Data/cookies_ORB.yml";
string ply_read_path = tutorial_path + "Data/box.ply";
double f = 55;
double sx = 22.3, sy = 14.9;
double width = 640, height = 480;
double params_WEBCAM[] = { width*f/sx,
height*f/sy,
width/2,
height/2};
Scalar red(0, 0, 255);
Scalar green(0,255,0);
Scalar blue(255,0,0);
Scalar yellow(0,255,255);
int numKeyPoints = 2000;
float ratioTest = 0.70f;
bool fast_match = true;
int iterationsCount = 500;
float reprojectionError = 2.0;
double confidence = 0.95;
int minInliersKalman = 30;
int pnpMethod = SOLVEPNP_ITERATIVE;
void help();
void initKalmanFilter( KalmanFilter &KF, int nStates, int nMeasurements, int nInputs, double dt);
void updateKalmanFilter( KalmanFilter &KF, Mat &measurements,
Mat &translation_estimated, Mat &rotation_estimated );
void fillMeasurements( Mat &measurements,
const Mat &translation_measured, const Mat &rotation_measured);
int main(int argc, char *argv[])
{
help();
const String keys =
"{help h | | print this message }"
"{video v | | path to recorded video }"
"{model | | path to yml model }"
"{mesh | | path to ply mesh }"
"{keypoints k |2000 | number of keypoints to detect }"
"{ratio r |0.7 | threshold for ratio test }"
"{iterations it |500 | RANSAC maximum iterations count }"
"{error e |2.0 | RANSAC reprojection errror }"
"{confidence c |0.95 | RANSAC confidence }"
"{inliers in |30 | minimum inliers for Kalman update }"
"{method pnp |0 | PnP method: (0) ITERATIVE - (1) EPNP - (2) P3P - (3) DLS}"
"{fast f |true | use of robust fast match }"
;
CommandLineParser parser(argc, argv, keys);
if (parser.has("help"))
{
parser.printMessage();
return 0;
}
else
{
video_read_path = parser.get<string>("video").size() > 0 ? parser.get<string>("video") : video_read_path;
yml_read_path = parser.get<string>("model").size() > 0 ? parser.get<string>("model") : yml_read_path;
ply_read_path = parser.get<string>("mesh").size() > 0 ? parser.get<string>("mesh") : ply_read_path;
numKeyPoints = !parser.has("keypoints") ? parser.get<int>("keypoints") : numKeyPoints;
ratioTest = !parser.has("ratio") ? parser.get<float>("ratio") : ratioTest;
fast_match = !parser.has("fast") ? parser.get<bool>("fast") : fast_match;
iterationsCount = !parser.has("iterations") ? parser.get<int>("iterations") : iterationsCount;
reprojectionError = !parser.has("error") ? parser.get<float>("error") : reprojectionError;
confidence = !parser.has("confidence") ? parser.get<float>("confidence") : confidence;
minInliersKalman = !parser.has("inliers") ? parser.get<int>("inliers") : minInliersKalman;
pnpMethod = !parser.has("method") ? parser.get<int>("method") : pnpMethod;
}
PnPProblem pnp_detection(params_WEBCAM);
PnPProblem pnp_detection_est(params_WEBCAM);
Model model;
model.load(yml_read_path);
Mesh mesh;
mesh.load(ply_read_path);
RobustMatcher rmatcher;
Ptr<FeatureDetector> orb = ORB::create();
rmatcher.setFeatureDetector(orb);
rmatcher.setDescriptorExtractor(orb);
Ptr<flann::IndexParams> indexParams = makePtr<flann::LshIndexParams>(6, 12, 1);
Ptr<flann::SearchParams> searchParams = makePtr<flann::SearchParams>(50);
Ptr<DescriptorMatcher> matcher = makePtr<FlannBasedMatcher>(indexParams, searchParams);
rmatcher.setDescriptorMatcher(matcher);
rmatcher.setRatio(ratioTest);
KalmanFilter KF;
int nStates = 18;
int nMeasurements = 6;
int nInputs = 0;
double dt = 0.125;
initKalmanFilter(KF, nStates, nMeasurements, nInputs, dt);
Mat measurements(nMeasurements, 1, CV_64F); measurements.setTo(Scalar(0));
bool good_measurement = false;
vector<Point3f> list_points3d_model = model.get_points3d();
Mat descriptors_model = model.get_descriptors();
namedWindow("REAL TIME DEMO", WINDOW_KEEPRATIO);
VideoCapture cap;
cap.open(video_read_path);
if(!cap.isOpened())
{
cout << "Could not open the camera device" << endl;
return -1;
}
time_t start, end;
double fps, sec;
int counter = 0;
time(&start);
Mat frame, frame_vis;
while(cap.read(frame) && waitKey(30) != 27)
{
frame_vis = frame.clone();
vector<DMatch> good_matches;
vector<KeyPoint> keypoints_scene;
if(fast_match)
{
rmatcher.fastRobustMatch(frame, good_matches, keypoints_scene, descriptors_model);
}
else
{
rmatcher.robustMatch(frame, good_matches, keypoints_scene, descriptors_model);
}
vector<Point3f> list_points3d_model_match;
vector<Point2f> list_points2d_scene_match;
for(unsigned int match_index = 0; match_index < good_matches.size(); ++match_index)
{
Point3f point3d_model = list_points3d_model[ good_matches[match_index].trainIdx ];
Point2f point2d_scene = keypoints_scene[ good_matches[match_index].queryIdx ].pt;
list_points3d_model_match.push_back(point3d_model);
list_points2d_scene_match.push_back(point2d_scene);
}
draw2DPoints(frame_vis, list_points2d_scene_match, red);
Mat inliers_idx;
vector<Point2f> list_points2d_inliers;
if(good_matches.size() > 0)
{
pnp_detection.estimatePoseRANSAC( list_points3d_model_match, list_points2d_scene_match,
pnpMethod, inliers_idx,
iterationsCount, reprojectionError, confidence );
for(int inliers_index = 0; inliers_index < inliers_idx.rows; ++inliers_index)
{
int n = inliers_idx.at<int>(inliers_index);
Point2f point2d = list_points2d_scene_match[n];
list_points2d_inliers.push_back(point2d);
}
draw2DPoints(frame_vis, list_points2d_inliers, blue);
good_measurement = false;
if( inliers_idx.rows >= minInliersKalman )
{
Mat translation_measured(3, 1, CV_64F);
translation_measured = pnp_detection.get_t_matrix();
Mat rotation_measured(3, 3, CV_64F);
rotation_measured = pnp_detection.get_R_matrix();
fillMeasurements(measurements, translation_measured, rotation_measured);
good_measurement = true;
}
Mat translation_estimated(3, 1, CV_64F);
Mat rotation_estimated(3, 3, CV_64F);
updateKalmanFilter( KF, measurements,
translation_estimated, rotation_estimated);
pnp_detection_est.set_P_matrix(rotation_estimated, translation_estimated);
}
if(good_measurement)
{
drawObjectMesh(frame_vis, &mesh, &pnp_detection, green);
}
else
{
drawObjectMesh(frame_vis, &mesh, &pnp_detection_est, yellow);
}
float l = 5;
vector<Point2f> pose_points2d;
pose_points2d.push_back(pnp_detection_est.backproject3DPoint(Point3f(0,0,0)));
pose_points2d.push_back(pnp_detection_est.backproject3DPoint(Point3f(l,0,0)));
pose_points2d.push_back(pnp_detection_est.backproject3DPoint(Point3f(0,l,0)));
pose_points2d.push_back(pnp_detection_est.backproject3DPoint(Point3f(0,0,l)));
draw3DCoordinateAxes(frame_vis, pose_points2d);
time(&end);
++counter;
sec = difftime (end, start);
fps = counter / sec;
drawFPS(frame_vis, fps, yellow);
double detection_ratio = ((double)inliers_idx.rows/(double)good_matches.size())*100;
drawConfidence(frame_vis, detection_ratio, yellow);
int inliers_int = inliers_idx.rows;
int outliers_int = (int)good_matches.size() - inliers_int;
string inliers_str = IntToString(inliers_int);
string outliers_str = IntToString(outliers_int);
string n = IntToString((int)good_matches.size());
string text = "Found " + inliers_str + " of " + n + " matches";
string text2 = "Inliers: " + inliers_str + " - Outliers: " + outliers_str;
drawText(frame_vis, text, green);
drawText2(frame_vis, text2, red);
imshow("REAL TIME DEMO", frame_vis);
}
destroyWindow("REAL TIME DEMO");
cout << "GOODBYE ..." << endl;
}
void help()
{
cout
<< "--------------------------------------------------------------------------" << endl
<< "This program shows how to detect an object given its 3D textured model. You can choose to "
<< "use a recorded video or the webcam." << endl
<< "Usage:" << endl
<< "./cpp-tutorial-pnp_detection -help" << endl
<< "Keys:" << endl
<< "'esc' - to quit." << endl
<< "--------------------------------------------------------------------------" << endl
<< endl;
}
void initKalmanFilter(KalmanFilter &KF, int nStates, int nMeasurements, int nInputs, double dt)
{
KF.init(nStates, nMeasurements, nInputs, CV_64F);
setIdentity(KF.processNoiseCov, Scalar::all(1e-5));
setIdentity(KF.measurementNoiseCov, Scalar::all(1e-2));
setIdentity(KF.errorCovPost, Scalar::all(1));
KF.transitionMatrix.at<double>(0,3) = dt;
KF.transitionMatrix.at<double>(1,4) = dt;
KF.transitionMatrix.at<double>(2,5) = dt;
KF.transitionMatrix.at<double>(3,6) = dt;
KF.transitionMatrix.at<double>(4,7) = dt;
KF.transitionMatrix.at<double>(5,8) = dt;
KF.transitionMatrix.at<double>(0,6) = 0.5*pow(dt,2);
KF.transitionMatrix.at<double>(1,7) = 0.5*pow(dt,2);
KF.transitionMatrix.at<double>(2,8) = 0.5*pow(dt,2);
KF.transitionMatrix.at<double>(9,12) = dt;
KF.transitionMatrix.at<double>(10,13) = dt;
KF.transitionMatrix.at<double>(11,14) = dt;
KF.transitionMatrix.at<double>(12,15) = dt;
KF.transitionMatrix.at<double>(13,16) = dt;
KF.transitionMatrix.at<double>(14,17) = dt;
KF.transitionMatrix.at<double>(9,15) = 0.5*pow(dt,2);
KF.transitionMatrix.at<double>(10,16) = 0.5*pow(dt,2);
KF.transitionMatrix.at<double>(11,17) = 0.5*pow(dt,2);
KF.measurementMatrix.at<double>(0,0) = 1;
KF.measurementMatrix.at<double>(1,1) = 1;
KF.measurementMatrix.at<double>(2,2) = 1;
KF.measurementMatrix.at<double>(3,9) = 1;
KF.measurementMatrix.at<double>(4,10) = 1;
KF.measurementMatrix.at<double>(5,11) = 1;
}
void updateKalmanFilter( KalmanFilter &KF, Mat &measurement,
Mat &translation_estimated, Mat &rotation_estimated )
{
Mat prediction = KF.predict();
Mat estimated = KF.correct(measurement);
translation_estimated.at<double>(0) = estimated.at<double>(0);
translation_estimated.at<double>(1) = estimated.at<double>(1);
translation_estimated.at<double>(2) = estimated.at<double>(2);
Mat eulers_estimated(3, 1, CV_64F);
eulers_estimated.at<double>(0) = estimated.at<double>(9);
eulers_estimated.at<double>(1) = estimated.at<double>(10);
eulers_estimated.at<double>(2) = estimated.at<double>(11);
rotation_estimated = euler2rot(eulers_estimated);
}
void fillMeasurements( Mat &measurements,
const Mat &translation_measured, const Mat &rotation_measured)
{
Mat measured_eulers(3, 1, CV_64F);
measured_eulers = rot2euler(rotation_measured);
measurements.at<double>(0) = translation_measured.at<double>(0);
measurements.at<double>(1) = translation_measured.at<double>(1);
measurements.at<double>(2) = translation_measured.at<double>(2);
measurements.at<double>(3) = measured_eulers.at<double>(0);
measurements.at<double>(4) = measured_eulers.at<double>(1);
measurements.at<double>(5) = measured_eulers.at<double>(2);
}