Pinhole init
This commit is contained in:
parent
fd7ccb2ad0
commit
619f6be6bd
|
@ -44,6 +44,9 @@ struct AprilGrid {
|
||||||
Eigen::aligned_vector<Eigen::Vector4d> aprilgrid_corner_pos_3d;
|
Eigen::aligned_vector<Eigen::Vector4d> aprilgrid_corner_pos_3d;
|
||||||
Eigen::aligned_vector<Eigen::Vector4d> aprilgrid_vignette_pos_3d;
|
Eigen::aligned_vector<Eigen::Vector4d> aprilgrid_vignette_pos_3d;
|
||||||
|
|
||||||
|
inline int getTagCols() const { return tagCols; }
|
||||||
|
inline int getTagRows() const { return tagRows; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int tagCols; // number of apriltags
|
int tagCols; // number of apriltags
|
||||||
int tagRows; // number of apriltags
|
int tagRows; // number of apriltags
|
||||||
|
|
|
@ -34,6 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <basalt/calibration/aprilgrid.h>
|
||||||
#include <basalt/io/dataset_io.h>
|
#include <basalt/io/dataset_io.h>
|
||||||
#include <basalt/utils/common_types.h>
|
#include <basalt/utils/common_types.h>
|
||||||
#include <basalt/calibration/calibration.hpp>
|
#include <basalt/calibration/calibration.hpp>
|
||||||
|
@ -85,9 +86,13 @@ class CalibHelper {
|
||||||
|
|
||||||
static bool initializeIntrinsics(
|
static bool initializeIntrinsics(
|
||||||
const Eigen::aligned_vector<Eigen::Vector2d>& corners,
|
const Eigen::aligned_vector<Eigen::Vector2d>& corners,
|
||||||
const std::vector<int>& corner_ids,
|
const std::vector<int>& corner_ids, const AprilGrid& aprilgrid, int cols,
|
||||||
const Eigen::aligned_vector<Eigen::Vector4d>& aprilgrid_corner_pos_3d,
|
int rows, Eigen::Vector4d& init_intr);
|
||||||
int cols, int rows, Eigen::Vector4d& init_intr);
|
|
||||||
|
static bool initializeIntrinsicsPinhole(
|
||||||
|
const std::vector<CalibCornerData*> pinhole_corners,
|
||||||
|
const AprilGrid& aprilgrid, int cols, int rows,
|
||||||
|
Eigen::Vector4d& init_intr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline static double square(double x) { return x * x; }
|
inline static double square(double x) { return x * x; }
|
||||||
|
|
|
@ -34,11 +34,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <basalt/calibration/aprilgrid.h>
|
||||||
#include <basalt/calibration/calibration_helper.h>
|
#include <basalt/calibration/calibration_helper.h>
|
||||||
#include <basalt/optimization/poses_linearize.h>
|
#include <basalt/optimization/poses_linearize.h>
|
||||||
|
|
||||||
#include <basalt/camera/unified_camera.hpp>
|
|
||||||
|
|
||||||
namespace basalt {
|
namespace basalt {
|
||||||
|
|
||||||
class PosesOptimization {
|
class PosesOptimization {
|
||||||
|
@ -61,21 +60,6 @@ class PosesOptimization {
|
||||||
PosesOptimization()
|
PosesOptimization()
|
||||||
: lambda(1e-6), min_lambda(1e-12), max_lambda(100), lambda_vee(2) {}
|
: lambda(1e-6), min_lambda(1e-12), max_lambda(100), lambda_vee(2) {}
|
||||||
|
|
||||||
bool initializeIntrinsics(
|
|
||||||
size_t cam_id, const Eigen::aligned_vector<Eigen::Vector2d> &corners,
|
|
||||||
const std::vector<int> &corner_ids,
|
|
||||||
const Eigen::aligned_vector<Eigen::Vector4d> &aprilgrid_corner_pos_3d,
|
|
||||||
int cols, int rows) {
|
|
||||||
Eigen::Vector4d init_intr;
|
|
||||||
|
|
||||||
bool val = CalibHelper::initializeIntrinsics(
|
|
||||||
corners, corner_ids, aprilgrid_corner_pos_3d, cols, rows, init_intr);
|
|
||||||
|
|
||||||
calib->intrinsics[cam_id].setFromInit(init_intr);
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2 getOpticalCenter(size_t i) {
|
Vector2 getOpticalCenter(size_t i) {
|
||||||
return calib->intrinsics[i].getParam().template segment<2>(2);
|
return calib->intrinsics[i].getParam().template segment<2>(2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <opengv/sac_problems/absolute_pose/AbsolutePoseSacProblem.hpp>
|
#include <opengv/sac_problems/absolute_pose/AbsolutePoseSacProblem.hpp>
|
||||||
#include <opengv/sac_problems/relative_pose/CentralRelativePoseSacProblem.hpp>
|
#include <opengv/sac_problems/relative_pose/CentralRelativePoseSacProblem.hpp>
|
||||||
|
|
||||||
|
#include <opencv2/calib3d/calib3d.hpp>
|
||||||
|
|
||||||
namespace basalt {
|
namespace basalt {
|
||||||
|
|
||||||
template <class CamT>
|
template <class CamT>
|
||||||
|
@ -171,9 +173,8 @@ void CalibHelper::initCamPoses(
|
||||||
|
|
||||||
bool CalibHelper::initializeIntrinsics(
|
bool CalibHelper::initializeIntrinsics(
|
||||||
const Eigen::aligned_vector<Eigen::Vector2d> &corners,
|
const Eigen::aligned_vector<Eigen::Vector2d> &corners,
|
||||||
const std::vector<int> &corner_ids,
|
const std::vector<int> &corner_ids, const AprilGrid &aprilgrid, int cols,
|
||||||
const Eigen::aligned_vector<Eigen::Vector4d> &aprilgrid_corner_pos_3d,
|
int rows, Eigen::Vector4d &init_intr) {
|
||||||
int cols, int rows, Eigen::Vector4d &init_intr) {
|
|
||||||
// First, initialize the image center at the center of the image.
|
// First, initialize the image center at the center of the image.
|
||||||
|
|
||||||
Eigen::aligned_map<int, Eigen::Vector2d> id_to_corner;
|
Eigen::aligned_map<int, Eigen::Vector2d> id_to_corner;
|
||||||
|
@ -181,17 +182,17 @@ bool CalibHelper::initializeIntrinsics(
|
||||||
id_to_corner[corner_ids[i]] = corners[i];
|
id_to_corner[corner_ids[i]] = corners[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
double _xi = 1.0;
|
const double _xi = 1.0;
|
||||||
double _cu = cols / 2.0 - 0.5;
|
const double _cu = cols / 2.0 - 0.5;
|
||||||
double _cv = rows / 2.0 - 0.5;
|
const double _cv = rows / 2.0 - 0.5;
|
||||||
|
|
||||||
/// Initialize some temporaries needed.
|
/// Initialize some temporaries needed.
|
||||||
double gamma0 = 0.0;
|
double gamma0 = 0.0;
|
||||||
double minReprojErr = std::numeric_limits<double>::max();
|
double minReprojErr = std::numeric_limits<double>::max();
|
||||||
|
|
||||||
// Now we try to find a non-radial line to initialize the focal length
|
// Now we try to find a non-radial line to initialize the focal length
|
||||||
const size_t target_cols = 6;
|
const size_t target_cols = aprilgrid.getTagCols();
|
||||||
const size_t target_rows = 6;
|
const size_t target_rows = aprilgrid.getTagRows();
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
for (int tag_corner_offset = 0; tag_corner_offset < 2; tag_corner_offset++)
|
for (int tag_corner_offset = 0; tag_corner_offset < 2; tag_corner_offset++)
|
||||||
|
@ -270,14 +271,14 @@ bool CalibHelper::initializeIntrinsics(
|
||||||
size_t num_inliers;
|
size_t num_inliers;
|
||||||
Sophus::SE3d T_target_camera;
|
Sophus::SE3d T_target_camera;
|
||||||
if (!estimateTransformation(cam_calib, corners, corner_ids,
|
if (!estimateTransformation(cam_calib, corners, corner_ids,
|
||||||
aprilgrid_corner_pos_3d, T_target_camera,
|
aprilgrid.aprilgrid_corner_pos_3d,
|
||||||
num_inliers)) {
|
T_target_camera, num_inliers)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
double reprojErr = 0.0;
|
double reprojErr = 0.0;
|
||||||
size_t numReprojected = computeReprojectionError(
|
size_t numReprojected = computeReprojectionError(
|
||||||
cam_calib, corners, corner_ids, aprilgrid_corner_pos_3d,
|
cam_calib, corners, corner_ids, aprilgrid.aprilgrid_corner_pos_3d,
|
||||||
T_target_camera, reprojErr);
|
T_target_camera, reprojErr);
|
||||||
|
|
||||||
// std::cerr << "numReprojected " << numReprojected << " reprojErr "
|
// std::cerr << "numReprojected " << numReprojected << " reprojErr "
|
||||||
|
@ -301,6 +302,105 @@ bool CalibHelper::initializeIntrinsics(
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CalibHelper::initializeIntrinsicsPinhole(
|
||||||
|
const std::vector<CalibCornerData *> pinhole_corners,
|
||||||
|
const AprilGrid &aprilgrid, int cols, int rows,
|
||||||
|
Eigen::Vector4d &init_intr) {
|
||||||
|
// First, initialize the image center at the center of the image.
|
||||||
|
|
||||||
|
const double _cu = cols / 2.0 - 0.5;
|
||||||
|
const double _cv = rows / 2.0 - 0.5;
|
||||||
|
|
||||||
|
// Z. Zhang, A Flexible New Technique for Camera Calibration, PAMI 2000
|
||||||
|
|
||||||
|
size_t nImages = pinhole_corners.size();
|
||||||
|
|
||||||
|
// Eigen::MatrixXd A(2 * nImages, 2);
|
||||||
|
// Eigen::VectorXd b(2 * nImages);
|
||||||
|
|
||||||
|
Eigen::MatrixXd A(nImages * 2, 2);
|
||||||
|
Eigen::VectorXd b(nImages * 2, 1);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (const CalibCornerData *ccd : pinhole_corners) {
|
||||||
|
const auto &corners = ccd->corners;
|
||||||
|
const auto &corner_ids = ccd->corner_ids;
|
||||||
|
|
||||||
|
std::vector<cv::Point2f> M(corners.size()), imagePoints(corners.size());
|
||||||
|
for (size_t j = 0; j < corners.size(); ++j) {
|
||||||
|
M.at(j) =
|
||||||
|
cv::Point2f(aprilgrid.aprilgrid_corner_pos_3d[corner_ids[j]][0],
|
||||||
|
aprilgrid.aprilgrid_corner_pos_3d[corner_ids[j]][1]);
|
||||||
|
|
||||||
|
// std::cout << "corner "
|
||||||
|
// <<
|
||||||
|
// aprilgrid.aprilgrid_corner_pos_3d[corner_ids[j]].transpose()
|
||||||
|
// << std::endl;
|
||||||
|
|
||||||
|
imagePoints.at(j) = cv::Point2f(corners[j][0], corners[j][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat H = cv::findHomography(M, imagePoints);
|
||||||
|
|
||||||
|
if (H.empty()) return false;
|
||||||
|
|
||||||
|
// std::cout << H << std::endl;
|
||||||
|
|
||||||
|
H.at<double>(0, 0) -= H.at<double>(2, 0) * _cu;
|
||||||
|
H.at<double>(0, 1) -= H.at<double>(2, 1) * _cu;
|
||||||
|
H.at<double>(0, 2) -= H.at<double>(2, 2) * _cu;
|
||||||
|
H.at<double>(1, 0) -= H.at<double>(2, 0) * _cv;
|
||||||
|
H.at<double>(1, 1) -= H.at<double>(2, 1) * _cv;
|
||||||
|
H.at<double>(1, 2) -= H.at<double>(2, 2) * _cv;
|
||||||
|
|
||||||
|
double h[3], v[3], d1[3], d2[3];
|
||||||
|
double n[4] = {0, 0, 0, 0};
|
||||||
|
|
||||||
|
for (int j = 0; j < 3; ++j) {
|
||||||
|
double t0 = H.at<double>(j, 0);
|
||||||
|
double t1 = H.at<double>(j, 1);
|
||||||
|
h[j] = t0;
|
||||||
|
v[j] = t1;
|
||||||
|
d1[j] = (t0 + t1) * 0.5;
|
||||||
|
d2[j] = (t0 - t1) * 0.5;
|
||||||
|
n[0] += t0 * t0;
|
||||||
|
n[1] += t1 * t1;
|
||||||
|
n[2] += d1[j] * d1[j];
|
||||||
|
n[3] += d2[j] * d2[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < 4; ++j) {
|
||||||
|
n[j] = 1.0 / sqrt(n[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < 3; ++j) {
|
||||||
|
h[j] *= n[0];
|
||||||
|
v[j] *= n[1];
|
||||||
|
d1[j] *= n[2];
|
||||||
|
d2[j] *= n[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
A(i * 2, 0) = h[0] * v[0];
|
||||||
|
A(i * 2, 1) = h[1] * v[1];
|
||||||
|
A(i * 2 + 1, 0) = d1[0] * d2[0];
|
||||||
|
A(i * 2 + 1, 1) = d1[1] * d2[1];
|
||||||
|
b(i * 2, 0) = -h[2] * v[2];
|
||||||
|
b(i * 2 + 1, 0) = -d1[2] * d2[2];
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Eigen::Vector2d f = (A.transpose() * A).ldlt().solve(A.transpose() * b);
|
||||||
|
|
||||||
|
double fx = sqrt(fabs(1.0 / f(0)));
|
||||||
|
double fy = sqrt(fabs(1.0 / f(1)));
|
||||||
|
|
||||||
|
init_intr << fx, fy, _cu, _cv;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void CalibHelper::computeInitialPose(
|
void CalibHelper::computeInitialPose(
|
||||||
const Calibration<double>::Ptr &calib, size_t cam_id,
|
const Calibration<double>::Ptr &calib, size_t cam_id,
|
||||||
const Eigen::aligned_vector<Eigen::Vector4d> &aprilgrid_corner_pos_3d,
|
const Eigen::aligned_vector<Eigen::Vector4d> &aprilgrid_corner_pos_3d,
|
||||||
|
|
|
@ -450,8 +450,14 @@ void CamCalib::initCamIntrinsics() {
|
||||||
|
|
||||||
calib_opt->resetCalib(vio_dataset->get_num_cams(), cam_types);
|
calib_opt->resetCalib(vio_dataset->get_num_cams(), cam_types);
|
||||||
|
|
||||||
|
std::vector<bool> cam_initialized(vio_dataset->get_num_cams(), false);
|
||||||
|
|
||||||
|
int inc = 1;
|
||||||
|
if (vio_dataset->get_image_timestamps().size() > 100) inc = 3;
|
||||||
|
|
||||||
for (size_t j = 0; j < vio_dataset->get_num_cams(); j++) {
|
for (size_t j = 0; j < vio_dataset->get_num_cams(); j++) {
|
||||||
for (size_t i = 0; i < vio_dataset->get_image_timestamps().size(); i++) {
|
for (size_t i = 0; i < vio_dataset->get_image_timestamps().size();
|
||||||
|
i += inc) {
|
||||||
const int64_t timestamp_ns = vio_dataset->get_image_timestamps()[i];
|
const int64_t timestamp_ns = vio_dataset->get_image_timestamps()[i];
|
||||||
const std::vector<basalt::ImageData> &img_vec =
|
const std::vector<basalt::ImageData> &img_vec =
|
||||||
vio_dataset->get_image_data(timestamp_ns);
|
vio_dataset->get_image_data(timestamp_ns);
|
||||||
|
@ -461,10 +467,59 @@ void CamCalib::initCamIntrinsics() {
|
||||||
if (calib_corners.find(tcid) != calib_corners.end()) {
|
if (calib_corners.find(tcid) != calib_corners.end()) {
|
||||||
CalibCornerData cid = calib_corners.at(tcid);
|
CalibCornerData cid = calib_corners.at(tcid);
|
||||||
|
|
||||||
bool success = calib_opt->initializeIntrinsics(
|
Eigen::Vector4d init_intr;
|
||||||
j, cid.corners, cid.corner_ids, april_grid.aprilgrid_corner_pos_3d,
|
|
||||||
img_vec[j].img->w, img_vec[j].img->h);
|
bool success = CalibHelper::initializeIntrinsics(
|
||||||
if (success) break;
|
cid.corners, cid.corner_ids, april_grid, img_vec[j].img->w,
|
||||||
|
img_vec[j].img->h, init_intr);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
cam_initialized[j] = true;
|
||||||
|
calib_opt->calib->intrinsics[j].setFromInit(init_intr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try perfect pinhole initialization for cameras that are not initalized.
|
||||||
|
for (size_t j = 0; j < vio_dataset->get_num_cams(); j++) {
|
||||||
|
if (!cam_initialized[j]) {
|
||||||
|
std::vector<CalibCornerData *> pinhole_corners;
|
||||||
|
int w, h;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < vio_dataset->get_image_timestamps().size();
|
||||||
|
i += inc) {
|
||||||
|
const int64_t timestamp_ns = vio_dataset->get_image_timestamps()[i];
|
||||||
|
const std::vector<basalt::ImageData> &img_vec =
|
||||||
|
vio_dataset->get_image_data(timestamp_ns);
|
||||||
|
|
||||||
|
TimeCamId tcid(timestamp_ns, j);
|
||||||
|
|
||||||
|
auto it = calib_corners.find(tcid);
|
||||||
|
if (it != calib_corners.end()) {
|
||||||
|
if (it->second.corners.size() > 8) {
|
||||||
|
pinhole_corners.emplace_back(&it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w = img_vec[j].img->w;
|
||||||
|
h = img_vec[j].img->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
Eigen::Vector4d init_intr;
|
||||||
|
|
||||||
|
bool success = CalibHelper::initializeIntrinsicsPinhole(
|
||||||
|
pinhole_corners, april_grid, w, h, init_intr);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
cam_initialized[j] = true;
|
||||||
|
|
||||||
|
std::cout << "Initialized camera " << j
|
||||||
|
<< " with pinhole model. You should set pinhole model for "
|
||||||
|
"this camera!"
|
||||||
|
<< std::endl;
|
||||||
|
calib_opt->calib->intrinsics[j].setFromInit(init_intr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 34668f662181af61b504400fa80c7f4416c7f6e2
|
Subproject commit d4c366688fa4c6daa74822dffdca3cefd0e04223
|
Loading…
Reference in New Issue