libavfi: added option to vf_perspective to specify transformation by giving destinations of corners of source.

Signed-off-by: Nicholas Robbins <nickrobbins@yahoo.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Nicholas Robbins 2014-10-19 09:20:22 -04:00 committed by Michael Niedermayer
parent 9d51bad625
commit 22cfa1f759
2 changed files with 85 additions and 19 deletions

View File

@ -6718,6 +6718,9 @@ A description of the accepted parameters follows.
@item y3 @item y3
Set coordinates expression for top left, top right, bottom left and bottom right corners. Set coordinates expression for top left, top right, bottom left and bottom right corners.
Default values are @code{0:0:W:0:0:H:W:H} with which perspective will remain unchanged. Default values are @code{0:0:W:0:0:H:W:H} with which perspective will remain unchanged.
If the @code{sense} option is set to @code{source}, then the specified points will be sent
to the corners of the destination. If the @code{sense} option is set to @code{destination},
then the corners of the source will be sent to the specified coordinates.
The expressions can use the following variables: The expressions can use the following variables:
@ -6737,6 +6740,24 @@ It accepts the following values:
@end table @end table
Default value is @samp{linear}. Default value is @samp{linear}.
@item sense
Set interpretation of coordinate options.
It accepts the following values:
@table @samp
@item 0, source
Send point in the source specified by the given coordinates to
the corners of the destination.
@item 1, destination
Send the corners of the source to the point in the destination specified
by the given coordinates.
Default value is @samp{source}.
@end table
@end table @end table
@section phase @section phase

View File

@ -46,6 +46,7 @@ typedef struct PerspectiveContext {
int height[4]; int height[4];
int hsub, vsub; int hsub, vsub;
int nb_planes; int nb_planes;
int sense;
int (*perspective)(AVFilterContext *ctx, int (*perspective)(AVFilterContext *ctx,
void *arg, int job, int nb_jobs); void *arg, int job, int nb_jobs);
@ -54,6 +55,11 @@ typedef struct PerspectiveContext {
#define OFFSET(x) offsetof(PerspectiveContext, x) #define OFFSET(x) offsetof(PerspectiveContext, x)
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
enum PERSPECTIVESense {
PERSPECTIVE_SENSE_SOURCE = 0, ///< coordinates give locations in source of corners of destination.
PERSPECTIVE_SENSE_DESTINATION = 1, ///< coordinates give locations in destination of corners of source.
};
static const AVOption perspective_options[] = { static const AVOption perspective_options[] = {
{ "x0", "set top left x coordinate", OFFSET(expr_str[0][0]), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS }, { "x0", "set top left x coordinate", OFFSET(expr_str[0][0]), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS },
{ "y0", "set top left y coordinate", OFFSET(expr_str[0][1]), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS }, { "y0", "set top left y coordinate", OFFSET(expr_str[0][1]), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS },
@ -66,6 +72,12 @@ static const AVOption perspective_options[] = {
{ "interpolation", "set interpolation", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=LINEAR}, 0, 1, FLAGS, "interpolation" }, { "interpolation", "set interpolation", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=LINEAR}, 0, 1, FLAGS, "interpolation" },
{ "linear", "", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "interpolation" }, { "linear", "", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "interpolation" },
{ "cubic", "", 0, AV_OPT_TYPE_CONST, {.i64=CUBIC}, 0, 0, FLAGS, "interpolation" }, { "cubic", "", 0, AV_OPT_TYPE_CONST, {.i64=CUBIC}, 0, 0, FLAGS, "interpolation" },
{ "sense", "specify the sense of the coordinates", OFFSET(sense), AV_OPT_TYPE_INT, {.i64=PERSPECTIVE_SENSE_SOURCE}, 0, 1, FLAGS, "sense"},
{ "source", "specify locations in source to send to corners in destination",
0, AV_OPT_TYPE_CONST, {.i64=PERSPECTIVE_SENSE_SOURCE}, 0, 0, FLAGS, "sense"},
{ "destination", "specify locations in destination to send corners of source",
0, AV_OPT_TYPE_CONST, {.i64=PERSPECTIVE_SENSE_DESTINATION}, 0, 0, FLAGS, "sense"},
{ NULL } { NULL }
}; };
@ -105,7 +117,8 @@ enum { VAR_W, VAR_H, VAR_VARS_NB };
static int config_input(AVFilterLink *inlink) static int config_input(AVFilterLink *inlink)
{ {
double x0, x1, x2, x3, x4, x5, x6, x7, q; double x0, x1, x2, x3, x4, x5, x6, x7, x8, q;
double t0, t1, t2, t3;
AVFilterContext *ctx = inlink->dst; AVFilterContext *ctx = inlink->dst;
PerspectiveContext *s = ctx->priv; PerspectiveContext *s = ctx->priv;
double (*ref)[2] = s->ref; double (*ref)[2] = s->ref;
@ -141,32 +154,64 @@ static int config_input(AVFilterLink *inlink)
if (!s->pv) if (!s->pv)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
x6 = ((ref[0][0] - ref[1][0] - ref[2][0] + ref[3][0]) * switch (s->sense) {
(ref[2][1] - ref[3][1]) - case PERSPECTIVE_SENSE_SOURCE:
( ref[0][1] - ref[1][1] - ref[2][1] + ref[3][1]) * x6 = ((ref[0][0] - ref[1][0] - ref[2][0] + ref[3][0]) *
(ref[2][0] - ref[3][0])) * h; (ref[2][1] - ref[3][1]) -
x7 = ((ref[0][1] - ref[1][1] - ref[2][1] + ref[3][1]) * ( ref[0][1] - ref[1][1] - ref[2][1] + ref[3][1]) *
(ref[1][0] - ref[3][0]) - (ref[2][0] - ref[3][0])) * h;
( ref[0][0] - ref[1][0] - ref[2][0] + ref[3][0]) * x7 = ((ref[0][1] - ref[1][1] - ref[2][1] + ref[3][1]) *
(ref[1][1] - ref[3][1])) * w; (ref[1][0] - ref[3][0]) -
q = ( ref[1][0] - ref[3][0]) * (ref[2][1] - ref[3][1]) - ( ref[0][0] - ref[1][0] - ref[2][0] + ref[3][0]) *
( ref[2][0] - ref[3][0]) * (ref[1][1] - ref[3][1]); (ref[1][1] - ref[3][1])) * w;
q = ( ref[1][0] - ref[3][0]) * (ref[2][1] - ref[3][1]) -
( ref[2][0] - ref[3][0]) * (ref[1][1] - ref[3][1]);
x0 = q * (ref[1][0] - ref[0][0]) * h + x6 * ref[1][0]; x0 = q * (ref[1][0] - ref[0][0]) * h + x6 * ref[1][0];
x1 = q * (ref[2][0] - ref[0][0]) * w + x7 * ref[2][0]; x1 = q * (ref[2][0] - ref[0][0]) * w + x7 * ref[2][0];
x2 = q * ref[0][0] * w * h; x2 = q * ref[0][0] * w * h;
x3 = q * (ref[1][1] - ref[0][1]) * h + x6 * ref[1][1]; x3 = q * (ref[1][1] - ref[0][1]) * h + x6 * ref[1][1];
x4 = q * (ref[2][1] - ref[0][1]) * w + x7 * ref[2][1]; x4 = q * (ref[2][1] - ref[0][1]) * w + x7 * ref[2][1];
x5 = q * ref[0][1] * w * h; x5 = q * ref[0][1] * w * h;
x8 = q * w * h;
break;
case PERSPECTIVE_SENSE_DESTINATION:
t0 = ref[0][0] * (ref[3][1] - ref[1][1]) +
ref[1][0] * (ref[0][1] - ref[3][1]) +
ref[3][0] * (ref[1][1] - ref[0][1]);
t1 = ref[1][0] * (ref[2][1] - ref[3][1]) +
ref[2][0] * (ref[3][1] - ref[1][1]) +
ref[3][0] * (ref[1][1] - ref[2][1]);
t2 = ref[0][0] * (ref[3][1] - ref[2][1]) +
ref[2][0] * (ref[0][1] - ref[3][1]) +
ref[3][0] * (ref[2][1] - ref[0][1]);
t3 = ref[0][0] * (ref[1][1] - ref[2][1]) +
ref[1][0] * (ref[2][1] - ref[0][1]) +
ref[2][0] * (ref[0][1] - ref[1][1]);
x0 = t0 * t1 * w * (ref[2][1] - ref[0][1]);
x1 = t0 * t1 * w * (ref[0][0] - ref[2][0]);
x2 = t0 * t1 * w * (ref[0][1] * ref[2][0] - ref[0][0] * ref[2][1]);
x3 = t1 * t2 * h * (ref[1][1] - ref[0][1]);
x4 = t1 * t2 * h * (ref[0][0] - ref[1][0]);
x5 = t1 * t2 * h * (ref[0][1] * ref[1][0] - ref[0][0] * ref[1][1]);
x6 = t1 * t2 * (ref[1][1] - ref[0][1]) +
t0 * t3 * (ref[2][1] - ref[3][1]);
x7 = t1 * t2 * (ref[0][0] - ref[1][0]) +
t0 * t3 * (ref[3][0] - ref[2][0]);
x8 = t1 * t2 * (ref[0][1] * ref[1][0] - ref[0][0] * ref[1][1]) +
t0 * t3 * (ref[2][0] * ref[3][1] - ref[2][1] * ref[3][0]);
break;
}
for (y = 0; y < h; y++){ for (y = 0; y < h; y++){
for (x = 0; x < w; x++){ for (x = 0; x < w; x++){
int u, v; int u, v;
u = (int)floor(SUB_PIXELS * (x0 * x + x1 * y + x2) / u = (int)floor(SUB_PIXELS * (x0 * x + x1 * y + x2) /
(x6 * x + x7 * y + q * w * h) + 0.5); (x6 * x + x7 * y + x8) + 0.5);
v = (int)floor(SUB_PIXELS * (x3 * x + x4 * y + x5) / v = (int)floor(SUB_PIXELS * (x3 * x + x4 * y + x5) /
(x6 * x + x7 * y + q * w * h) + 0.5); (x6 * x + x7 * y + x8) + 0.5);
s->pv[x + y * w][0] = u; s->pv[x + y * w][0] = u;
s->pv[x + y * w][1] = v; s->pv[x + y * w][1] = v;