mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2025-02-28 17:51:05 +00:00
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:
parent
9d51bad625
commit
22cfa1f759
@ -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
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user