shorten parameter values
parent
224af650bb
commit
937cdcf4d9
|
@ -0,0 +1,236 @@
|
||||||
|
/**
|
||||||
|
* @file ISAM2_SmartFactorStereo_IMU.cpp
|
||||||
|
* @brief test of iSAM2 with smart stereo factors and IMU preintegration,
|
||||||
|
* originally used to debug valgrind invalid reads with Eigen
|
||||||
|
* @author Nghia Ho
|
||||||
|
*
|
||||||
|
* Setup is a stationary stereo camera with an IMU attached.
|
||||||
|
* The data file is at examples/Data/ISAM2_SmartFactorStereo_IMU.txt
|
||||||
|
* It contains 5 frames of stereo matches and IMU data.
|
||||||
|
*/
|
||||||
|
#include <gtsam/navigation/CombinedImuFactor.h>
|
||||||
|
#include <gtsam/nonlinear/ISAM2.h>
|
||||||
|
#include <gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace gtsam;
|
||||||
|
using symbol_shorthand::X;
|
||||||
|
using symbol_shorthand::V;
|
||||||
|
using symbol_shorthand::B;
|
||||||
|
|
||||||
|
struct IMUHelper {
|
||||||
|
IMUHelper() {
|
||||||
|
{
|
||||||
|
auto gaussian = noiseModel::Diagonal::Sigmas(
|
||||||
|
(Vector(6) << Vector3::Constant(5.0e-2), Vector3::Constant(5.0e-3))
|
||||||
|
.finished());
|
||||||
|
|
||||||
|
auto huber = noiseModel::Robust::Create(
|
||||||
|
noiseModel::mEstimator::Huber::Create(1.345), gaussian);
|
||||||
|
|
||||||
|
biasNoiseModel = huber;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto gaussian = noiseModel::Isotropic::Sigma(3, 0.01);
|
||||||
|
auto huber = noiseModel::Robust::Create(
|
||||||
|
noiseModel::mEstimator::Huber::Create(1.345), gaussian);
|
||||||
|
|
||||||
|
velocityNoiseModel = huber;
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect IMU to be rotated in image space co-ords
|
||||||
|
auto p = boost::make_shared<PreintegratedCombinedMeasurements::Params>(
|
||||||
|
Vector3(0.0, 9.8, 0.0));
|
||||||
|
|
||||||
|
p->accelerometerCovariance =
|
||||||
|
I_3x3 * pow(0.0565, 2.0); // acc white noise in continuous
|
||||||
|
p->integrationCovariance =
|
||||||
|
I_3x3 * 1e-9; // integration uncertainty continuous
|
||||||
|
p->gyroscopeCovariance =
|
||||||
|
I_3x3 * pow(4.0e-5, 2.0); // gyro white noise in continuous
|
||||||
|
p->biasAccCovariance = I_3x3 * pow(0.00002, 2.0); // acc bias in continuous
|
||||||
|
p->biasOmegaCovariance =
|
||||||
|
I_3x3 * pow(0.001, 2.0); // gyro bias in continuous
|
||||||
|
p->biasAccOmegaInt = Matrix::Identity(6, 6) * 1e-5;
|
||||||
|
|
||||||
|
// body to IMU rotation
|
||||||
|
Rot3 iRb(
|
||||||
|
0.036129, -0.998727, 0.035207,
|
||||||
|
0.045417, -0.033553, -0.99840,4
|
||||||
|
0.998315, 0.037670, 0.044147);
|
||||||
|
|
||||||
|
// body to IMU translation (meters)
|
||||||
|
Point3 iTb(0.03, -0.025, -0.06);
|
||||||
|
|
||||||
|
// body in this example is the left camera
|
||||||
|
p->body_P_sensor = Pose3(iRb, iTb);
|
||||||
|
|
||||||
|
Rot3 prior_rotation = Rot3(I_3x3);
|
||||||
|
Pose3 prior_pose(prior_rotation, Point3(0, 0, 0));
|
||||||
|
|
||||||
|
Vector3 acc_bias(0.0, -0.0942015, 0.0); // in camera frame
|
||||||
|
Vector3 gyro_bias(-0.00527483, -0.00757152, -0.00469968);
|
||||||
|
|
||||||
|
priorImuBias = imuBias::ConstantBias(acc_bias, gyro_bias);
|
||||||
|
|
||||||
|
prevState = NavState(prior_pose, Vector3(0, 0, 0));
|
||||||
|
propState = prevState;
|
||||||
|
prevBias = priorImuBias;
|
||||||
|
|
||||||
|
preintegrated = new PreintegratedCombinedMeasurements(p, priorImuBias);
|
||||||
|
}
|
||||||
|
|
||||||
|
imuBias::ConstantBias priorImuBias; // assume zero initial bias
|
||||||
|
noiseModel::Robust::shared_ptr velocityNoiseModel;
|
||||||
|
noiseModel::Robust::shared_ptr biasNoiseModel;
|
||||||
|
NavState prevState;
|
||||||
|
NavState propState;
|
||||||
|
imuBias::ConstantBias prevBias;
|
||||||
|
PreintegratedCombinedMeasurements* preintegrated;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
if (argc != 2) {
|
||||||
|
cout << "./main [data.txt]\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ifstream in(argv[1]);
|
||||||
|
|
||||||
|
if (!in) {
|
||||||
|
cerr << "error opening: " << argv[1] << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Camera parameters
|
||||||
|
double fx = 822.37;
|
||||||
|
double fy = 822.37;
|
||||||
|
double cx = 538.73;
|
||||||
|
double cy = 579.10;
|
||||||
|
double baseline = 0.372; // meters
|
||||||
|
|
||||||
|
Cal3_S2Stereo::shared_ptr K(new Cal3_S2Stereo(fx, fy, 0.0, cx, cy, baseline));
|
||||||
|
|
||||||
|
ISAM2Params parameters;
|
||||||
|
parameters.relinearizeThreshold = 0.1;
|
||||||
|
ISAM2 isam(parameters);
|
||||||
|
|
||||||
|
// Create a factor graph
|
||||||
|
std::map<size_t, SmartStereoProjectionPoseFactor::shared_ptr> smartFactors;
|
||||||
|
NonlinearFactorGraph graph;
|
||||||
|
Values initialEstimate;
|
||||||
|
IMUHelper imu;
|
||||||
|
|
||||||
|
// Pose prior - at identity
|
||||||
|
auto priorPoseNoise = noiseModel::Diagonal::Sigmas(
|
||||||
|
(Vector(6) << Vector3::Constant(0.1), Vector3::Constant(0.1)).finished());
|
||||||
|
graph.emplace_shared<PriorFactor<Pose3>>(X(1), Pose3::identity(),
|
||||||
|
priorPoseNoise);
|
||||||
|
initialEstimate.insert(X(0), Pose3::identity());
|
||||||
|
|
||||||
|
// Bias prior
|
||||||
|
graph.add(PriorFactor<imuBias::ConstantBias>(B(1), imu.priorImuBias,
|
||||||
|
imu.biasNoiseModel));
|
||||||
|
initialEstimate.insert(B(0), imu.priorImuBias);
|
||||||
|
|
||||||
|
// Velocity prior - assume stationary
|
||||||
|
graph.add(
|
||||||
|
PriorFactor<Vector3>(V(1), Vector3(0, 0, 0), imu.velocityNoiseModel));
|
||||||
|
initialEstimate.insert(V(0), Vector3(0, 0, 0));
|
||||||
|
|
||||||
|
int lastFrame = 1;
|
||||||
|
int frame;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
char line[1024];
|
||||||
|
|
||||||
|
in.getline(line, sizeof(line));
|
||||||
|
stringstream ss(line);
|
||||||
|
char type;
|
||||||
|
|
||||||
|
ss >> type;
|
||||||
|
ss >> frame;
|
||||||
|
|
||||||
|
if (frame != lastFrame || in.eof()) {
|
||||||
|
cout << "Running iSAM for frame: " << lastFrame << "\n";
|
||||||
|
|
||||||
|
initialEstimate.insert(X(lastFrame), Pose3::identity());
|
||||||
|
initialEstimate.insert(V(lastFrame), Vector3(0, 0, 0));
|
||||||
|
initialEstimate.insert(B(lastFrame), imu.prevBias);
|
||||||
|
|
||||||
|
CombinedImuFactor imuFactor(X(lastFrame - 1), V(lastFrame - 1),
|
||||||
|
X(lastFrame), V(lastFrame), B(lastFrame - 1),
|
||||||
|
B(lastFrame), *imu.preintegrated);
|
||||||
|
|
||||||
|
graph.add(imuFactor);
|
||||||
|
|
||||||
|
isam.update(graph, initialEstimate);
|
||||||
|
|
||||||
|
Values currentEstimate = isam.calculateEstimate();
|
||||||
|
|
||||||
|
imu.propState = imu.preintegrated->predict(imu.prevState, imu.prevBias);
|
||||||
|
imu.prevState = NavState(currentEstimate.at<Pose3>(X(lastFrame)),
|
||||||
|
currentEstimate.at<Vector3>(V(lastFrame)));
|
||||||
|
imu.prevBias = currentEstimate.at<imuBias::ConstantBias>(B(lastFrame));
|
||||||
|
imu.preintegrated->resetIntegrationAndSetBias(imu.prevBias);
|
||||||
|
|
||||||
|
graph.resize(0);
|
||||||
|
initialEstimate.clear();
|
||||||
|
|
||||||
|
if (in.eof()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == 'i') { // Process IMU measurement
|
||||||
|
double ax, ay, az;
|
||||||
|
double gx, gy, gz;
|
||||||
|
double dt = 1 / 800.0; // IMU at ~800Hz
|
||||||
|
|
||||||
|
ss >> ax;
|
||||||
|
ss >> ay;
|
||||||
|
ss >> az;
|
||||||
|
|
||||||
|
ss >> gx;
|
||||||
|
ss >> gy;
|
||||||
|
ss >> gz;
|
||||||
|
|
||||||
|
Vector3 acc(ax, ay, az);
|
||||||
|
Vector3 gyr(gx, gy, gz);
|
||||||
|
|
||||||
|
imu.preintegrated->integrateMeasurement(acc, gyr, dt);
|
||||||
|
} else if (type == 's') { // Process stereo measurement
|
||||||
|
int landmark;
|
||||||
|
double xl, xr, y;
|
||||||
|
|
||||||
|
ss >> landmark;
|
||||||
|
ss >> xl;
|
||||||
|
ss >> xr;
|
||||||
|
ss >> y;
|
||||||
|
|
||||||
|
if (smartFactors.count(landmark) == 0) {
|
||||||
|
auto gaussian = noiseModel::Isotropic::Sigma(3, 1.0);
|
||||||
|
|
||||||
|
SmartProjectionParams params(HESSIAN, ZERO_ON_DEGENERACY);
|
||||||
|
|
||||||
|
smartFactors[landmark] = SmartStereoProjectionPoseFactor::shared_ptr(
|
||||||
|
new SmartStereoProjectionPoseFactor(gaussian, params));
|
||||||
|
graph.push_back(smartFactors[landmark]);
|
||||||
|
}
|
||||||
|
|
||||||
|
smartFactors[landmark]->add(StereoPoint2(xl, xr, y), X(frame), K);
|
||||||
|
} else {
|
||||||
|
throw runtime_error("unexpected data type: " + type);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastFrame = frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -1,222 +0,0 @@
|
||||||
#include <gtsam/nonlinear/ISAM2.h>
|
|
||||||
#include <gtsam/slam/BetweenFactor.h>
|
|
||||||
#include <gtsam_unstable/slam/SmartStereoProjectionPoseFactor.h>
|
|
||||||
#include <gtsam/navigation/CombinedImuFactor.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
#include <sstream>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace gtsam;
|
|
||||||
using symbol_shorthand::X;
|
|
||||||
using symbol_shorthand::V;
|
|
||||||
using symbol_shorthand::B;
|
|
||||||
|
|
||||||
struct IMUHelper
|
|
||||||
{
|
|
||||||
IMUHelper()
|
|
||||||
{
|
|
||||||
gtsam::Matrix33 measured_acc_cov = gtsam::Matrix33::Identity(3,3) * pow(0.113, 2.0);
|
|
||||||
gtsam::Matrix33 measured_omega_cov = gtsam::Matrix33::Identity(3,3) * pow(4.0e-5, 2.0);
|
|
||||||
gtsam::Matrix33 bias_acc_cov = gtsam::Matrix33::Identity(3,3) * pow( 0.00002, 2.0);
|
|
||||||
gtsam::Matrix33 bias_omega_cov = gtsam::Matrix33::Identity(3,3) * pow(0.001, 2.0);
|
|
||||||
gtsam::Matrix33 integration_error_cov = gtsam::Matrix33::Identity(3,3)*1e-9; // error committed in integrating position from velocities
|
|
||||||
gtsam::Matrix bias_acc_omega_int = gtsam::Matrix::Identity(6,6)*1e-5; // error in the bias used for preintegration
|
|
||||||
|
|
||||||
{
|
|
||||||
auto gaussian = gtsam::noiseModel::Diagonal::Sigmas(
|
|
||||||
(gtsam::Vector(6) <<
|
|
||||||
gtsam::Vector3::Constant(5.0e-2),
|
|
||||||
gtsam::Vector3::Constant(5.0e-3)).finished());
|
|
||||||
|
|
||||||
auto huber = gtsam::noiseModel::Robust::Create(gtsam::noiseModel::mEstimator::Huber::Create(1.345), gaussian);
|
|
||||||
|
|
||||||
bias_noise_model = huber;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
auto gaussian = gtsam::noiseModel::Isotropic::Sigma(3,0.01);
|
|
||||||
auto huber = gtsam::noiseModel::Robust::Create(gtsam::noiseModel::mEstimator::Huber::Create(1.345), gaussian);
|
|
||||||
|
|
||||||
velocity_noise_model = huber;
|
|
||||||
}
|
|
||||||
|
|
||||||
// expect IMU to be rotated in image space co-ords
|
|
||||||
auto p = boost::make_shared<gtsam::PreintegratedCombinedMeasurements::Params>(gtsam::Vector3(0.0, 9.8, 0.0));
|
|
||||||
|
|
||||||
p->accelerometerCovariance = measured_acc_cov; // acc white noise in continuous
|
|
||||||
p->integrationCovariance = integration_error_cov; // integration uncertainty continuous
|
|
||||||
p->gyroscopeCovariance = measured_omega_cov; // gyro white noise in continuous
|
|
||||||
p->biasAccCovariance = bias_acc_cov; // acc bias in continuous
|
|
||||||
p->biasOmegaCovariance = bias_omega_cov; // gyro bias in continuous
|
|
||||||
p->biasAccOmegaInt = bias_acc_omega_int;
|
|
||||||
|
|
||||||
// from SVD comparing gyro and vision estimates, no bias modelled
|
|
||||||
gtsam::Rot3 body_to_imu_rot(
|
|
||||||
3.612861008216737e-02, -9.987267865568920e-01, 3.520695026944293e-02,
|
|
||||||
4.541686330383411e-02, -3.355264881270600e-02, -9.984044913186698e-01,
|
|
||||||
9.983145957368207e-01, 3.766995581886975e-02, 4.414682737675374e-02);
|
|
||||||
|
|
||||||
gtsam::Point3 body_to_imu_trans(0.03, -0.025, -0.06);
|
|
||||||
|
|
||||||
p->body_P_sensor = gtsam::Pose3(body_to_imu_rot, body_to_imu_trans);
|
|
||||||
|
|
||||||
gtsam::Rot3 prior_rotation = gtsam::Rot3(gtsam::Matrix33::Identity());
|
|
||||||
gtsam::Pose3 prior_pose(prior_rotation, gtsam::Point3(0,0,0));
|
|
||||||
|
|
||||||
gtsam::Vector3 acc_bias(2.05998e-18, -0.0942015, 1.17663e-16);
|
|
||||||
gtsam::Vector3 gyro_bias(0,0,0);
|
|
||||||
|
|
||||||
prior_imu_bias = gtsam::imuBias::ConstantBias(acc_bias, gyro_bias);
|
|
||||||
|
|
||||||
prev_state = gtsam::NavState(prior_pose, gtsam::Vector3(0,0,0));
|
|
||||||
prop_state = prev_state;
|
|
||||||
prev_bias = prior_imu_bias;
|
|
||||||
|
|
||||||
preintegrated = new gtsam::PreintegratedCombinedMeasurements(p, prior_imu_bias);
|
|
||||||
}
|
|
||||||
|
|
||||||
gtsam::imuBias::ConstantBias prior_imu_bias; // assume zero initial bias
|
|
||||||
gtsam::noiseModel::Robust::shared_ptr velocity_noise_model;
|
|
||||||
gtsam::noiseModel::Robust::shared_ptr bias_noise_model;
|
|
||||||
gtsam::NavState prev_state;
|
|
||||||
gtsam::NavState prop_state;
|
|
||||||
gtsam::imuBias::ConstantBias prev_bias;
|
|
||||||
gtsam::PreintegratedCombinedMeasurements *preintegrated;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
if (argc != 2) {
|
|
||||||
cout << "./main [data.txt]\n";
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
double fx = 8.2237229542137766e+02;
|
|
||||||
double fy = fx;
|
|
||||||
double cx = 5.3872524261474609e+02;
|
|
||||||
double cy = 5.7909587860107422e+02;
|
|
||||||
double baseline = 7.4342307430851651e-01;
|
|
||||||
|
|
||||||
Cal3_S2Stereo::shared_ptr K(new Cal3_S2Stereo(fx, fy, 0.0, cx, cy, baseline));
|
|
||||||
|
|
||||||
ISAM2Params parameters;
|
|
||||||
parameters.relinearizeThreshold = 0.1;
|
|
||||||
ISAM2 isam(parameters);
|
|
||||||
|
|
||||||
// Create a factor graph
|
|
||||||
std::map<size_t, gtsam::SmartStereoProjectionPoseFactor::shared_ptr> smartFactors;
|
|
||||||
NonlinearFactorGraph graph;
|
|
||||||
Values initialEstimate;
|
|
||||||
IMUHelper imu;
|
|
||||||
|
|
||||||
// Pose prior
|
|
||||||
auto priorPoseNoise = noiseModel::Diagonal::Sigmas((Vector(6) << Vector3::Constant(0.1), Vector3::Constant(0.1)).finished());
|
|
||||||
graph.emplace_shared<PriorFactor<Pose3>>(X(1), Pose3::identity(), priorPoseNoise);
|
|
||||||
initialEstimate.insert(X(0), Pose3::identity());
|
|
||||||
|
|
||||||
// Bias prior
|
|
||||||
graph.add(PriorFactor<imuBias::ConstantBias>(B(1), imu.prior_imu_bias, imu.bias_noise_model));
|
|
||||||
initialEstimate.insert(B(0), imu.prior_imu_bias);
|
|
||||||
|
|
||||||
// Velocity prior
|
|
||||||
graph.add(PriorFactor<Vector3>(V(1), Vector3(0,0,0), imu.velocity_noise_model));
|
|
||||||
initialEstimate.insert(V(0), Vector3(0,0,0));
|
|
||||||
|
|
||||||
ifstream in(argv[1]);
|
|
||||||
|
|
||||||
if (!in) {
|
|
||||||
cerr << "error opening: " << argv[1] << "\n";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int last_frame = 1;
|
|
||||||
int frame;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
char line[1024];
|
|
||||||
|
|
||||||
in.getline(line, sizeof(line));
|
|
||||||
stringstream ss(line);
|
|
||||||
char type;
|
|
||||||
|
|
||||||
ss >> type;
|
|
||||||
ss >> frame;
|
|
||||||
|
|
||||||
if (frame != last_frame || in.eof()) {
|
|
||||||
cout << "Running isam for frame: " << last_frame << "\n";
|
|
||||||
|
|
||||||
initialEstimate.insert(X(last_frame), Pose3::identity());
|
|
||||||
initialEstimate.insert(V(last_frame), Vector3(0,0,0));
|
|
||||||
initialEstimate.insert(B(last_frame), imu.prev_bias);
|
|
||||||
|
|
||||||
CombinedImuFactor imu_factor(
|
|
||||||
X(last_frame-1), V(last_frame-1),
|
|
||||||
X(last_frame), V(last_frame),
|
|
||||||
B(last_frame-1), B(last_frame),
|
|
||||||
*imu.preintegrated);
|
|
||||||
|
|
||||||
graph.add(imu_factor);
|
|
||||||
|
|
||||||
isam.update(graph, initialEstimate);
|
|
||||||
|
|
||||||
Values currentEstimate = isam.calculateEstimate();
|
|
||||||
//currentEstimate.print("Current estimate: ");
|
|
||||||
|
|
||||||
imu.prop_state = imu.preintegrated->predict(imu.prev_state, imu.prev_bias);
|
|
||||||
imu.prev_state = NavState(currentEstimate.at<Pose3>(X(last_frame)), currentEstimate.at<Vector3>(V(last_frame)));
|
|
||||||
imu.prev_bias = currentEstimate.at<imuBias::ConstantBias>(B(last_frame));
|
|
||||||
imu.preintegrated->resetIntegrationAndSetBias(imu.prev_bias);
|
|
||||||
|
|
||||||
graph.resize(0);
|
|
||||||
initialEstimate.clear();
|
|
||||||
|
|
||||||
if (in.eof()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == 'i') {
|
|
||||||
double ax, ay, az;
|
|
||||||
double gx, gy, gz;
|
|
||||||
double dt = 1/800.0;
|
|
||||||
|
|
||||||
ss >> ax;
|
|
||||||
ss >> ay;
|
|
||||||
ss >> az;
|
|
||||||
|
|
||||||
ss >> gx;
|
|
||||||
ss >> gy;
|
|
||||||
ss >> gz;
|
|
||||||
|
|
||||||
Vector3 acc(ax, ay, az);
|
|
||||||
Vector3 gyr(gx, gy, gz);
|
|
||||||
|
|
||||||
imu.preintegrated->integrateMeasurement(acc, gyr, dt);
|
|
||||||
} else if (type == 's') {
|
|
||||||
int landmark;
|
|
||||||
double xl, xr, y;
|
|
||||||
|
|
||||||
ss >> landmark;
|
|
||||||
ss >> xl;
|
|
||||||
ss >> xr;
|
|
||||||
ss >> y;
|
|
||||||
|
|
||||||
if (smartFactors.count(landmark) == 0) {
|
|
||||||
auto gaussian = noiseModel::Isotropic::Sigma(3, 1.0);
|
|
||||||
|
|
||||||
SmartProjectionParams params(HESSIAN, ZERO_ON_DEGENERACY);
|
|
||||||
|
|
||||||
smartFactors[landmark] = SmartStereoProjectionPoseFactor::shared_ptr(new SmartStereoProjectionPoseFactor(gaussian, params));
|
|
||||||
graph.push_back(smartFactors[landmark]);
|
|
||||||
}
|
|
||||||
|
|
||||||
smartFactors[landmark]->add(StereoPoint2(xl, xr, y), X(frame), K);
|
|
||||||
}
|
|
||||||
|
|
||||||
last_frame = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
Loading…
Reference in New Issue