[FFmpeg-devel] [Patch] [avfilter] refactor floating point based interpolation and introduce in vf_lenscorrection

Daniel Oberhoff danieloberhoff at gmail.com
Wed Aug 20 00:12:49 CEST 2014


Hello,

As a follow-up to my last patch I now factored out the floating point based interpolation from transform.h/transform.c and applied it in the vf_lenscorrection filter I introduced in my last patch. What I did not do is also factor out fixed point based interpolation as used in vf_rotate and vf_perspective and maybe others as could probably also be done. Also I did not look further for uses of floating point based interpolation. Basically I just wanted to introduce interpolation in vf_lenscorrection without code duplication. As a side note I also tried to introduce fixed point calculations to vf_lenscorrection but found myself effectively doing floating point “by hand” since due to the high order of the algorithm (up to 4th order) it is very hard to keep track of the right amount of pre/post-comma digits for a given step in the algorithm and given parameters and it felt rather futile after a while.

Looking forward to reviews :).

From 4b271f72946aeebf5603cc8779f6b61ff0c1bd49 Mon Sep 17 00:00:00 2001
From: James Almer <jamrial at gmail.com>
Date: Sun, 10 Aug 2014 02:24:01 -0300
Subject: [PATCH] afvilter: re-factor/re-use floating point based interpolation
 from vf_perspective

---
 doc/filters.texi                |  11 +++
 libavfilter/interpolate.h       | 144 ++++++++++++++++++++++++++++++++++++++++
 libavfilter/transform.c         |  91 ++-----------------------
 libavfilter/transform.h         |  14 +---
 libavfilter/vf_lenscorrection.c |  21 ++++--
 5 files changed, 176 insertions(+), 105 deletions(-)
 create mode 100644 libavfilter/interpolate.h

diff --git a/doc/filters.texi b/doc/filters.texi
index 0ca1d6f..2edefc4 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -5582,6 +5582,17 @@ height.
 Coefficient of the quadratic correction term. 0.5 means no correction.
 @item k2
 Coefficient of the double quadratic correction term. 0.5 means no correction.
+ at item interpolation
+Set the interpolation method for the transformation
+
+It accepts the following values:
+ at table @samp
+ at item nearest
+ at item linear
+ at item cubic
+ at end table
+Default value is @samp{linear}.
+
 @end table
 
 The formula that generates the correction is:
diff --git a/libavfilter/interpolate.h b/libavfilter/interpolate.h
new file mode 100644
index 0000000..6f7a849
--- /dev/null
+++ b/libavfilter/interpolate.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2010 Georg Martius <georg.martius at web.de>
+ * Copyright (C) 2010 Daniel G. Taylor <dan at programmer-art.org>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVFILTER_INTERPOLATE_H
+#define AVFILTER_INTERPOLATE_H
+
+enum InterpolateMethod {
+    INTERPOLATE_NEAREST,        //< Nearest-neighbor (fast)
+    INTERPOLATE_BILINEAR,       //< Bilinear
+    INTERPOLATE_BIQUADRATIC,    //< Biquadratic (best)
+    INTERPOLATE_COUNT,          //< Number of interpolation methods
+};
+
+// Shortcuts for the fastest and best interpolation methods
+#define INTERPOLATE_DEFAULT INTERPOLATE_BILINEAR
+#define INTERPOLATE_FAST    INTERPOLATE_NEAREST
+#define INTERPOLATE_BEST    INTERPOLATE_BIQUADRATIC
+
+#define INTERPOLATE_METHOD(name) \
+    static av_always_inline uint8_t name(float x, float y, const uint8_t *src, \
+                                         int width, int height, int stride, uint8_t def)
+
+/**
+ * Nearest neighbor interpolation
+ */
+INTERPOLATE_METHOD(interpolate_nearest)
+{
+    if (x < 0 || x >= width || y < 0 || y >= height) {
+        return def;
+    } else {
+        return src[(int)(x + 0.5f) + stride * (int)(y + 0.5f)];
+    }
+}
+
+/**
+ * Bilinear interpolation
+ */
+INTERPOLATE_METHOD(interpolate_bilinear)
+{
+    int x_c, x_f, y_c, y_f;
+    int v1, v2, v3, v4;
+    const uint8_t *line_y_f, *line_y_c;
+
+    if (x < 0 || x >= width || y < 0 || y >= height) {
+        return def;
+    } else {
+        x_f = (int)x;
+        x_c = x_f + 1;
+
+        y_f = (int)y;
+        y_c = y_f + 1;
+
+        line_y_f = src + stride * y_c;
+        line_y_c = line_y_f + stride;
+
+        v1 = line_y_c[x_c];
+        v2 = line_y_f[x_c];
+        v3 = line_y_c[x_f];
+        v4 = line_y_f[x_f];
+
+        return (v1*(x - x_f)*(y - y_f) + v2*((x - x_f)*(y_c - y)) +
+                v3*(x_c - x)*(y - y_f) + v4*((x_c - x)*(y_c - y)));
+    }
+}
+
+/**
+ * Biquadratic interpolation
+ */
+INTERPOLATE_METHOD(interpolate_biquadratic)
+{
+    int     x_c, x_f, y_c, y_f;
+    uint8_t v1,  v2,  v3,  v4;
+    float   f1,  f2,  f3,  f4;
+    const uint8_t *line_y_f, *line_y_c;
+
+    if (x < 0 || x >= width || y < 0 || y >= height) {
+        return def;
+    } else {
+        x_f = (int)x;
+        x_c = x_f + 1;
+        y_f = (int)y;
+        y_c = y_f + 1;
+
+        line_y_f = src + stride * y_c;
+        line_y_c = line_y_f + stride;
+
+        v1 = line_y_c[x_c];
+        v2 = line_y_f[x_c];
+        v3 = line_y_c[x_f];
+        v4 = line_y_f[x_f];
+
+        f1 = 1 - sqrt((x_c - x) * (y_c - y));
+        f2 = 1 - sqrt((x_c - x) * (y - y_f));
+        f3 = 1 - sqrt((x - x_f) * (y_c - y));
+        f4 = 1 - sqrt((x - x_f) * (y - y_f));
+        return (v1 * f1 + v2 * f2 + v3 * f3 + v4 * f4) / (f1 + f2 + f3 + f4);
+    }
+}
+
+static av_always_inline uint8_t is_valid_interpolation_method(enum InterpolateMethod method)
+{
+    switch(method) {
+        case INTERPOLATE_NEAREST:
+        case INTERPOLATE_BILINEAR:
+        case INTERPOLATE_BIQUADRATIC:
+            return 1;
+        default:
+            return 0;
+    }
+}
+
+static av_always_inline uint8_t interpolate(float x, float y, const uint8_t *src, int width, int height, int stride, uint8_t def, enum InterpolateMethod method)
+{
+    switch(method) {
+        case INTERPOLATE_NEAREST:
+            return interpolate_nearest(x, y, src, width, height, stride, def);
+        case INTERPOLATE_BILINEAR:
+            return interpolate_bilinear(x, y, src, width, height, stride, def);
+        case INTERPOLATE_BIQUADRATIC:
+            return interpolate_biquadratic(x, y, src, width, height, stride, def);
+        default:
+            return def;
+    }
+}
+
+#endif /* AVFILTER_INTERPOLATE_H */
\ No newline at end of file
diff --git a/libavfilter/transform.c b/libavfilter/transform.c
index 3fc547e..c0c6c73 100644
--- a/libavfilter/transform.c
+++ b/libavfilter/transform.c
@@ -29,79 +29,6 @@
 
 #include "transform.h"
 
-#define INTERPOLATE_METHOD(name) \
-    static uint8_t name(float x, float y, const uint8_t *src, \
-                        int width, int height, int stride, uint8_t def)
-
-#define PIXEL(img, x, y, w, h, stride, def) \
-    ((x) < 0 || (y) < 0) ? (def) : \
-    (((x) >= (w) || (y) >= (h)) ? (def) : \
-    img[(x) + (y) * (stride)])
-
-/**
- * Nearest neighbor interpolation
- */
-INTERPOLATE_METHOD(interpolate_nearest)
-{
-    return PIXEL(src, (int)(x + 0.5), (int)(y + 0.5), width, height, stride, def);
-}
-
-/**
- * Bilinear interpolation
- */
-INTERPOLATE_METHOD(interpolate_bilinear)
-{
-    int x_c, x_f, y_c, y_f;
-    int v1, v2, v3, v4;
-
-    if (x < -1 || x > width || y < -1 || y > height) {
-        return def;
-    } else {
-        x_f = (int)x;
-        x_c = x_f + 1;
-
-        y_f = (int)y;
-        y_c = y_f + 1;
-
-        v1 = PIXEL(src, x_c, y_c, width, height, stride, def);
-        v2 = PIXEL(src, x_c, y_f, width, height, stride, def);
-        v3 = PIXEL(src, x_f, y_c, width, height, stride, def);
-        v4 = PIXEL(src, x_f, y_f, width, height, stride, def);
-
-        return (v1*(x - x_f)*(y - y_f) + v2*((x - x_f)*(y_c - y)) +
-                v3*(x_c - x)*(y - y_f) + v4*((x_c - x)*(y_c - y)));
-    }
-}
-
-/**
- * Biquadratic interpolation
- */
-INTERPOLATE_METHOD(interpolate_biquadratic)
-{
-    int     x_c, x_f, y_c, y_f;
-    uint8_t v1,  v2,  v3,  v4;
-    float   f1,  f2,  f3,  f4;
-
-    if (x < - 1 || x > width || y < -1 || y > height)
-        return def;
-    else {
-        x_f = (int)x;
-        x_c = x_f + 1;
-        y_f = (int)y;
-        y_c = y_f + 1;
-
-        v1 = PIXEL(src, x_c, y_c, width, height, stride, def);
-        v2 = PIXEL(src, x_c, y_f, width, height, stride, def);
-        v3 = PIXEL(src, x_f, y_c, width, height, stride, def);
-        v4 = PIXEL(src, x_f, y_f, width, height, stride, def);
-
-        f1 = 1 - sqrt((x_c - x) * (y_c - y));
-        f2 = 1 - sqrt((x_c - x) * (y - y_f));
-        f3 = 1 - sqrt((x - x_f) * (y_c - y));
-        f4 = 1 - sqrt((x - x_f) * (y - y_f));
-        return (v1 * f1 + v2 * f2 + v3 * f3 + v4 * f4) / (f1 + f2 + f3 + f4);
-    }
-}
 
 void avfilter_get_matrix(float x_shift, float y_shift, float angle, float zoom, float *matrix) {
     matrix[0] = zoom * cos(angle);
@@ -149,7 +76,7 @@ static inline int mirror(int v, int m)
 int avfilter_transform(const uint8_t *src, uint8_t *dst,
                         int src_stride, int dst_stride,
                         int width, int height, const float *matrix,
-                        enum InterpolateMethod interpolate,
+                        const enum InterpolateMethod interpolation_method,
                         enum FillMethod fill)
 {
     int x, y;
@@ -157,18 +84,8 @@ int avfilter_transform(const uint8_t *src, uint8_t *dst,
     uint8_t def = 0;
     uint8_t (*func)(float, float, const uint8_t *, int, int, int, uint8_t) = NULL;
 
-    switch(interpolate) {
-        case INTERPOLATE_NEAREST:
-            func = interpolate_nearest;
-            break;
-        case INTERPOLATE_BILINEAR:
-            func = interpolate_bilinear;
-            break;
-        case INTERPOLATE_BIQUADRATIC:
-            func = interpolate_biquadratic;
-            break;
-        default:
-            return AVERROR(EINVAL);
+    if (!is_valid_interpolation_method(interpolation_method)){
+        return AVERROR(EINVAL);
     }
 
     for (y = 0; y < height; y++) {
@@ -194,7 +111,7 @@ int avfilter_transform(const uint8_t *src, uint8_t *dst,
                     def = src[(int)y_s * src_stride + (int)x_s];
             }
 
-            dst[y * dst_stride + x] = func(x_s, y_s, src, width, height, src_stride, def);
+            dst[y * dst_stride + x] = interpolate(x_s, y_s, src, width, height, src_stride, def, interpolation_method);
         }
     }
     return 0;
diff --git a/libavfilter/transform.h b/libavfilter/transform.h
index 07436bf..9983b69 100644
--- a/libavfilter/transform.h
+++ b/libavfilter/transform.h
@@ -24,6 +24,8 @@
 
 #include <stdint.h>
 
+#include "interpolate.h"
+
 /**
  * @file
  * transform input video
@@ -36,18 +38,6 @@
  *                      0, 0, 1};
  */
 
-enum InterpolateMethod {
-    INTERPOLATE_NEAREST,        //< Nearest-neighbor (fast)
-    INTERPOLATE_BILINEAR,       //< Bilinear
-    INTERPOLATE_BIQUADRATIC,    //< Biquadratic (best)
-    INTERPOLATE_COUNT,          //< Number of interpolation methods
-};
-
-// Shortcuts for the fastest and best interpolation methods
-#define INTERPOLATE_DEFAULT INTERPOLATE_BILINEAR
-#define INTERPOLATE_FAST    INTERPOLATE_NEAREST
-#define INTERPOLATE_BEST    INTERPOLATE_BIQUADRATIC
-
 enum FillMethod {
     FILL_BLANK,         //< Fill zeroes at blank locations
     FILL_ORIGINAL,      //< Original image at blank locations
diff --git a/libavfilter/vf_lenscorrection.c b/libavfilter/vf_lenscorrection.c
index f4b1676..8c3558f 100644
--- a/libavfilter/vf_lenscorrection.c
+++ b/libavfilter/vf_lenscorrection.c
@@ -32,6 +32,7 @@
 
 #include "avfilter.h"
 #include "internal.h"
+#include "interpolate.h"
 #include "video.h"
 
 typedef struct LenscorrectionCtx {
@@ -41,6 +42,7 @@ typedef struct LenscorrectionCtx {
     int hsub, vsub;
     int nb_planes;
     double cx, cy, k1, k2;
+    int interpolation;
 } LenscorrectionCtx;
 
 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
@@ -49,6 +51,10 @@ static const AVOption lenscorrection_options[] = {
     { "cy",     "set relative center y", offsetof(LenscorrectionCtx, cy), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 1, .flags=FLAGS },
     { "k1",     "set quadratic distortion factor", offsetof(LenscorrectionCtx, k1), AV_OPT_TYPE_DOUBLE, {.dbl=0.0}, -1, 1, .flags=FLAGS },
     { "k2",     "set double quadratic distortion factor", offsetof(LenscorrectionCtx, k2), AV_OPT_TYPE_DOUBLE, {.dbl=0.0}, -1, 1, .flags=FLAGS },
+    { "interpolation", "set interpolation", offsetof(LenscorrectionCtx, interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_DEFAULT}, 0, INTERPOLATE_COUNT-1, FLAGS, "interpolation" },
+    {      "nearest"  , "", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_NEAREST},     0, 0, FLAGS, "interpolation" },
+    {      "linear"   , "", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_BILINEAR},    0, 0, FLAGS, "interpolation" },
+    {      "quadratic", "", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_BIQUADRATIC}, 0, 0, FLAGS, "interpolation" },
     { NULL }
 };
 
@@ -60,15 +66,17 @@ typedef struct ThreadData {
     int plane;
     float xcenter, ycenter;
     float k1, k2;
+    enum InterpolateMethod interpolation_method;
 } ThreadData;
 
 static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs)
 {
-    ThreadData *td = (ThreadData*)arg;
+    const ThreadData *td = (ThreadData*)arg;
     AVFrame *in = td->in;
     AVFrame *out = td->out;
 
     const float w = td->w, h = td->h;
+    const enum InterpolateMethod interpolation_method = td->interpolation_method;
     const float xcenter = td->xcenter;
     const float ycenter = td->ycenter;
     const float r2inv = 4.0 / (w * w + h * h);
@@ -91,10 +99,9 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs)
             const float off_x = j - xcenter;
             const float r2 = (off_x * off_x + off_y2) * r2inv;
             const float radius_mult = 1.0f + r2 * k1 + r2 * r2 * k2;
-            const int x = xcenter + radius_mult * off_x + 0.5f;
-            const int y = ycenter + radius_mult * off_y + 0.5f;
-            const char isvalid = x > 0 && x < w - 1 && y > 0 && y < h - 1;
-            *out++ =  isvalid ? indata[y * inlinesize + x] : 0;
+            const float x = xcenter + radius_mult * off_x;
+            const float y = ycenter + radius_mult * off_y;
+            *out++ = interpolate(x, y, indata, w, h, inlinesize, 0, interpolation_method);
         }
     }
     return 0;
@@ -160,7 +167,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
             .ycenter = rect->cy * h,
             .k1 = rect->k1,
             .k2 = rect->k2,
-            .plane = plane};
+            .plane = plane,
+            .interpolation_method = rect->interpolation
+        };
         ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(h, ctx->graph->nb_threads));
     }
 
-- 
1.8.2



More information about the ffmpeg-devel mailing list