Fix T50908: Motion Tracker ignored grease pencil mask

This feature got lost with new auto-track API,

Added it back by extending frame accessor class. This isn't really
a frame thing, but we don't have other type of accessor here.

Surely, we can use old-style API here and pass mask via region
tracker options for this particular case, but then it becomes much
less obvious how real auto-tracker will access this mask with old
style API.

So seems we do need an accessor for such data, just matter of
finding better place than frame accessor.
This commit is contained in:
2017-05-26 15:21:15 +02:00
parent ac66fb193f
commit b0015686e2
10 changed files with 230 additions and 27 deletions

View File

@@ -40,10 +40,14 @@ using mv::Region;
struct LibmvFrameAccessor : public FrameAccessor {
LibmvFrameAccessor(libmv_FrameAccessorUserData* user_data,
libmv_GetImageCallback get_image_callback,
libmv_ReleaseImageCallback release_image_callback)
libmv_ReleaseImageCallback release_image_callback,
libmv_GetMaskForTrackCallback get_mask_for_track_callback,
libmv_ReleaseMaskCallback release_mask_callback)
: user_data_(user_data),
get_image_callback_(get_image_callback),
release_image_callback_(release_image_callback) { }
release_image_callback_(release_image_callback),
get_mask_for_track_callback_(get_mask_for_track_callback),
release_mask_callback_(release_mask_callback) { }
virtual ~LibmvFrameAccessor() {
}
@@ -109,6 +113,41 @@ struct LibmvFrameAccessor : public FrameAccessor {
release_image_callback_(cache_key);
}
Key GetMaskForTrack(int clip,
int frame,
int track,
const Region* region,
FloatImage* destination) {
float *float_buffer;
int width, height;
libmv_Region libmv_region;
if (region) {
get_libmv_region(*region, &libmv_region);
}
Key cache_key = get_mask_for_track_callback_(
user_data_,
clip,
frame,
track,
region != NULL ? &libmv_region : NULL,
&float_buffer,
&width,
&height);
// TODO(sergey): Dumb code for until we can set data directly.
FloatImage temp_image(float_buffer,
height,
width,
1);
destination->CopyFrom(temp_image);
return cache_key;
}
void ReleaseMask(Key key) {
release_mask_callback_(key);
}
bool GetClipDimensions(int /*clip*/, int * /*width*/, int * /*height*/) {
return false;
}
@@ -124,6 +163,8 @@ struct LibmvFrameAccessor : public FrameAccessor {
libmv_FrameAccessorUserData* user_data_;
libmv_GetImageCallback get_image_callback_;
libmv_ReleaseImageCallback release_image_callback_;
libmv_GetMaskForTrackCallback get_mask_for_track_callback_;
libmv_ReleaseMaskCallback release_mask_callback_;
};
} // namespace
@@ -131,11 +172,15 @@ struct LibmvFrameAccessor : public FrameAccessor {
libmv_FrameAccessor* libmv_FrameAccessorNew(
libmv_FrameAccessorUserData* user_data,
libmv_GetImageCallback get_image_callback,
libmv_ReleaseImageCallback release_image_callback) {
libmv_ReleaseImageCallback release_image_callback,
libmv_GetMaskForTrackCallback get_mask_for_track_callback,
libmv_ReleaseMaskCallback release_mask_callback) {
return (libmv_FrameAccessor*) LIBMV_OBJECT_NEW(LibmvFrameAccessor,
user_data,
get_image_callback,
release_image_callback);
release_image_callback,
get_mask_for_track_callback,
release_mask_callback);
}
void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor) {

View File

@@ -61,10 +61,23 @@ typedef libmv_CacheKey (*libmv_GetImageCallback) (
typedef void (*libmv_ReleaseImageCallback) (libmv_CacheKey cache_key);
typedef libmv_CacheKey (*libmv_GetMaskForTrackCallback) (
libmv_FrameAccessorUserData* user_data,
int clip,
int frame,
int track,
const libmv_Region* region,
float** destination,
int* width,
int* height);
typedef void (*libmv_ReleaseMaskCallback) (libmv_CacheKey cache_key);
libmv_FrameAccessor* libmv_FrameAccessorNew(
libmv_FrameAccessorUserData* user_data,
libmv_GetImageCallback get_image_callback,
libmv_ReleaseImageCallback release_image_callback);
libmv_ReleaseImageCallback release_image_callback,
libmv_GetMaskForTrackCallback get_mask_for_track_callback,
libmv_ReleaseMaskCallback release_mask_callback);
void libmv_FrameAccessorDestroy(libmv_FrameAccessor* frame_accessor);
int64_t libmv_frameAccessorgetTransformKey(const libmv_FrameTransform *transform);

View File

@@ -375,7 +375,9 @@ int libmv_autoTrackGetMarker(libmv_AutoTrack* /*libmv_autotrack*/,
libmv_FrameAccessor* libmv_FrameAccessorNew(
libmv_FrameAccessorUserData* /*user_data**/,
libmv_GetImageCallback /*get_image_callback*/,
libmv_ReleaseImageCallback /*release_image_callback*/)
libmv_ReleaseImageCallback /*release_image_callback*/,
libmv_GetMaskForTrackCallback /*get_mask_for_track_callback*/,
libmv_ReleaseMaskCallback /*release_mask_callback*/)
{
return NULL;
}

View File

@@ -36,7 +36,7 @@
/* define this to generate PNG images with content of search areas
on every itteration of tracking */
#undef DUMP_ALWAYS
#define DUMP_ALWAYS
using libmv::FloatImage;
using libmv::TrackRegionOptions;

View File

@@ -111,6 +111,17 @@ FrameAccessor::Key GetImageForMarker(const Marker& marker,
image);
}
FrameAccessor::Key GetMaskForMarker(const Marker& marker,
FrameAccessor* frame_accessor,
FloatImage* mask) {
Region region = marker.search_region.Rounded();
return frame_accessor->GetMaskForTrack(marker.clip,
marker.frame,
marker.track,
&region,
mask);
}
} // namespace
bool AutoTrack::TrackMarker(Marker* tracked_marker,
@@ -149,6 +160,11 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker,
return false;
}
FloatImage reference_mask;
FrameAccessor::Key reference_mask_key = GetMaskForMarker(reference_marker,
frame_accessor_,
&reference_mask);
FloatImage tracked_image;
FrameAccessor::Key tracked_key = GetImageForMarker(*tracked_marker,
frame_accessor_,
@@ -167,6 +183,10 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker,
if (track_options) {
local_track_region_options = *track_options;
}
if (reference_mask_key != NULL) {
LG << "Using mask for reference marker: " << reference_marker;
local_track_region_options.image1_mask = &reference_mask;
}
local_track_region_options.num_extra_points = 1; // For center point.
local_track_region_options.attempt_refine_before_brute = predicted_position;
TrackRegion(reference_image,
@@ -191,9 +211,10 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker,
tracked_marker->reference_clip = reference_marker.clip;
tracked_marker->reference_frame = reference_marker.frame;
// Release the images from the accessor cache.
// Release the images and masks from the accessor cache.
frame_accessor_->ReleaseImage(reference_key);
frame_accessor_->ReleaseImage(tracked_key);
frame_accessor_->ReleaseMask(reference_mask_key);
// TODO(keir): Possibly the return here should get removed since the results
// are part of TrackResult. However, eventually the autotrack stuff will have

View File

@@ -76,6 +76,25 @@ struct FrameAccessor {
// free the image immediately; others may hold onto the image.
virtual void ReleaseImage(Key) = 0;
// Get mask image for the given track.
//
// Implementation of this method should sample mask associated with the track
// within given region to the given destination.
//
// Result is supposed to be a single channel image.
//
// If region is NULL, it it assumed to be full-frame.
virtual Key GetMaskForTrack(int clip,
int frame,
int track,
const Region* region,
FloatImage* destination) = 0;
// Release a specified mask.
//
// Non-caching implementation may free used memory immediately.
virtual void ReleaseMask(Key key) = 0;
virtual bool GetClipDimensions(int clip, int* width, int* height) = 0;
virtual int NumClips() = 0;
virtual int NumFrames(int clip) = 0;

View File

@@ -974,8 +974,11 @@ static void track_mask_set_pixel_cb(int x, int x_end, int y, void *user_data)
}
static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height,
MovieTrackingMarker *marker, bGPDlayer *layer,
float *mask, int mask_width, int mask_height)
const float region_min[2],
bGPDlayer *layer,
float *mask,
int mask_width,
int mask_height)
{
bGPDframe *frame = layer->frames.first;
TrackMaskSetPixelData data;
@@ -994,8 +997,8 @@ static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height
point = mask_points = MEM_callocN(2 * stroke->totpoints * sizeof(int),
"track mask rasterization points");
for (int i = 0; i < stroke->totpoints; i++, point += 2) {
point[0] = (stroke_points[i].x - marker->search_min[0]) * frame_width;
point[1] = (stroke_points[i].y - marker->search_min[1]) * frame_height;
point[0] = stroke_points[i].x * frame_width - region_min[0];
point[1] = stroke_points[i].y * frame_height - region_min[1];
}
/* TODO: add an option to control whether AA is enabled or not */
BLI_bitmap_draw_2d_poly_v2i_n(
@@ -1010,26 +1013,42 @@ static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height
}
}
float *BKE_tracking_track_get_mask(int frame_width, int frame_height,
MovieTrackingTrack *track, MovieTrackingMarker *marker)
/* Region is in pixel space, relative to marker's center. */
float *tracking_track_get_mask_for_region(int frame_width, int frame_height,
const float region_min[2],
const float region_max[2],
MovieTrackingTrack *track)
{
float *mask = NULL;
bGPDlayer *layer = track_mask_gpencil_layer_get(track);
int mask_width, mask_height;
mask_width = (marker->search_max[0] - marker->search_min[0]) * frame_width;
mask_height = (marker->search_max[1] - marker->search_min[1]) * frame_height;
if (layer) {
if (layer != NULL) {
const int mask_width = region_max[0] - region_min[0];
const int mask_height = region_max[1] - region_min[1];
mask = MEM_callocN(mask_width * mask_height * sizeof(float), "track mask");
track_mask_gpencil_layer_rasterize(frame_width, frame_height, marker, layer,
mask, mask_width, mask_height);
track_mask_gpencil_layer_rasterize(frame_width, frame_height,
region_min,
layer,
mask,
mask_width, mask_height);
}
return mask;
}
float *BKE_tracking_track_get_mask(int frame_width, int frame_height,
MovieTrackingTrack *track,
MovieTrackingMarker *marker)
{
/* Convert normalized space marker's search area to pixel-space region. */
const float region_min[2] = {marker->search_min[0] * frame_width,
marker->search_min[1] * frame_height};
const float region_max[2] = {marker->search_max[0] * frame_width,
marker->search_max[1] * frame_height};
return tracking_track_get_mask_for_region(frame_width, frame_height,
region_min,
region_max,
track);
}
float BKE_tracking_track_get_weight_for_marker(MovieClip *clip, MovieTrackingTrack *track, MovieTrackingMarker *marker)
{
FCurve *weight_fcurve;

View File

@@ -36,8 +36,9 @@
#include "DNA_movieclip_types.h"
#include "DNA_object_types.h" /* SELECT */
#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_threads.h"
#include "BLI_math.h"
#include "BKE_movieclip.h"
@@ -76,6 +77,9 @@ typedef struct AutoTrackContext {
int num_tracks; /* Number of tracks being tracked. */
AutoTrackOptions *options; /* Per-tracking track options. */
/* Array of all tracks, indexed by track_index. */
MovieTrackingTrack **tracks;
bool backwards;
bool sequence;
int first_frame;
@@ -306,8 +310,15 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
BLI_spin_init(&context->spin_lock);
int num_total_tracks = BLI_listbase_count(tracksbase);
context->tracks =
MEM_callocN(sizeof(MovieTrackingTrack*) * num_total_tracks,
"auto track pointers");
context->image_accessor =
tracking_image_accessor_new(context->clips, 1, user->framenr);
tracking_image_accessor_new(context->clips, 1,
context->tracks, num_total_tracks,
user->framenr);
context->autotrack =
libmv_autoTrackNew(context->image_accessor->libmv_accessor);
@@ -361,6 +372,7 @@ AutoTrackContext *BKE_autotrack_context_new(MovieClip *clip,
options->use_keyframe_match =
track->pattern_match == TRACK_MATCH_KEYFRAME;
}
context->tracks[track_index] = track;
++track_index;
}
@@ -565,6 +577,7 @@ void BKE_autotrack_context_free(AutoTrackContext *context)
libmv_autoTrackDestroy(context->autotrack);
tracking_image_accessor_destroy(context->image_accessor);
MEM_freeN(context->options);
MEM_freeN(context->tracks);
BLI_spin_end(&context->spin_lock);
MEM_freeN(context);
}

View File

@@ -875,8 +875,64 @@ static void accessor_release_image_callback(libmv_CacheKey cache_key)
IMB_freeImBuf(ibuf);
}
static libmv_CacheKey accessor_get_mask_for_track_callback(
libmv_FrameAccessorUserData* user_data,
int clip_index,
int frame,
int track_index,
const libmv_Region *region,
float **r_destination,
int *r_width,
int *r_height)
{
/* Perform sanity checks first. */
TrackingImageAccessor *accessor = (TrackingImageAccessor *) user_data;
BLI_assert(clip_index < accessor->num_clips);
BLI_assert(track_index < accessor->num_tracks);
MovieTrackingTrack *track = accessor->tracks[track_index];
/* Early output, track does not use mask. */
if ((track->algorithm_flag & TRACK_ALGORITHM_FLAG_USE_MASK) == 0) {
return NULL;
}
MovieClip *clip = accessor->clips[clip_index];
/* Construct fake user so we can access movie clip. */
MovieClipUser user;
int scene_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, frame);
BKE_movieclip_user_set_frame(&user, scene_frame);
user.render_size = MCLIP_PROXY_RENDER_SIZE_FULL;
user.render_flag = 0;
/* Get frame width and height so we can convert stroke coordinates
* and other things from normalized to pixel space.
*/
int frame_width, frame_height;
BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
/* Actual mask sampling. */
MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, frame);
const float region_min[2] = {region->min[0] - marker->pos[0] * frame_width,
region->min[1] - marker->pos[1] * frame_height};
const float region_max[2] = {region->max[0] - marker->pos[0] * frame_width,
region->max[1] - marker->pos[1] * frame_height};
*r_destination = tracking_track_get_mask_for_region(frame_width, frame_height,
region_min,
region_max,
track);
*r_width = region->max[0] - region->min[0];
*r_height = region->max[1] - region->min[1];
return *r_destination;
}
static void accessor_release_mask_callback(libmv_CacheKey cache_key)
{
if (cache_key != NULL) {
float *mask = (float *)cache_key;
MEM_freeN(mask);
}
}
TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP],
int num_clips,
MovieTrackingTrack **tracks,
int num_tracks,
int start_frame)
{
TrackingImageAccessor *accessor =
@@ -891,12 +947,16 @@ TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR
memcpy(accessor->clips, clips, num_clips * sizeof(MovieClip *));
accessor->num_clips = num_clips;
accessor->tracks = tracks;
accessor->num_tracks = num_tracks;
accessor->start_frame = start_frame;
accessor->libmv_accessor =
libmv_FrameAccessorNew((libmv_FrameAccessorUserData *) accessor,
accessor_get_image_callback,
accessor_release_image_callback);
accessor_release_image_callback,
accessor_get_mask_for_track_callback,
accessor_release_mask_callback);
return accessor;
}

View File

@@ -105,6 +105,13 @@ struct MovieTrackingMarker *tracking_get_keyframed_marker(
int current_frame,
bool backwards);
/*********************** Masking *************************/
float *tracking_track_get_mask_for_region(int frame_width, int frame_height,
const float region_min[2],
const float region_max[2],
MovieTrackingTrack *track);
/*********************** Frame accessr *************************/
struct libmv_FrameAccessor;
@@ -114,12 +121,16 @@ typedef struct TrackingImageAccessor {
struct MovieCache *cache;
struct MovieClip *clips[MAX_ACCESSOR_CLIP];
int num_clips;
struct MovieTrackingTrack **tracks;
int num_tracks;
int start_frame;
struct libmv_FrameAccessor *libmv_accessor;
} TrackingImageAccessor;
TrackingImageAccessor *tracking_image_accessor_new(MovieClip *clips[MAX_ACCESSOR_CLIP],
int num_clips,
MovieTrackingTrack **tracks,
int num_tracks,
int start_frame);
void tracking_image_accessor_destroy(TrackingImageAccessor *accessor);