Compare commits
48 Commits
temp-sprea
...
soc-2013-m
Author | SHA1 | Date | |
---|---|---|---|
9e023dc9cc | |||
9c6a60ab60 | |||
d7e23e1783 | |||
4bffc83835 | |||
2a7a733784 | |||
9fdd86106c | |||
2e9c5fd705 | |||
be42beaacb | |||
39943f1486 | |||
1fb09b9d60 | |||
e494139b59 | |||
b319768af9 | |||
b6a6aaf937 | |||
0a9163c885 | |||
78b484831d | |||
e4b201f7b7 | |||
d24a4a9b63 | |||
cb21085634 | |||
ce17c21303 | |||
8896abe995 | |||
14816b3a9c | |||
600145d273 | |||
d56589fc61 | |||
67313f607a | |||
ac183d3da0 | |||
bc875d1742 | |||
18020c064c | |||
d08a4292f1 | |||
c8c9996e54 | |||
6e83ce4b70 | |||
9dfc38fe46 | |||
cefc0dd68e | |||
9ab6dba74b | |||
1305ae3380 | |||
058985fbb9 | |||
46510ad0ea | |||
0a087e78e7 | |||
280b13c3a5 | |||
8d49700939 | |||
48f811f9d6 | |||
de6c513163 | |||
8e1cac34cb | |||
6fd3c9e2e1 | |||
0efe5d47e2 | |||
732b3720d1 | |||
0f0be925bb | |||
7d53177d57 | |||
132acfbb44 |
433
extern/libmv/libmv-capi.cc
vendored
433
extern/libmv/libmv-capi.cc
vendored
@@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
#include "libmv-capi.h"
|
#include "libmv-capi.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
@@ -69,7 +71,7 @@ struct libmv_Reconstruction {
|
|||||||
|
|
||||||
/* used for per-track average error calculation after reconstruction */
|
/* used for per-track average error calculation after reconstruction */
|
||||||
libmv::Tracks tracks;
|
libmv::Tracks tracks;
|
||||||
libmv::CameraIntrinsics intrinsics;
|
std::vector<libmv::CameraIntrinsics> intrinsics;
|
||||||
|
|
||||||
double error;
|
double error;
|
||||||
};
|
};
|
||||||
@@ -398,13 +400,24 @@ void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks)
|
|||||||
delete (libmv::Tracks*) libmv_tracks;
|
delete (libmv::Tracks*) libmv_tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y)
|
void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y, int camera)
|
||||||
{
|
{
|
||||||
((libmv::Tracks*) libmv_tracks)->Insert(image, track, x, y);
|
((libmv::Tracks*)libmv_tracks)->Insert(image, track, x, y, camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************ Reconstruction ************ */
|
/* ************ Reconstruction ************ */
|
||||||
|
|
||||||
|
class LoggingCallback : public ceres::IterationCallback {
|
||||||
|
public:
|
||||||
|
~LoggingCallback() {}
|
||||||
|
|
||||||
|
ceres::CallbackReturnType operator()(const ceres::IterationSummary &summary) {
|
||||||
|
LG << "Iteration #" << summary.iteration
|
||||||
|
<< ": " << summary.cost;
|
||||||
|
return ceres::SOLVER_CONTINUE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class ReconstructUpdateCallback : public libmv::ProgressUpdateCallback {
|
class ReconstructUpdateCallback : public libmv::ProgressUpdateCallback {
|
||||||
public:
|
public:
|
||||||
ReconstructUpdateCallback(reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
|
ReconstructUpdateCallback(reconstruct_progress_update_cb progress_update_callback, void *callback_customdata)
|
||||||
@@ -424,39 +437,6 @@ protected:
|
|||||||
void *callback_customdata_;
|
void *callback_customdata_;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void libmv_solveRefineIntrinsics(const libmv::Tracks &tracks,
|
|
||||||
const int refine_intrinsics,
|
|
||||||
const int bundle_constraints,
|
|
||||||
reconstruct_progress_update_cb progress_update_callback,
|
|
||||||
void *callback_customdata,
|
|
||||||
libmv::EuclideanReconstruction *reconstruction,
|
|
||||||
libmv::CameraIntrinsics *intrinsics)
|
|
||||||
{
|
|
||||||
/* only a few combinations are supported but trust the caller */
|
|
||||||
int bundle_intrinsics = 0;
|
|
||||||
|
|
||||||
if (refine_intrinsics & LIBMV_REFINE_FOCAL_LENGTH) {
|
|
||||||
bundle_intrinsics |= libmv::BUNDLE_FOCAL_LENGTH;
|
|
||||||
}
|
|
||||||
if (refine_intrinsics & LIBMV_REFINE_PRINCIPAL_POINT) {
|
|
||||||
bundle_intrinsics |= libmv::BUNDLE_PRINCIPAL_POINT;
|
|
||||||
}
|
|
||||||
if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K1) {
|
|
||||||
bundle_intrinsics |= libmv::BUNDLE_RADIAL_K1;
|
|
||||||
}
|
|
||||||
if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K2) {
|
|
||||||
bundle_intrinsics |= libmv::BUNDLE_RADIAL_K2;
|
|
||||||
}
|
|
||||||
|
|
||||||
progress_update_callback(callback_customdata, 1.0, "Refining solution");
|
|
||||||
|
|
||||||
libmv::EuclideanBundleCommonIntrinsics(tracks,
|
|
||||||
bundle_intrinsics,
|
|
||||||
bundle_constraints,
|
|
||||||
reconstruction,
|
|
||||||
intrinsics);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cameraIntrinsicsFromOptions(const libmv_CameraIntrinsicsOptions *camera_intrinsics_options,
|
static void cameraIntrinsicsFromOptions(const libmv_CameraIntrinsicsOptions *camera_intrinsics_options,
|
||||||
libmv::CameraIntrinsics *camera_intrinsics)
|
libmv::CameraIntrinsics *camera_intrinsics)
|
||||||
{
|
{
|
||||||
@@ -474,20 +454,140 @@ static void cameraIntrinsicsFromOptions(const libmv_CameraIntrinsicsOptions *cam
|
|||||||
camera_intrinsics_options->image_height);
|
camera_intrinsics_options->image_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static libmv::Tracks getNormalizedTracks(const libmv::Tracks &tracks, const libmv::CameraIntrinsics &camera_intrinsics)
|
static void cameraIntrinsicsFromOptions(const libmv_CameraIntrinsicsOptions camera_intrinsics_options[],
|
||||||
|
int num_cameras,
|
||||||
|
std::vector<libmv::CameraIntrinsics> &camera_intrinsics)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < num_cameras; ++i) {
|
||||||
|
camera_intrinsics.push_back(libmv::CameraIntrinsics());
|
||||||
|
cameraIntrinsicsFromOptions(camera_intrinsics_options, &camera_intrinsics[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static libmv::Tracks getNormalizedTracks(const libmv::Tracks &tracks,
|
||||||
|
const std::vector<libmv::CameraIntrinsics> &camera_intrinsics)
|
||||||
{
|
{
|
||||||
libmv::vector<libmv::Marker> markers = tracks.AllMarkers();
|
libmv::vector<libmv::Marker> markers = tracks.AllMarkers();
|
||||||
|
|
||||||
for (int i = 0; i < markers.size(); ++i) {
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
camera_intrinsics.InvertIntrinsics(markers[i].x, markers[i].y,
|
int camera = markers[i].camera;
|
||||||
|
camera_intrinsics[camera].InvertIntrinsics(markers[i].x, markers[i].y,
|
||||||
&(markers[i].x), &(markers[i].y));
|
&(markers[i].x), &(markers[i].y));
|
||||||
}
|
}
|
||||||
|
|
||||||
return libmv::Tracks(markers);
|
return libmv::Tracks(markers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finishReconstruction(const libmv::Tracks &tracks, const libmv::CameraIntrinsics &camera_intrinsics,
|
static bool selectTwoInitialImages(
|
||||||
struct libmv_Reconstruction *libmv_reconstruction,
|
libmv::Tracks &tracks,
|
||||||
|
libmv::Tracks &normalized_tracks,
|
||||||
|
std::vector<libmv::CameraIntrinsics> &camera_intrinsics,
|
||||||
|
libmv::ReconstructionOptions &reconstruction_options,
|
||||||
|
int &image1,
|
||||||
|
int &image2)
|
||||||
|
{
|
||||||
|
libmv::vector<int> images;
|
||||||
|
|
||||||
|
/* Get list of all image candidates first. */
|
||||||
|
SelectKeyframesBasedOnGRICAndVariance(normalized_tracks,
|
||||||
|
camera_intrinsics,
|
||||||
|
images);
|
||||||
|
|
||||||
|
if (images.size() < 2) {
|
||||||
|
LG << "Not enough keyframes detected by GRIC";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (images.size() == 2) {
|
||||||
|
image1 = images[0];
|
||||||
|
image2 = images[1];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now choose two images with minimal reprojection error after initial
|
||||||
|
* reconstruction choose images with the least reprojection error after
|
||||||
|
* solving from two candidate images.
|
||||||
|
*
|
||||||
|
* In fact, currently libmv returns single pair only, so this code will
|
||||||
|
* not actually run. But in the future this could change, so let's stay
|
||||||
|
* prepared.
|
||||||
|
*/
|
||||||
|
int previous_image = images[0];
|
||||||
|
double best_error = std::numeric_limits<double>::max();
|
||||||
|
for (int i = 1; i < images.size(); i++) {
|
||||||
|
libmv::EuclideanReconstruction reconstruction;
|
||||||
|
int current_image = images[i];
|
||||||
|
|
||||||
|
libmv::vector<libmv::Marker> image_markers =
|
||||||
|
normalized_tracks.MarkersForTracksInBothImages(previous_image,
|
||||||
|
current_image);
|
||||||
|
|
||||||
|
libmv::Tracks image_tracks(image_markers);
|
||||||
|
|
||||||
|
/* get a solution from two images only */
|
||||||
|
libmv::EuclideanReconstructTwoFrames(image_markers, &reconstruction);
|
||||||
|
libmv::EuclideanBundle(image_tracks, &reconstruction);
|
||||||
|
libmv::EuclideanCompleteReconstruction(reconstruction_options,
|
||||||
|
image_tracks,
|
||||||
|
&reconstruction, NULL);
|
||||||
|
|
||||||
|
double current_error =
|
||||||
|
libmv::EuclideanReprojectionError(tracks,
|
||||||
|
reconstruction,
|
||||||
|
camera_intrinsics);
|
||||||
|
|
||||||
|
LG << "Error between " << previous_image
|
||||||
|
<< " and " << current_image
|
||||||
|
<< ": " << current_error;
|
||||||
|
|
||||||
|
if (current_error < best_error) {
|
||||||
|
best_error = current_error;
|
||||||
|
image1 = previous_image;
|
||||||
|
image2 = current_image;
|
||||||
|
}
|
||||||
|
|
||||||
|
previous_image = current_image;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static libmv::BundleOptions refinementOptionsFromReconstructionOptions(
|
||||||
|
const libmv_ReconstructionOptions &reconstruction_options)
|
||||||
|
{
|
||||||
|
/* only a few combinations are supported but trust the caller */
|
||||||
|
libmv::BundleOptions bundle_options;
|
||||||
|
|
||||||
|
const int motion_flag = reconstruction_options.motion_flag;
|
||||||
|
const int refine_intrinsics = reconstruction_options.refine_intrinsics;
|
||||||
|
const int constrain_intrinsics = reconstruction_options.constrain_intrinsics;
|
||||||
|
|
||||||
|
if (motion_flag & LIBMV_TRACKING_MOTION_MODAL) {
|
||||||
|
bundle_options.constraints |= libmv::BUNDLE_NO_TRANSLATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refine_intrinsics & LIBMV_REFINE_FOCAL_LENGTH) {
|
||||||
|
bundle_options.bundle_intrinsics |= libmv::BUNDLE_FOCAL_LENGTH;
|
||||||
|
if (constrain_intrinsics & LIBMV_CONSTRAIN_FOCAL_LENGTH) {
|
||||||
|
bundle_options.constraints |= libmv::BUNDLE_CONSTRAIN_FOCAL_LENGTH;
|
||||||
|
bundle_options.focal_length_min = reconstruction_options.focal_length_min;
|
||||||
|
bundle_options.focal_length_max = reconstruction_options.focal_length_max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (refine_intrinsics & LIBMV_REFINE_PRINCIPAL_POINT) {
|
||||||
|
bundle_options.bundle_intrinsics |= libmv::BUNDLE_PRINCIPAL_POINT;
|
||||||
|
}
|
||||||
|
if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K1) {
|
||||||
|
bundle_options.bundle_intrinsics |= libmv::BUNDLE_RADIAL_K1;
|
||||||
|
}
|
||||||
|
if (refine_intrinsics & LIBMV_REFINE_RADIAL_DISTORTION_K2) {
|
||||||
|
bundle_options.bundle_intrinsics |= libmv::BUNDLE_RADIAL_K2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bundle_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void finishReconstruction(const libmv::Tracks &tracks, const std::vector<libmv::CameraIntrinsics> &camera_intrinsics,
|
||||||
|
libmv_Reconstruction *libmv_reconstruction,
|
||||||
reconstruct_progress_update_cb progress_update_callback,
|
reconstruct_progress_update_cb progress_update_callback,
|
||||||
void *callback_customdata)
|
void *callback_customdata)
|
||||||
{
|
{
|
||||||
@@ -499,96 +599,24 @@ static void finishReconstruction(const libmv::Tracks &tracks, const libmv::Camer
|
|||||||
libmv_reconstruction->error = libmv::EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics);
|
libmv_reconstruction->error = libmv::EuclideanReprojectionError(tracks, reconstruction, camera_intrinsics);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool selectTwoKeyframesBasedOnGRICAndVariance(
|
libmv_Reconstruction *libmv_solve(const libmv_Tracks *libmv_tracks,
|
||||||
libmv::Tracks &tracks,
|
const libmv_CameraIntrinsicsOptions libmv_camera_intrinsics_options[],
|
||||||
libmv::Tracks &normalized_tracks,
|
|
||||||
libmv::CameraIntrinsics &camera_intrinsics,
|
|
||||||
libmv::ReconstructionOptions &reconstruction_options,
|
|
||||||
int &keyframe1,
|
|
||||||
int &keyframe2)
|
|
||||||
{
|
|
||||||
libmv::vector<int> keyframes;
|
|
||||||
|
|
||||||
/* Get list of all keyframe candidates first. */
|
|
||||||
SelectKeyframesBasedOnGRICAndVariance(normalized_tracks,
|
|
||||||
camera_intrinsics,
|
|
||||||
keyframes);
|
|
||||||
|
|
||||||
if (keyframes.size() < 2) {
|
|
||||||
LG << "Not enough keyframes detected by GRIC";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (keyframes.size() == 2) {
|
|
||||||
keyframe1 = keyframes[0];
|
|
||||||
keyframe2 = keyframes[1];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now choose two keyframes with minimal reprojection error after initial
|
|
||||||
* reconstruction choose keyframes with the least reprojection error after
|
|
||||||
* solving from two candidate keyframes.
|
|
||||||
*
|
|
||||||
* In fact, currently libmv returns single pair only, so this code will
|
|
||||||
* not actually run. But in the future this could change, so let's stay
|
|
||||||
* prepared.
|
|
||||||
*/
|
|
||||||
int previous_keyframe = keyframes[0];
|
|
||||||
double best_error = std::numeric_limits<double>::max();
|
|
||||||
for (int i = 1; i < keyframes.size(); i++) {
|
|
||||||
libmv::EuclideanReconstruction reconstruction;
|
|
||||||
int current_keyframe = keyframes[i];
|
|
||||||
|
|
||||||
libmv::vector<libmv::Marker> keyframe_markers =
|
|
||||||
normalized_tracks.MarkersForTracksInBothImages(previous_keyframe,
|
|
||||||
current_keyframe);
|
|
||||||
|
|
||||||
libmv::Tracks keyframe_tracks(keyframe_markers);
|
|
||||||
|
|
||||||
/* get a solution from two keyframes only */
|
|
||||||
libmv::EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction);
|
|
||||||
libmv::EuclideanBundle(keyframe_tracks, &reconstruction);
|
|
||||||
libmv::EuclideanCompleteReconstruction(reconstruction_options,
|
|
||||||
keyframe_tracks,
|
|
||||||
&reconstruction, NULL);
|
|
||||||
|
|
||||||
double current_error =
|
|
||||||
libmv::EuclideanReprojectionError(tracks,
|
|
||||||
reconstruction,
|
|
||||||
camera_intrinsics);
|
|
||||||
|
|
||||||
LG << "Error between " << previous_keyframe
|
|
||||||
<< " and " << current_keyframe
|
|
||||||
<< ": " << current_error;
|
|
||||||
|
|
||||||
if (current_error < best_error) {
|
|
||||||
best_error = current_error;
|
|
||||||
keyframe1 = previous_keyframe;
|
|
||||||
keyframe2 = current_keyframe;
|
|
||||||
}
|
|
||||||
|
|
||||||
previous_keyframe = current_keyframe;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libmv_Reconstruction *libmv_solveReconstruction(const struct libmv_Tracks *libmv_tracks,
|
|
||||||
const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options,
|
|
||||||
libmv_ReconstructionOptions *libmv_reconstruction_options,
|
libmv_ReconstructionOptions *libmv_reconstruction_options,
|
||||||
reconstruct_progress_update_cb progress_update_callback,
|
reconstruct_progress_update_cb progress_update_callback,
|
||||||
void *callback_customdata)
|
void *callback_customdata)
|
||||||
{
|
{
|
||||||
struct libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
|
struct libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
|
||||||
|
libmv::EuclideanReconstruction &reconstruction = libmv_reconstruction->reconstruction;
|
||||||
|
std::vector<libmv::CameraIntrinsics> &camera_intrinsics = libmv_reconstruction->intrinsics;
|
||||||
|
|
||||||
libmv::Tracks &tracks = *((libmv::Tracks *) libmv_tracks);
|
libmv::Tracks &tracks = *((libmv::Tracks *) libmv_tracks);
|
||||||
libmv::EuclideanReconstruction &reconstruction = libmv_reconstruction->reconstruction;
|
int num_cameras = tracks.MaxCamera() + 1;
|
||||||
libmv::CameraIntrinsics &camera_intrinsics = libmv_reconstruction->intrinsics;
|
|
||||||
|
|
||||||
ReconstructUpdateCallback update_callback =
|
ReconstructUpdateCallback update_callback(progress_update_callback,
|
||||||
ReconstructUpdateCallback(progress_update_callback, callback_customdata);
|
callback_customdata);
|
||||||
|
|
||||||
/* Retrieve reconstruction options from C-API to libmv API */
|
/* Convert options from C-API to libmv API */
|
||||||
cameraIntrinsicsFromOptions(libmv_camera_intrinsics_options, &camera_intrinsics);
|
cameraIntrinsicsFromOptions(libmv_camera_intrinsics_options, num_cameras, camera_intrinsics);
|
||||||
|
|
||||||
libmv::ReconstructionOptions reconstruction_options;
|
libmv::ReconstructionOptions reconstruction_options;
|
||||||
reconstruction_options.success_threshold = libmv_reconstruction_options->success_threshold;
|
reconstruction_options.success_threshold = libmv_reconstruction_options->success_threshold;
|
||||||
@@ -597,104 +625,70 @@ struct libmv_Reconstruction *libmv_solveReconstruction(const struct libmv_Tracks
|
|||||||
/* Invert the camera intrinsics */
|
/* Invert the camera intrinsics */
|
||||||
libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics);
|
libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics);
|
||||||
|
|
||||||
/* keyframe selection */
|
if (libmv_reconstruction_options->motion_flag & LIBMV_TRACKING_MOTION_MODAL &&
|
||||||
int keyframe1 = libmv_reconstruction_options->keyframe1,
|
num_cameras == 1) {
|
||||||
keyframe2 = libmv_reconstruction_options->keyframe2;
|
/* Perform modal solving */
|
||||||
|
libmv::ModalSolver(normalized_tracks, &reconstruction, &update_callback);
|
||||||
|
|
||||||
|
/* Perform bundle adjustment */
|
||||||
|
libmv::EuclideanBundleModal(tracks,
|
||||||
|
&reconstruction);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Image selection */
|
||||||
|
int &image1 = libmv_reconstruction_options->keyframe1,
|
||||||
|
&image2 = libmv_reconstruction_options->keyframe2;
|
||||||
|
|
||||||
if (libmv_reconstruction_options->select_keyframes) {
|
if (libmv_reconstruction_options->select_keyframes) {
|
||||||
LG << "Using automatic keyframe selection";
|
LG << "Using automatic image selection";
|
||||||
|
|
||||||
update_callback.invoke(0, "Selecting keyframes");
|
update_callback.invoke(0, "Selecting images");
|
||||||
|
|
||||||
selectTwoKeyframesBasedOnGRICAndVariance(tracks,
|
selectTwoInitialImages(tracks,
|
||||||
normalized_tracks,
|
normalized_tracks,
|
||||||
camera_intrinsics,
|
camera_intrinsics,
|
||||||
reconstruction_options,
|
reconstruction_options,
|
||||||
keyframe1,
|
image1,
|
||||||
keyframe2);
|
image2);
|
||||||
|
|
||||||
/* so keyframes in the interface would be updated */
|
|
||||||
libmv_reconstruction_options->keyframe1 = keyframe1;
|
|
||||||
libmv_reconstruction_options->keyframe2 = keyframe2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* actual reconstruction */
|
LG << "frames to init from: " << image1 << " " << image2;
|
||||||
LG << "frames to init from: " << keyframe1 << " " << keyframe2;
|
|
||||||
|
|
||||||
libmv::vector<libmv::Marker> keyframe_markers =
|
/* Reconstruct for two images */
|
||||||
normalized_tracks.MarkersForTracksInBothImages(keyframe1, keyframe2);
|
libmv::vector<libmv::Marker> image_markers =
|
||||||
|
normalized_tracks.MarkersForTracksInBothImages(image1, image2);
|
||||||
|
|
||||||
LG << "number of markers for init: " << keyframe_markers.size();
|
LG << "number of markers for init: " << image_markers.size();
|
||||||
|
|
||||||
update_callback.invoke(0, "Initial reconstruction");
|
update_callback.invoke(0, "Initial reconstruction");
|
||||||
|
|
||||||
libmv::EuclideanReconstructTwoFrames(keyframe_markers, &reconstruction);
|
libmv::EuclideanReconstructTwoFrames(image_markers, &reconstruction);
|
||||||
|
|
||||||
|
/* Perform bundle adjustment */
|
||||||
libmv::EuclideanBundle(normalized_tracks, &reconstruction);
|
libmv::EuclideanBundle(normalized_tracks, &reconstruction);
|
||||||
|
|
||||||
|
/* Reconstruct for all frames */
|
||||||
libmv::EuclideanCompleteReconstruction(reconstruction_options, normalized_tracks,
|
libmv::EuclideanCompleteReconstruction(reconstruction_options, normalized_tracks,
|
||||||
&reconstruction, &update_callback);
|
&reconstruction, &update_callback);
|
||||||
|
|
||||||
/* refinement */
|
|
||||||
if (libmv_reconstruction_options->refine_intrinsics) {
|
|
||||||
libmv_solveRefineIntrinsics(tracks,
|
|
||||||
libmv_reconstruction_options->refine_intrinsics,
|
|
||||||
libmv::BUNDLE_NO_CONSTRAINTS,
|
|
||||||
progress_update_callback,
|
|
||||||
callback_customdata,
|
|
||||||
&reconstruction,
|
|
||||||
&camera_intrinsics);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set reconstruction scale to unity */
|
if (libmv_reconstruction_options->refine_intrinsics) {
|
||||||
|
/* Refine bundle parameters */
|
||||||
|
libmv::BundleOptions refinement_bundle_options =
|
||||||
|
refinementOptionsFromReconstructionOptions(*libmv_reconstruction_options);
|
||||||
|
|
||||||
|
progress_update_callback(callback_customdata, 1.0, "Refining solution");
|
||||||
|
|
||||||
|
libmv::EuclideanBundleCommonIntrinsics(tracks,
|
||||||
|
refinement_bundle_options,
|
||||||
|
&reconstruction,
|
||||||
|
camera_intrinsics);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set reconstruction scale to unity */
|
||||||
libmv::EuclideanScaleToUnity(&reconstruction);
|
libmv::EuclideanScaleToUnity(&reconstruction);
|
||||||
|
|
||||||
/* finish reconstruction */
|
/* Finish reconstruction */
|
||||||
finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction,
|
|
||||||
progress_update_callback, callback_customdata);
|
|
||||||
|
|
||||||
return (struct libmv_Reconstruction *)libmv_reconstruction;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libmv_Reconstruction *libmv_solveModal(const struct libmv_Tracks *libmv_tracks,
|
|
||||||
const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options,
|
|
||||||
const libmv_ReconstructionOptions *libmv_reconstruction_options,
|
|
||||||
reconstruct_progress_update_cb progress_update_callback,
|
|
||||||
void *callback_customdata)
|
|
||||||
{
|
|
||||||
struct libmv_Reconstruction *libmv_reconstruction = new libmv_Reconstruction();
|
|
||||||
|
|
||||||
libmv::Tracks &tracks = *((libmv::Tracks *) libmv_tracks);
|
|
||||||
libmv::EuclideanReconstruction &reconstruction = libmv_reconstruction->reconstruction;
|
|
||||||
libmv::CameraIntrinsics &camera_intrinsics = libmv_reconstruction->intrinsics;
|
|
||||||
|
|
||||||
ReconstructUpdateCallback update_callback =
|
|
||||||
ReconstructUpdateCallback(progress_update_callback, callback_customdata);
|
|
||||||
|
|
||||||
cameraIntrinsicsFromOptions(libmv_camera_intrinsics_options, &camera_intrinsics);
|
|
||||||
|
|
||||||
/* Invert the camera intrinsics. */
|
|
||||||
libmv::Tracks normalized_tracks = getNormalizedTracks(tracks, camera_intrinsics);
|
|
||||||
|
|
||||||
/* Actual reconstruction. */
|
|
||||||
libmv::ModalSolver(normalized_tracks, &reconstruction, &update_callback);
|
|
||||||
|
|
||||||
libmv::CameraIntrinsics empty_intrinsics;
|
|
||||||
libmv::EuclideanBundleCommonIntrinsics(normalized_tracks,
|
|
||||||
libmv::BUNDLE_NO_INTRINSICS,
|
|
||||||
libmv::BUNDLE_NO_TRANSLATION,
|
|
||||||
&reconstruction,
|
|
||||||
&empty_intrinsics);
|
|
||||||
|
|
||||||
/* Refinement. */
|
|
||||||
if (libmv_reconstruction_options->refine_intrinsics) {
|
|
||||||
libmv_solveRefineIntrinsics(tracks,
|
|
||||||
libmv_reconstruction_options->refine_intrinsics,
|
|
||||||
libmv::BUNDLE_NO_TRANSLATION,
|
|
||||||
progress_update_callback, callback_customdata,
|
|
||||||
&reconstruction,
|
|
||||||
&camera_intrinsics);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finish reconstruction. */
|
|
||||||
finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction,
|
finishReconstruction(tracks, camera_intrinsics, libmv_reconstruction,
|
||||||
progress_update_callback, callback_customdata);
|
progress_update_callback, callback_customdata);
|
||||||
|
|
||||||
@@ -723,16 +717,16 @@ int libmv_reprojectionPointForTrack(const struct libmv_Reconstruction *libmv_rec
|
|||||||
}
|
}
|
||||||
|
|
||||||
static libmv::Marker ProjectMarker(const libmv::EuclideanPoint &point,
|
static libmv::Marker ProjectMarker(const libmv::EuclideanPoint &point,
|
||||||
const libmv::EuclideanCamera &camera,
|
const libmv::EuclideanView &view,
|
||||||
const libmv::CameraIntrinsics &intrinsics)
|
const libmv::CameraIntrinsics &intrinsics)
|
||||||
{
|
{
|
||||||
libmv::Vec3 projected = camera.R * point.X + camera.t;
|
libmv::Vec3 projected = view.R * point.X + view.t;
|
||||||
projected /= projected(2);
|
projected /= projected(2);
|
||||||
|
|
||||||
libmv::Marker reprojected_marker;
|
libmv::Marker reprojected_marker;
|
||||||
intrinsics.ApplyIntrinsics(projected(0), projected(1), &reprojected_marker.x, &reprojected_marker.y);
|
intrinsics.ApplyIntrinsics(projected(0), projected(1), &reprojected_marker.x, &reprojected_marker.y);
|
||||||
|
|
||||||
reprojected_marker.image = camera.image;
|
reprojected_marker.image = view.image;
|
||||||
reprojected_marker.track = point.track;
|
reprojected_marker.track = point.track;
|
||||||
|
|
||||||
return reprojected_marker;
|
return reprojected_marker;
|
||||||
@@ -741,23 +735,25 @@ static libmv::Marker ProjectMarker(const libmv::EuclideanPoint &point,
|
|||||||
double libmv_reprojectionErrorForTrack(const struct libmv_Reconstruction *libmv_reconstruction, int track)
|
double libmv_reprojectionErrorForTrack(const struct libmv_Reconstruction *libmv_reconstruction, int track)
|
||||||
{
|
{
|
||||||
const libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
|
const libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
|
||||||
const libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
|
const std::vector<libmv::CameraIntrinsics> *intrinsics = &libmv_reconstruction->intrinsics;
|
||||||
libmv::vector<libmv::Marker> markers = libmv_reconstruction->tracks.MarkersForTrack(track);
|
libmv::vector<libmv::Marker> markers = libmv_reconstruction->tracks.MarkersForTrack(track);
|
||||||
|
|
||||||
int num_reprojected = 0;
|
int num_reprojected = 0;
|
||||||
double total_error = 0.0;
|
double total_error = 0.0;
|
||||||
|
|
||||||
for (int i = 0; i < markers.size(); ++i) {
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
|
int camera = markers[i].camera;
|
||||||
|
const libmv::EuclideanView *view = reconstruction->ViewForImage(markers[i].image);
|
||||||
const libmv::EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
|
const libmv::EuclideanPoint *point = reconstruction->PointForTrack(markers[i].track);
|
||||||
|
const libmv::CameraIntrinsics camera_intrinsics = (*intrinsics)[camera];
|
||||||
|
|
||||||
if (!camera || !point) {
|
if (!view || !point) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_reprojected++;
|
num_reprojected++;
|
||||||
|
|
||||||
libmv::Marker reprojected_marker = ProjectMarker(*point, *camera, *intrinsics);
|
libmv::Marker reprojected_marker = ProjectMarker(*point, *view, camera_intrinsics);
|
||||||
double ex = reprojected_marker.x - markers[i].x;
|
double ex = reprojected_marker.x - markers[i].x;
|
||||||
double ey = reprojected_marker.y - markers[i].y;
|
double ey = reprojected_marker.y - markers[i].y;
|
||||||
|
|
||||||
@@ -767,16 +763,18 @@ double libmv_reprojectionErrorForTrack(const struct libmv_Reconstruction *libmv_
|
|||||||
return total_error / num_reprojected;
|
return total_error / num_reprojected;
|
||||||
}
|
}
|
||||||
|
|
||||||
double libmv_reprojectionErrorForImage(const struct libmv_Reconstruction *libmv_reconstruction, int image)
|
double libmv_reprojectionErrorForImage(const struct libmv_Reconstruction *libmv_reconstruction,
|
||||||
|
int image)
|
||||||
{
|
{
|
||||||
const libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
|
const libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
|
||||||
const libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics;
|
int camera = libmv_reconstruction->tracks.CameraFromImage(image);
|
||||||
|
const libmv::CameraIntrinsics *intrinsics = &libmv_reconstruction->intrinsics[camera];
|
||||||
libmv::vector<libmv::Marker> markers = libmv_reconstruction->tracks.MarkersInImage(image);
|
libmv::vector<libmv::Marker> markers = libmv_reconstruction->tracks.MarkersInImage(image);
|
||||||
const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(image);
|
const libmv::EuclideanView *view = reconstruction->ViewForImage(image);
|
||||||
int num_reprojected = 0;
|
int num_reprojected = 0;
|
||||||
double total_error = 0.0;
|
double total_error = 0.0;
|
||||||
|
|
||||||
if (!camera)
|
if (!view)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (int i = 0; i < markers.size(); ++i) {
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
@@ -788,7 +786,7 @@ double libmv_reprojectionErrorForImage(const struct libmv_Reconstruction *libmv_
|
|||||||
|
|
||||||
num_reprojected++;
|
num_reprojected++;
|
||||||
|
|
||||||
libmv::Marker reprojected_marker = ProjectMarker(*point, *camera, *intrinsics);
|
libmv::Marker reprojected_marker = ProjectMarker(*point, *view, *intrinsics);
|
||||||
double ex = reprojected_marker.x - markers[i].x;
|
double ex = reprojected_marker.x - markers[i].x;
|
||||||
double ey = reprojected_marker.y - markers[i].y;
|
double ey = reprojected_marker.y - markers[i].y;
|
||||||
|
|
||||||
@@ -802,9 +800,9 @@ int libmv_reprojectionCameraForImage(const struct libmv_Reconstruction *libmv_re
|
|||||||
int image, double mat[4][4])
|
int image, double mat[4][4])
|
||||||
{
|
{
|
||||||
const libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
|
const libmv::EuclideanReconstruction *reconstruction = &libmv_reconstruction->reconstruction;
|
||||||
const libmv::EuclideanCamera *camera = reconstruction->CameraForImage(image);
|
const libmv::EuclideanView *view = reconstruction->ViewForImage(image);
|
||||||
|
|
||||||
if (camera) {
|
if (view) {
|
||||||
for (int j = 0; j < 3; ++j) {
|
for (int j = 0; j < 3; ++j) {
|
||||||
for (int k = 0; k < 3; ++k) {
|
for (int k = 0; k < 3; ++k) {
|
||||||
int l = k;
|
int l = k;
|
||||||
@@ -812,13 +810,13 @@ int libmv_reprojectionCameraForImage(const struct libmv_Reconstruction *libmv_re
|
|||||||
if (k == 1) l = 2;
|
if (k == 1) l = 2;
|
||||||
else if (k == 2) l = 1;
|
else if (k == 2) l = 1;
|
||||||
|
|
||||||
if (j == 2) mat[j][l] = -camera->R(j,k);
|
if (j == 2) mat[j][l] = -view->R(j,k);
|
||||||
else mat[j][l] = camera->R(j,k);
|
else mat[j][l] = view->R(j,k);
|
||||||
}
|
}
|
||||||
mat[j][3] = 0.0;
|
mat[j][3] = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
libmv::Vec3 optical_center = -camera->R.transpose() * camera->t;
|
libmv::Vec3 optical_center = -view->R.transpose() * view->t;
|
||||||
|
|
||||||
mat[3][0] = optical_center(0);
|
mat[3][0] = optical_center(0);
|
||||||
mat[3][1] = optical_center(2);
|
mat[3][1] = optical_center(2);
|
||||||
@@ -837,9 +835,10 @@ double libmv_reprojectionError(const struct libmv_Reconstruction *libmv_reconstr
|
|||||||
return libmv_reconstruction->error;
|
return libmv_reconstruction->error;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_reconstruction)
|
struct libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_reconstruction,
|
||||||
|
int camera)
|
||||||
{
|
{
|
||||||
return (struct libmv_CameraIntrinsics *)&libmv_reconstruction->intrinsics;
|
return (struct libmv_CameraIntrinsics *)&libmv_reconstruction->intrinsics[camera];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************ Feature detector ************ */
|
/* ************ Feature detector ************ */
|
||||||
|
24
extern/libmv/libmv-capi.h
vendored
24
extern/libmv/libmv-capi.h
vendored
@@ -73,14 +73,18 @@ void libmv_samplePlanarPatch(const float *image, int width, int height,
|
|||||||
/* Tracks */
|
/* Tracks */
|
||||||
struct libmv_Tracks *libmv_tracksNew(void);
|
struct libmv_Tracks *libmv_tracksNew(void);
|
||||||
void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks);
|
void libmv_tracksDestroy(struct libmv_Tracks *libmv_tracks);
|
||||||
void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y);
|
void libmv_tracksInsert(struct libmv_Tracks *libmv_tracks, int image, int track, double x, double y, int camera);
|
||||||
|
|
||||||
/* Reconstruction */
|
/* Reconstruction */
|
||||||
|
#define LIBMV_TRACKING_MOTION_MODAL (1 << 0)
|
||||||
|
|
||||||
#define LIBMV_REFINE_FOCAL_LENGTH (1 << 0)
|
#define LIBMV_REFINE_FOCAL_LENGTH (1 << 0)
|
||||||
#define LIBMV_REFINE_PRINCIPAL_POINT (1 << 1)
|
#define LIBMV_REFINE_PRINCIPAL_POINT (1 << 1)
|
||||||
#define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1 << 2)
|
#define LIBMV_REFINE_RADIAL_DISTORTION_K1 (1 << 2)
|
||||||
#define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1 << 4)
|
#define LIBMV_REFINE_RADIAL_DISTORTION_K2 (1 << 4)
|
||||||
|
|
||||||
|
#define LIBMV_CONSTRAIN_FOCAL_LENGTH (1 << 0)
|
||||||
|
|
||||||
typedef struct libmv_CameraIntrinsicsOptions {
|
typedef struct libmv_CameraIntrinsicsOptions {
|
||||||
double focal_length;
|
double focal_length;
|
||||||
double principal_point_x, principal_point_y;
|
double principal_point_x, principal_point_y;
|
||||||
@@ -93,7 +97,11 @@ typedef struct libmv_ReconstructionOptions {
|
|||||||
int select_keyframes;
|
int select_keyframes;
|
||||||
int keyframe1, keyframe2;
|
int keyframe1, keyframe2;
|
||||||
|
|
||||||
int refine_intrinsics;
|
short motion_flag;
|
||||||
|
|
||||||
|
short refine_intrinsics;
|
||||||
|
short constrain_intrinsics;
|
||||||
|
double focal_length_min, focal_length_max;
|
||||||
|
|
||||||
double success_threshold;
|
double success_threshold;
|
||||||
int use_fallback_reconstruction;
|
int use_fallback_reconstruction;
|
||||||
@@ -101,16 +109,11 @@ typedef struct libmv_ReconstructionOptions {
|
|||||||
|
|
||||||
typedef void (*reconstruct_progress_update_cb) (void *customdata, double progress, const char *message);
|
typedef void (*reconstruct_progress_update_cb) (void *customdata, double progress, const char *message);
|
||||||
|
|
||||||
struct libmv_Reconstruction *libmv_solveReconstruction(const struct libmv_Tracks *libmv_tracks,
|
struct libmv_Reconstruction *libmv_solve(const struct libmv_Tracks *libmv_tracks,
|
||||||
const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options,
|
const libmv_CameraIntrinsicsOptions libmv_camera_intrinsics_options[],
|
||||||
libmv_ReconstructionOptions *libmv_reconstruction_options,
|
libmv_ReconstructionOptions *libmv_reconstruction_options,
|
||||||
reconstruct_progress_update_cb progress_update_callback,
|
reconstruct_progress_update_cb progress_update_callback,
|
||||||
void *callback_customdata);
|
void *callback_customdata);
|
||||||
struct libmv_Reconstruction *libmv_solveModal(const struct libmv_Tracks *libmv_tracks,
|
|
||||||
const libmv_CameraIntrinsicsOptions *libmv_camera_intrinsics_options,
|
|
||||||
const libmv_ReconstructionOptions *libmv_reconstruction_options,
|
|
||||||
reconstruct_progress_update_cb progress_update_callback,
|
|
||||||
void *callback_customdata);
|
|
||||||
void libmv_reconstructionDestroy(struct libmv_Reconstruction *libmv_reconstruction);
|
void libmv_reconstructionDestroy(struct libmv_Reconstruction *libmv_reconstruction);
|
||||||
int libmv_reprojectionPointForTrack(const struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]);
|
int libmv_reprojectionPointForTrack(const struct libmv_Reconstruction *libmv_reconstruction, int track, double pos[3]);
|
||||||
double libmv_reprojectionErrorForTrack(const struct libmv_Reconstruction *libmv_reconstruction, int track);
|
double libmv_reprojectionErrorForTrack(const struct libmv_Reconstruction *libmv_reconstruction, int track);
|
||||||
@@ -118,7 +121,8 @@ double libmv_reprojectionErrorForImage(const struct libmv_Reconstruction *libmv_
|
|||||||
int libmv_reprojectionCameraForImage(const struct libmv_Reconstruction *libmv_reconstruction,
|
int libmv_reprojectionCameraForImage(const struct libmv_Reconstruction *libmv_reconstruction,
|
||||||
int image, double mat[4][4]);
|
int image, double mat[4][4]);
|
||||||
double libmv_reprojectionError(const struct libmv_Reconstruction *libmv_reconstruction);
|
double libmv_reprojectionError(const struct libmv_Reconstruction *libmv_reconstruction);
|
||||||
struct libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_Reconstruction);
|
struct libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(struct libmv_Reconstruction *libmv_Reconstruction,
|
||||||
|
int camera);
|
||||||
|
|
||||||
/* Feature detector */
|
/* Feature detector */
|
||||||
struct libmv_Features *libmv_detectFeaturesFAST(const unsigned char *data, int width, int height, int stride,
|
struct libmv_Features *libmv_detectFeaturesFAST(const unsigned char *data, int width, int height, int stride,
|
||||||
|
27
extern/libmv/libmv-capi_stub.cc
vendored
27
extern/libmv/libmv-capi_stub.cc
vendored
@@ -84,8 +84,10 @@ struct libmv_Tracks *libmv_tracksNew(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void libmv_tracksInsert(struct libmv_Tracks * /*libmv_tracks*/, int /*image*/,
|
void libmv_tracksInsert(struct libmv_Tracks * /*libmv_tracks*/,
|
||||||
int /*track*/, double /*x*/, double /*y*/)
|
int /*image*/, int /*track*/,
|
||||||
|
double /*x*/, double /*y*/,
|
||||||
|
int /*camera*/)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +97,7 @@ void libmv_tracksDestroy(struct libmv_Tracks * /*libmv_tracks*/)
|
|||||||
|
|
||||||
/* ************ Reconstruction solver ************ */
|
/* ************ Reconstruction solver ************ */
|
||||||
|
|
||||||
struct libmv_Reconstruction *libmv_solveReconstruction(const struct libmv_Tracks * /*libmv_tracks*/,
|
libmv_Reconstruction *libmv_solve(const libmv_Tracks * /*libmv_tracks*/,
|
||||||
const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
|
const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
|
||||||
libmv_ReconstructionOptions * /*libmv_reconstruction_options*/,
|
libmv_ReconstructionOptions * /*libmv_reconstruction_options*/,
|
||||||
reconstruct_progress_update_cb /*progress_update_callback*/,
|
reconstruct_progress_update_cb /*progress_update_callback*/,
|
||||||
@@ -104,15 +106,6 @@ struct libmv_Reconstruction *libmv_solveReconstruction(const struct libmv_Tracks
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct libmv_Reconstruction *libmv_solveModal(const struct libmv_Tracks * /*libmv_tracks*/,
|
|
||||||
const libmv_CameraIntrinsicsOptions * /*libmv_camera_intrinsics_options*/,
|
|
||||||
const libmv_ReconstructionOptions * /*libmv_reconstruction_options*/,
|
|
||||||
reconstruct_progress_update_cb /*progress_update_callback*/,
|
|
||||||
void * /*callback_customdata*/)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int libmv_reprojectionPointForTrack(const struct libmv_Reconstruction * /*libmv_reconstruction*/,
|
int libmv_reprojectionPointForTrack(const struct libmv_Reconstruction * /*libmv_reconstruction*/,
|
||||||
int /*track*/, double /*pos*/[3])
|
int /*track*/, double /*pos*/[3])
|
||||||
{
|
{
|
||||||
@@ -124,13 +117,14 @@ double libmv_reprojectionErrorForTrack(const struct libmv_Reconstruction * /*lib
|
|||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double libmv_reprojectionErrorForImage(const struct libmv_Reconstruction * /*libmv_reconstruction*/, int /*image*/)
|
double libmv_reprojectionErrorForImage(const struct libmv_Reconstruction * /*libmv_reconstruction*/,
|
||||||
|
int /*image*/)
|
||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int libmv_reprojectionCameraForImage(const struct libmv_Reconstruction * /*libmv_reconstruction*/, int /*image*/,
|
int libmv_reprojectionCameraForImage(const struct libmv_Reconstruction * /*libmv_reconstruction*/,
|
||||||
double /*mat*/[4][4])
|
int /*image*/, double /*mat*/[4][4])
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -180,7 +174,8 @@ void libmv_featuresDestroy(struct libmv_Features * /*libmv_features*/)
|
|||||||
/* ************ camera intrinsics ************ */
|
/* ************ camera intrinsics ************ */
|
||||||
|
|
||||||
struct libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(
|
struct libmv_CameraIntrinsics *libmv_reconstructionExtractIntrinsics(
|
||||||
struct libmv_Reconstruction * /*libmv_reconstruction*/)
|
struct libmv_Reconstruction * /*libmv_reconstruction*/,
|
||||||
|
int /*camera*/)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
276
extern/libmv/libmv/simple_pipeline/bundle.cc
vendored
276
extern/libmv/libmv/simple_pipeline/bundle.cc
vendored
@@ -21,8 +21,10 @@
|
|||||||
#include "libmv/simple_pipeline/bundle.h"
|
#include "libmv/simple_pipeline/bundle.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include "ceres/ceres.h"
|
#include "ceres/ceres.h"
|
||||||
|
#include "ceres/iteration_callback.h"
|
||||||
#include "ceres/rotation.h"
|
#include "ceres/rotation.h"
|
||||||
#include "libmv/base/vector.h"
|
#include "libmv/base/vector.h"
|
||||||
#include "libmv/logging/logging.h"
|
#include "libmv/logging/logging.h"
|
||||||
@@ -54,14 +56,42 @@ enum {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
// Convert a constrained focal length into an uncontrained bundle parameter for
|
||||||
|
// passing to Ceres.
|
||||||
|
template <typename T>
|
||||||
|
T ConstrainFocalLength(const T focal_length,
|
||||||
|
const double min_focal,
|
||||||
|
const double max_focal) {
|
||||||
|
using std::asin;
|
||||||
|
return asin(-T(1) + (((focal_length - T(min_focal))
|
||||||
|
/ (T(max_focal) - T(min_focal)))
|
||||||
|
* T(2.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert an unconstrained bundle parameter received from Ceres back to the
|
||||||
|
// corresponding constrained focal length.
|
||||||
|
template <typename T>
|
||||||
|
T UnconstrainFocalLength(const T bundled_focal,
|
||||||
|
const double min_focal,
|
||||||
|
const double max_focal) {
|
||||||
|
using std::sin;
|
||||||
|
return T(min_focal) + (T(max_focal) - T(min_focal))
|
||||||
|
* (T(1) + sin(bundled_focal))
|
||||||
|
/ T(2.0);
|
||||||
|
}
|
||||||
|
|
||||||
// Cost functor which computes reprojection error of 3D point X
|
// Cost functor which computes reprojection error of 3D point X
|
||||||
// on camera defined by angle-axis rotation and it's translation
|
// on camera defined by angle-axis rotation and it's translation
|
||||||
// (which are in the same block due to optimization reasons).
|
// (which are in the same block due to optimization reasons).
|
||||||
//
|
//
|
||||||
// This functor uses a radial distortion model.
|
// This functor uses a radial distortion model.
|
||||||
struct OpenCVReprojectionError {
|
struct OpenCVReprojectionError {
|
||||||
OpenCVReprojectionError(const double observed_x, const double observed_y)
|
OpenCVReprojectionError(const double observed_x, const double observed_y,
|
||||||
: observed_x(observed_x), observed_y(observed_y) {}
|
const double focal_length_min = 0.0,
|
||||||
|
const double focal_length_max = 0.0)
|
||||||
|
: observed_x(observed_x), observed_y(observed_y),
|
||||||
|
focal_length_min(focal_length_min),
|
||||||
|
focal_length_max(focal_length_max) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool operator()(const T* const intrinsics,
|
bool operator()(const T* const intrinsics,
|
||||||
@@ -98,11 +128,17 @@ struct OpenCVReprojectionError {
|
|||||||
|
|
||||||
T predicted_x, predicted_y;
|
T predicted_x, predicted_y;
|
||||||
|
|
||||||
|
T unconstrained_focal = focal_length;
|
||||||
|
if (focal_length_min != 0.0 || focal_length_max != 0.0) {
|
||||||
|
unconstrained_focal = UnconstrainFocalLength(
|
||||||
|
focal_length, focal_length_min, focal_length_max);
|
||||||
|
}
|
||||||
|
|
||||||
// Apply distortion to the normalized points to get (xd, yd).
|
// Apply distortion to the normalized points to get (xd, yd).
|
||||||
// TODO(keir): Do early bailouts for zero distortion; these are expensive
|
// TODO(keir): Do early bailouts for zero distortion; these are expensive
|
||||||
// jet operations.
|
// jet operations.
|
||||||
ApplyRadialDistortionCameraIntrinsics(focal_length,
|
ApplyRadialDistortionCameraIntrinsics(unconstrained_focal,
|
||||||
focal_length,
|
unconstrained_focal,
|
||||||
principal_point_x,
|
principal_point_x,
|
||||||
principal_point_y,
|
principal_point_y,
|
||||||
k1, k2, k3,
|
k1, k2, k3,
|
||||||
@@ -119,6 +155,8 @@ struct OpenCVReprojectionError {
|
|||||||
|
|
||||||
const double observed_x;
|
const double observed_x;
|
||||||
const double observed_y;
|
const double observed_y;
|
||||||
|
const double focal_length_min;
|
||||||
|
const double focal_length_max;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Print a message to the log which camera intrinsics are gonna to be optimixed.
|
// Print a message to the log which camera intrinsics are gonna to be optimixed.
|
||||||
@@ -148,34 +186,66 @@ void BundleIntrinsicsLogMessage(const int bundle_intrinsics) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pack intrinsics from object to an array for easier
|
// Pack intrinsics from object to an array for easier
|
||||||
// and faster minimization.
|
// and faster minimization, constraining the focal length
|
||||||
void PackIntrinisicsIntoArray(const CameraIntrinsics &intrinsics,
|
// according to the given BundleOptions.
|
||||||
double ceres_intrinsics[8]) {
|
vector<Vec8> PackIntrinsics(const std::vector<CameraIntrinsics> &intrinsics,
|
||||||
ceres_intrinsics[OFFSET_FOCAL_LENGTH] = intrinsics.focal_length();
|
const BundleOptions &bundle_options) {
|
||||||
ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X] = intrinsics.principal_point_x();
|
int num_intrinsics = intrinsics.size();
|
||||||
ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y] = intrinsics.principal_point_y();
|
vector<Vec8> ceres_intrinsics(num_intrinsics);
|
||||||
ceres_intrinsics[OFFSET_K1] = intrinsics.k1();
|
|
||||||
ceres_intrinsics[OFFSET_K2] = intrinsics.k2();
|
for (int i = 0; i < num_intrinsics; ++i) {
|
||||||
ceres_intrinsics[OFFSET_K3] = intrinsics.k3();
|
if (bundle_options.constraints & BUNDLE_CONSTRAIN_FOCAL_LENGTH) {
|
||||||
ceres_intrinsics[OFFSET_P1] = intrinsics.p1();
|
ceres_intrinsics[i][OFFSET_FOCAL_LENGTH] = ConstrainFocalLength(
|
||||||
ceres_intrinsics[OFFSET_P2] = intrinsics.p2();
|
intrinsics[i].focal_length(),
|
||||||
|
bundle_options.focal_length_min,
|
||||||
|
bundle_options.focal_length_max);
|
||||||
|
} else {
|
||||||
|
ceres_intrinsics[i][OFFSET_FOCAL_LENGTH] = intrinsics[i].focal_length();
|
||||||
|
}
|
||||||
|
ceres_intrinsics[i][OFFSET_PRINCIPAL_POINT_X] = intrinsics[i].principal_point_x();
|
||||||
|
ceres_intrinsics[i][OFFSET_PRINCIPAL_POINT_Y] = intrinsics[i].principal_point_y();
|
||||||
|
ceres_intrinsics[i][OFFSET_K1] = intrinsics[i].k1();
|
||||||
|
ceres_intrinsics[i][OFFSET_K2] = intrinsics[i].k2();
|
||||||
|
ceres_intrinsics[i][OFFSET_K3] = intrinsics[i].k3();
|
||||||
|
ceres_intrinsics[i][OFFSET_P1] = intrinsics[i].p1();
|
||||||
|
ceres_intrinsics[i][OFFSET_P2] = intrinsics[i].p2();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ceres_intrinsics;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpack intrinsics back from an array to an object.
|
// Unpack intrinsics back from an array to an object, converting
|
||||||
void UnpackIntrinsicsFromArray(const double ceres_intrinsics[8],
|
// unconstrained bundle parameter to constrained focal length.
|
||||||
CameraIntrinsics *intrinsics) {
|
std::vector<CameraIntrinsics> UnpackIntrinsics(
|
||||||
intrinsics->SetFocalLength(ceres_intrinsics[OFFSET_FOCAL_LENGTH],
|
const vector<Vec8> &ceres_intrinsics,
|
||||||
ceres_intrinsics[OFFSET_FOCAL_LENGTH]);
|
const BundleOptions &bundle_options) {
|
||||||
|
int num_intrinsics = ceres_intrinsics.size();
|
||||||
|
std::vector<CameraIntrinsics> intrinsics(num_intrinsics);
|
||||||
|
|
||||||
intrinsics->SetPrincipalPoint(ceres_intrinsics[OFFSET_PRINCIPAL_POINT_X],
|
for (int i = 0; i < num_intrinsics; ++i) {
|
||||||
ceres_intrinsics[OFFSET_PRINCIPAL_POINT_Y]);
|
if (bundle_options.constraints & BUNDLE_CONSTRAIN_FOCAL_LENGTH) {
|
||||||
|
double focal_length = UnconstrainFocalLength(
|
||||||
|
ceres_intrinsics[i][OFFSET_FOCAL_LENGTH],
|
||||||
|
bundle_options.focal_length_min,
|
||||||
|
bundle_options.focal_length_max);
|
||||||
|
intrinsics[i].SetFocalLength(focal_length, focal_length);
|
||||||
|
} else {
|
||||||
|
intrinsics[i].SetFocalLength(ceres_intrinsics[i][OFFSET_FOCAL_LENGTH],
|
||||||
|
ceres_intrinsics[i][OFFSET_FOCAL_LENGTH]);
|
||||||
|
}
|
||||||
|
|
||||||
intrinsics->SetRadialDistortion(ceres_intrinsics[OFFSET_K1],
|
intrinsics[i].SetPrincipalPoint(ceres_intrinsics[i][OFFSET_PRINCIPAL_POINT_X],
|
||||||
ceres_intrinsics[OFFSET_K2],
|
ceres_intrinsics[i][OFFSET_PRINCIPAL_POINT_Y]);
|
||||||
ceres_intrinsics[OFFSET_K3]);
|
|
||||||
|
|
||||||
intrinsics->SetTangentialDistortion(ceres_intrinsics[OFFSET_P1],
|
intrinsics[i].SetRadialDistortion(ceres_intrinsics[i][OFFSET_K1],
|
||||||
ceres_intrinsics[OFFSET_P2]);
|
ceres_intrinsics[i][OFFSET_K2],
|
||||||
|
ceres_intrinsics[i][OFFSET_K3]);
|
||||||
|
|
||||||
|
intrinsics[i].SetTangentialDistortion(ceres_intrinsics[i][OFFSET_P1],
|
||||||
|
ceres_intrinsics[i][OFFSET_P2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return intrinsics;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a vector of camera's rotations denoted by angle axis
|
// Get a vector of camera's rotations denoted by angle axis
|
||||||
@@ -183,45 +253,45 @@ void UnpackIntrinsicsFromArray(const double ceres_intrinsics[8],
|
|||||||
//
|
//
|
||||||
// Element with index i matches to a rotation+translation for
|
// Element with index i matches to a rotation+translation for
|
||||||
// camera at image i.
|
// camera at image i.
|
||||||
vector<Vec6> PackCamerasRotationAndTranslation(
|
vector<Vec6> PackViewsRotationAndTranslation(
|
||||||
const Tracks &tracks,
|
const Tracks &tracks,
|
||||||
const EuclideanReconstruction &reconstruction) {
|
const EuclideanReconstruction &reconstruction) {
|
||||||
vector<Vec6> all_cameras_R_t;
|
vector<Vec6> all_views_R_t;
|
||||||
int max_image = tracks.MaxImage();
|
int max_image = tracks.MaxImage();
|
||||||
|
|
||||||
all_cameras_R_t.resize(max_image + 1);
|
all_views_R_t.resize(max_image + 1);
|
||||||
|
|
||||||
for (int i = 0; i <= max_image; i++) {
|
for (int i = 0; i <= max_image; i++) {
|
||||||
const EuclideanCamera *camera = reconstruction.CameraForImage(i);
|
const EuclideanView *view = reconstruction.ViewForImage(i);
|
||||||
|
|
||||||
if (!camera) {
|
if (!view) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ceres::RotationMatrixToAngleAxis(&camera->R(0, 0),
|
ceres::RotationMatrixToAngleAxis(&view->R(0, 0),
|
||||||
&all_cameras_R_t[i](0));
|
&all_views_R_t[i](0));
|
||||||
all_cameras_R_t[i].tail<3>() = camera->t;
|
all_views_R_t[i].tail<3>() = view->t;
|
||||||
}
|
}
|
||||||
return all_cameras_R_t;
|
return all_views_R_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert cameras rotations fro mangle axis back to rotation matrix.
|
// Convert cameras rotations fro mangle axis back to rotation matrix.
|
||||||
void UnpackCamerasRotationAndTranslation(
|
void UnpackViewsRotationAndTranslation(
|
||||||
const Tracks &tracks,
|
const Tracks &tracks,
|
||||||
const vector<Vec6> &all_cameras_R_t,
|
const vector<Vec6> &all_views_R_t,
|
||||||
EuclideanReconstruction *reconstruction) {
|
EuclideanReconstruction *reconstruction) {
|
||||||
int max_image = tracks.MaxImage();
|
int max_image = tracks.MaxImage();
|
||||||
|
|
||||||
for (int i = 0; i <= max_image; i++) {
|
for (int i = 0; i <= max_image; i++) {
|
||||||
EuclideanCamera *camera = reconstruction->CameraForImage(i);
|
EuclideanView *view = reconstruction->ViewForImage(i);
|
||||||
|
|
||||||
if (!camera) {
|
if (!view) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ceres::AngleAxisToRotationMatrix(&all_cameras_R_t[i](0),
|
ceres::AngleAxisToRotationMatrix(&all_views_R_t[i](0),
|
||||||
&camera->R(0, 0));
|
&view->R(0, 0));
|
||||||
camera->t = all_cameras_R_t[i].tail<3>();
|
view->t = all_views_R_t[i].tail<3>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,8 +350,8 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks,
|
|||||||
int max_image = tracks.MaxImage();
|
int max_image = tracks.MaxImage();
|
||||||
bool is_first_camera = true;
|
bool is_first_camera = true;
|
||||||
for (int i = 0; i <= max_image; i++) {
|
for (int i = 0; i <= max_image; i++) {
|
||||||
const EuclideanCamera *camera = reconstruction->CameraForImage(i);
|
const EuclideanView *view = reconstruction->ViewForImage(i);
|
||||||
if (camera) {
|
if (view) {
|
||||||
double *current_camera_R_t = &(*all_cameras_R_t)[i](0);
|
double *current_camera_R_t = &(*all_cameras_R_t)[i](0);
|
||||||
|
|
||||||
// All cameras are variable now.
|
// All cameras are variable now.
|
||||||
@@ -312,42 +382,68 @@ void EuclideanBundlerPerformEvaluation(const Tracks &tracks,
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
BundleOptions::BundleOptions() :
|
||||||
|
bundle_intrinsics(BUNDLE_NO_INTRINSICS),
|
||||||
|
constraints(BUNDLE_NO_CONSTRAINTS),
|
||||||
|
focal_length_min(0.0),
|
||||||
|
focal_length_max(0.0),
|
||||||
|
iteration_callback(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
void EuclideanBundle(const Tracks &tracks,
|
void EuclideanBundle(const Tracks &tracks,
|
||||||
EuclideanReconstruction *reconstruction) {
|
EuclideanReconstruction *reconstruction) {
|
||||||
CameraIntrinsics intrinsics;
|
BundleOptions bundle_options;
|
||||||
|
|
||||||
|
std::vector<CameraIntrinsics> empty_intrinsics;
|
||||||
EuclideanBundleCommonIntrinsics(tracks,
|
EuclideanBundleCommonIntrinsics(tracks,
|
||||||
BUNDLE_NO_INTRINSICS,
|
bundle_options,
|
||||||
BUNDLE_NO_CONSTRAINTS,
|
|
||||||
reconstruction,
|
reconstruction,
|
||||||
&intrinsics,
|
empty_intrinsics);
|
||||||
NULL);
|
}
|
||||||
|
|
||||||
|
void EuclideanBundleModal(const Tracks &tracks,
|
||||||
|
EuclideanReconstruction *reconstruction) {
|
||||||
|
BundleOptions bundle_options;
|
||||||
|
bundle_options.constraints = libmv::BUNDLE_NO_TRANSLATION;
|
||||||
|
|
||||||
|
std::vector<CameraIntrinsics> empty_intrinsics;
|
||||||
|
EuclideanBundleCommonIntrinsics(tracks,
|
||||||
|
bundle_options,
|
||||||
|
reconstruction,
|
||||||
|
empty_intrinsics);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
|
void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
|
||||||
const int bundle_intrinsics,
|
const BundleOptions &bundle_options,
|
||||||
const int bundle_constraints,
|
|
||||||
EuclideanReconstruction *reconstruction,
|
EuclideanReconstruction *reconstruction,
|
||||||
CameraIntrinsics *intrinsics,
|
std::vector<CameraIntrinsics> &intrinsics,
|
||||||
BundleEvaluation *evaluation) {
|
BundleEvaluation *evaluation) {
|
||||||
LG << "Original intrinsics: " << *intrinsics;
|
const int bundle_intrinsics = bundle_options.bundle_intrinsics;
|
||||||
|
const int bundle_constraints = bundle_options.constraints;
|
||||||
|
|
||||||
|
//LG << "Original intrinsics: " << *intrinsics;
|
||||||
vector<Marker> markers = tracks.AllMarkers();
|
vector<Marker> markers = tracks.AllMarkers();
|
||||||
|
|
||||||
|
int num_cameras = tracks.MaxCamera() + 1;
|
||||||
|
if (intrinsics.size() < num_cameras) {
|
||||||
|
intrinsics.resize(num_cameras);
|
||||||
|
}
|
||||||
|
|
||||||
ceres::Problem::Options problem_options;
|
ceres::Problem::Options problem_options;
|
||||||
ceres::Problem problem(problem_options);
|
ceres::Problem problem(problem_options);
|
||||||
|
|
||||||
// Residual blocks with 10 parameters are unwieldly with Ceres, so pack the
|
// Residual blocks with 10 parameters are unwieldly with Ceres, so pack the
|
||||||
// intrinsics into a single block and rely on local parameterizations to
|
// intrinsics into a single block and rely on local parameterizations to
|
||||||
// control which intrinsics are allowed to vary.
|
// control which intrinsics are allowed to vary.
|
||||||
double ceres_intrinsics[8];
|
vector<Vec8> ceres_intrinsics = PackIntrinsics(intrinsics, bundle_options);
|
||||||
PackIntrinisicsIntoArray(*intrinsics, ceres_intrinsics);
|
|
||||||
|
|
||||||
// Convert cameras rotations to angle axis and merge with translation
|
// Convert views rotations to angle axis and merge with translation
|
||||||
// into single parameter block for maximal minimization speed.
|
// into single parameter block for maximal minimization speed.
|
||||||
//
|
//
|
||||||
// Block for minimization has got the following structure:
|
// Block for minimization has got the following structure:
|
||||||
// <3 elements for angle-axis> <3 elements for translation>
|
// <3 elements for angle-axis> <3 elements for translation>
|
||||||
vector<Vec6> all_cameras_R_t =
|
vector<Vec6> all_views_R_t =
|
||||||
PackCamerasRotationAndTranslation(tracks, *reconstruction);
|
PackViewsRotationAndTranslation(tracks, *reconstruction);
|
||||||
|
|
||||||
// Parameterization used to restrict camera motion for modal solvers.
|
// Parameterization used to restrict camera motion for modal solvers.
|
||||||
ceres::SubsetParameterization *constant_translation_parameterization = NULL;
|
ceres::SubsetParameterization *constant_translation_parameterization = NULL;
|
||||||
@@ -365,37 +461,46 @@ void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
|
|||||||
|
|
||||||
// Add residual blocks to the problem.
|
// Add residual blocks to the problem.
|
||||||
int num_residuals = 0;
|
int num_residuals = 0;
|
||||||
bool have_locked_camera = false;
|
bool have_locked_view = false;
|
||||||
for (int i = 0; i < markers.size(); ++i) {
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
const Marker &marker = markers[i];
|
const Marker &marker = markers[i];
|
||||||
EuclideanCamera *camera = reconstruction->CameraForImage(marker.image);
|
EuclideanView *view = reconstruction->ViewForImage(marker.image);
|
||||||
EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
|
EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
|
||||||
if (camera == NULL || point == NULL) {
|
if (view == NULL || point == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int camera = view->camera;
|
||||||
|
|
||||||
// Rotation of camera denoted in angle axis followed with
|
// Rotation of camera denoted in angle axis followed with
|
||||||
// camera translaiton.
|
// camera translaiton.
|
||||||
double *current_camera_R_t = &all_cameras_R_t[camera->image](0);
|
double *current_view_R_t = &all_views_R_t[view->image](0);
|
||||||
|
|
||||||
|
OpenCVReprojectionError *cost_function;
|
||||||
|
if (bundle_options.constraints & BUNDLE_CONSTRAIN_FOCAL_LENGTH) {
|
||||||
|
cost_function = new OpenCVReprojectionError(
|
||||||
|
marker.x, marker.y,
|
||||||
|
bundle_options.focal_length_min,
|
||||||
|
bundle_options.focal_length_max);
|
||||||
|
} else {
|
||||||
|
cost_function = new OpenCVReprojectionError(marker.x, marker.y);
|
||||||
|
}
|
||||||
|
|
||||||
problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
|
problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
|
||||||
OpenCVReprojectionError, 2, 8, 6, 3>(
|
OpenCVReprojectionError, 2, 8, 6, 3>(cost_function),
|
||||||
new OpenCVReprojectionError(
|
|
||||||
marker.x,
|
|
||||||
marker.y)),
|
|
||||||
NULL,
|
NULL,
|
||||||
ceres_intrinsics,
|
&ceres_intrinsics[camera](0),
|
||||||
current_camera_R_t,
|
current_view_R_t,
|
||||||
&point->X(0));
|
&point->X(0));
|
||||||
|
|
||||||
// We lock the first camera to better deal with scene orientation ambiguity.
|
// We lock the first camera to better deal with scene orientation ambiguity.
|
||||||
if (!have_locked_camera) {
|
if (!have_locked_view) {
|
||||||
problem.SetParameterBlockConstant(current_camera_R_t);
|
problem.SetParameterBlockConstant(current_view_R_t);
|
||||||
have_locked_camera = true;
|
have_locked_view = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
|
if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
|
||||||
problem.SetParameterization(current_camera_R_t,
|
problem.SetParameterization(current_view_R_t,
|
||||||
constant_translation_parameterization);
|
constant_translation_parameterization);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,7 +518,7 @@ void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
|
|||||||
if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
|
if (bundle_intrinsics == BUNDLE_NO_INTRINSICS) {
|
||||||
// No camera intrinsics are being refined,
|
// No camera intrinsics are being refined,
|
||||||
// set the whole parameter block as constant for best performance.
|
// set the whole parameter block as constant for best performance.
|
||||||
problem.SetParameterBlockConstant(ceres_intrinsics);
|
problem.SetParameterBlockConstant(&ceres_intrinsics[0](0));
|
||||||
} else {
|
} else {
|
||||||
// Set the camera intrinsics that are not to be bundled as
|
// Set the camera intrinsics that are not to be bundled as
|
||||||
// constant using some macro trickery.
|
// constant using some macro trickery.
|
||||||
@@ -438,7 +543,11 @@ void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
|
|||||||
ceres::SubsetParameterization *subset_parameterization =
|
ceres::SubsetParameterization *subset_parameterization =
|
||||||
new ceres::SubsetParameterization(8, constant_intrinsics);
|
new ceres::SubsetParameterization(8, constant_intrinsics);
|
||||||
|
|
||||||
problem.SetParameterization(ceres_intrinsics, subset_parameterization);
|
problem.SetParameterization(&ceres_intrinsics[0](0), subset_parameterization);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < ceres_intrinsics.size(); ++i) {
|
||||||
|
problem.SetParameterBlockConstant(&ceres_intrinsics[i](0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure the solver.
|
// Configure the solver.
|
||||||
@@ -448,6 +557,9 @@ void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
|
|||||||
options.linear_solver_type = ceres::ITERATIVE_SCHUR;
|
options.linear_solver_type = ceres::ITERATIVE_SCHUR;
|
||||||
options.use_inner_iterations = true;
|
options.use_inner_iterations = true;
|
||||||
options.max_num_iterations = 100;
|
options.max_num_iterations = 100;
|
||||||
|
if (bundle_options.iteration_callback != NULL) {
|
||||||
|
options.callbacks.push_back(bundle_options.iteration_callback);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _OPENMP
|
#ifdef _OPENMP
|
||||||
options.num_threads = omp_get_max_threads();
|
options.num_threads = omp_get_max_threads();
|
||||||
@@ -461,18 +573,20 @@ void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
|
|||||||
LG << "Final report:\n" << summary.FullReport();
|
LG << "Final report:\n" << summary.FullReport();
|
||||||
|
|
||||||
// Copy rotations and translations back.
|
// Copy rotations and translations back.
|
||||||
UnpackCamerasRotationAndTranslation(tracks,
|
UnpackViewsRotationAndTranslation(tracks,
|
||||||
all_cameras_R_t,
|
all_views_R_t,
|
||||||
reconstruction);
|
reconstruction);
|
||||||
|
|
||||||
// Copy intrinsics back.
|
// Copy intrinsics back.
|
||||||
if (bundle_intrinsics != BUNDLE_NO_INTRINSICS)
|
if (bundle_intrinsics != BUNDLE_NO_INTRINSICS) {
|
||||||
UnpackIntrinsicsFromArray(ceres_intrinsics, intrinsics);
|
intrinsics = UnpackIntrinsics(ceres_intrinsics,
|
||||||
|
bundle_options);
|
||||||
|
}
|
||||||
|
|
||||||
LG << "Final intrinsics: " << *intrinsics;
|
//LG << "Final intrinsics: " << *intrinsics;
|
||||||
|
|
||||||
if (evaluation) {
|
if (evaluation) {
|
||||||
EuclideanBundlerPerformEvaluation(tracks, reconstruction, &all_cameras_R_t,
|
EuclideanBundlerPerformEvaluation(tracks, reconstruction, &all_views_R_t,
|
||||||
&problem, evaluation);
|
&problem, evaluation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
extern/libmv/libmv/simple_pipeline/bundle.h
vendored
54
extern/libmv/libmv/simple_pipeline/bundle.h
vendored
@@ -21,6 +21,10 @@
|
|||||||
#ifndef LIBMV_SIMPLE_PIPELINE_BUNDLE_H
|
#ifndef LIBMV_SIMPLE_PIPELINE_BUNDLE_H
|
||||||
#define LIBMV_SIMPLE_PIPELINE_BUNDLE_H
|
#define LIBMV_SIMPLE_PIPELINE_BUNDLE_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "ceres/types.h"
|
||||||
|
#include "ceres/iteration_callback.h"
|
||||||
#include "libmv/numeric/numeric.h"
|
#include "libmv/numeric/numeric.h"
|
||||||
|
|
||||||
namespace libmv {
|
namespace libmv {
|
||||||
@@ -75,6 +79,27 @@ struct BundleEvaluation {
|
|||||||
void EuclideanBundle(const Tracks &tracks,
|
void EuclideanBundle(const Tracks &tracks,
|
||||||
EuclideanReconstruction *reconstruction);
|
EuclideanReconstruction *reconstruction);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Refine camera poses and 3D coordinates using bundle adjustment.
|
||||||
|
|
||||||
|
This routine adjusts all cameras and points in \a *reconstruction. This
|
||||||
|
assumes a full observation for reconstructed tracks; this implies that if
|
||||||
|
there is a reconstructed 3D point (a bundle) for a track, then all markers
|
||||||
|
for that track will be included in the minimization. \a tracks should
|
||||||
|
contain markers used in the initial reconstruction.
|
||||||
|
|
||||||
|
The cameras and bundles (3D points), except the camera positions, are
|
||||||
|
refined in-place.
|
||||||
|
|
||||||
|
\note This assumes an outlier-free set of markers.
|
||||||
|
\note This assumes a calibrated reconstruction, e.g. the markers are
|
||||||
|
already corrected for camera intrinsics and radial distortion.
|
||||||
|
|
||||||
|
\sa EuclideanResect, EuclideanIntersect, EuclideanReconstructTwoFrames
|
||||||
|
*/
|
||||||
|
void EuclideanBundleModal(const Tracks &tracks,
|
||||||
|
EuclideanReconstruction *reconstruction);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Refine camera poses and 3D coordinates using bundle adjustment.
|
Refine camera poses and 3D coordinates using bundle adjustment.
|
||||||
|
|
||||||
@@ -91,7 +116,7 @@ void EuclideanBundle(const Tracks &tracks,
|
|||||||
For example it is useful to keep camera translations constant
|
For example it is useful to keep camera translations constant
|
||||||
when bundling tripod motions.
|
when bundling tripod motions.
|
||||||
|
|
||||||
If evaluaiton is not null, different evaluation statistics is filled in
|
If evaluation is not null, different evaluation statistics is filled in
|
||||||
there, plus all the requested additional information (like jacobian) is
|
there, plus all the requested additional information (like jacobian) is
|
||||||
also calculating there. Also see comments for BundleEvaluation.
|
also calculating there. Also see comments for BundleEvaluation.
|
||||||
|
|
||||||
@@ -110,15 +135,36 @@ enum BundleIntrinsics {
|
|||||||
BUNDLE_TANGENTIAL_P2 = 32,
|
BUNDLE_TANGENTIAL_P2 = 32,
|
||||||
BUNDLE_TANGENTIAL = 48,
|
BUNDLE_TANGENTIAL = 48,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BundleConstraints {
|
enum BundleConstraints {
|
||||||
BUNDLE_NO_CONSTRAINTS = 0,
|
BUNDLE_NO_CONSTRAINTS = 0,
|
||||||
BUNDLE_NO_TRANSLATION = 1,
|
BUNDLE_NO_TRANSLATION = 1,
|
||||||
|
BUNDLE_CONSTRAIN_FOCAL_LENGTH = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BundleOptions {
|
||||||
|
BundleOptions();
|
||||||
|
|
||||||
|
// Bitfield denoting the camera intrinsics to adjust during
|
||||||
|
// bundling. Use BundleIntrinsics flags.
|
||||||
|
short bundle_intrinsics;
|
||||||
|
|
||||||
|
// Bitfield denoting the constraints to place on bundle parameters.
|
||||||
|
// Use BundleConstraints flags.
|
||||||
|
int constraints;
|
||||||
|
|
||||||
|
// Minimum and maximum constraints for the focal length. To be useful,
|
||||||
|
// BUNDLE_CONSTRAIN_FOCAL_LENGTH flag must be set on constraints.
|
||||||
|
double focal_length_min, focal_length_max;
|
||||||
|
|
||||||
|
// Callback which is called after each iteration of the solver.
|
||||||
|
ceres::IterationCallback *iteration_callback;
|
||||||
|
};
|
||||||
|
|
||||||
void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
|
void EuclideanBundleCommonIntrinsics(const Tracks &tracks,
|
||||||
const int bundle_intrinsics,
|
const BundleOptions &bundle_options,
|
||||||
const int bundle_constraints,
|
|
||||||
EuclideanReconstruction *reconstruction,
|
EuclideanReconstruction *reconstruction,
|
||||||
CameraIntrinsics *intrinsics,
|
std::vector<CameraIntrinsics> &intrinsics,
|
||||||
BundleEvaluation *evaluation = NULL);
|
BundleEvaluation *evaluation = NULL);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@@ -32,15 +32,18 @@
|
|||||||
namespace libmv {
|
namespace libmv {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void GetImagesInMarkers(const vector<Marker> &markers,
|
void GetImagesAndCamerasInMarkers(const vector<Marker> &markers,
|
||||||
int *image1, int *image2) {
|
int *image1, int *image2,
|
||||||
|
int *camera1, int *camera2) {
|
||||||
if (markers.size() < 2) {
|
if (markers.size() < 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*image1 = markers[0].image;
|
*image1 = markers[0].image;
|
||||||
|
*camera1 = markers[0].camera;
|
||||||
for (int i = 1; i < markers.size(); ++i) {
|
for (int i = 1; i < markers.size(); ++i) {
|
||||||
if (markers[i].image != *image1) {
|
if (markers[i].image != *image1) {
|
||||||
*image2 = markers[i].image;
|
*image2 = markers[i].image;
|
||||||
|
*camera2 = markers[i].camera;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +61,8 @@ bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int image1, image2;
|
int image1, image2;
|
||||||
GetImagesInMarkers(markers, &image1, &image2);
|
int camera1, camera2;
|
||||||
|
GetImagesAndCamerasInMarkers(markers, &image1, &image2, &camera1, &camera2);
|
||||||
|
|
||||||
Mat x1, x2;
|
Mat x1, x2;
|
||||||
CoordinatesForMarkersInImage(markers, image1, &x1);
|
CoordinatesForMarkersInImage(markers, image1, &x1);
|
||||||
@@ -85,8 +89,8 @@ bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Image 1 gets the reference frame, image 2 gets the relative motion.
|
// Image 1 gets the reference frame, image 2 gets the relative motion.
|
||||||
reconstruction->InsertCamera(image1, Mat3::Identity(), Vec3::Zero());
|
reconstruction->InsertView(image1, Mat3::Identity(), Vec3::Zero(), camera1);
|
||||||
reconstruction->InsertCamera(image2, R, t);
|
reconstruction->InsertView(image2, R, t, camera2);
|
||||||
|
|
||||||
LG << "From two frame reconstruction got:\nR:\n" << R
|
LG << "From two frame reconstruction got:\nR:\n" << R
|
||||||
<< "\nt:" << t.transpose();
|
<< "\nt:" << t.transpose();
|
||||||
@@ -146,7 +150,8 @@ bool ProjectiveReconstructTwoFrames(const vector<Marker> &markers,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int image1, image2;
|
int image1, image2;
|
||||||
GetImagesInMarkers(markers, &image1, &image2);
|
int camera1, camera2;
|
||||||
|
GetImagesAndCamerasInMarkers(markers, &image1, &image2, &camera1, &camera2);
|
||||||
|
|
||||||
Mat x1, x2;
|
Mat x1, x2;
|
||||||
CoordinatesForMarkersInImage(markers, image1, &x1);
|
CoordinatesForMarkersInImage(markers, image1, &x1);
|
||||||
@@ -186,8 +191,8 @@ bool ProjectiveReconstructTwoFrames(const vector<Marker> &markers,
|
|||||||
Mat34 P2;
|
Mat34 P2;
|
||||||
ProjectionsFromFundamental(F, &P1, &P2);
|
ProjectionsFromFundamental(F, &P1, &P2);
|
||||||
|
|
||||||
reconstruction->InsertCamera(image1, P1);
|
reconstruction->InsertView(image1, P1, camera1);
|
||||||
reconstruction->InsertCamera(image2, P2);
|
reconstruction->InsertView(image2, P2, camera2);
|
||||||
|
|
||||||
LG << "From two frame reconstruction got P2:\n" << P2;
|
LG << "From two frame reconstruction got P2:\n" << P2;
|
||||||
return true;
|
return true;
|
||||||
|
@@ -34,8 +34,8 @@ class ProjectiveReconstruction;
|
|||||||
two frames.
|
two frames.
|
||||||
|
|
||||||
\a markers should contain all \l Marker markers \endlink belonging to
|
\a markers should contain all \l Marker markers \endlink belonging to
|
||||||
tracks visible in both frames. The pose estimation of the camera for
|
tracks visible in both frames from the same camera. The pose estimation of
|
||||||
these frames will be inserted into \a *reconstruction.
|
the camera for these frames will be inserted into \a *reconstruction.
|
||||||
|
|
||||||
\note The two frames need to have both enough parallax and enough common tracks
|
\note The two frames need to have both enough parallax and enough common tracks
|
||||||
for accurate reconstruction. At least 8 tracks are suggested.
|
for accurate reconstruction. At least 8 tracks are suggested.
|
||||||
@@ -55,8 +55,8 @@ bool EuclideanReconstructTwoFrames(const vector<Marker> &markers,
|
|||||||
two frames.
|
two frames.
|
||||||
|
|
||||||
\a markers should contain all \l Marker markers \endlink belonging to
|
\a markers should contain all \l Marker markers \endlink belonging to
|
||||||
tracks visible in both frames. An estimate of the projection matrices for
|
tracks visible in both frames from the same camera. An estimate of the
|
||||||
the two frames will get added to the reconstruction.
|
projection matrices for the two frames will get added to the reconstruction.
|
||||||
|
|
||||||
\note The two frames need to have both enough parallax and enough common tracks
|
\note The two frames need to have both enough parallax and enough common tracks
|
||||||
for accurate reconstruction. At least 8 tracks are suggested.
|
for accurate reconstruction. At least 8 tracks are suggested.
|
||||||
|
42
extern/libmv/libmv/simple_pipeline/intersect.cc
vendored
42
extern/libmv/libmv/simple_pipeline/intersect.cc
vendored
@@ -39,8 +39,8 @@ namespace {
|
|||||||
class EuclideanIntersectCostFunctor {
|
class EuclideanIntersectCostFunctor {
|
||||||
public:
|
public:
|
||||||
EuclideanIntersectCostFunctor(const Marker &marker,
|
EuclideanIntersectCostFunctor(const Marker &marker,
|
||||||
const EuclideanCamera &camera)
|
const EuclideanView &view)
|
||||||
: marker_(marker), camera_(camera) {}
|
: marker_(marker), view_(view) {}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
bool operator()(const T *X, T *residuals) const {
|
bool operator()(const T *X, T *residuals) const {
|
||||||
@@ -48,8 +48,8 @@ class EuclideanIntersectCostFunctor {
|
|||||||
typedef Eigen::Matrix<T, 3, 1> Vec3;
|
typedef Eigen::Matrix<T, 3, 1> Vec3;
|
||||||
|
|
||||||
Vec3 x(X);
|
Vec3 x(X);
|
||||||
Mat3 R(camera_.R.cast<T>());
|
Mat3 R(view_.R.cast<T>());
|
||||||
Vec3 t(camera_.t.cast<T>());
|
Vec3 t(view_.t.cast<T>());
|
||||||
|
|
||||||
Vec3 projected = R * x + t;
|
Vec3 projected = R * x + t;
|
||||||
projected /= projected(2);
|
projected /= projected(2);
|
||||||
@@ -61,7 +61,7 @@ class EuclideanIntersectCostFunctor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Marker &marker_;
|
const Marker &marker_;
|
||||||
const EuclideanCamera &camera_;
|
const EuclideanView &view_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -78,8 +78,8 @@ bool EuclideanIntersect(const vector<Marker> &markers,
|
|||||||
vector<Mat34> cameras;
|
vector<Mat34> cameras;
|
||||||
Mat34 P;
|
Mat34 P;
|
||||||
for (int i = 0; i < markers.size(); ++i) {
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
EuclideanCamera *camera = reconstruction->CameraForImage(markers[i].image);
|
EuclideanView *view = reconstruction->ViewForImage(markers[i].image);
|
||||||
P_From_KRt(K, camera->R, camera->t, &P);
|
P_From_KRt(K, view->R, view->t, &P);
|
||||||
cameras.push_back(P);
|
cameras.push_back(P);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,14 +102,14 @@ bool EuclideanIntersect(const vector<Marker> &markers,
|
|||||||
|
|
||||||
for (int i = 0; i < markers.size(); ++i) {
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
const Marker &marker = markers[i];
|
const Marker &marker = markers[i];
|
||||||
const EuclideanCamera &camera =
|
const EuclideanView &view =
|
||||||
*reconstruction->CameraForImage(marker.image);
|
*reconstruction->ViewForImage(marker.image);
|
||||||
|
|
||||||
problem.AddResidualBlock(
|
problem.AddResidualBlock(
|
||||||
new ceres::AutoDiffCostFunction<
|
new ceres::AutoDiffCostFunction<
|
||||||
EuclideanIntersectCostFunctor,
|
EuclideanIntersectCostFunctor,
|
||||||
2, /* num_residuals */
|
2, /* num_residuals */
|
||||||
3>(new EuclideanIntersectCostFunctor(marker, camera)),
|
3>(new EuclideanIntersectCostFunctor(marker, view)),
|
||||||
NULL,
|
NULL,
|
||||||
&X(0));
|
&X(0));
|
||||||
}
|
}
|
||||||
@@ -130,9 +130,9 @@ bool EuclideanIntersect(const vector<Marker> &markers,
|
|||||||
|
|
||||||
// Try projecting the point; make sure it's in front of everyone.
|
// Try projecting the point; make sure it's in front of everyone.
|
||||||
for (int i = 0; i < cameras.size(); ++i) {
|
for (int i = 0; i < cameras.size(); ++i) {
|
||||||
const EuclideanCamera &camera =
|
const EuclideanView &view =
|
||||||
*reconstruction->CameraForImage(markers[i].image);
|
*reconstruction->ViewForImage(markers[i].image);
|
||||||
Vec3 x = camera.R * X + camera.t;
|
Vec3 x = view.R * X + view.t;
|
||||||
if (x(2) < 0) {
|
if (x(2) < 0) {
|
||||||
LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
|
LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
|
||||||
<< ": " << x.transpose();
|
<< ": " << x.transpose();
|
||||||
@@ -163,9 +163,9 @@ struct ProjectiveIntersectCostFunction {
|
|||||||
Vec residuals(2 * markers.size());
|
Vec residuals(2 * markers.size());
|
||||||
residuals.setZero();
|
residuals.setZero();
|
||||||
for (int i = 0; i < markers.size(); ++i) {
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
const ProjectiveCamera &camera =
|
const ProjectiveView &view =
|
||||||
*reconstruction.CameraForImage(markers[i].image);
|
*reconstruction.ViewForImage(markers[i].image);
|
||||||
Vec3 projected = camera.P * X;
|
Vec3 projected = view.P * X;
|
||||||
projected /= projected(2);
|
projected /= projected(2);
|
||||||
residuals[2*i + 0] = projected(0) - markers[i].x;
|
residuals[2*i + 0] = projected(0) - markers[i].x;
|
||||||
residuals[2*i + 1] = projected(1) - markers[i].y;
|
residuals[2*i + 1] = projected(1) - markers[i].y;
|
||||||
@@ -187,8 +187,8 @@ bool ProjectiveIntersect(const vector<Marker> &markers,
|
|||||||
// Get the cameras to use for the intersection.
|
// Get the cameras to use for the intersection.
|
||||||
vector<Mat34> cameras;
|
vector<Mat34> cameras;
|
||||||
for (int i = 0; i < markers.size(); ++i) {
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
ProjectiveCamera *camera = reconstruction->CameraForImage(markers[i].image);
|
ProjectiveView *view = reconstruction->ViewForImage(markers[i].image);
|
||||||
cameras.push_back(camera->P);
|
cameras.push_back(view->P);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stack the 2D coordinates together as required by NViewTriangulate.
|
// Stack the 2D coordinates together as required by NViewTriangulate.
|
||||||
@@ -214,9 +214,9 @@ bool ProjectiveIntersect(const vector<Marker> &markers,
|
|||||||
|
|
||||||
// Try projecting the point; make sure it's in front of everyone.
|
// Try projecting the point; make sure it's in front of everyone.
|
||||||
for (int i = 0; i < cameras.size(); ++i) {
|
for (int i = 0; i < cameras.size(); ++i) {
|
||||||
const ProjectiveCamera &camera =
|
const ProjectiveView &view =
|
||||||
*reconstruction->CameraForImage(markers[i].image);
|
*reconstruction->ViewForImage(markers[i].image);
|
||||||
Vec3 x = camera.P * X;
|
Vec3 x = view.P * X;
|
||||||
if (x(2) < 0) {
|
if (x(2) < 0) {
|
||||||
LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
|
LOG(ERROR) << "POINT BEHIND CAMERA " << markers[i].image
|
||||||
<< ": " << x.transpose();
|
<< ": " << x.transpose();
|
||||||
|
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include "libmv/simple_pipeline/keyframe_selection.h"
|
#include "libmv/simple_pipeline/keyframe_selection.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "libmv/numeric/numeric.h"
|
#include "libmv/numeric/numeric.h"
|
||||||
#include "ceres/ceres.h"
|
#include "ceres/ceres.h"
|
||||||
#include "libmv/logging/logging.h"
|
#include "libmv/logging/logging.h"
|
||||||
@@ -97,7 +99,7 @@ class HomographySymmetricGeometricCostFunctor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void ComputeHomographyFromCorrespondences(const Mat &x1, const Mat &x2,
|
void ComputeHomographyFromCorrespondences(const Mat &x1, const Mat &x2,
|
||||||
CameraIntrinsics &intrinsics,
|
const CameraIntrinsics &intrinsics,
|
||||||
Mat3 *H) {
|
Mat3 *H) {
|
||||||
// Algebraic homography estimation, happens with normalized coordinates
|
// Algebraic homography estimation, happens with normalized coordinates
|
||||||
Homography2DFromCorrespondencesLinear(x1, x2, H, 1e-12);
|
Homography2DFromCorrespondencesLinear(x1, x2, H, 1e-12);
|
||||||
@@ -172,7 +174,7 @@ class FundamentalSymmetricEpipolarCostFunctor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void ComputeFundamentalFromCorrespondences(const Mat &x1, const Mat &x2,
|
void ComputeFundamentalFromCorrespondences(const Mat &x1, const Mat &x2,
|
||||||
CameraIntrinsics &intrinsics,
|
const CameraIntrinsics &intrinsics,
|
||||||
Mat3 *F) {
|
Mat3 *F) {
|
||||||
// Algebraic fundamental estimation, happens with normalized coordinates
|
// Algebraic fundamental estimation, happens with normalized coordinates
|
||||||
NormalizedEightPointSolver(x1, x2, F);
|
NormalizedEightPointSolver(x1, x2, F);
|
||||||
@@ -288,15 +290,20 @@ Mat pseudoInverse(const Mat &matrix) {
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks,
|
void SelectKeyframesBasedOnGRICAndVariance(
|
||||||
CameraIntrinsics &intrinsics,
|
const Tracks &tracks,
|
||||||
|
const std::vector<CameraIntrinsics> &intrinsics,
|
||||||
|
int camera,
|
||||||
vector<int> &keyframes) {
|
vector<int> &keyframes) {
|
||||||
// Mirza Tahir Ahmed, Matthew N. Dailey
|
// Mirza Tahir Ahmed, Matthew N. Dailey
|
||||||
// Robust key frame extraction for 3D reconstruction from video streams
|
// Robust key frame extraction for 3D reconstruction from video streams
|
||||||
//
|
//
|
||||||
// http://www.cs.ait.ac.th/~mdailey/papers/Tahir-KeyFrame.pdf
|
// http://www.cs.ait.ac.th/~mdailey/papers/Tahir-KeyFrame.pdf
|
||||||
|
|
||||||
int max_image = tracks.MaxImage();
|
Tracks camera_tracks(tracks.MarkersForCamera(camera));
|
||||||
|
const CameraIntrinsics &camera_intrinsics = intrinsics[camera];
|
||||||
|
|
||||||
|
int max_image = camera_tracks.MaxImage();
|
||||||
int next_keyframe = 1;
|
int next_keyframe = 1;
|
||||||
int number_keyframes = 0;
|
int number_keyframes = 0;
|
||||||
|
|
||||||
@@ -308,7 +315,7 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks,
|
|||||||
const double Tmin = 0.8;
|
const double Tmin = 0.8;
|
||||||
const double Tmax = 1.0;
|
const double Tmax = 1.0;
|
||||||
|
|
||||||
Mat3 N = IntrinsicsNormalizationMatrix(intrinsics);
|
Mat3 N = IntrinsicsNormalizationMatrix(camera_intrinsics);
|
||||||
Mat3 N_inverse = N.inverse();
|
Mat3 N_inverse = N.inverse();
|
||||||
|
|
||||||
double Sc_best = std::numeric_limits<double>::max();
|
double Sc_best = std::numeric_limits<double>::max();
|
||||||
@@ -328,11 +335,11 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks,
|
|||||||
candidate_image++) {
|
candidate_image++) {
|
||||||
// Conjunction of all markers from both keyframes
|
// Conjunction of all markers from both keyframes
|
||||||
vector<Marker> all_markers =
|
vector<Marker> all_markers =
|
||||||
tracks.MarkersInBothImages(current_keyframe, candidate_image);
|
camera_tracks.MarkersInBothImages(current_keyframe, candidate_image);
|
||||||
|
|
||||||
// Match keypoints between frames current_keyframe and candidate_image
|
// Match keypoints between frames current_keyframe and candidate_image
|
||||||
vector<Marker> tracked_markers =
|
vector<Marker> tracked_markers =
|
||||||
tracks.MarkersForTracksInBothImages(current_keyframe, candidate_image);
|
camera_tracks.MarkersForTracksInBothImages(current_keyframe, candidate_image);
|
||||||
|
|
||||||
// Correspondences in normalized space
|
// Correspondences in normalized space
|
||||||
Mat x1, x2;
|
Mat x1, x2;
|
||||||
@@ -360,8 +367,8 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
Mat3 H, F;
|
Mat3 H, F;
|
||||||
ComputeHomographyFromCorrespondences(x1, x2, intrinsics, &H);
|
ComputeHomographyFromCorrespondences(x1, x2, camera_intrinsics, &H);
|
||||||
ComputeFundamentalFromCorrespondences(x1, x2, intrinsics, &F);
|
ComputeFundamentalFromCorrespondences(x1, x2, camera_intrinsics, &F);
|
||||||
|
|
||||||
// TODO(sergey): STEP 2: Discard outlier matches
|
// TODO(sergey): STEP 2: Discard outlier matches
|
||||||
|
|
||||||
@@ -373,9 +380,9 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks,
|
|||||||
F_e.resize(x1.cols());
|
F_e.resize(x1.cols());
|
||||||
for (int i = 0; i < x1.cols(); i++) {
|
for (int i = 0; i < x1.cols(); i++) {
|
||||||
Vec2 current_x1 =
|
Vec2 current_x1 =
|
||||||
NorrmalizedToPixelSpace(Vec2(x1(0, i), x1(1, i)), intrinsics);
|
NorrmalizedToPixelSpace(Vec2(x1(0, i), x1(1, i)), camera_intrinsics);
|
||||||
Vec2 current_x2 =
|
Vec2 current_x2 =
|
||||||
NorrmalizedToPixelSpace(Vec2(x2(0, i), x2(1, i)), intrinsics);
|
NorrmalizedToPixelSpace(Vec2(x2(0, i), x2(1, i)), camera_intrinsics);
|
||||||
|
|
||||||
H_e(i) = SymmetricGeometricDistance(H, current_x1, current_x2);
|
H_e(i) = SymmetricGeometricDistance(H, current_x1, current_x2);
|
||||||
F_e(i) = SymmetricEpipolarDistance(F, current_x1, current_x2);
|
F_e(i) = SymmetricEpipolarDistance(F, current_x1, current_x2);
|
||||||
@@ -442,10 +449,11 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks,
|
|||||||
<< "\nt:" << t.transpose();
|
<< "\nt:" << t.transpose();
|
||||||
|
|
||||||
// First camera is identity, second one is relative to it
|
// First camera is identity, second one is relative to it
|
||||||
reconstruction.InsertCamera(current_keyframe,
|
reconstruction.InsertView(current_keyframe,
|
||||||
Mat3::Identity(),
|
Mat3::Identity(),
|
||||||
Vec3::Zero());
|
Vec3::Zero(),
|
||||||
reconstruction.InsertCamera(candidate_image, R, t);
|
camera);
|
||||||
|
reconstruction.InsertView(candidate_image, R, t, camera);
|
||||||
|
|
||||||
// Reconstruct 3D points
|
// Reconstruct 3D points
|
||||||
int intersects_total = 0, intersects_success = 0;
|
int intersects_total = 0, intersects_success = 0;
|
||||||
@@ -494,15 +502,15 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks,
|
|||||||
success_intersects_factor_best = success_intersects_factor;
|
success_intersects_factor_best = success_intersects_factor;
|
||||||
|
|
||||||
Tracks two_frames_tracks(tracked_markers);
|
Tracks two_frames_tracks(tracked_markers);
|
||||||
CameraIntrinsics empty_intrinsics;
|
std::vector<CameraIntrinsics> empty_intrinsics;
|
||||||
BundleEvaluation evaluation;
|
BundleEvaluation evaluation;
|
||||||
evaluation.evaluate_jacobian = true;
|
evaluation.evaluate_jacobian = true;
|
||||||
|
|
||||||
|
BundleOptions bundle_options;
|
||||||
EuclideanBundleCommonIntrinsics(two_frames_tracks,
|
EuclideanBundleCommonIntrinsics(two_frames_tracks,
|
||||||
BUNDLE_NO_INTRINSICS,
|
bundle_options,
|
||||||
BUNDLE_NO_CONSTRAINTS,
|
|
||||||
&reconstruction,
|
&reconstruction,
|
||||||
&empty_intrinsics,
|
empty_intrinsics,
|
||||||
&evaluation);
|
&evaluation);
|
||||||
|
|
||||||
Mat &jacobian = evaluation.jacobian;
|
Mat &jacobian = evaluation.jacobian;
|
||||||
@@ -579,4 +587,11 @@ void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SelectKeyframesBasedOnGRICAndVariance(
|
||||||
|
const Tracks &tracks,
|
||||||
|
const std::vector<CameraIntrinsics> &intrinsics,
|
||||||
|
vector<int> &keyframes) {
|
||||||
|
SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, 0, keyframes);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace libmv
|
} // namespace libmv
|
||||||
|
@@ -21,30 +21,41 @@
|
|||||||
#ifndef LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_
|
#ifndef LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_
|
||||||
#define LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_
|
#define LIBMV_SIMPLE_PIPELINE_KEYFRAME_SELECTION_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "libmv/base/vector.h"
|
#include "libmv/base/vector.h"
|
||||||
#include "libmv/simple_pipeline/tracks.h"
|
#include "libmv/simple_pipeline/tracks.h"
|
||||||
#include "libmv/simple_pipeline/camera_intrinsics.h"
|
#include "libmv/simple_pipeline/camera_intrinsics.h"
|
||||||
|
|
||||||
namespace libmv {
|
namespace libmv {
|
||||||
|
|
||||||
// Get list of all images which are good enough to be as keyframes from
|
// Get list of all images from given camera which are good enough to be as
|
||||||
// camera reconstruction. Based on GRIC criteria and uses Pollefeys'
|
// keyframes for camera reconstruction. Based on GRIC criteria and uses
|
||||||
// approach for correspondence ratio constraint.
|
// Pollefeys' approach for correspondence ratio constraint.
|
||||||
//
|
//
|
||||||
// As an additional, additional criteria based on reconstruction
|
// Additional criteria based on reconstruction variance are used. This means if
|
||||||
// variance is used. This means if correspondence and GRIC criteria
|
// correspondence and GRIC criteria are passed, two-frame reconstruction using
|
||||||
// are passed, two-frames reconstruction using candidate keyframes
|
// candidate keyframes happens. After reconstruction, the variance of 3D points
|
||||||
// happens. After reconstruction variance of 3D points is calculating
|
// is calculated and, if the expected error estimation is too large, the keyframe
|
||||||
// and if expected error estimation is too large, keyframe candidate
|
// candidate is rejected.
|
||||||
// is rejecting.
|
|
||||||
//
|
//
|
||||||
// \param tracks contains all tracked correspondences between frames
|
// \param tracks contains all tracked correspondences between frames
|
||||||
// expected to be undistorted and normalized
|
// expected to be undistorted and normalized
|
||||||
// \param intrinsics is camera intrinsics
|
// \param intrinsics is camera intrinsics
|
||||||
// \param keyframes will contain all images number which are considered
|
// \param keyframes will contain all images number which are considered
|
||||||
// good to be used for reconstruction
|
// good to be used for reconstruction
|
||||||
void SelectKeyframesBasedOnGRICAndVariance(const Tracks &tracks,
|
//
|
||||||
CameraIntrinsics &intrinsics,
|
// TODO(sftrabbit): Use algorithm that finds images of high variance from
|
||||||
|
// multiple cameras.
|
||||||
|
void SelectKeyframesBasedOnGRICAndVariance(
|
||||||
|
const Tracks &tracks,
|
||||||
|
const std::vector<CameraIntrinsics> &intrinsics,
|
||||||
|
int camera,
|
||||||
|
vector<int> &keyframes);
|
||||||
|
|
||||||
|
void SelectKeyframesBasedOnGRICAndVariance(
|
||||||
|
const Tracks &tracks,
|
||||||
|
const std::vector<CameraIntrinsics> &intrinsics,
|
||||||
vector<int> &keyframes);
|
vector<int> &keyframes);
|
||||||
|
|
||||||
} // namespace libmv
|
} // namespace libmv
|
||||||
|
@@ -99,8 +99,11 @@ struct ModalReprojectionError {
|
|||||||
void ModalSolver(const Tracks &tracks,
|
void ModalSolver(const Tracks &tracks,
|
||||||
EuclideanReconstruction *reconstruction,
|
EuclideanReconstruction *reconstruction,
|
||||||
ProgressUpdateCallback *update_callback) {
|
ProgressUpdateCallback *update_callback) {
|
||||||
int max_image = tracks.MaxImage();
|
static const int kModalCamera = 0;
|
||||||
int max_track = tracks.MaxTrack();
|
Tracks camera_tracks(tracks.MarkersForCamera(kModalCamera));
|
||||||
|
|
||||||
|
int max_image = camera_tracks.MaxImage();
|
||||||
|
int max_track = camera_tracks.MaxTrack();
|
||||||
|
|
||||||
LG << "Max image: " << max_image;
|
LG << "Max image: " << max_image;
|
||||||
LG << "Max track: " << max_track;
|
LG << "Max track: " << max_track;
|
||||||
@@ -111,12 +114,12 @@ void ModalSolver(const Tracks &tracks,
|
|||||||
ceres::AngleAxisToQuaternion(&zero_rotation(0), &quaternion(0));
|
ceres::AngleAxisToQuaternion(&zero_rotation(0), &quaternion(0));
|
||||||
|
|
||||||
for (int image = 0; image <= max_image; ++image) {
|
for (int image = 0; image <= max_image; ++image) {
|
||||||
vector<Marker> all_markers = tracks.MarkersInImage(image);
|
vector<Marker> image_markers = camera_tracks.MarkersInImage(image);
|
||||||
|
|
||||||
ModalSolverLogProress(update_callback, (float) image / max_image);
|
ModalSolverLogProress(update_callback, (float) image / max_image);
|
||||||
|
|
||||||
// Skip empty images without doing anything.
|
// Skip empty images without doing anything.
|
||||||
if (all_markers.size() == 0) {
|
if (image_markers.size() == 0) {
|
||||||
LG << "Skipping image: " << image;
|
LG << "Skipping image: " << image;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -124,13 +127,12 @@ void ModalSolver(const Tracks &tracks,
|
|||||||
// STEP 1: Estimate rotation analytically.
|
// STEP 1: Estimate rotation analytically.
|
||||||
Mat3 current_R;
|
Mat3 current_R;
|
||||||
ceres::QuaternionToRotation(&quaternion(0), ¤t_R(0, 0));
|
ceres::QuaternionToRotation(&quaternion(0), ¤t_R(0, 0));
|
||||||
|
|
||||||
// Construct point cloud for current and previous images,
|
// Construct point cloud for current and previous images,
|
||||||
// using markers appear at current image for which we know
|
// using markers appear at current image for which we know
|
||||||
// 3D positions.
|
// 3D positions.
|
||||||
Mat x1, x2;
|
Mat x1, x2;
|
||||||
for (int i = 0; i < all_markers.size(); ++i) {
|
for (int i = 0; i < image_markers.size(); ++i) {
|
||||||
Marker &marker = all_markers[i];
|
Marker &marker = image_markers[i];
|
||||||
EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
|
EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
|
||||||
if (point) {
|
if (point) {
|
||||||
Vec3 X;
|
Vec3 X;
|
||||||
@@ -176,8 +178,8 @@ void ModalSolver(const Tracks &tracks,
|
|||||||
new ceres::QuaternionParameterization;
|
new ceres::QuaternionParameterization;
|
||||||
|
|
||||||
int num_residuals = 0;
|
int num_residuals = 0;
|
||||||
for (int i = 0; i < all_markers.size(); ++i) {
|
for (int i = 0; i < image_markers.size(); ++i) {
|
||||||
Marker &marker = all_markers[i];
|
Marker &marker = image_markers[i];
|
||||||
EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
|
EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
|
||||||
|
|
||||||
if (point) {
|
if (point) {
|
||||||
@@ -218,7 +220,7 @@ void ModalSolver(const Tracks &tracks,
|
|||||||
// Convert quaternion to rotation matrix.
|
// Convert quaternion to rotation matrix.
|
||||||
Mat3 R;
|
Mat3 R;
|
||||||
ceres::QuaternionToRotation(&quaternion(0), &R(0, 0));
|
ceres::QuaternionToRotation(&quaternion(0), &R(0, 0));
|
||||||
reconstruction->InsertCamera(image, R, Vec3::Zero());
|
reconstruction->InsertView(image, R, Vec3::Zero(), kModalCamera);
|
||||||
|
|
||||||
// STEP 3: reproject all new markers appeared at image
|
// STEP 3: reproject all new markers appeared at image
|
||||||
|
|
||||||
@@ -226,7 +228,7 @@ void ModalSolver(const Tracks &tracks,
|
|||||||
// and reproject them on sphere to obtain 3D position/
|
// and reproject them on sphere to obtain 3D position/
|
||||||
for (int track = 0; track <= max_track; ++track) {
|
for (int track = 0; track <= max_track; ++track) {
|
||||||
if (!reconstruction->PointForTrack(track)) {
|
if (!reconstruction->PointForTrack(track)) {
|
||||||
Marker marker = tracks.MarkerInImageForTrack(image, track);
|
Marker marker = camera_tracks.MarkerInImageForTrack(image, track);
|
||||||
|
|
||||||
if (marker.image == image) {
|
if (marker.image == image) {
|
||||||
// New track appeared on this image,
|
// New track appeared on this image,
|
||||||
|
@@ -29,15 +29,16 @@ namespace libmv {
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
This solver solves such camera motion as tripod rotation, reconstructing
|
This solver solves such camera motion as tripod rotation, reconstructing
|
||||||
only camera motion itself. Bundles are not reconstructing properly, they're
|
only camera motion itself. Bundles are not reconstructing properly; they're
|
||||||
just getting projected onto sphere.
|
projected onto sphere.
|
||||||
|
|
||||||
Markers from tracks object would be used for recosntruction, and algorithm
|
Markers from tracks object are used for reconstruction. The algorithm
|
||||||
assumes thir's positions are undistorted already and they're in nnormalized
|
assumes their positions are undistorted already and that they're in
|
||||||
space.
|
normalized space.
|
||||||
|
|
||||||
Reconstructed cameras and projected bundles would be added to reconstruction
|
Reconstructed cameras and projected bundles are added to the given
|
||||||
object.
|
reconstruction object. Only camera 0 is reconstructed, using only the
|
||||||
|
markers associated with camera 0.
|
||||||
*/
|
*/
|
||||||
void ModalSolver(const Tracks &tracks,
|
void ModalSolver(const Tracks &tracks,
|
||||||
EuclideanReconstruction *reconstruction,
|
EuclideanReconstruction *reconstruction,
|
||||||
|
39
extern/libmv/libmv/simple_pipeline/pipeline.cc
vendored
39
extern/libmv/libmv/simple_pipeline/pipeline.cc
vendored
@@ -43,7 +43,7 @@ namespace {
|
|||||||
// template bloat and making interface changes much easier.
|
// template bloat and making interface changes much easier.
|
||||||
struct EuclideanPipelineRoutines {
|
struct EuclideanPipelineRoutines {
|
||||||
typedef EuclideanReconstruction Reconstruction;
|
typedef EuclideanReconstruction Reconstruction;
|
||||||
typedef EuclideanCamera Camera;
|
typedef EuclideanView View;
|
||||||
typedef EuclideanPoint Point;
|
typedef EuclideanPoint Point;
|
||||||
|
|
||||||
static void Bundle(const Tracks &tracks,
|
static void Bundle(const Tracks &tracks,
|
||||||
@@ -63,9 +63,9 @@ struct EuclideanPipelineRoutines {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Marker ProjectMarker(const EuclideanPoint &point,
|
static Marker ProjectMarker(const EuclideanPoint &point,
|
||||||
const EuclideanCamera &camera,
|
const EuclideanView &view,
|
||||||
const CameraIntrinsics &intrinsics) {
|
const CameraIntrinsics &intrinsics) {
|
||||||
Vec3 projected = camera.R * point.X + camera.t;
|
Vec3 projected = view.R * point.X + view.t;
|
||||||
projected /= projected(2);
|
projected /= projected(2);
|
||||||
|
|
||||||
Marker reprojected_marker;
|
Marker reprojected_marker;
|
||||||
@@ -74,7 +74,7 @@ struct EuclideanPipelineRoutines {
|
|||||||
&reprojected_marker.x,
|
&reprojected_marker.x,
|
||||||
&reprojected_marker.y);
|
&reprojected_marker.y);
|
||||||
|
|
||||||
reprojected_marker.image = camera.image;
|
reprojected_marker.image = view.image;
|
||||||
reprojected_marker.track = point.track;
|
reprojected_marker.track = point.track;
|
||||||
return reprojected_marker;
|
return reprojected_marker;
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ struct EuclideanPipelineRoutines {
|
|||||||
|
|
||||||
struct ProjectivePipelineRoutines {
|
struct ProjectivePipelineRoutines {
|
||||||
typedef ProjectiveReconstruction Reconstruction;
|
typedef ProjectiveReconstruction Reconstruction;
|
||||||
typedef ProjectiveCamera Camera;
|
typedef ProjectiveView View;
|
||||||
typedef ProjectivePoint Point;
|
typedef ProjectivePoint Point;
|
||||||
|
|
||||||
static void Bundle(const Tracks &tracks,
|
static void Bundle(const Tracks &tracks,
|
||||||
@@ -105,9 +105,9 @@ struct ProjectivePipelineRoutines {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Marker ProjectMarker(const ProjectivePoint &point,
|
static Marker ProjectMarker(const ProjectivePoint &point,
|
||||||
const ProjectiveCamera &camera,
|
const ProjectiveView &view,
|
||||||
const CameraIntrinsics &intrinsics) {
|
const CameraIntrinsics &intrinsics) {
|
||||||
Vec3 projected = camera.P * point.X;
|
Vec3 projected = view.P * point.X;
|
||||||
projected /= projected(2);
|
projected /= projected(2);
|
||||||
|
|
||||||
Marker reprojected_marker;
|
Marker reprojected_marker;
|
||||||
@@ -116,7 +116,7 @@ struct ProjectivePipelineRoutines {
|
|||||||
&reprojected_marker.x,
|
&reprojected_marker.x,
|
||||||
&reprojected_marker.y);
|
&reprojected_marker.y);
|
||||||
|
|
||||||
reprojected_marker.image = camera.image;
|
reprojected_marker.image = view.image;
|
||||||
reprojected_marker.track = point.track;
|
reprojected_marker.track = point.track;
|
||||||
return reprojected_marker;
|
return reprojected_marker;
|
||||||
}
|
}
|
||||||
@@ -169,7 +169,7 @@ void InternalCompleteReconstruction(
|
|||||||
|
|
||||||
vector<Marker> reconstructed_markers;
|
vector<Marker> reconstructed_markers;
|
||||||
for (int i = 0; i < all_markers.size(); ++i) {
|
for (int i = 0; i < all_markers.size(); ++i) {
|
||||||
if (reconstruction->CameraForImage(all_markers[i].image)) {
|
if (reconstruction->ViewForImage(all_markers[i].image)) {
|
||||||
reconstructed_markers.push_back(all_markers[i]);
|
reconstructed_markers.push_back(all_markers[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,7 +199,7 @@ void InternalCompleteReconstruction(
|
|||||||
// Do all possible resections.
|
// Do all possible resections.
|
||||||
num_resects = 0;
|
num_resects = 0;
|
||||||
for (int image = 0; image <= max_image; ++image) {
|
for (int image = 0; image <= max_image; ++image) {
|
||||||
if (reconstruction->CameraForImage(image)) {
|
if (reconstruction->ViewForImage(image)) {
|
||||||
LG << "Skipping frame: " << image;
|
LG << "Skipping frame: " << image;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -239,7 +239,7 @@ void InternalCompleteReconstruction(
|
|||||||
// One last pass...
|
// One last pass...
|
||||||
num_resects = 0;
|
num_resects = 0;
|
||||||
for (int image = 0; image <= max_image; ++image) {
|
for (int image = 0; image <= max_image; ++image) {
|
||||||
if (reconstruction->CameraForImage(image)) {
|
if (reconstruction->ViewForImage(image)) {
|
||||||
LG << "Skipping frame: " << image;
|
LG << "Skipping frame: " << image;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -275,24 +275,24 @@ template<typename PipelineRoutines>
|
|||||||
double InternalReprojectionError(
|
double InternalReprojectionError(
|
||||||
const Tracks &image_tracks,
|
const Tracks &image_tracks,
|
||||||
const typename PipelineRoutines::Reconstruction &reconstruction,
|
const typename PipelineRoutines::Reconstruction &reconstruction,
|
||||||
const CameraIntrinsics &intrinsics) {
|
const std::vector<CameraIntrinsics> &intrinsics) {
|
||||||
int num_skipped = 0;
|
int num_skipped = 0;
|
||||||
int num_reprojected = 0;
|
int num_reprojected = 0;
|
||||||
double total_error = 0.0;
|
double total_error = 0.0;
|
||||||
vector<Marker> markers = image_tracks.AllMarkers();
|
vector<Marker> markers = image_tracks.AllMarkers();
|
||||||
for (int i = 0; i < markers.size(); ++i) {
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
const typename PipelineRoutines::Camera *camera =
|
const typename PipelineRoutines::View *view =
|
||||||
reconstruction.CameraForImage(markers[i].image);
|
reconstruction.ViewForImage(markers[i].image);
|
||||||
const typename PipelineRoutines::Point *point =
|
const typename PipelineRoutines::Point *point =
|
||||||
reconstruction.PointForTrack(markers[i].track);
|
reconstruction.PointForTrack(markers[i].track);
|
||||||
if (!camera || !point) {
|
if (!view || !point) {
|
||||||
num_skipped++;
|
num_skipped++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
num_reprojected++;
|
num_reprojected++;
|
||||||
|
|
||||||
Marker reprojected_marker =
|
Marker reprojected_marker =
|
||||||
PipelineRoutines::ProjectMarker(*point, *camera, intrinsics);
|
PipelineRoutines::ProjectMarker(*point, *view, intrinsics[markers[i].camera]);
|
||||||
double ex = reprojected_marker.x - markers[i].x;
|
double ex = reprojected_marker.x - markers[i].x;
|
||||||
double ey = reprojected_marker.y - markers[i].y;
|
double ey = reprojected_marker.y - markers[i].y;
|
||||||
|
|
||||||
@@ -326,16 +326,15 @@ double InternalReprojectionError(
|
|||||||
|
|
||||||
double EuclideanReprojectionError(const Tracks &image_tracks,
|
double EuclideanReprojectionError(const Tracks &image_tracks,
|
||||||
const EuclideanReconstruction &reconstruction,
|
const EuclideanReconstruction &reconstruction,
|
||||||
const CameraIntrinsics &intrinsics) {
|
const std::vector<CameraIntrinsics> &intrinsics) {
|
||||||
return InternalReprojectionError<EuclideanPipelineRoutines>(image_tracks,
|
return InternalReprojectionError<EuclideanPipelineRoutines>(image_tracks,
|
||||||
reconstruction,
|
reconstruction,
|
||||||
intrinsics);
|
intrinsics);
|
||||||
}
|
}
|
||||||
|
|
||||||
double ProjectiveReprojectionError(
|
double ProjectiveReprojectionError(const Tracks &image_tracks,
|
||||||
const Tracks &image_tracks,
|
|
||||||
const ProjectiveReconstruction &reconstruction,
|
const ProjectiveReconstruction &reconstruction,
|
||||||
const CameraIntrinsics &intrinsics) {
|
const std::vector<CameraIntrinsics> &intrinsics) {
|
||||||
return InternalReprojectionError<ProjectivePipelineRoutines>(image_tracks,
|
return InternalReprojectionError<ProjectivePipelineRoutines>(image_tracks,
|
||||||
reconstruction,
|
reconstruction,
|
||||||
intrinsics);
|
intrinsics);
|
||||||
|
@@ -21,6 +21,8 @@
|
|||||||
#ifndef LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
|
#ifndef LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
|
||||||
#define LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
|
#define LIBMV_SIMPLE_PIPELINE_PIPELINE_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "libmv/simple_pipeline/callbacks.h"
|
#include "libmv/simple_pipeline/callbacks.h"
|
||||||
#include "libmv/simple_pipeline/tracks.h"
|
#include "libmv/simple_pipeline/tracks.h"
|
||||||
#include "libmv/simple_pipeline/reconstruction.h"
|
#include "libmv/simple_pipeline/reconstruction.h"
|
||||||
@@ -90,12 +92,11 @@ class CameraIntrinsics;
|
|||||||
|
|
||||||
double EuclideanReprojectionError(const Tracks &image_tracks,
|
double EuclideanReprojectionError(const Tracks &image_tracks,
|
||||||
const EuclideanReconstruction &reconstruction,
|
const EuclideanReconstruction &reconstruction,
|
||||||
const CameraIntrinsics &intrinsics);
|
const std::vector<CameraIntrinsics> &intrinsics);
|
||||||
|
|
||||||
double ProjectiveReprojectionError(
|
double ProjectiveReprojectionError(const Tracks &image_tracks,
|
||||||
const Tracks &image_tracks,
|
|
||||||
const ProjectiveReconstruction &reconstruction,
|
const ProjectiveReconstruction &reconstruction,
|
||||||
const CameraIntrinsics &intrinsics);
|
const std::vector<CameraIntrinsics> &intrinsics);
|
||||||
|
|
||||||
void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
|
void InvertIntrinsicsForTracks(const Tracks &raw_tracks,
|
||||||
const CameraIntrinsics &camera_intrinsics,
|
const CameraIntrinsics &camera_intrinsics,
|
||||||
|
123
extern/libmv/libmv/simple_pipeline/reconstruction.cc
vendored
123
extern/libmv/libmv/simple_pipeline/reconstruction.cc
vendored
@@ -18,6 +18,8 @@
|
|||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "libmv/simple_pipeline/reconstruction.h"
|
#include "libmv/simple_pipeline/reconstruction.h"
|
||||||
#include "libmv/numeric/numeric.h"
|
#include "libmv/numeric/numeric.h"
|
||||||
#include "libmv/logging/logging.h"
|
#include "libmv/logging/logging.h"
|
||||||
@@ -27,29 +29,32 @@ namespace libmv {
|
|||||||
EuclideanReconstruction::EuclideanReconstruction() {}
|
EuclideanReconstruction::EuclideanReconstruction() {}
|
||||||
EuclideanReconstruction::EuclideanReconstruction(
|
EuclideanReconstruction::EuclideanReconstruction(
|
||||||
const EuclideanReconstruction &other) {
|
const EuclideanReconstruction &other) {
|
||||||
cameras_ = other.cameras_;
|
views_ = other.views_;
|
||||||
points_ = other.points_;
|
points_ = other.points_;
|
||||||
}
|
}
|
||||||
|
|
||||||
EuclideanReconstruction &EuclideanReconstruction::operator=(
|
EuclideanReconstruction &EuclideanReconstruction::operator=(
|
||||||
const EuclideanReconstruction &other) {
|
const EuclideanReconstruction &other) {
|
||||||
if (&other != this) {
|
if (&other != this) {
|
||||||
cameras_ = other.cameras_;
|
views_ = other.views_;
|
||||||
points_ = other.points_;
|
points_ = other.points_;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EuclideanReconstruction::InsertCamera(int image,
|
void EuclideanReconstruction::InsertView(int image,
|
||||||
const Mat3 &R,
|
const Mat3 &R,
|
||||||
const Vec3 &t) {
|
const Vec3 &t,
|
||||||
LG << "InsertCamera " << image << ":\nR:\n"<< R << "\nt:\n" << t;
|
int camera) {
|
||||||
if (image >= cameras_.size()) {
|
LG << "InsertView camera " << camera << ", image " << image
|
||||||
cameras_.resize(image + 1);
|
<< ":\nR:\n"<< R << "\nt:\n" << t;
|
||||||
|
if (image >= views_.size()) {
|
||||||
|
views_.resize(image + 1);
|
||||||
}
|
}
|
||||||
cameras_[image].image = image;
|
views_[image].image = image;
|
||||||
cameras_[image].R = R;
|
views_[image].R = R;
|
||||||
cameras_[image].t = t;
|
views_[image].t = t;
|
||||||
|
views_[image].camera = camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) {
|
void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) {
|
||||||
@@ -61,32 +66,43 @@ void EuclideanReconstruction::InsertPoint(int track, const Vec3 &X) {
|
|||||||
points_[track].X = X;
|
points_[track].X = X;
|
||||||
}
|
}
|
||||||
|
|
||||||
EuclideanCamera *EuclideanReconstruction::CameraForImage(int image) {
|
EuclideanView *EuclideanReconstruction::ViewForImage(int image) {
|
||||||
return const_cast<EuclideanCamera *>(
|
return const_cast<EuclideanView *>(
|
||||||
static_cast<const EuclideanReconstruction *>(
|
static_cast<const EuclideanReconstruction *>(
|
||||||
this)->CameraForImage(image));
|
this)->ViewForImage(image));
|
||||||
}
|
}
|
||||||
|
|
||||||
const EuclideanCamera *EuclideanReconstruction::CameraForImage(
|
const EuclideanView *EuclideanReconstruction::ViewForImage(int image) const {
|
||||||
int image) const {
|
if (image < 0 || image >= views_.size()) {
|
||||||
if (image < 0 || image >= cameras_.size()) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
const EuclideanCamera *camera = &cameras_[image];
|
const EuclideanView *view = &views_[image];
|
||||||
if (camera->image == -1) {
|
if (view->camera == -1 || view->image == -1) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return camera;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<EuclideanCamera> EuclideanReconstruction::AllCameras() const {
|
vector<EuclideanView> EuclideanReconstruction::AllViews(
|
||||||
vector<EuclideanCamera> cameras;
|
) const {
|
||||||
for (int i = 0; i < cameras_.size(); ++i) {
|
vector<EuclideanView> views;
|
||||||
if (cameras_[i].image != -1) {
|
for (int i = 0; i < views_.size(); ++i) {
|
||||||
cameras.push_back(cameras_[i]);
|
if (views_[i].camera != -1 && views_[i].image != -1) {
|
||||||
|
views.push_back(views_[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cameras;
|
return views;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<EuclideanView> EuclideanReconstruction::AllViewsForCamera(
|
||||||
|
int camera) const {
|
||||||
|
vector<EuclideanView> views;
|
||||||
|
for (int i = 0; i < views_.size(); ++i) {
|
||||||
|
if (views_[i].image != -1 && views_[i].camera == camera) {
|
||||||
|
views.push_back(views_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return views;
|
||||||
}
|
}
|
||||||
|
|
||||||
EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) {
|
EuclideanPoint *EuclideanReconstruction::PointForTrack(int track) {
|
||||||
@@ -115,14 +131,17 @@ vector<EuclideanPoint> EuclideanReconstruction::AllPoints() const {
|
|||||||
return points;
|
return points;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectiveReconstruction::InsertCamera(int image,
|
void ProjectiveReconstruction::InsertView(int image,
|
||||||
const Mat34 &P) {
|
const Mat34 &P,
|
||||||
LG << "InsertCamera " << image << ":\nP:\n"<< P;
|
int camera) {
|
||||||
if (image >= cameras_.size()) {
|
LG << "InsertView camera " << camera << ", image " << image
|
||||||
cameras_.resize(image + 1);
|
<< ":\nP:\n"<< P;
|
||||||
|
if (image >= views_.size()) {
|
||||||
|
views_.resize(image + 1);
|
||||||
}
|
}
|
||||||
cameras_[image].image = image;
|
views_[image].image = image;
|
||||||
cameras_[image].P = P;
|
views_[image].P = P;
|
||||||
|
views_[image].camera = camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) {
|
void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) {
|
||||||
@@ -134,32 +153,42 @@ void ProjectiveReconstruction::InsertPoint(int track, const Vec4 &X) {
|
|||||||
points_[track].X = X;
|
points_[track].X = X;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectiveCamera *ProjectiveReconstruction::CameraForImage(int image) {
|
ProjectiveView *ProjectiveReconstruction::ViewForImage(int image) {
|
||||||
return const_cast<ProjectiveCamera *>(
|
return const_cast<ProjectiveView *>(
|
||||||
static_cast<const ProjectiveReconstruction *>(
|
static_cast<const ProjectiveReconstruction *>(
|
||||||
this)->CameraForImage(image));
|
this)->ViewForImage(image));
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProjectiveCamera *ProjectiveReconstruction::CameraForImage(
|
const ProjectiveView *ProjectiveReconstruction::ViewForImage(int image) const {
|
||||||
int image) const {
|
if (image < 0 || image >= views_.size()) {
|
||||||
if (image < 0 || image >= cameras_.size()) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
const ProjectiveCamera *camera = &cameras_[image];
|
const ProjectiveView *view = &views_[image];
|
||||||
if (camera->image == -1) {
|
if (view->camera == -1 || view->image == -1) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return camera;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<ProjectiveCamera> ProjectiveReconstruction::AllCameras() const {
|
vector<ProjectiveView> ProjectiveReconstruction::AllViews() const {
|
||||||
vector<ProjectiveCamera> cameras;
|
vector<ProjectiveView> views;
|
||||||
for (int i = 0; i < cameras_.size(); ++i) {
|
for (int i = 0; i < views_.size(); ++i) {
|
||||||
if (cameras_[i].image != -1) {
|
if (views_[i].camera != 1 && views_[i].image != -1) {
|
||||||
cameras.push_back(cameras_[i]);
|
views.push_back(views_[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cameras;
|
return views;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<ProjectiveView> ProjectiveReconstruction::AllViewsForCamera(
|
||||||
|
int camera) const {
|
||||||
|
vector<ProjectiveView> views;
|
||||||
|
for (int i = 0; i < views_.size(); ++i) {
|
||||||
|
if (views_[i].image != -1 && views_[i].camera == camera) {
|
||||||
|
views.push_back(views_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return views;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) {
|
ProjectivePoint *ProjectiveReconstruction::PointForTrack(int track) {
|
||||||
|
118
extern/libmv/libmv/simple_pipeline/reconstruction.h
vendored
118
extern/libmv/libmv/simple_pipeline/reconstruction.h
vendored
@@ -21,6 +21,8 @@
|
|||||||
#ifndef LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
|
#ifndef LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
|
||||||
#define LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
|
#define LIBMV_SIMPLE_PIPELINE_RECONSTRUCTION_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "libmv/base/vector.h"
|
#include "libmv/base/vector.h"
|
||||||
#include "libmv/numeric/numeric.h"
|
#include "libmv/numeric/numeric.h"
|
||||||
|
|
||||||
@@ -38,21 +40,28 @@ struct ReconstructionOptions {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
A EuclideanCamera is the location and rotation of the camera viewing \a image.
|
A EuclideanView is the location and orientation of a camera viewing an
|
||||||
|
\a image. A EuclideanView may be associated with a particular \a camera for
|
||||||
|
a multicamera reconstruction. All EuclideanViews for the same \a camera
|
||||||
|
represent the motion of a particular video camera across all of its
|
||||||
|
corresponding images.
|
||||||
|
|
||||||
\a image identify which image from \l Tracks this camera represents.
|
\a image identify which image from \l Tracks this view represents.
|
||||||
\a R is a 3x3 matrix representing the rotation of the camera.
|
\a R is a 3x3 matrix representing the rotation of the view.
|
||||||
\a t is a translation vector representing its positions.
|
\a t is a translation vector representing its positions.
|
||||||
|
\a camera identify which camera from \l Tracks this view is associated with.
|
||||||
|
|
||||||
\sa Reconstruction
|
\sa Reconstruction
|
||||||
*/
|
*/
|
||||||
struct EuclideanCamera {
|
struct EuclideanView {
|
||||||
EuclideanCamera() : image(-1) {}
|
EuclideanView() : image(-1), camera(0) {}
|
||||||
EuclideanCamera(const EuclideanCamera &c) : image(c.image), R(c.R), t(c.t) {}
|
EuclideanView(const EuclideanView &v)
|
||||||
|
: image(v.image), R(v.R), t(v.t), camera(v.camera) {}
|
||||||
|
|
||||||
int image;
|
int image;
|
||||||
Mat3 R;
|
Mat3 R;
|
||||||
Vec3 t;
|
Vec3 t;
|
||||||
|
int camera;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -71,16 +80,16 @@ struct EuclideanPoint {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
The EuclideanReconstruction class stores \link EuclideanCamera cameras
|
The EuclideanReconstruction class stores \link EuclideanView views
|
||||||
\endlink and \link EuclideanPoint points \endlink.
|
\endlink and \link EuclideanPoint points \endlink.
|
||||||
|
|
||||||
The EuclideanReconstruction container is intended as the store of 3D
|
The EuclideanReconstruction container is intended as the store of 3D
|
||||||
reconstruction data to be used with the MultiView API.
|
reconstruction data to be used with the MultiView API.
|
||||||
|
|
||||||
The container has lookups to query a \a EuclideanCamera from an \a image or
|
The container has lookups to query a \a EuclideanView for an \a image, or a
|
||||||
a \a EuclideanPoint from a \a track.
|
\a EuclideanPoint from a \a track.
|
||||||
|
|
||||||
\sa Camera, Point
|
\sa View, Point
|
||||||
*/
|
*/
|
||||||
class EuclideanReconstruction {
|
class EuclideanReconstruction {
|
||||||
public:
|
public:
|
||||||
@@ -93,16 +102,20 @@ class EuclideanReconstruction {
|
|||||||
EuclideanReconstruction &operator=(const EuclideanReconstruction &other);
|
EuclideanReconstruction &operator=(const EuclideanReconstruction &other);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Insert a camera into the set. If there is already a camera for the given
|
Insert a view into the set. If there is already a view for the given
|
||||||
\a image, the existing camera is replaced. If there is no camera for the
|
\a image, the existing view is replaced. If there is no view for the given
|
||||||
given \a image, a new one is added.
|
\a image, a new one is added. A view may be associated with a \a camera
|
||||||
|
in a multicamera reconstruction.
|
||||||
|
|
||||||
\a image is the key used to retrieve the cameras with the other methods
|
\a image and \a camera are the keys used to retrieve the views with the
|
||||||
in this class.
|
other methods in this class.
|
||||||
|
|
||||||
\note You should use the same \a image identifier as in \l Tracks.
|
\note You should use the same \a camera and \a image identifiers as in
|
||||||
|
\l Tracks.
|
||||||
|
\note All markers for a single \a image should have the same \a camera
|
||||||
|
identifiers.
|
||||||
*/
|
*/
|
||||||
void InsertCamera(int image, const Mat3 &R, const Vec3 &t);
|
void InsertView(int image, const Mat3 &R, const Vec3 &t, int camera = 0);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Insert a point into the reconstruction. If there is already a point for
|
Insert a point into the reconstruction. If there is already a point for
|
||||||
@@ -116,12 +129,15 @@ class EuclideanReconstruction {
|
|||||||
*/
|
*/
|
||||||
void InsertPoint(int track, const Vec3 &X);
|
void InsertPoint(int track, const Vec3 &X);
|
||||||
|
|
||||||
/// Returns a pointer to the camera corresponding to \a image.
|
/// Returns a pointer to the view corresponding to \a image.
|
||||||
EuclideanCamera *CameraForImage(int image);
|
EuclideanView *ViewForImage(int image);
|
||||||
const EuclideanCamera *CameraForImage(int image) const;
|
const EuclideanView *ViewForImage(int image) const;
|
||||||
|
|
||||||
/// Returns all cameras.
|
/// Returns all views for all images.
|
||||||
vector<EuclideanCamera> AllCameras() const;
|
vector<EuclideanView> AllViews() const;
|
||||||
|
|
||||||
|
/// Returns all views for a particular \a camera.
|
||||||
|
vector<EuclideanView> AllViewsForCamera(int camera) const;
|
||||||
|
|
||||||
/// Returns a pointer to the point corresponding to \a track.
|
/// Returns a pointer to the point corresponding to \a track.
|
||||||
EuclideanPoint *PointForTrack(int track);
|
EuclideanPoint *PointForTrack(int track);
|
||||||
@@ -131,24 +147,31 @@ class EuclideanReconstruction {
|
|||||||
vector<EuclideanPoint> AllPoints() const;
|
vector<EuclideanPoint> AllPoints() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector<EuclideanCamera> cameras_;
|
vector<EuclideanView> views_;
|
||||||
vector<EuclideanPoint> points_;
|
vector<EuclideanPoint> points_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
A ProjectiveCamera is the projection matrix for the camera of \a image.
|
A ProjectiveView is the projection matrix for the view of an \a image. A
|
||||||
|
ProjectiveView may be associated with a particular \a camera for a
|
||||||
|
multicamera reconstruction. All ProjectiveViews for the same \a camera
|
||||||
|
represent the motion of a particular video camera across all of its
|
||||||
|
corresponding images.
|
||||||
|
|
||||||
\a image identify which image from \l Tracks this camera represents.
|
\a image identify which image from \l Tracks this view represents.
|
||||||
\a P is the 3x4 projection matrix.
|
\a P is the 3x4 projection matrix.
|
||||||
|
\a camera identify which camera from \l Tracks this view is associated with.
|
||||||
|
|
||||||
\sa ProjectiveReconstruction
|
\sa ProjectiveReconstruction
|
||||||
*/
|
*/
|
||||||
struct ProjectiveCamera {
|
struct ProjectiveView {
|
||||||
ProjectiveCamera() : image(-1) {}
|
ProjectiveView() : image(-1), camera(0) {}
|
||||||
ProjectiveCamera(const ProjectiveCamera &c) : image(c.image), P(c.P) {}
|
ProjectiveView(const ProjectiveView &v)
|
||||||
|
: image(v.image), P(v.P), camera(v.camera) {}
|
||||||
|
|
||||||
int image;
|
int image;
|
||||||
Mat34 P;
|
Mat34 P;
|
||||||
|
int camera;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -167,30 +190,34 @@ struct ProjectivePoint {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
The ProjectiveReconstruction class stores \link ProjectiveCamera cameras
|
The ProjectiveReconstruction class stores \link ProjectiveView views
|
||||||
\endlink and \link ProjectivePoint points \endlink.
|
\endlink and \link ProjectivePoint points \endlink.
|
||||||
|
|
||||||
The ProjectiveReconstruction container is intended as the store of 3D
|
The ProjectiveReconstruction container is intended as the store of 3D
|
||||||
reconstruction data to be used with the MultiView API.
|
reconstruction data to be used with the MultiView API.
|
||||||
|
|
||||||
The container has lookups to query a \a ProjectiveCamera from an \a image or
|
The container has lookups to query a \a ProjectiveView for an \a image, or
|
||||||
a \a ProjectivePoint from a \a track.
|
a \a ProjectivePoint from a \a track.
|
||||||
|
|
||||||
\sa Camera, Point
|
\sa View, Point
|
||||||
*/
|
*/
|
||||||
class ProjectiveReconstruction {
|
class ProjectiveReconstruction {
|
||||||
public:
|
public:
|
||||||
/*!
|
/*!
|
||||||
Insert a camera into the set. If there is already a camera for the given
|
Insert a view into the set. If there is already a view for the given
|
||||||
\a image, the existing camera is replaced. If there is no camera for the
|
\a image, the existing view is replaced. If there is no view for the given
|
||||||
given \a image, a new one is added.
|
\a image, a new one is added. A view may be associated with a \a camera
|
||||||
|
in a multicamera reconstruction.
|
||||||
|
|
||||||
\a image is the key used to retrieve the cameras with the other methods
|
\a image and \a camera are the keys used to retrieve the views with the
|
||||||
in this class.
|
other methods in this class.
|
||||||
|
|
||||||
\note You should use the same \a image identifier as in \l Tracks.
|
\note You should use the same \a camera and \a image identifiers as in
|
||||||
|
\l Tracks.
|
||||||
|
\note All markers for a single \a image should have the same \a camera
|
||||||
|
identifiers.
|
||||||
*/
|
*/
|
||||||
void InsertCamera(int image, const Mat34 &P);
|
void InsertView(int image, const Mat34 &P, int camera = 0);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Insert a point into the reconstruction. If there is already a point for
|
Insert a point into the reconstruction. If there is already a point for
|
||||||
@@ -204,12 +231,15 @@ class ProjectiveReconstruction {
|
|||||||
*/
|
*/
|
||||||
void InsertPoint(int track, const Vec4 &X);
|
void InsertPoint(int track, const Vec4 &X);
|
||||||
|
|
||||||
/// Returns a pointer to the camera corresponding to \a image.
|
/// Returns a pointer to the view corresponding to \a image.
|
||||||
ProjectiveCamera *CameraForImage(int image);
|
ProjectiveView *ViewForImage(int image);
|
||||||
const ProjectiveCamera *CameraForImage(int image) const;
|
const ProjectiveView *ViewForImage(int image) const;
|
||||||
|
|
||||||
/// Returns all cameras.
|
/// Returns all views.
|
||||||
vector<ProjectiveCamera> AllCameras() const;
|
vector<ProjectiveView> AllViews() const;
|
||||||
|
|
||||||
|
/// Returns all views for a particular \a camera.
|
||||||
|
vector<ProjectiveView> AllViewsForCamera(int camera) const;
|
||||||
|
|
||||||
/// Returns a pointer to the point corresponding to \a track.
|
/// Returns a pointer to the point corresponding to \a track.
|
||||||
ProjectivePoint *PointForTrack(int track);
|
ProjectivePoint *PointForTrack(int track);
|
||||||
@@ -219,7 +249,7 @@ class ProjectiveReconstruction {
|
|||||||
vector<ProjectivePoint> AllPoints() const;
|
vector<ProjectivePoint> AllPoints() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector<ProjectiveCamera> cameras_;
|
vector<ProjectiveView> views_;
|
||||||
vector<ProjectivePoint> points_;
|
vector<ProjectivePoint> points_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -24,37 +24,37 @@
|
|||||||
namespace libmv {
|
namespace libmv {
|
||||||
|
|
||||||
void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction) {
|
void EuclideanScaleToUnity(EuclideanReconstruction *reconstruction) {
|
||||||
vector<EuclideanCamera> all_cameras = reconstruction->AllCameras();
|
vector<EuclideanView> all_views = reconstruction->AllViews();
|
||||||
vector<EuclideanPoint> all_points = reconstruction->AllPoints();
|
vector<EuclideanPoint> all_points = reconstruction->AllPoints();
|
||||||
|
|
||||||
// Calculate center of the mass of all cameras.
|
// Calculate center of the mass of all views.
|
||||||
Vec3 cameras_mass_center = Vec3::Zero();
|
Vec3 views_mass_center = Vec3::Zero();
|
||||||
for (int i = 0; i < all_cameras.size(); ++i) {
|
for (int i = 0; i < all_views.size(); ++i) {
|
||||||
cameras_mass_center += all_cameras[i].t;
|
views_mass_center += all_views[i].t;
|
||||||
}
|
}
|
||||||
cameras_mass_center /= all_cameras.size();
|
views_mass_center /= all_views.size();
|
||||||
|
|
||||||
// Find the most distant camera from the mass center.
|
// Find the most distant view from the mass center.
|
||||||
double max_distance = 0.0;
|
double max_distance = 0.0;
|
||||||
for (int i = 0; i < all_cameras.size(); ++i) {
|
for (int i = 0; i < all_views.size(); ++i) {
|
||||||
double distance = (all_cameras[i].t - cameras_mass_center).squaredNorm();
|
double distance = (all_views[i].t - views_mass_center).squaredNorm();
|
||||||
if (distance > max_distance) {
|
if (distance > max_distance) {
|
||||||
max_distance = distance;
|
max_distance = distance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_distance == 0.0) {
|
if (max_distance == 0.0) {
|
||||||
LG << "Cameras position variance is too small, can not rescale";
|
LG << "Views position variance is too small, can not rescale";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double scale_factor = 1.0 / sqrt(max_distance);
|
double scale_factor = 1.0 / sqrt(max_distance);
|
||||||
|
|
||||||
// Rescale cameras positions.
|
// Rescale views positions.
|
||||||
for (int i = 0; i < all_cameras.size(); ++i) {
|
for (int i = 0; i < all_views.size(); ++i) {
|
||||||
int image = all_cameras[i].image;
|
int image = all_views[i].image;
|
||||||
EuclideanCamera *camera = reconstruction->CameraForImage(image);
|
EuclideanView *view = reconstruction->ViewForImage(image);
|
||||||
camera->t = camera->t * scale_factor;
|
view->t = view->t * scale_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rescale points positions.
|
// Rescale points positions.
|
||||||
|
4
extern/libmv/libmv/simple_pipeline/resect.cc
vendored
4
extern/libmv/libmv/simple_pipeline/resect.cc
vendored
@@ -183,7 +183,7 @@ bool EuclideanResect(const ReconstructionOptions &options,
|
|||||||
|
|
||||||
LG << "Resection for image " << markers[0].image << " got:\n"
|
LG << "Resection for image " << markers[0].image << " got:\n"
|
||||||
<< "R:\n" << R << "\nt:\n" << t;
|
<< "R:\n" << R << "\nt:\n" << t;
|
||||||
reconstruction->InsertCamera(markers[0].image, R, t);
|
reconstruction->InsertView(markers[0].image, R, t, markers[0].camera);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ bool ProjectiveResect(const vector<Marker> &markers,
|
|||||||
|
|
||||||
LG << "Resection for image " << markers[0].image << " got:\n"
|
LG << "Resection for image " << markers[0].image << " got:\n"
|
||||||
<< "P:\n" << P;
|
<< "P:\n" << P;
|
||||||
reconstruction->InsertCamera(markers[0].image, P);
|
reconstruction->InsertView(markers[0].image, P, markers[0].camera);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // namespace libmv
|
} // namespace libmv
|
||||||
|
68
extern/libmv/libmv/simple_pipeline/tracks.cc
vendored
68
extern/libmv/libmv/simple_pipeline/tracks.cc
vendored
@@ -23,6 +23,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#include "libmv/numeric/numeric.h"
|
#include "libmv/numeric/numeric.h"
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ Tracks::Tracks(const Tracks &other) {
|
|||||||
|
|
||||||
Tracks::Tracks(const vector<Marker> &markers) : markers_(markers) {}
|
Tracks::Tracks(const vector<Marker> &markers) : markers_(markers) {}
|
||||||
|
|
||||||
void Tracks::Insert(int image, int track, double x, double y) {
|
void Tracks::Insert(int image, int track, double x, double y, int camera) {
|
||||||
// TODO(keir): Wow, this is quadratic for repeated insertions. Fix this by
|
// TODO(keir): Wow, this is quadratic for repeated insertions. Fix this by
|
||||||
// adding a smarter data structure like a set<>.
|
// adding a smarter data structure like a set<>.
|
||||||
for (int i = 0; i < markers_.size(); ++i) {
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
@@ -45,7 +46,7 @@ void Tracks::Insert(int image, int track, double x, double y) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Marker marker = { image, track, x, y };
|
Marker marker = { image, track, x, y, camera };
|
||||||
markers_.push_back(marker);
|
markers_.push_back(marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,13 +74,24 @@ vector<Marker> Tracks::MarkersForTrack(int track) const {
|
|||||||
return markers;
|
return markers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vector<Marker> Tracks::MarkersForCamera(int camera) const {
|
||||||
|
vector<Marker> markers;
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
if (camera == markers_[i].camera) {
|
||||||
|
markers.push_back(markers_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return markers;
|
||||||
|
}
|
||||||
|
|
||||||
vector<Marker> Tracks::MarkersInBothImages(int image1, int image2) const {
|
vector<Marker> Tracks::MarkersInBothImages(int image1, int image2) const {
|
||||||
vector<Marker> markers;
|
vector<Marker> markers;
|
||||||
for (int i = 0; i < markers_.size(); ++i) {
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
int image = markers_[i].image;
|
int image = markers_[i].image;
|
||||||
if (image == image1 || image == image2)
|
if (image == image1 || image == image2) {
|
||||||
markers.push_back(markers_[i]);
|
markers.push_back(markers_[i]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return markers;
|
return markers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,14 +130,25 @@ vector<Marker> Tracks::MarkersForTracksInBothImages(int image1,
|
|||||||
|
|
||||||
Marker Tracks::MarkerInImageForTrack(int image, int track) const {
|
Marker Tracks::MarkerInImageForTrack(int image, int track) const {
|
||||||
for (int i = 0; i < markers_.size(); ++i) {
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
if (markers_[i].image == image && markers_[i].track == track) {
|
if (markers_[i].image == image &&
|
||||||
|
markers_[i].track == track) {
|
||||||
return markers_[i];
|
return markers_[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Marker null = { -1, -1, -1, -1 };
|
Marker null = { -1, -1, -1, -1, -1 };
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Tracks::RemoveMarkersInImage(int image) {
|
||||||
|
int size = 0;
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
if (markers_[i].image != image) {
|
||||||
|
markers_[size++] = markers_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
markers_.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
void Tracks::RemoveMarkersForTrack(int track) {
|
void Tracks::RemoveMarkersForTrack(int track) {
|
||||||
int size = 0;
|
int size = 0;
|
||||||
for (int i = 0; i < markers_.size(); ++i) {
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
@@ -136,16 +159,36 @@ void Tracks::RemoveMarkersForTrack(int track) {
|
|||||||
markers_.resize(size);
|
markers_.resize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tracks::RemoveMarker(int image, int track) {
|
void Tracks::RemoveMarkersForCamera(int camera) {
|
||||||
int size = 0;
|
int size = 0;
|
||||||
for (int i = 0; i < markers_.size(); ++i) {
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
if (markers_[i].image != image || markers_[i].track != track) {
|
if (markers_[i].camera != camera) {
|
||||||
markers_[size++] = markers_[i];
|
markers_[size++] = markers_[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
markers_.resize(size);
|
markers_.resize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Tracks::RemoveMarker(int image, int track) {
|
||||||
|
int size = 0;
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
if (markers_[i].image != image ||
|
||||||
|
markers_[i].track != track) {
|
||||||
|
markers_[size++] = markers_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
markers_.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Tracks::CameraFromImage(int image) const {
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
if (markers_[i].image == image) {
|
||||||
|
return markers_[i].camera;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int Tracks::MaxImage() const {
|
int Tracks::MaxImage() const {
|
||||||
// TODO(MatthiasF): maintain a max_image_ member (updated on Insert)
|
// TODO(MatthiasF): maintain a max_image_ member (updated on Insert)
|
||||||
int max_image = 0;
|
int max_image = 0;
|
||||||
@@ -164,6 +207,15 @@ int Tracks::MaxTrack() const {
|
|||||||
return max_track;
|
return max_track;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Tracks::MaxCamera() const {
|
||||||
|
// TODO(MatthiasF): maintain a max_camera_ member (updated on Insert)
|
||||||
|
int max_camera = 0;
|
||||||
|
for (int i = 0; i < markers_.size(); ++i) {
|
||||||
|
max_camera = std::max(markers_[i].camera, max_camera);
|
||||||
|
}
|
||||||
|
return max_camera;
|
||||||
|
}
|
||||||
|
|
||||||
int Tracks::NumMarkers() const {
|
int Tracks::NumMarkers() const {
|
||||||
return markers_.size();
|
return markers_.size();
|
||||||
}
|
}
|
||||||
@@ -174,7 +226,7 @@ void CoordinatesForMarkersInImage(const vector<Marker> &markers,
|
|||||||
vector<Vec2> coords;
|
vector<Vec2> coords;
|
||||||
for (int i = 0; i < markers.size(); ++i) {
|
for (int i = 0; i < markers.size(); ++i) {
|
||||||
const Marker &marker = markers[i];
|
const Marker &marker = markers[i];
|
||||||
if (markers[i].image == image) {
|
if (marker.image == image) {
|
||||||
coords.push_back(Vec2(marker.x, marker.y));
|
coords.push_back(Vec2(marker.x, marker.y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
43
extern/libmv/libmv/simple_pipeline/tracks.h
vendored
43
extern/libmv/libmv/simple_pipeline/tracks.h
vendored
@@ -30,8 +30,11 @@ namespace libmv {
|
|||||||
A Marker is the 2D location of a tracked point in an image.
|
A Marker is the 2D location of a tracked point in an image.
|
||||||
|
|
||||||
\a x, \a y is the position of the marker in pixels from the top left corner
|
\a x, \a y is the position of the marker in pixels from the top left corner
|
||||||
in the image identified by \a image. All markers for to the same target
|
of the image identified by \a image. All markers for the same target form a
|
||||||
form a track identified by a common \a track number.
|
track identified by a common \a track number. All markers for a single
|
||||||
|
\a image can be associated with a particular camera identified by \a camera.
|
||||||
|
Markers for a particular track but with different \a camera numbers
|
||||||
|
correspond to the same target filmed from an alternate viewpoint.
|
||||||
|
|
||||||
\note Markers are typically aggregated with the help of the \l Tracks class.
|
\note Markers are typically aggregated with the help of the \l Tracks class.
|
||||||
|
|
||||||
@@ -41,6 +44,7 @@ struct Marker {
|
|||||||
int image;
|
int image;
|
||||||
int track;
|
int track;
|
||||||
double x, y;
|
double x, y;
|
||||||
|
int camera;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -67,29 +71,36 @@ class Tracks {
|
|||||||
/*!
|
/*!
|
||||||
Inserts a marker into the set. If there is already a marker for the given
|
Inserts a marker into the set. If there is already a marker for the given
|
||||||
\a image and \a track, the existing marker is replaced. If there is no
|
\a image and \a track, the existing marker is replaced. If there is no
|
||||||
marker for the given \a image and \a track, a new one is added.
|
marker for the given \a image and \a track, a new one is added. The marker
|
||||||
|
can be associated with a \a camera for use with multicamera reconsturction.
|
||||||
|
|
||||||
\a image and \a track are the keys used to retrieve the markers with the
|
\a camera, \a image and \a track are the keys used to retrieve the markers
|
||||||
other methods in this class.
|
with the other methods in this class.
|
||||||
|
|
||||||
\note To get an identifier for a new track, use \l MaxTrack() + 1.
|
\note To get an identifier for a new track, use \l MaxTrack() + 1.
|
||||||
|
\note All markers for a single \a image should belong to the same
|
||||||
|
\a camera.
|
||||||
*/
|
*/
|
||||||
void Insert(int image, int track, double x, double y);
|
void Insert(int image, int track, double x, double y, int camera = 0);
|
||||||
|
|
||||||
/// Returns all the markers.
|
/// Returns all the markers.
|
||||||
vector<Marker> AllMarkers() const;
|
vector<Marker> AllMarkers() const;
|
||||||
|
|
||||||
|
/// Returns all the markers visible in an \a image.
|
||||||
|
vector<Marker> MarkersInImage(int image) const;
|
||||||
|
|
||||||
/// Returns all the markers belonging to a track.
|
/// Returns all the markers belonging to a track.
|
||||||
vector<Marker> MarkersForTrack(int track) const;
|
vector<Marker> MarkersForTrack(int track) const;
|
||||||
|
|
||||||
/// Returns all the markers visible in \a image.
|
/// Returns all the markers visible from a \a camera.
|
||||||
vector<Marker> MarkersInImage(int image) const;
|
vector<Marker> MarkersForCamera(int camera) const;
|
||||||
|
|
||||||
/// Returns all the markers visible in \a image1 and \a image2.
|
/// Returns all the markers visible in \a image1 and \a image2.
|
||||||
vector<Marker> MarkersInBothImages(int image1, int image2) const;
|
vector<Marker> MarkersInBothImages(int image1, int image2) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns the markers in \a image1 and \a image2 which have a common track.
|
Returns the markers in \a image1 and \a image2 (both from \a camera) which
|
||||||
|
have a common track.
|
||||||
|
|
||||||
This is not the same as the union of the markers in \a image1 and \a
|
This is not the same as the union of the markers in \a image1 and \a
|
||||||
image2; each marker is for a track that appears in both images.
|
image2; each marker is for a track that appears in both images.
|
||||||
@@ -99,18 +110,30 @@ class Tracks {
|
|||||||
/// Returns the marker in \a image belonging to \a track.
|
/// Returns the marker in \a image belonging to \a track.
|
||||||
Marker MarkerInImageForTrack(int image, int track) const;
|
Marker MarkerInImageForTrack(int image, int track) const;
|
||||||
|
|
||||||
|
/// Removes all the markers belonging to \a image.
|
||||||
|
void RemoveMarkersInImage(int image);
|
||||||
|
|
||||||
/// Removes all the markers belonging to \a track.
|
/// Removes all the markers belonging to \a track.
|
||||||
void RemoveMarkersForTrack(int track);
|
void RemoveMarkersForTrack(int track);
|
||||||
|
|
||||||
/// Removes the marker in \a image belonging to \a track.
|
/// Removes all the markers belonging to \a camera.
|
||||||
|
void RemoveMarkersForCamera(int camera);
|
||||||
|
|
||||||
|
/// Removes the marker in \a image of \a camera belonging to \a track.
|
||||||
void RemoveMarker(int image, int track);
|
void RemoveMarker(int image, int track);
|
||||||
|
|
||||||
|
/// Returns the camera that \a image belongs to.
|
||||||
|
int CameraFromImage(int image) const;
|
||||||
|
|
||||||
/// Returns the maximum image identifier used.
|
/// Returns the maximum image identifier used.
|
||||||
int MaxImage() const;
|
int MaxImage() const;
|
||||||
|
|
||||||
/// Returns the maximum track identifier used.
|
/// Returns the maximum track identifier used.
|
||||||
int MaxTrack() const;
|
int MaxTrack() const;
|
||||||
|
|
||||||
|
/// Returns the maximum camera identifier used.
|
||||||
|
int MaxCamera() const;
|
||||||
|
|
||||||
/// Returns the number of markers.
|
/// Returns the number of markers.
|
||||||
int NumMarkers() const;
|
int NumMarkers() const;
|
||||||
|
|
||||||
|
Binary file not shown.
@@ -352,6 +352,19 @@ class CLIP_PT_tools_solve(CLIP_PT_tracking_panel, Panel):
|
|||||||
col.label(text="Refine:")
|
col.label(text="Refine:")
|
||||||
col.prop(settings, "refine_intrinsics", text="")
|
col.prop(settings, "refine_intrinsics", text="")
|
||||||
|
|
||||||
|
col = layout.column(align=True)
|
||||||
|
col.active = "FOCAL_LENGTH" in settings.refine_intrinsics
|
||||||
|
col.prop(settings, "use_focal_length_constraint");
|
||||||
|
sub = col.column(align=True)
|
||||||
|
sub.active = settings.use_focal_length_constraint
|
||||||
|
if tracking.camera.units == 'MILLIMETERS':
|
||||||
|
sub.prop(settings, "focal_length_min", text="Min")
|
||||||
|
sub.prop(settings, "focal_length_max", text="Max")
|
||||||
|
else:
|
||||||
|
sub.prop(settings, "focal_length_min_pixels", text="Min")
|
||||||
|
sub.prop(settings, "focal_length_max_pixels", text="Max")
|
||||||
|
|
||||||
|
|
||||||
col = layout.column(align=True)
|
col = layout.column(align=True)
|
||||||
col.active = not settings.use_tripod_solver
|
col.active = not settings.use_tripod_solver
|
||||||
col.prop(settings, "use_fallback_reconstruction",
|
col.prop(settings, "use_fallback_reconstruction",
|
||||||
@@ -943,6 +956,17 @@ class CLIP_PT_tools_clip(CLIP_PT_clip_view_panel, Panel):
|
|||||||
layout.operator("clip.set_scene_frames")
|
layout.operator("clip.set_scene_frames")
|
||||||
|
|
||||||
|
|
||||||
|
class CLIP_PT_multicamera_clip(CLIP_PT_clip_view_panel, Panel):
|
||||||
|
bl_space_type = 'CLIP_EDITOR'
|
||||||
|
bl_region_type = 'TOOLS'
|
||||||
|
bl_label = "Multicamera"
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
layout.operator("clip.create_correspondence")
|
||||||
|
|
||||||
|
|
||||||
class CLIP_MT_view(Menu):
|
class CLIP_MT_view(Menu):
|
||||||
bl_label = "View"
|
bl_label = "View"
|
||||||
|
|
||||||
|
@@ -160,6 +160,7 @@ struct MovieTrackingReconstruction *BKE_tracking_object_get_reconstruction(struc
|
|||||||
struct MovieTrackingObject *object);
|
struct MovieTrackingObject *object);
|
||||||
|
|
||||||
/* **** Camera **** */
|
/* **** Camera **** */
|
||||||
|
void BKE_tracking_camera_focal_length_set(struct MovieTracking *tracking, float value);
|
||||||
void BKE_tracking_camera_shift_get(struct MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty);
|
void BKE_tracking_camera_shift_get(struct MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty);
|
||||||
void BKE_tracking_camera_to_blender(struct MovieTracking *tracking, struct Scene *scene,
|
void BKE_tracking_camera_to_blender(struct MovieTracking *tracking, struct Scene *scene,
|
||||||
struct Camera *camera, int width, int height);
|
struct Camera *camera, int width, int height);
|
||||||
|
@@ -57,6 +57,8 @@
|
|||||||
#include "DNA_scene_types.h"
|
#include "DNA_scene_types.h"
|
||||||
#include "DNA_view3d_types.h"
|
#include "DNA_view3d_types.h"
|
||||||
|
|
||||||
|
#include "RNA_access.h"
|
||||||
|
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
#include "BLI_blenlib.h"
|
#include "BLI_blenlib.h"
|
||||||
@@ -657,10 +659,12 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
|
|||||||
detect_clip_source(clip);
|
detect_clip_source(clip);
|
||||||
|
|
||||||
movieclip_load_get_szie(clip);
|
movieclip_load_get_szie(clip);
|
||||||
|
|
||||||
if (clip->lastsize[0]) {
|
if (clip->lastsize[0]) {
|
||||||
int width = clip->lastsize[0];
|
int width = clip->lastsize[0];
|
||||||
|
|
||||||
clip->tracking.camera.focal = 24.0f * width / clip->tracking.camera.sensor_width;
|
float focal = 24.0f * width / clip->tracking.camera.sensor_width;
|
||||||
|
BKE_tracking_camera_focal_length_set(&clip->tracking, focal);
|
||||||
}
|
}
|
||||||
|
|
||||||
movieclip_calc_length(clip);
|
movieclip_calc_length(clip);
|
||||||
|
@@ -213,6 +213,8 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
|
|||||||
tracking->settings.dist = 1;
|
tracking->settings.dist = 1;
|
||||||
tracking->settings.object_distance = 1;
|
tracking->settings.object_distance = 1;
|
||||||
tracking->settings.reconstruction_success_threshold = 1e-3f;
|
tracking->settings.reconstruction_success_threshold = 1e-3f;
|
||||||
|
tracking->settings.focal_length_min = 0.0f;
|
||||||
|
tracking->settings.focal_length_max = 5000.0f;
|
||||||
|
|
||||||
tracking->stabilization.scaleinf = 1.0f;
|
tracking->stabilization.scaleinf = 1.0f;
|
||||||
tracking->stabilization.locinf = 1.0f;
|
tracking->stabilization.locinf = 1.0f;
|
||||||
@@ -1798,6 +1800,20 @@ static void reconstructed_camera_scale_set(MovieTrackingObject *object, float ma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BKE_tracking_camera_focal_length_set(MovieTracking *tracking, float value)
|
||||||
|
{
|
||||||
|
MovieTrackingSettings *settings = &tracking->settings;
|
||||||
|
MovieTrackingCamera *camera = &tracking->camera;
|
||||||
|
|
||||||
|
if (!(settings->refine_intrinsics & REFINE_FOCAL_LENGTH) ||
|
||||||
|
!(settings->constrain_intrinsics & CONSTRAIN_FOCAL_LENGTH))
|
||||||
|
{
|
||||||
|
settings->focal_length_min = value;
|
||||||
|
settings->focal_length_max = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
camera->focal = value;
|
||||||
|
}
|
||||||
|
|
||||||
/* converts principal offset from center to offset of blender's camera */
|
/* converts principal offset from center to offset of blender's camera */
|
||||||
void BKE_tracking_camera_shift_get(MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty)
|
void BKE_tracking_camera_shift_get(MovieTracking *tracking, int winx, int winy, float *shiftx, float *shifty)
|
||||||
@@ -3415,7 +3431,9 @@ typedef struct MovieReconstructContext {
|
|||||||
struct libmv_Tracks *tracks;
|
struct libmv_Tracks *tracks;
|
||||||
bool select_keyframes;
|
bool select_keyframes;
|
||||||
int keyframe1, keyframe2;
|
int keyframe1, keyframe2;
|
||||||
int refine_flags;
|
short refine_intrinsics;
|
||||||
|
short constrain_intrinsics;
|
||||||
|
float focal_length_min, focal_length_max;
|
||||||
|
|
||||||
struct libmv_Reconstruction *reconstruction;
|
struct libmv_Reconstruction *reconstruction;
|
||||||
|
|
||||||
@@ -3464,7 +3482,8 @@ static struct libmv_Tracks *libmv_tracks_new(ListBase *tracksbase, int width, in
|
|||||||
if ((marker->flag & MARKER_DISABLED) == 0) {
|
if ((marker->flag & MARKER_DISABLED) == 0) {
|
||||||
libmv_tracksInsert(tracks, marker->framenr, tracknr,
|
libmv_tracksInsert(tracks, marker->framenr, tracknr,
|
||||||
(marker->pos[0] + track->offset[0]) * width,
|
(marker->pos[0] + track->offset[0]) * width,
|
||||||
(marker->pos[1] + track->offset[1]) * height);
|
(marker->pos[1] + track->offset[1]) * height,
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3479,7 +3498,7 @@ static struct libmv_Tracks *libmv_tracks_new(ListBase *tracksbase, int width, in
|
|||||||
static void reconstruct_retrieve_libmv_intrinsics(MovieReconstructContext *context, MovieTracking *tracking)
|
static void reconstruct_retrieve_libmv_intrinsics(MovieReconstructContext *context, MovieTracking *tracking)
|
||||||
{
|
{
|
||||||
struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
|
struct libmv_Reconstruction *libmv_reconstruction = context->reconstruction;
|
||||||
struct libmv_CameraIntrinsics *libmv_intrinsics = libmv_reconstructionExtractIntrinsics(libmv_reconstruction);
|
struct libmv_CameraIntrinsics *libmv_intrinsics = libmv_reconstructionExtractIntrinsics(libmv_reconstruction, 0);
|
||||||
|
|
||||||
float aspy = 1.0f / tracking->camera.pixel_aspect;
|
float aspy = 1.0f / tracking->camera.pixel_aspect;
|
||||||
|
|
||||||
@@ -3634,27 +3653,38 @@ static int reconstruct_retrieve_libmv(MovieReconstructContext *context, MovieTra
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Convert blender's refinement flags to libmv's. */
|
/* Convert blender's refinement flags to libmv's. */
|
||||||
static int reconstruct_refine_intrinsics_get_flags(MovieTracking *tracking, MovieTrackingObject *object)
|
static void reconstruct_refine_intrinsics_get_flags(const MovieTracking *tracking,
|
||||||
|
const MovieTrackingObject *object,
|
||||||
|
MovieReconstructContext *context)
|
||||||
{
|
{
|
||||||
int refine = tracking->settings.refine_camera_intrinsics;
|
short refine = tracking->settings.refine_intrinsics;
|
||||||
int flags = 0;
|
short constrain = tracking->settings.constrain_intrinsics;
|
||||||
|
short libmv_refine = 0;
|
||||||
|
short libmv_constrain = 0;
|
||||||
|
|
||||||
if ((object->flag & TRACKING_OBJECT_CAMERA) == 0)
|
if ((object->flag & TRACKING_OBJECT_CAMERA) == 0) {
|
||||||
return 0;
|
context->refine_intrinsics = 0;
|
||||||
|
context->constrain_intrinsics = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (refine & REFINE_FOCAL_LENGTH)
|
if (refine & REFINE_FOCAL_LENGTH) {
|
||||||
flags |= LIBMV_REFINE_FOCAL_LENGTH;
|
libmv_refine |= LIBMV_REFINE_FOCAL_LENGTH;
|
||||||
|
if (constrain & CONSTRAIN_FOCAL_LENGTH)
|
||||||
|
libmv_constrain |= LIBMV_CONSTRAIN_FOCAL_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
if (refine & REFINE_PRINCIPAL_POINT)
|
if (refine & REFINE_PRINCIPAL_POINT)
|
||||||
flags |= LIBMV_REFINE_PRINCIPAL_POINT;
|
libmv_refine |= LIBMV_REFINE_PRINCIPAL_POINT;
|
||||||
|
|
||||||
if (refine & REFINE_RADIAL_DISTORTION_K1)
|
if (refine & REFINE_RADIAL_DISTORTION_K1)
|
||||||
flags |= LIBMV_REFINE_RADIAL_DISTORTION_K1;
|
libmv_refine |= LIBMV_REFINE_RADIAL_DISTORTION_K1;
|
||||||
|
|
||||||
if (refine & REFINE_RADIAL_DISTORTION_K2)
|
if (refine & REFINE_RADIAL_DISTORTION_K2)
|
||||||
flags |= LIBMV_REFINE_RADIAL_DISTORTION_K2;
|
libmv_refine |= LIBMV_REFINE_RADIAL_DISTORTION_K2;
|
||||||
|
|
||||||
return flags;
|
context->refine_intrinsics = libmv_refine;
|
||||||
|
context->constrain_intrinsics = libmv_constrain;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Count tracks which has markers at both of keyframes. */
|
/* Count tracks which has markers at both of keyframes. */
|
||||||
@@ -3780,7 +3810,10 @@ MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieTracking *
|
|||||||
context->tracks = libmv_tracks_new(tracksbase, width, height * aspy);
|
context->tracks = libmv_tracks_new(tracksbase, width, height * aspy);
|
||||||
context->keyframe1 = keyframe1;
|
context->keyframe1 = keyframe1;
|
||||||
context->keyframe2 = keyframe2;
|
context->keyframe2 = keyframe2;
|
||||||
context->refine_flags = reconstruct_refine_intrinsics_get_flags(tracking, object);
|
|
||||||
|
reconstruct_refine_intrinsics_get_flags(tracking, object, context);
|
||||||
|
context->focal_length_min = tracking->settings.focal_length_min;
|
||||||
|
context->focal_length_max = tracking->settings.focal_length_max;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
@@ -3811,10 +3844,12 @@ static void reconstruct_update_solve_cb(void *customdata, double progress, const
|
|||||||
BLI_snprintf(progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
|
BLI_snprintf(progressdata->stats_message, progressdata->message_size, "Solving camera | %s", message);
|
||||||
}
|
}
|
||||||
/* FIll in camera intrinsics structure from reconstruction context. */
|
/* FIll in camera intrinsics structure from reconstruction context. */
|
||||||
static void camraIntrincicsOptionsFromContext(libmv_CameraIntrinsicsOptions *camera_intrinsics_options,
|
static void cameraIntrinsicsOptionsFromContext(const MovieReconstructContext *context,
|
||||||
MovieReconstructContext *context)
|
libmv_CameraIntrinsicsOptions *camera_intrinsics_options)
|
||||||
{
|
{
|
||||||
camera_intrinsics_options->focal_length = context->focal_length;
|
camera_intrinsics_options->focal_length = context->focal_length;
|
||||||
|
CLAMP(camera_intrinsics_options->focal_length,
|
||||||
|
context->focal_length_min, context->focal_length_max);
|
||||||
|
|
||||||
camera_intrinsics_options->principal_point_x = context->principal_point[0];
|
camera_intrinsics_options->principal_point_x = context->principal_point[0];
|
||||||
camera_intrinsics_options->principal_point_y = context->principal_point[1];
|
camera_intrinsics_options->principal_point_y = context->principal_point[1];
|
||||||
@@ -3828,15 +3863,20 @@ static void camraIntrincicsOptionsFromContext(libmv_CameraIntrinsicsOptions *cam
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in reconstruction options structure from reconstruction context. */
|
/* Fill in reconstruction options structure from reconstruction context. */
|
||||||
static void reconstructionOptionsFromContext(libmv_ReconstructionOptions *reconstruction_options,
|
static void reconstructionOptionsFromContext(MovieReconstructContext *context,
|
||||||
MovieReconstructContext *context)
|
libmv_ReconstructionOptions *reconstruction_options)
|
||||||
{
|
{
|
||||||
reconstruction_options->select_keyframes = context->select_keyframes;
|
reconstruction_options->select_keyframes = context->select_keyframes;
|
||||||
|
|
||||||
reconstruction_options->keyframe1 = context->keyframe1;
|
reconstruction_options->keyframe1 = context->keyframe1;
|
||||||
reconstruction_options->keyframe2 = context->keyframe2;
|
reconstruction_options->keyframe2 = context->keyframe2;
|
||||||
|
|
||||||
reconstruction_options->refine_intrinsics = context->refine_flags;
|
reconstruction_options->motion_flag = context->motion_flag;
|
||||||
|
|
||||||
|
reconstruction_options->refine_intrinsics = context->refine_intrinsics;
|
||||||
|
reconstruction_options->constrain_intrinsics = context->constrain_intrinsics;
|
||||||
|
reconstruction_options->focal_length_min = context->focal_length_min;
|
||||||
|
reconstruction_options->focal_length_max = context->focal_length_max;
|
||||||
|
|
||||||
reconstruction_options->success_threshold = context->success_threshold;
|
reconstruction_options->success_threshold = context->success_threshold;
|
||||||
reconstruction_options->use_fallback_reconstruction = context->use_fallback_reconstruction;
|
reconstruction_options->use_fallback_reconstruction = context->use_fallback_reconstruction;
|
||||||
@@ -3867,27 +3907,21 @@ void BKE_tracking_reconstruction_solve(MovieReconstructContext *context, short *
|
|||||||
progressdata.stats_message = stats_message;
|
progressdata.stats_message = stats_message;
|
||||||
progressdata.message_size = message_size;
|
progressdata.message_size = message_size;
|
||||||
|
|
||||||
camraIntrincicsOptionsFromContext(&camera_intrinsics_options, context);
|
cameraIntrinsicsOptionsFromContext(context, &camera_intrinsics_options);
|
||||||
reconstructionOptionsFromContext(&reconstruction_options, context);
|
reconstructionOptionsFromContext(context, &reconstruction_options);
|
||||||
|
|
||||||
if (context->motion_flag & TRACKING_MOTION_MODAL) {
|
context->reconstruction = libmv_solve(context->tracks,
|
||||||
context->reconstruction = libmv_solveModal(context->tracks,
|
|
||||||
&camera_intrinsics_options,
|
&camera_intrinsics_options,
|
||||||
&reconstruction_options,
|
&reconstruction_options,
|
||||||
reconstruct_update_solve_cb, &progressdata);
|
reconstruct_update_solve_cb,
|
||||||
}
|
&progressdata);
|
||||||
else {
|
if ((context->motion_flag & TRACKING_MOTION_MODAL) &&
|
||||||
context->reconstruction = libmv_solveReconstruction(context->tracks,
|
context->select_keyframes)
|
||||||
&camera_intrinsics_options,
|
{
|
||||||
&reconstruction_options,
|
|
||||||
reconstruct_update_solve_cb, &progressdata);
|
|
||||||
|
|
||||||
if (context->select_keyframes) {
|
|
||||||
/* store actual keyframes used for reconstruction to update them in the interface later */
|
/* store actual keyframes used for reconstruction to update them in the interface later */
|
||||||
context->keyframe1 = reconstruction_options.keyframe1;
|
context->keyframe1 = reconstruction_options.keyframe1;
|
||||||
context->keyframe2 = reconstruction_options.keyframe2;
|
context->keyframe2 = reconstruction_options.keyframe2;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
error = libmv_reprojectionError(context->reconstruction);
|
error = libmv_reprojectionError(context->reconstruction);
|
||||||
|
|
||||||
|
@@ -201,6 +201,8 @@ void CLIP_OT_slide_plane_marker(struct wmOperatorType *ot);
|
|||||||
void CLIP_OT_keyframe_insert(struct wmOperatorType *ot);
|
void CLIP_OT_keyframe_insert(struct wmOperatorType *ot);
|
||||||
void CLIP_OT_keyframe_delete(struct wmOperatorType *ot);
|
void CLIP_OT_keyframe_delete(struct wmOperatorType *ot);
|
||||||
|
|
||||||
|
void CLIP_OT_create_correspondence(struct wmOperatorType *ot);
|
||||||
|
|
||||||
/* tracking_select.c */
|
/* tracking_select.c */
|
||||||
void CLIP_OT_select(struct wmOperatorType *ot);
|
void CLIP_OT_select(struct wmOperatorType *ot);
|
||||||
void CLIP_OT_select_all(struct wmOperatorType *ot);
|
void CLIP_OT_select_all(struct wmOperatorType *ot);
|
||||||
|
@@ -526,6 +526,9 @@ static void clip_operatortypes(void)
|
|||||||
WM_operatortype_append(CLIP_OT_keyframe_insert);
|
WM_operatortype_append(CLIP_OT_keyframe_insert);
|
||||||
WM_operatortype_append(CLIP_OT_keyframe_delete);
|
WM_operatortype_append(CLIP_OT_keyframe_delete);
|
||||||
|
|
||||||
|
/* Multicamera */
|
||||||
|
WM_operatortype_append(CLIP_OT_create_correspondence);
|
||||||
|
|
||||||
/* ** clip_graph_ops.c ** */
|
/* ** clip_graph_ops.c ** */
|
||||||
|
|
||||||
/* graph editing */
|
/* graph editing */
|
||||||
|
@@ -4188,3 +4188,20 @@ void CLIP_OT_keyframe_delete(wmOperatorType *ot)
|
|||||||
/* flags */
|
/* flags */
|
||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************** Multicamera operators ******************************/
|
||||||
|
|
||||||
|
void CLIP_OT_create_correspondence(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
/* identifiers */
|
||||||
|
ot->name = "Create correspondence";
|
||||||
|
ot->description = "Create a correspondence between selected tracks across multiple clips";
|
||||||
|
ot->idname = "CLIP_OT_create_correspondence";
|
||||||
|
|
||||||
|
/* api callbacks */
|
||||||
|
//ot->poll = ;
|
||||||
|
//ot->exec = ;
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
}
|
||||||
|
@@ -210,8 +210,10 @@ typedef struct MovieTrackingSettings {
|
|||||||
float reconstruction_success_threshold;
|
float reconstruction_success_threshold;
|
||||||
int reconstruction_flag;
|
int reconstruction_flag;
|
||||||
|
|
||||||
/* which camera intrinsics to refine. uses on the REFINE_* flags */
|
/* refinement */
|
||||||
short refine_camera_intrinsics, pad2;
|
short refine_intrinsics; /* camera intrinsics to refine */
|
||||||
|
short constrain_intrinsics; /* camera intrinsics to constrain */
|
||||||
|
float focal_length_min, focal_length_max; /* minimum and maximum values for focal length refinement in pixels */
|
||||||
|
|
||||||
/* ** tool settings ** */
|
/* ** tool settings ** */
|
||||||
|
|
||||||
@@ -413,7 +415,7 @@ enum {
|
|||||||
TRACKING_USE_KEYFRAME_SELECTION = (1 << 1)
|
TRACKING_USE_KEYFRAME_SELECTION = (1 << 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
/* MovieTrackingSettings->refine_camera_intrinsics */
|
/* MovieTrackingSettings->refine_intrinsics */
|
||||||
enum {
|
enum {
|
||||||
REFINE_FOCAL_LENGTH = (1 << 0),
|
REFINE_FOCAL_LENGTH = (1 << 0),
|
||||||
REFINE_PRINCIPAL_POINT = (1 << 1),
|
REFINE_PRINCIPAL_POINT = (1 << 1),
|
||||||
@@ -421,6 +423,11 @@ enum {
|
|||||||
REFINE_RADIAL_DISTORTION_K2 = (1 << 4)
|
REFINE_RADIAL_DISTORTION_K2 = (1 << 4)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* MovieTrackingSettings->constrain_intrinsics */
|
||||||
|
enum {
|
||||||
|
CONSTRAIN_FOCAL_LENGTH = (1 << 0)
|
||||||
|
};
|
||||||
|
|
||||||
/* MovieTrackingStrabilization->flag */
|
/* MovieTrackingStrabilization->flag */
|
||||||
enum {
|
enum {
|
||||||
TRACKING_2D_STABILIZATION = (1 << 0),
|
TRACKING_2D_STABILIZATION = (1 << 0),
|
||||||
|
@@ -55,6 +55,76 @@
|
|||||||
|
|
||||||
#include "WM_api.h"
|
#include "WM_api.h"
|
||||||
|
|
||||||
|
static void rna_trackingSettings_focal_length_min_pixels_set(PointerRNA *ptr, float value)
|
||||||
|
{
|
||||||
|
MovieClip *clip = (MovieClip *)ptr->id.data;
|
||||||
|
MovieTrackingSettings *settings = &clip->tracking.settings;
|
||||||
|
|
||||||
|
if (value > settings->focal_length_max)
|
||||||
|
value = settings->focal_length_max;
|
||||||
|
|
||||||
|
settings->focal_length_min = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_trackingSettings_focal_length_max_pixels_set(PointerRNA *ptr, float value)
|
||||||
|
{
|
||||||
|
MovieClip *clip = (MovieClip *)ptr->id.data;
|
||||||
|
MovieTrackingSettings *settings = &clip->tracking.settings;
|
||||||
|
|
||||||
|
if (value < settings->focal_length_min)
|
||||||
|
value = settings->focal_length_min;
|
||||||
|
|
||||||
|
settings->focal_length_max = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float rna_trackingSettings_focal_length_min_get(PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
MovieClip *clip = (MovieClip *)ptr->id.data;
|
||||||
|
MovieTrackingSettings *settings = &clip->tracking.settings;
|
||||||
|
MovieTrackingCamera *camera = &clip->tracking.camera;
|
||||||
|
float value = settings->focal_length_min;
|
||||||
|
|
||||||
|
if (clip->lastsize[0])
|
||||||
|
value = value * camera->sensor_width / (float)clip->lastsize[0];
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_trackingSettings_focal_length_min_set(PointerRNA *ptr, float value)
|
||||||
|
{
|
||||||
|
MovieClip *clip = (MovieClip *)ptr->id.data;
|
||||||
|
MovieTrackingCamera *camera = &clip->tracking.camera;
|
||||||
|
|
||||||
|
if (clip->lastsize[0])
|
||||||
|
value = clip->lastsize[0] * value / camera->sensor_width;
|
||||||
|
|
||||||
|
rna_trackingSettings_focal_length_min_pixels_set(ptr, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float rna_trackingSettings_focal_length_max_get(PointerRNA *ptr)
|
||||||
|
{
|
||||||
|
MovieClip *clip = (MovieClip *)ptr->id.data;
|
||||||
|
MovieTrackingSettings *settings = &clip->tracking.settings;
|
||||||
|
MovieTrackingCamera *camera = &clip->tracking.camera;
|
||||||
|
float value = settings->focal_length_max;
|
||||||
|
|
||||||
|
if (clip->lastsize[0])
|
||||||
|
value = value * camera->sensor_width / (float)clip->lastsize[0];
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rna_trackingSettings_focal_length_max_set(PointerRNA *ptr, float value)
|
||||||
|
{
|
||||||
|
MovieClip *clip = (MovieClip *)ptr->id.data;
|
||||||
|
MovieTrackingCamera *camera = &clip->tracking.camera;
|
||||||
|
|
||||||
|
if (clip->lastsize[0])
|
||||||
|
value = clip->lastsize[0] * value / camera->sensor_width;
|
||||||
|
|
||||||
|
rna_trackingSettings_focal_length_max_pixels_set(ptr, value);
|
||||||
|
}
|
||||||
|
|
||||||
static char *rna_tracking_path(PointerRNA *UNUSED(ptr))
|
static char *rna_tracking_path(PointerRNA *UNUSED(ptr))
|
||||||
{
|
{
|
||||||
return BLI_sprintfN("tracking");
|
return BLI_sprintfN("tracking");
|
||||||
@@ -305,7 +375,13 @@ static char *rna_trackingCamera_path(PointerRNA *UNUSED(ptr))
|
|||||||
return BLI_sprintfN("tracking.camera");
|
return BLI_sprintfN("tracking.camera");
|
||||||
}
|
}
|
||||||
|
|
||||||
static float rna_trackingCamera_focal_mm_get(PointerRNA *ptr)
|
static void rna_trackingCamera_focal_length_pixels_set(PointerRNA *ptr, float value)
|
||||||
|
{
|
||||||
|
MovieClip *clip = (MovieClip *)ptr->id.data;
|
||||||
|
BKE_tracking_camera_focal_length_set(&clip->tracking, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float rna_trackingCamera_focal_length_get(PointerRNA *ptr)
|
||||||
{
|
{
|
||||||
MovieClip *clip = (MovieClip *)ptr->id.data;
|
MovieClip *clip = (MovieClip *)ptr->id.data;
|
||||||
MovieTrackingCamera *camera = &clip->tracking.camera;
|
MovieTrackingCamera *camera = &clip->tracking.camera;
|
||||||
@@ -317,7 +393,7 @@ static float rna_trackingCamera_focal_mm_get(PointerRNA *ptr)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rna_trackingCamera_focal_mm_set(PointerRNA *ptr, float value)
|
static void rna_trackingCamera_focal_length_set(PointerRNA *ptr, float value)
|
||||||
{
|
{
|
||||||
MovieClip *clip = (MovieClip *)ptr->id.data;
|
MovieClip *clip = (MovieClip *)ptr->id.data;
|
||||||
MovieTrackingCamera *camera = &clip->tracking.camera;
|
MovieTrackingCamera *camera = &clip->tracking.camera;
|
||||||
@@ -326,7 +402,7 @@ static void rna_trackingCamera_focal_mm_set(PointerRNA *ptr, float value)
|
|||||||
value = clip->lastsize[0] * value / camera->sensor_width;
|
value = clip->lastsize[0] * value / camera->sensor_width;
|
||||||
|
|
||||||
if (value >= 0.0001f)
|
if (value >= 0.0001f)
|
||||||
camera->focal = value;
|
BKE_tracking_camera_focal_length_set(&clip->tracking, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *rna_trackingStabilization_path(PointerRNA *UNUSED(ptr))
|
static char *rna_trackingStabilization_path(PointerRNA *UNUSED(ptr))
|
||||||
@@ -793,11 +869,56 @@ static void rna_def_trackingSettings(BlenderRNA *brna)
|
|||||||
|
|
||||||
/* intrinsics refinement during bundle adjustment */
|
/* intrinsics refinement during bundle adjustment */
|
||||||
prop = RNA_def_property(srna, "refine_intrinsics", PROP_ENUM, PROP_NONE);
|
prop = RNA_def_property(srna, "refine_intrinsics", PROP_ENUM, PROP_NONE);
|
||||||
RNA_def_property_enum_sdna(prop, NULL, "refine_camera_intrinsics");
|
RNA_def_property_enum_sdna(prop, NULL, "refine_intrinsics");
|
||||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||||
RNA_def_property_enum_items(prop, refine_items);
|
RNA_def_property_enum_items(prop, refine_items);
|
||||||
RNA_def_property_ui_text(prop, "Refine", "Refine intrinsics during camera solving");
|
RNA_def_property_ui_text(prop, "Refine", "Refine intrinsics during camera solving");
|
||||||
|
|
||||||
|
/* constrain focal length for intrinsics refinement */
|
||||||
|
prop = RNA_def_property(srna, "use_focal_length_constraint", PROP_BOOLEAN, PROP_NONE);
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||||
|
RNA_def_property_boolean_sdna(prop, NULL, "constrain_intrinsics", CONSTRAIN_FOCAL_LENGTH);
|
||||||
|
RNA_def_property_ui_text(prop, "Constrain Focal Length",
|
||||||
|
"Constrain the focal length during intrinsics refinement");
|
||||||
|
|
||||||
|
/* focal length constraint values in pixels */
|
||||||
|
prop = RNA_def_property(srna, "focal_length_min_pixels", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||||
|
RNA_def_property_float_sdna(prop, NULL, "focal_length_min");
|
||||||
|
RNA_def_property_range(prop, 0.0f, 10000.0f);
|
||||||
|
RNA_def_property_float_default(prop, 0.0f);
|
||||||
|
RNA_def_property_float_funcs(prop, NULL, "rna_trackingSettings_focal_length_min_pixels_set", NULL);
|
||||||
|
RNA_def_property_ui_text(prop, "Min Focal Length",
|
||||||
|
"Minimum focal length in pixels");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "focal_length_max_pixels", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||||
|
RNA_def_property_float_sdna(prop, NULL, "focal_length_max");
|
||||||
|
RNA_def_property_range(prop, 0.0f, 10000.0f);
|
||||||
|
RNA_def_property_float_default(prop, 10000.0f);
|
||||||
|
RNA_def_property_float_funcs(prop, NULL, "rna_trackingSettings_focal_length_max_pixels_set", NULL);
|
||||||
|
RNA_def_property_ui_text(prop, "Max Focal Length",
|
||||||
|
"Maximum focal length in pixels");
|
||||||
|
|
||||||
|
/* focal length constraint values in millimeters */
|
||||||
|
prop = RNA_def_property(srna, "focal_length_min", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||||
|
RNA_def_property_range(prop, 0.0f, 10000.0f);
|
||||||
|
RNA_def_property_float_default(prop, 0.0f);
|
||||||
|
RNA_def_property_float_funcs(prop, "rna_trackingSettings_focal_length_min_get",
|
||||||
|
"rna_trackingSettings_focal_length_min_set", NULL);
|
||||||
|
RNA_def_property_ui_text(prop, "Min Focal Length",
|
||||||
|
"Minimum focal length in millimeters");
|
||||||
|
|
||||||
|
prop = RNA_def_property(srna, "focal_length_max", PROP_FLOAT, PROP_NONE);
|
||||||
|
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||||
|
RNA_def_property_range(prop, 0.0f, 10000.0f);
|
||||||
|
RNA_def_property_float_default(prop, 10000.0f);
|
||||||
|
RNA_def_property_float_funcs(prop, "rna_trackingSettings_focal_length_max_get",
|
||||||
|
"rna_trackingSettings_focal_length_max_set", NULL);
|
||||||
|
RNA_def_property_ui_text(prop, "Max Focal Length",
|
||||||
|
"Maximum focal length in millimeters");
|
||||||
|
|
||||||
/* tool settings */
|
/* tool settings */
|
||||||
|
|
||||||
/* distance */
|
/* distance */
|
||||||
@@ -977,7 +1098,8 @@ static void rna_def_trackingCamera(BlenderRNA *brna)
|
|||||||
RNA_def_property_float_sdna(prop, NULL, "focal");
|
RNA_def_property_float_sdna(prop, NULL, "focal");
|
||||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||||
RNA_def_property_range(prop, 0.0001f, 5000.0f);
|
RNA_def_property_range(prop, 0.0001f, 5000.0f);
|
||||||
RNA_def_property_float_funcs(prop, "rna_trackingCamera_focal_mm_get", "rna_trackingCamera_focal_mm_set", NULL);
|
RNA_def_property_float_funcs(prop, "rna_trackingCamera_focal_length_get",
|
||||||
|
"rna_trackingCamera_focal_length_set", NULL);
|
||||||
RNA_def_property_ui_text(prop, "Focal Length", "Camera's focal length");
|
RNA_def_property_ui_text(prop, "Focal Length", "Camera's focal length");
|
||||||
RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL);
|
RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL);
|
||||||
|
|
||||||
@@ -986,6 +1108,7 @@ static void rna_def_trackingCamera(BlenderRNA *brna)
|
|||||||
RNA_def_property_float_sdna(prop, NULL, "focal");
|
RNA_def_property_float_sdna(prop, NULL, "focal");
|
||||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||||
RNA_def_property_range(prop, 0.0f, 5000.0f);
|
RNA_def_property_range(prop, 0.0f, 5000.0f);
|
||||||
|
RNA_def_property_float_funcs(prop, NULL, "rna_trackingCamera_focal_length_pixels_set", NULL);
|
||||||
RNA_def_property_ui_text(prop, "Focal Length", "Camera's focal length");
|
RNA_def_property_ui_text(prop, "Focal Length", "Camera's focal length");
|
||||||
RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL);
|
RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL);
|
||||||
|
|
||||||
@@ -993,9 +1116,9 @@ static void rna_def_trackingCamera(BlenderRNA *brna)
|
|||||||
prop = RNA_def_property(srna, "units", PROP_ENUM, PROP_NONE);
|
prop = RNA_def_property(srna, "units", PROP_ENUM, PROP_NONE);
|
||||||
RNA_def_property_enum_sdna(prop, NULL, "units");
|
RNA_def_property_enum_sdna(prop, NULL, "units");
|
||||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
|
||||||
RNA_def_property_enum_items(prop, camera_units_items);
|
RNA_def_property_enum_items(prop, camera_units_items);
|
||||||
RNA_def_property_ui_text(prop, "Units", "Units used for camera focal length");
|
RNA_def_property_ui_text(prop, "Units", "Units used for camera focal length");
|
||||||
|
RNA_def_property_update(prop, NC_MOVIECLIP | NA_EDITED, NULL);
|
||||||
|
|
||||||
/* Principal Point */
|
/* Principal Point */
|
||||||
prop = RNA_def_property(srna, "principal", PROP_FLOAT, PROP_NONE);
|
prop = RNA_def_property(srna, "principal", PROP_FLOAT, PROP_NONE);
|
||||||
|
Reference in New Issue
Block a user