LIBMV_OBJECT_DELETE(libmv_tracks, 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, double weight)
{
- ((libmv::Tracks*) libmv_tracks)->Insert(image, track, x, y);
+ ((libmv::Tracks*) libmv_tracks)->Insert(image, track, x, y, weight);
}
/* ************ Reconstruction ************ */
/* Tracks */
struct libmv_Tracks *libmv_tracksNew(void);
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, double weight);
/* Reconstruction */
#define LIBMV_REFINE_FOCAL_LENGTH (1 << 0)
}
void libmv_tracksInsert(struct libmv_Tracks * /*libmv_tracks*/, int /*image*/,
- int /*track*/, double /*x*/, double /*y*/)
+ int /*track*/, double /*x*/, double /*y*/, double /*weight*/)
{
}
//
// This functor uses a radial distortion model.
struct OpenCVReprojectionError {
- OpenCVReprojectionError(const double observed_x, const double observed_y)
- : observed_x(observed_x), observed_y(observed_y) {}
+ OpenCVReprojectionError(const double observed_x,
+ const double observed_y,
+ const double weight)
+ : observed_x_(observed_x), observed_y_(observed_y),
+ weight_(weight) {}
template <typename T>
bool operator()(const T* const intrinsics,
&predicted_y);
// The error is the difference between the predicted and observed position.
- residuals[0] = predicted_x - T(observed_x);
- residuals[1] = predicted_y - T(observed_y);
+ residuals[0] = (predicted_x - T(observed_x_)) * weight_;
+ residuals[1] = (predicted_y - T(observed_y_)) * weight_;
return true;
}
- const double observed_x;
- const double observed_y;
+ const double observed_x_;
+ const double observed_y_;
+ const double weight_;
};
// Print a message to the log which camera intrinsics are gonna to be optimixed.
// camera translaiton.
double *current_camera_R_t = &all_cameras_R_t[camera->image](0);
- problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
- OpenCVReprojectionError, 2, 8, 6, 3>(
- new OpenCVReprojectionError(
- marker.x,
- marker.y)),
- NULL,
- ceres_intrinsics,
- current_camera_R_t,
- &point->X(0));
-
- // We lock the first camera to better deal with scene orientation ambiguity.
- if (!have_locked_camera) {
- problem.SetParameterBlockConstant(current_camera_R_t);
- have_locked_camera = true;
- }
+ // Skip residual block for markers which does have absolutely
+ // no affect on the final solution.
+ // This way ceres is not gonna to go crazy.
+ if (marker.weight != 0.0) {
+ problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
+ OpenCVReprojectionError, 2, 8, 6, 3>(
+ new OpenCVReprojectionError(
+ marker.x,
+ marker.y,
+ marker.weight)),
+ NULL,
+ ceres_intrinsics,
+ current_camera_R_t,
+ &point->X(0));
+
+ // We lock the first camera to better deal with scene orientation ambiguity.
+ if (!have_locked_camera) {
+ problem.SetParameterBlockConstant(current_camera_R_t);
+ have_locked_camera = true;
+ }
- if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
- problem.SetParameterization(current_camera_R_t,
+ if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
+ problem.SetParameterization(current_camera_R_t,
constant_translation_parameterization);
+ }
}
num_residuals++;
struct ModalReprojectionError {
ModalReprojectionError(double observed_x,
double observed_y,
+ const double weight,
const Vec3 &bundle)
- : observed_x(observed_x), observed_y(observed_y), bundle(bundle) { }
+ : observed_x_(observed_x), observed_y_(observed_y),
+ weight_(weight), bundle_(bundle) { }
template <typename T>
bool operator()(const T* quaternion, // Rotation quaternion
// Convert bundle position from double to T.
T X[3];
- X[0] = T(bundle(0));
- X[1] = T(bundle(1));
- X[2] = T(bundle(2));
+ X[0] = T(bundle_(0));
+ X[1] = T(bundle_(1));
+ X[2] = T(bundle_(2));
// Compute projective coordinates: x = RX.
T x[3];
// The error is the difference between reprojected
// and observed marker position.
- residuals[0] = xn - T(observed_x);
- residuals[1] = yn - T(observed_y);
+ residuals[0] = xn - T(observed_x_);
+ residuals[1] = yn - T(observed_y_);
return true;
}
- double observed_x;
- double observed_y;
- Vec3 bundle;
+ double observed_x_;
+ double observed_y_;
+ double weight_;
+ Vec3 bundle_;
};
} // namespace
Marker &marker = all_markers[i];
EuclideanPoint *point = reconstruction->PointForTrack(marker.track);
- if (point) {
+ if (point && marker.weight != 0.0) {
problem.AddResidualBlock(new ceres::AutoDiffCostFunction<
ModalReprojectionError,
2, /* num_residuals */
- 4>(new ModalReprojectionError(marker.x, marker.y,
+ 4>(new ModalReprojectionError(marker.x,
+ marker.y,
+ marker.weight,
point->X)),
NULL,
&quaternion(0));
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, double weight) {
// TODO(keir): Wow, this is quadratic for repeated insertions. Fix this by
// adding a smarter data structure like a set<>.
for (int i = 0; i < markers_.size(); ++i) {
return;
}
}
- Marker marker = { image, track, x, y };
+ Marker marker = { image, track, x, y, weight };
markers_.push_back(marker);
}
return markers_[i];
}
}
- Marker null = { -1, -1, -1, -1 };
+ Marker null = { -1, -1, -1, -1, 0.0 };
return null;
}
in the image identified by \a image. All markers for to the same target
form a track identified by a common \a track number.
+ \a weight is used by bundle adjustment and weight means how much the
+ track affects on a final solution.
+
\note Markers are typically aggregated with the help of the \l Tracks class.
\sa Tracks
*/
+// TODO(sergey): Consider using comment for every member separately
+// instead of having one giantic comment block.
struct Marker {
int image;
int track;
double x, y;
+ double weight;
};
/*!
\a image and \a track are the keys used to retrieve the markers with the
other methods in this class.
+ \a weight is used by bundle adjustment and weight means how much the
+ track affects on a final solution.
+
\note To get an identifier for a new track, use \l MaxTrack() + 1.
*/
- void Insert(int image, int track, double x, double y);
+ // TODO(sergey): Consider using InsetWeightedMarker istead of using
+ // stupid default value?
+ void Insert(int image, int track, double x, double y, double weight = 1.0);
/// Returns all the markers.
vector<Marker> AllMarkers() const;
if act_track.use_custom_color:
row.prop(act_track, "color", text="")
+ layout.prop(act_track, "weight")
+
if act_track.has_bundle:
label_text = "Average Error: %.4f" % (act_track.average_error)
layout.label(text=label_text)
bool BKE_tracking_reconstruction_check(struct MovieTracking *tracking, struct MovieTrackingObject *object,
char *error_msg, int error_size);
-struct MovieReconstructContext *BKE_tracking_reconstruction_context_new(struct MovieTracking *tracking,
+struct MovieReconstructContext *BKE_tracking_reconstruction_context_new(struct MovieClip *clip,
struct MovieTrackingObject *object,
int keyframe1, int keyframe2,
int width, int height);
#include "MEM_guardedalloc.h"
+#include "DNA_anim_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_camera_types.h"
#include "DNA_movieclip_types.h"
#include "BLF_translation.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_tracking.h"
#include "BKE_movieclip.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
+#include "RNA_access.h"
+
#include "raskter.h"
#include "libmv-capi.h"
track->frames_limit = settings->default_frames_limit;
track->flag = settings->default_flag;
track->algorithm_flag = settings->default_algorithm_flag;
+ track->weight = 1.0f;
memset(&marker, 0, sizeof(marker));
marker.pos[0] = x;
} ReconstructProgressData;
/* Create new libmv Tracks structure from blender's tracks list. */
-static struct libmv_Tracks *libmv_tracks_new(ListBase *tracksbase, int width, int height)
+static struct libmv_Tracks *libmv_tracks_new(MovieClip *clip, ListBase *tracksbase, int width, int height)
{
int tracknr = 0;
MovieTrackingTrack *track;
track = tracksbase->first;
while (track) {
+ FCurve *weight_fcurve;
int a = 0;
+ weight_fcurve = id_data_find_fcurve(&clip->id, track, &RNA_MovieTrackingTrack,
+ "weight", 0, NULL);
+
for (a = 0; a < track->markersnr; a++) {
MovieTrackingMarker *marker = &track->markers[a];
if ((marker->flag & MARKER_DISABLED) == 0) {
+ float weight = track->weight;
+
+ if (weight_fcurve) {
+ int scene_framenr =
+ BKE_movieclip_remap_clip_to_scene_frame(clip, marker->framenr);
+ weight = evaluate_fcurve(weight_fcurve, scene_framenr);
+ }
+
libmv_tracksInsert(tracks, marker->framenr, tracknr,
(marker->pos[0] + track->offset[0]) * width,
- (marker->pos[1] + track->offset[1]) * height);
+ (marker->pos[1] + track->offset[1]) * height,
+ weight);
}
}
* clip datablock, so editing this clip is safe during
* reconstruction job is in progress.
*/
-MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieTracking *tracking, MovieTrackingObject *object,
+MovieReconstructContext *BKE_tracking_reconstruction_context_new(MovieClip *clip, MovieTrackingObject *object,
int keyframe1, int keyframe2, int width, int height)
{
+ MovieTracking *tracking = &clip->tracking;
MovieReconstructContext *context = MEM_callocN(sizeof(MovieReconstructContext), "MovieReconstructContext data");
MovieTrackingCamera *camera = &tracking->camera;
ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
context->sfra = sfra;
context->efra = efra;
- context->tracks = libmv_tracks_new(tracksbase, width, height * aspy);
+ context->tracks = libmv_tracks_new(clip, tracksbase, width, height * aspy);
context->keyframe1 = keyframe1;
context->keyframe2 = keyframe2;
context->refine_flags = reconstruct_refine_intrinsics_get_flags(tracking, object);
}
}
}
+
+ if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight")) {
+ MovieClip *clip;
+ for (clip = main->movieclip.first; clip; clip = clip->id.next) {
+ MovieTracking *tracking = &clip->tracking;
+ MovieTrackingObject *tracking_object;
+ for (tracking_object = tracking->objects.first;
+ tracking_object;
+ tracking_object = tracking_object->next)
+ {
+ ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
+ MovieTrackingTrack *track;
+ for (track = tracksbase->first;
+ track;
+ track = track->next)
+ {
+ track->weight = 1.0f;
+ }
+ }
+ }
+ }
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
MovieTrackingPlaneTrack *plane_track, *next_plane_track;
ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(tracking);
-
bool has_bundle = false, update_stab = false;
+ char track_name_escaped[MAX_NAME], prefix[MAX_NAME * 2];
if (track == act_track)
tracking->act_track = NULL;
}
}
+ /* Delete f-curves associated with the track (such as weight, i.e.) */
+ BLI_strescape(track_name_escaped, track->name, sizeof(track_name_escaped));
+ BLI_snprintf(prefix, sizeof(prefix), "tracks[\"%s\"]", track_name_escaped);
+ BKE_animdata_fix_paths_remove(&clip->id, prefix);
+
BKE_tracking_track_free(track);
BLI_freelinkN(tracksbase, track);
scj->reports = op->reports;
scj->user = sc->user;
- scj->context = BKE_tracking_reconstruction_context_new(tracking, object,
+ scj->context = BKE_tracking_reconstruction_context_new(clip, object,
object->keyframe1, object->keyframe2, width, height);
tracking->stats = MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
float minimum_correlation; /* minimal correlation which is still treated as successful tracking */
struct bGPdata *gpd; /* grease-pencil data */
+
+ /* Weight of this track.
+ *
+ * Weight defines how much the track affects on the final reconstruction,
+ * usually gets animated in a way so when track has just appeared it's
+ * weight is zero and then it gets faded up.
+ *
+ * Used to prevent jumps of the camera when tracks are appearing or
+ * disappearing.
+ */
+ float weight, pad;
} MovieTrackingTrack;
typedef struct MovieTrackingPlaneMarker {
RNA_def_property_struct_type(prop, "GreasePencil");
RNA_def_property_ui_text(prop, "Grease Pencil", "Grease pencil data for this track");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
+
+ /* weight */
+ prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "weight");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Weight", "How much this track affects on a final solution");
}
static void rna_def_trackingPlaneMarker(BlenderRNA *brna)