summaryrefslogtreecommitdiff
path: root/libavfilter/vf_guided.c
diff options
context:
space:
mode:
authorXuewei Meng <xwmeng96@gmail.com>2021-05-10 21:42:31 +0800
committerSteven Liu <liuqi05@kuaishou.com>2021-05-13 11:59:11 +0800
commit43d70feb788318b124418c5c666f2120ee5ca930 (patch)
tree3514a1f05abba2a701eb3b92f6bee43fa41823cd /libavfilter/vf_guided.c
parentb5ea0980c5c78df25277f9a1baf640b60184ab61 (diff)
downloadffmpeg-43d70feb788318b124418c5c666f2120ee5ca930.tar.gz
GSoC: Support fast guided filter.
Two modes are supported in guided filter, basic mode and fast mode. Basic mode is the initial pushed guided filter without optimization. Fast mode is implemented based on the basic one by sub-sampling method. The sub-sampling ratio which can be defined by users controls the algorithm complexity. The larger the sub-sampling ratio, the lower the algorithm complexity. Signed-off-by: Xuewei Meng <xwmeng96@gmail.com> Reviewed-by: Steven Liu <liuqi05@kuaishou.com>
Diffstat (limited to 'libavfilter/vf_guided.c')
-rw-r--r--libavfilter/vf_guided.c104
1 files changed, 70 insertions, 34 deletions
diff --git a/libavfilter/vf_guided.c b/libavfilter/vf_guided.c
index 20c142337a..e7c689e7be 100644
--- a/libavfilter/vf_guided.c
+++ b/libavfilter/vf_guided.c
@@ -27,12 +27,20 @@
#include "internal.h"
#include "video.h"
+enum FilterModes {
+ BASIC,
+ FAST,
+ NB_MODES,
+};
+
typedef struct GuidedContext {
const AVClass *class;
FFFrameSync fs;
int radius;
float eps;
+ int mode;
+ int sub;
int planes;
@@ -51,9 +59,13 @@ typedef struct GuidedContext {
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
static const AVOption guided_options[] = {
- { "radius", "set the box radius", OFFSET(radius), AV_OPT_TYPE_INT, {.i64=3 }, 1, 20, FLAGS },
- { "eps", "set the regularization parameter (with square)", OFFSET(eps), AV_OPT_TYPE_FLOAT, {.dbl=0.01 }, 0.0, 1, FLAGS },
- { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=1 }, 0, 0xF, FLAGS },
+ { "radius", "set the box radius", OFFSET(radius), AV_OPT_TYPE_INT, {.i64 = 3 }, 1, 20, FLAGS },
+ { "eps", "set the regularization parameter (with square)", OFFSET(eps), AV_OPT_TYPE_FLOAT, {.dbl = 0.01 }, 0.0, 1, FLAGS },
+ { "mode", "set filtering mode (0: basic mode; 1: fast mode)", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = BASIC}, 0, NB_MODES - 1, FLAGS, "mode" },
+ { "basic", "basic guided filter", 0, AV_OPT_TYPE_CONST, {.i64 = BASIC}, 0, 0, FLAGS, "mode" },
+ { "fast", "fast guided filter", 0, AV_OPT_TYPE_CONST, {.i64 = FAST }, 0, 0, FLAGS, "mode" },
+ { "sub", "subsampling ratio", OFFSET(sub), AV_OPT_TYPE_INT, {.i64 = 1 }, 1, 64, FLAGS },
+ { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=1 }, 0, 0xF, FLAGS },
{ NULL }
};
@@ -147,6 +159,26 @@ static int config_input(AVFilterLink *inlink)
return AVERROR(EINVAL);
}
+ if (s->mode == BASIC) {
+ if (s->sub != 1) {
+ av_log(ctx, AV_LOG_WARNING, "Subsampling ratio is 1 in basic mode.\n");
+ s->sub = 1;
+ }
+ }
+ else if (s->mode == FAST) {
+ if (s->sub == 1) {
+ av_log(ctx, AV_LOG_WARNING, "Subsampling ratio is larger than 1 in fast mode.\n");
+ s->sub = 4;
+ }
+ if (s->radius >= s->sub)
+ s->radius = s->radius / s->sub;
+ else {
+ s->radius = 1;
+ }
+ }
+ else {
+ return AVERROR_BUG;
+ }
s->depth = desc->comp[0].depth;
s->width = ctx->inputs[0]->w;
@@ -174,6 +206,10 @@ static int guided_##name(AVFilterContext *ctx, GuidedContext *s,
const type *src = (const type *)ssrc; \
const type *srcRef = (const type *)ssrcRef; \
\
+ int sub = s->sub; \
+ int h = (height % sub) == 0 ? height / sub : height / sub + 1; \
+ int w = (width % sub) == 0 ? width / sub : width / sub + 1; \
+ \
ThreadData t; \
const int nb_threads = ff_filter_get_nb_threads(ctx); \
float *I; \
@@ -189,55 +225,55 @@ static int guided_##name(AVFilterContext *ctx, GuidedContext *s,
float *meanA; \
float *meanB; \
\
- I = av_calloc(width * height, sizeof(float)); \
- II = av_calloc(width * height, sizeof(float)); \
- P = av_calloc(width * height, sizeof(float)); \
- IP = av_calloc(width * height, sizeof(float)); \
- meanI = av_calloc(width * height, sizeof(float)); \
- meanII = av_calloc(width * height, sizeof(float)); \
- meanP = av_calloc(width * height, sizeof(float)); \
- meanIP = av_calloc(width * height, sizeof(float)); \
+ I = av_calloc(w * h, sizeof(float)); \
+ II = av_calloc(w * h, sizeof(float)); \
+ P = av_calloc(w * h, sizeof(float)); \
+ IP = av_calloc(w * h, sizeof(float)); \
+ meanI = av_calloc(w * h, sizeof(float)); \
+ meanII = av_calloc(w * h, sizeof(float)); \
+ meanP = av_calloc(w * h, sizeof(float)); \
+ meanIP = av_calloc(w * h, sizeof(float)); \
\
- A = av_calloc(width * height, sizeof(float)); \
- B = av_calloc(width * height, sizeof(float)); \
- meanA = av_calloc(width * height, sizeof(float)); \
- meanB = av_calloc(width * height, sizeof(float)); \
+ A = av_calloc(w * h, sizeof(float)); \
+ B = av_calloc(w * h, sizeof(float)); \
+ meanA = av_calloc(w * h, sizeof(float)); \
+ meanB = av_calloc(w * h, sizeof(float)); \
\
if (!I || !II || !P || !IP || !meanI || !meanII || !meanP || \
!meanIP || !A || !B || !meanA || !meanB){ \
ret = AVERROR(ENOMEM); \
goto end; \
} \
- for (int i = 0;i < height;i++) { \
- for (int j = 0;j < width;j++) { \
- int x = i * width + j; \
- I[x] = src[i * src_stride + j] / maxval; \
+ for (int i = 0;i < h;i++) { \
+ for (int j = 0;j < w;j++) { \
+ int x = i * w + j; \
+ I[x] = src[(i * src_stride + j) * sub] / maxval; \
II[x] = I[x] * I[x]; \
- P[x] = srcRef[i * src_ref_stride + j] / maxval; \
+ P[x] = srcRef[(i * src_ref_stride + j) * sub] / maxval; \
IP[x] = I[x] * P[x]; \
} \
} \
\
- t.width = width; \
- t.height = height; \
- t.srcStride = width; \
- t.dstStride = width; \
+ t.width = w; \
+ t.height = h; \
+ t.srcStride = w; \
+ t.dstStride = w; \
t.src = I; \
t.dst = meanI; \
- ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(height, nb_threads)); \
+ ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(h, nb_threads)); \
t.src = II; \
t.dst = meanII; \
- ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(height, nb_threads)); \
+ ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(h, nb_threads)); \
t.src = P; \
t.dst = meanP; \
- ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(height, nb_threads)); \
+ ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(h, nb_threads)); \
t.src = IP; \
t.dst = meanIP; \
- ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(height, nb_threads)); \
+ ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(h, nb_threads)); \
\
- for (int i = 0;i < height;i++) { \
- for (int j = 0;j < width;j++) { \
- int x = i * width + j; \
+ for (int i = 0;i < h;i++) { \
+ for (int j = 0;j < w;j++) { \
+ int x = i * w + j; \
float varI = meanII[x] - (meanI[x] * meanI[x]); \
float covIP = meanIP[x] - (meanI[x] * meanP[x]); \
A[x] = covIP / (varI + eps); \
@@ -247,14 +283,14 @@ static int guided_##name(AVFilterContext *ctx, GuidedContext *s,
\
t.src = A; \
t.dst = meanA; \
- ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(height, nb_threads)); \
+ ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(h, nb_threads)); \
t.src = B; \
t.dst = meanB; \
- ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(height, nb_threads)); \
+ ctx->internal->execute(ctx, s->box_slice, &t, NULL, FFMIN(h, nb_threads)); \
\
for (int i = 0;i < height;i++) { \
for (int j = 0;j < width;j++) { \
- int x = i * width + j; \
+ int x = i / sub * w + j / sub; \
dst[i * dst_stride + j] = meanA[x] * src[i * src_stride + j] + \
meanB[x] * maxval; \
} \