From: Jakub Ksiezniak Date: Thu, 9 Jan 2014 20:44:44 +0000 (+0100) Subject: Added a fourth filter, that combines both detect and transform passes. X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=280eedef0228a13381797dec1b6f08004cc89265;hp=473ece6065411284b74163d92d2cd12608875a1f;p=mlt Added a fourth filter, that combines both detect and transform passes. * Increased a default smoothing factor, according to the original vid.stab default settings. * Added a deshake data clear when seeking is performed. * Added a version check in configure script. --- diff --git a/src/modules/vid.stab/Makefile b/src/modules/vid.stab/Makefile index 24eba4d7..b90cf75f 100644 --- a/src/modules/vid.stab/Makefile +++ b/src/modules/vid.stab/Makefile @@ -11,6 +11,7 @@ OBJS = factory.o CPPOBJS = filter_deshake.o CPPOBJS += filter_detect.o CPPOBJS += filter_transform.o +CPPOBJS += filter_vidstab.o CXXFLAGS += -Wno-deprecated $(CFLAGS) CXXFLAGS += $(shell pkg-config --cflags vidstab) diff --git a/src/modules/vid.stab/common.h b/src/modules/vid.stab/common.h index b373dbdd..96a2c9b0 100644 --- a/src/modules/vid.stab/common.h +++ b/src/modules/vid.stab/common.h @@ -26,4 +26,7 @@ inline VSPixelFormat convertImageFormat(mlt_image_format &format) { } } +int get_image_and_detect(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable); +int get_image_and_transform(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable); + #endif /* VIDSTAB_COMMON_H_ */ diff --git a/src/modules/vid.stab/configure b/src/modules/vid.stab/configure old mode 100755 new mode 100644 index 7a852a1d..2929d079 --- a/src/modules/vid.stab/configure +++ b/src/modules/vid.stab/configure @@ -8,6 +8,15 @@ then touch ../disable-vidstab exit 0 fi + + minver="0.98" + modver=$(pkg-config --modversion vidstab) + if [ 0 == $(expr $modver \>= $minver) ] + then + echo "- vid.stab $modver found, but $minver or newer is required: disabling" + touch ../disable-opencv + exit 0 + fi echo > config.mak case $targetos in diff --git a/src/modules/vid.stab/factory.c b/src/modules/vid.stab/factory.c index 967e74c5..25e5b430 100644 --- a/src/modules/vid.stab/factory.c +++ b/src/modules/vid.stab/factory.c @@ -21,10 +21,10 @@ #include #include -// extern mlt_filter filter_vidstab_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_deshake_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_detect_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); extern mlt_filter filter_transform_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); +extern mlt_filter filter_vidstab_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg ); static mlt_properties metadata( mlt_service_type type, const char *id, void *data ) { @@ -38,8 +38,10 @@ MLT_REPOSITORY MLT_REGISTER( filter_type, "vid.stab.deshake", filter_deshake_init ); MLT_REGISTER( filter_type, "vid.stab.detect", filter_detect_init ); MLT_REGISTER( filter_type, "vid.stab.transform", filter_transform_init ); + MLT_REGISTER( filter_type, "vid.stab", filter_vidstab_init ); MLT_REGISTER_METADATA( filter_type, "vid.stab.deshake", metadata, "filter_deshake.yml" ); MLT_REGISTER_METADATA( filter_type, "vid.stab.detect", metadata, "filter_detect.yml" ); MLT_REGISTER_METADATA( filter_type, "vid.stab.transform", metadata, "filter_transform.yml" ); + MLT_REGISTER_METADATA( filter_type, "vid.stab", metadata, "filter_vidstab.yml" ); } diff --git a/src/modules/vid.stab/filter_deshake.cpp b/src/modules/vid.stab/filter_deshake.cpp index ccae5a8f..9ca5cacd 100644 --- a/src/modules/vid.stab/filter_deshake.cpp +++ b/src/modules/vid.stab/filter_deshake.cpp @@ -38,7 +38,7 @@ typedef struct _deshake_data VSTransformData td; VSSlidingAvgTrans avg; - void *parent; + mlt_position lastFrame; } DeshakeData; int init_deshake(DeshakeData *data, mlt_properties properties, @@ -115,6 +115,14 @@ static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, data->initialized = false; } + // clear deshake data, when seeking or dropping frames + mlt_position pos = mlt_filter_get_position(filter, frame); + if(pos != data->lastFrame+1) { + clear_deshake(data); + data->initialized = false; + } + data->lastFrame = pos; + if (!data->initialized) { char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp"); @@ -184,7 +192,6 @@ mlt_filter filter_deshake_init(mlt_profile profile, mlt_service_type type, filter->process = process_filter; filter->close = close_filter; filter->child = data; - data->parent = filter; mlt_properties properties = MLT_FILTER_PROPERTIES(filter); //properties for stabilize @@ -195,7 +202,7 @@ mlt_filter filter_deshake_init(mlt_profile profile, mlt_service_type type, mlt_properties_set(properties, "mincontrast", "0.3"); //properties for transform - mlt_properties_set(properties, "smoothing", "10"); + mlt_properties_set(properties, "smoothing", "15"); mlt_properties_set(properties, "maxshift", "-1"); mlt_properties_set(properties, "maxangle", "-1"); mlt_properties_set(properties, "crop", "0"); diff --git a/src/modules/vid.stab/filter_deshake.yml b/src/modules/vid.stab/filter_deshake.yml index f9c5b4fb..96457219 100644 --- a/src/modules/vid.stab/filter_deshake.yml +++ b/src/modules/vid.stab/filter_deshake.yml @@ -85,7 +85,7 @@ parameters: required: no minimum: 0 maximum: 100 - default: 10 + default: 15 mutable: yes widget: spinner diff --git a/src/modules/vid.stab/filter_detect.cpp b/src/modules/vid.stab/filter_detect.cpp index a31b17b2..a38f8bce 100644 --- a/src/modules/vid.stab/filter_detect.cpp +++ b/src/modules/vid.stab/filter_detect.cpp @@ -30,15 +30,10 @@ extern "C" #include #include "common.h" -#define FILTER_NAME "vid.stab.detect" - typedef struct _stab_data { - bool initialized; VSMotionDetect md; mlt_animation animation; - - void *parent; } StabData; char* vectors_serializer(mlt_animation animation, int length) @@ -85,13 +80,19 @@ static void serialize_localmotions(StabData* data, LocalMotions &vectors, mlt_po mlt_property_close(item.property); } -int init_detect(StabData *data, mlt_properties properties, mlt_image_format *format, int *width, int *height) +static StabData* init_detect(mlt_properties properties, mlt_image_format *format, int *width, int *height) { + StabData *data = new StabData; + memset(data, 0, sizeof(StabData)); + data->animation = mlt_animation_new(); + VSPixelFormat pf = convertImageFormat(*format); VSFrameInfo fi; vsFrameInfoInit(&fi, *width, *height, pf); - VSMotionDetectConfig conf = vsMotionDetectGetDefaultConfig(FILTER_NAME); + const char* filterName = mlt_properties_get(properties, "mlt_service"); + + VSMotionDetectConfig conf = vsMotionDetectGetDefaultConfig(filterName); conf.shakiness = mlt_properties_get_int(properties, "shakiness"); conf.accuracy = mlt_properties_get_int(properties, "accuracy"); conf.stepSize = mlt_properties_get_int(properties, "stepsize"); @@ -99,21 +100,31 @@ int init_detect(StabData *data, mlt_properties properties, mlt_image_format *for conf.contrastThreshold = mlt_properties_get_double(properties, "mincontrast"); conf.show = mlt_properties_get_int(properties, "show"); conf.virtualTripod = mlt_properties_get_int(properties, "tripod"); - vsMotionDetectInit(&data->md, &conf, &fi); - // change name of the filter, so the vid.stab.transform will be used in 2nd-pass. - mlt_properties_set(properties, "mlt_service", "vid.stab.transform"); - return 0; + // add vectors to properties + mlt_properties_set_data(properties, "vectors", data->animation, 1, (mlt_destructor) mlt_animation_close, + (mlt_serialiser) vectors_serializer); + return data; +} + +void destroy_detect(StabData *data) +{ + if (data) + { + vsMotionDetectionCleanup(&data->md); + delete data; + } } -static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable) +int get_image_and_detect(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame); mlt_properties properties = MLT_FILTER_PROPERTIES(filter); *format = mlt_image_yuv420p; - StabData *data = static_cast(filter->child); + + writable = writable || mlt_properties_get_int(properties, "show") ? 1 : 0; int error = mlt_frame_get_image(frame, image, format, width, height, writable); if (!error) @@ -121,10 +132,11 @@ static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, // Service locks are for concurrency control mlt_service_lock(MLT_FILTER_SERVICE(filter)); - if (!data->initialized) + StabData *data = static_cast(mlt_properties_get_data(properties, "_stab_data", NULL)); + if (!data) { - init_detect(data, properties, format, width, height); - data->initialized = true; + data = init_detect(properties, format, width, height); + mlt_properties_set_data(properties, "_stab_data", data, 0, (mlt_destructor) destroy_detect, NULL); } VSMotionDetect* md = &data->md; @@ -146,24 +158,10 @@ static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, static mlt_frame process_filter(mlt_filter filter, mlt_frame frame) { mlt_frame_push_service(frame, filter); - mlt_frame_push_get_image(frame, get_image); + mlt_frame_push_get_image(frame, get_image_and_detect); return frame; } -static void close_filter(mlt_filter filter) -{ - StabData *data = static_cast(filter->child); - if (data) - { - if (data->initialized) - { - vsMotionDetectionCleanup(&data->md); - } - delete data; - filter->child = NULL; - } -} - extern "C" { @@ -171,20 +169,11 @@ mlt_filter filter_detect_init(mlt_profile profile, mlt_service_type type, const { mlt_filter filter = NULL; - StabData *data = new StabData; - memset(data, 0, sizeof(StabData)); - if ((filter = mlt_filter_new())) { filter->process = process_filter; - filter->close = close_filter; - filter->child = data; - - data->animation = mlt_animation_new(); - data->parent = filter; mlt_properties properties = MLT_FILTER_PROPERTIES(filter); - mlt_properties_set(properties, "mlt_service", "vid.stab.transform"); //properties for stabilize mlt_properties_set(properties, "shakiness", "4"); @@ -196,7 +185,7 @@ mlt_filter filter_detect_init(mlt_profile profile, mlt_service_type type, const mlt_properties_set(properties, "tripod", "0"); // properties for transform - mlt_properties_set(properties, "smoothing", "10"); + mlt_properties_set(properties, "smoothing", "15"); mlt_properties_set(properties, "maxshift", "-1"); mlt_properties_set(properties, "maxangle", "-1"); mlt_properties_set(properties, "crop", "0"); @@ -207,13 +196,10 @@ mlt_filter filter_detect_init(mlt_profile profile, mlt_service_type type, const mlt_properties_set(properties, "zoomspeed", "0.25"); mlt_properties_set(properties, "vid.stab.version", LIBVIDSTAB_VERSION); - mlt_properties_set_data(properties, "vectors", data->animation, 1, (mlt_destructor) mlt_animation_close, - (mlt_serialiser) vectors_serializer); return filter; } - delete data; return NULL; } diff --git a/src/modules/vid.stab/filter_detect.yml b/src/modules/vid.stab/filter_detect.yml index 6bb73eaa..a02da168 100644 --- a/src/modules/vid.stab/filter_detect.yml +++ b/src/modules/vid.stab/filter_detect.yml @@ -119,7 +119,7 @@ parameters: required: no minimum: 0 maximum: 100 - default: 10 + default: 15 mutable: yes widget: spinner diff --git a/src/modules/vid.stab/filter_transform.cpp b/src/modules/vid.stab/filter_transform.cpp index c69d395c..66e36435 100644 --- a/src/modules/vid.stab/filter_transform.cpp +++ b/src/modules/vid.stab/filter_transform.cpp @@ -31,15 +31,10 @@ extern "C" #include #include "common.h" -#define FILTER_NAME "vid.stab.transform" - typedef struct { - bool initialized; VSTransformData td; VSTransformations trans; - - void *parent; } TransformData; int lm_deserialize(LocalMotions *lms, mlt_property property) @@ -87,15 +82,30 @@ int vectors_deserialize(mlt_animation anim, VSManyLocalMotions *mlms) return error; } -inline int initialize_transforms(TransformData *data, int *width, int *height, mlt_image_format *format, - mlt_properties properties, char* interps) +void destroy_transforms(TransformData *data) +{ + if (data) + { + vsTransformDataCleanup(&data->td); + vsTransformationsCleanup(&data->trans); + delete data; + } +} + +TransformData* initialize_transforms(int *width, int *height, mlt_image_format *format, + mlt_properties properties, const char* interps) { + TransformData *data = new TransformData; + memset(data, 0, sizeof(TransformData)); + VSPixelFormat pf = convertImageFormat(*format); VSFrameInfo fi_src, fi_dst; vsFrameInfoInit(&fi_src, *width, *height, pf); vsFrameInfoInit(&fi_dst, *width, *height, pf); - VSTransformConfig conf = vsTransformGetDefaultConfig(FILTER_NAME); + const char* filterName = mlt_properties_get(properties, "mlt_service"); + + VSTransformConfig conf = vsTransformGetDefaultConfig(filterName); conf.smoothing = mlt_properties_get_int(properties, "smoothing"); conf.maxShift = mlt_properties_get_int(properties, "maxshift"); conf.maxAngle = mlt_properties_get_double(properties, "maxangle"); @@ -120,7 +130,6 @@ inline int initialize_transforms(TransformData *data, int *width, int *height, m conf.interpolType = VS_Linear; vsTransformDataInit(&data->td, &conf, &fi_src, &fi_dst); - vsTransformationsInit(&data->trans); // load transformations @@ -129,39 +138,33 @@ inline int initialize_transforms(TransformData *data, int *width, int *height, m if (mlt_animation_parse(animation, strAnim, 0, 0, NULL)) { mlt_log_warning(NULL, "parse failed\n"); - return 1; + mlt_animation_close(animation); + destroy_transforms(data); + return NULL; } VSManyLocalMotions mlms; if (vectors_deserialize(animation, &mlms)) { - return 1; + mlt_animation_close(animation); + destroy_transforms(data); + return NULL; } mlt_animation_close(animation); vsLocalmotions2Transforms(&data->td, &mlms, &data->trans); vsPreprocessTransforms(&data->td, &data->trans); - return 0; -} - -void clear_transforms(TransformData *data) -{ - if (data->initialized) - { - vsTransformDataCleanup(&data->td); - vsTransformationsCleanup(&data->trans); - } + return data; } -static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable) +int get_image_and_transform(mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable) { int error = 0; mlt_filter filter = (mlt_filter) mlt_frame_pop_service(frame); mlt_properties properties = MLT_FILTER_PROPERTIES(filter); *format = mlt_image_yuv420p; - TransformData *data = static_cast(filter->child); error = mlt_frame_get_image(frame, image, format, width, height, 1); if (!error) @@ -169,19 +172,25 @@ static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, // Service locks are for concurrency control mlt_service_lock(MLT_FILTER_SERVICE(filter)); + TransformData *data = static_cast(mlt_properties_get_data(properties, "_transform_data", NULL)); + // Handle signal from app to re-init data if (mlt_properties_get_int(properties, "refresh")) { mlt_properties_set(properties, "refresh", NULL); - clear_transforms(data); - data->initialized = false; + destroy_transforms(data); + data = NULL; } - if (!data->initialized) + if (!data) { - char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp"); - initialize_transforms(data, width, height, format, properties, interps); - data->initialized = true; + const char *interps = mlt_properties_get(MLT_FRAME_PROPERTIES(frame), "rescale.interp"); + data = initialize_transforms(width, height, format, properties, interps); + if(!data) { + mlt_service_unlock(MLT_FILTER_SERVICE(filter)); + return 1; // return error code + } + mlt_properties_set_data(properties, "_transform_data", data, 0, (mlt_destructor) destroy_transforms, NULL); } VSTransformData* td = &data->td; @@ -204,21 +213,10 @@ static int get_image(mlt_frame frame, uint8_t **image, mlt_image_format *format, static mlt_frame process_filter(mlt_filter filter, mlt_frame frame) { mlt_frame_push_service(frame, filter); - mlt_frame_push_get_image(frame, get_image); + mlt_frame_push_get_image(frame, get_image_and_transform); return frame; } -static void close_filter(mlt_filter filter) -{ - TransformData *data = static_cast(filter->child); - if (data) - { - clear_transforms(data); - delete data; - filter->child = NULL; - } -} - extern "C" { @@ -226,16 +224,9 @@ mlt_filter filter_transform_init(mlt_profile profile, mlt_service_type type, con { mlt_filter filter = NULL; - TransformData *data = new TransformData; - memset(data, 0, sizeof(TransformData)); - if ((filter = mlt_filter_new())) { filter->process = process_filter; - filter->close = close_filter; - filter->child = data; - - data->parent = filter; mlt_properties properties = MLT_FILTER_PROPERTIES(filter); @@ -253,7 +244,6 @@ mlt_filter filter_transform_init(mlt_profile profile, mlt_service_type type, con return filter; } - delete data; return NULL; } diff --git a/src/modules/vid.stab/filter_transform.yml b/src/modules/vid.stab/filter_transform.yml index 3df01e23..1e33c43d 100644 --- a/src/modules/vid.stab/filter_transform.yml +++ b/src/modules/vid.stab/filter_transform.yml @@ -107,7 +107,7 @@ parameters: required: no minimum: 0 maximum: 100 - default: 10 + default: 15 mutable: yes widget: spinner diff --git a/src/modules/vid.stab/filter_vidstab.cpp b/src/modules/vid.stab/filter_vidstab.cpp new file mode 100644 index 00000000..ada37322 --- /dev/null +++ b/src/modules/vid.stab/filter_vidstab.cpp @@ -0,0 +1,107 @@ +/* + * filter_deshake.cpp + * Copyright (C) 2013 + * Marco Gittler + * Jakub Ksiezniak + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +extern "C" +{ +#include +#include +} + +#include +#include +#include "common.h" + +static mlt_frame process_filter(mlt_filter filter, mlt_frame frame) +{ + mlt_properties properties = MLT_FILTER_PROPERTIES(filter); + mlt_get_image vidstab_get_image = (mlt_get_image) mlt_properties_get_data( properties, "_vidstab_get_image", NULL ); + +#if 1 + mlt_position pos = mlt_filter_get_position(filter, frame); + mlt_position length = mlt_filter_get_length2(filter, frame) - 1; + if(pos >= length) + { + mlt_properties_set_data(properties, "_vidstab_get_image", NULL, 0, NULL, NULL); + } +#endif + + if(vidstab_get_image == NULL) + { + if(mlt_properties_get(properties, "vectors") == NULL) + { + // vectors are NULL, so use a detect filter + vidstab_get_image = get_image_and_detect; + } else { + // found vectors, so use a transform filter + vidstab_get_image = get_image_and_transform; + } + + mlt_properties_set_data( properties, "_vidstab_get_image", (void*)vidstab_get_image, 0, NULL, NULL ); + } + + mlt_frame_push_service(frame, filter); + mlt_frame_push_get_image(frame, vidstab_get_image); + return frame; +} + +extern "C" +{ + +mlt_filter filter_vidstab_init(mlt_profile profile, mlt_service_type type, + const char *id, char *arg) +{ + mlt_filter filter = NULL; + + if ((filter = mlt_filter_new())) + { + filter->process = process_filter; + + mlt_properties properties = MLT_FILTER_PROPERTIES(filter); + + //properties for stabilize + mlt_properties_set(properties, "shakiness", "4"); + mlt_properties_set(properties, "accuracy", "4"); + mlt_properties_set(properties, "stepsize", "6"); + mlt_properties_set(properties, "algo", "1"); + mlt_properties_set(properties, "mincontrast", "0.3"); + mlt_properties_set(properties, "show", "0"); + mlt_properties_set(properties, "tripod", "0"); + + // properties for transform + mlt_properties_set(properties, "smoothing", "15"); + mlt_properties_set(properties, "maxshift", "-1"); + mlt_properties_set(properties, "maxangle", "-1"); + mlt_properties_set(properties, "crop", "0"); + mlt_properties_set(properties, "invert", "0"); + mlt_properties_set(properties, "relative", "1"); + mlt_properties_set(properties, "zoom", "0"); + mlt_properties_set(properties, "optzoom", "1"); + mlt_properties_set(properties, "zoomspeed", "0.25"); + + mlt_properties_set(properties, "vid.stab.version", LIBVIDSTAB_VERSION); + + return filter; + } + + return NULL; +} + +} diff --git a/src/modules/vid.stab/filter_vidstab.yml b/src/modules/vid.stab/filter_vidstab.yml new file mode 100644 index 00000000..b298cd3a --- /dev/null +++ b/src/modules/vid.stab/filter_vidstab.yml @@ -0,0 +1,230 @@ +schema_version: 0.1 +type: filter +identifier: vid.stab +title: Vid.Stab Detect and Transform +copyright: Jakub Ksiezniak +creator: Marco Gittler +version: 1 +license: GPL +language: en +url: http://public.hronopik.de/vid.stab/ +tags: + - Video +description: Stabilize Video (for wiggly/rolling video) +notes: > + This filter requires two passes. The first pass performs analysis and stores + the result in the vectors property. The second pass applies the vectors to + the image. + To use with melt, use 'melt ... -consumer xml:output.mlt all=1' for the + first pass. For the second pass, use output.mlt as the input. + +parameters: + - identifier: vectors (transform) + title: Vectors + type: geometry + description: > + A set of X/Y coordinates by which to adjust the image. + When this is not supplied, the filter computes the vectors and stores + them in this property when the last frame has been processed. + + - identifier: shakiness + title: Shakiness + type: integer + description: How shaky is the video (analysis) + readonly: no + required: no + minimum: 1 + maximum: 10 + default: 4 + mutable: yes + widget: spinner + + - identifier: accuracy + title: Accuracy + type: integer + description: Accuracy of shakiness detection (analysis) + readonly: no + required: no + minimum: 1 + maximum: 15 + default: 4 + mutable: yes + widget: spinner + + - identifier: stepsize + title: Stepsize + type: integer + description: Step size of search process (analysis) + readonly: no + required: no + minimum: 0 + maximum: 100 + default: 6 + mutable: yes + widget: spinner + + - identifier: algo + title: Algorithm + type: integer + description: 0 = brute force (translation only), 1 = small measurement fields (analysis) + readonly: no + required: no + minimum: 0 + maximum: 1 + default: 1 + mutable: yes + widget: spinner + + - identifier: mincontrast + title: Minimum Contrast + type: float + description: Below this contrast, a field is discarded (analysis) + readonly: no + required: no + minimum: 0 + maximum: 1 + default: 0.3 + mutable: yes + widget: spinner + + - identifier: show + title: Show + type: integer + description: 0 = draw nothing, 1 or 2 = show fields and transforms (analysis) + readonly: no + required: no + minimum: 0 + maximum: 2 + default: 0 + mutable: yes + widget: spinner + + - identifier: tripod + title: Tripod + type: integer + description: virtual tripod mode (if >0): motion is compared to a reference frame (frame N is the value) + readonly: no + required: no + minimum: 0 + maximum: 100000 + default: 0 + mutable: yes + widget: spinner + + - identifier: smoothing + title: Smoothing + type: integer + description: number of frames for lowpass filtering (2N + 1 frames) (transform) + readonly: no + required: no + minimum: 0 + maximum: 100 + default: 15 + mutable: yes + widget: spinner + + - identifier: maxshift + title: Maxshift + type: integer + description: maximum translation, -1 = no limit (transform) + unit: pixels + readonly: no + required: no + minimum: -1 + maximum: 1000 + default: -1 + mutable: yes + widget: spinner + + - identifier: maxangle + title: Maxangle + type: float + description: max angle to rotate, -1 = no limit (transform) + unit: radians + readonly: no + required: no + minimum: -1 + maximum: 3.142 + default: -1 + mutable: yes + widget: spinner + + - identifier: crop + title: Crop + type: integer + description: 0 = keep border, 1 = black background (transform) + readonly: no + required: no + minimum: 0 + maximum: 1 + default: 0 + mutable: yes + widget: spinner + + - identifier: invert + title: Invert + type: integer + description: Invert transforms (transform) + readonly: no + required: no + minimum: 0 + maximum: 1 + default: 0 + mutable: yes + widget: spinner + + - identifier: relative + title: Relative Transform + type: integer + description: 0 = absolute, 1 = relative (transform) + readonly: no + required: no + minimum: 0 + maximum: 1 + default: 1 + mutable: yes + widget: spinner + + - identifier: zoom + title: Zoom + type: integer + description: additional zoom amount (transform) + unit: percent + readonly: no + required: no + minimum: -500 + maximum: 500 + default: 0 + mutable: yes + widget: spinner + + - identifier: optzoom + title: Optimal Zoom + type: integer + description: automatically determine optimal zoom. 1 - static zoom, 2 - adaptive zoom (transform) + readonly: no + required: no + minimum: 0 + maximum: 2 + default: 1 + mutable: yes + widget: spinner + + - identifier: zoomspeed + title: Optimal Zoom Speed + type: float + description: zoom per frame in percent, (used when optzoom = 2) (transform) + readonly: no + required: no + minimum: 0 + maximum: 1 + default: 0.25 + mutable: yes + widget: spinner + + - identifier: refresh + description: > + Applications should set this when it updates a transform parameter. + type: integer + minimum: 0 + maximum: 1