From 47773f7979d77c1fcd08b57e85af1ad08d9248c8 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Wed, 12 Feb 2020 14:34:00 +0100 Subject: [PATCH] avfilter/vf_xmedian: implement percentile option --- doc/filters.texi | 5 +++++ libavfilter/vf_xmedian.c | 29 +++++++++++++++++++---------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index c2af80dd51..9fadf3687f 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -20094,6 +20094,11 @@ If number of inputs is even number, than result will be mean value between two m @item planes Set which planes to filter. Default value is @code{15}, by which all planes are processed. + +@item percentile +Set median percentile. Default value is @code{0.5}. +Default value of @code{0.5} will pick always median values, while @code{0} will pick +minimum values, and @code{1} maximum values. @end table @section xstack diff --git a/libavfilter/vf_xmedian.c b/libavfilter/vf_xmedian.c index 49ba8f44f1..52c5b060fa 100644 --- a/libavfilter/vf_xmedian.c +++ b/libavfilter/vf_xmedian.c @@ -36,8 +36,10 @@ typedef struct XMedianContext { const AVPixFmtDescriptor *desc; int nb_inputs; int planes; + float percentile; int radius; + int index; int depth; int max; int nb_planes; @@ -94,6 +96,10 @@ static av_cold int init(AVFilterContext *ctx) int ret; s->radius = s->nb_inputs / 2; + if (s->nb_inputs & 1) + s->index = s->radius * 2.f * s->percentile; + else + s->index = av_clip(s->radius * 2.f * s->percentile, 1, s->nb_inputs - 1); s->frames = av_calloc(s->nb_inputs, sizeof(*s->frames)); if (!s->frames) return AVERROR(ENOMEM); @@ -134,6 +140,7 @@ static int median_frames16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo AVFrame *out = td->out; const int nb_inputs = s->nb_inputs; const int radius = s->radius; + const int index = s->index; int values[256]; for (int p = 0; p < s->nb_planes; p++) { @@ -143,8 +150,8 @@ static int median_frames16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo if (!((1 << p) & s->planes)) { av_image_copy_plane((uint8_t *)dst, out->linesize[p], - in[0]->data[p] + slice_start * in[radius]->linesize[p], - in[0]->linesize[p], + in[radius]->data[p] + slice_start * in[radius]->linesize[p], + in[radius]->linesize[p], s->linesize[p], slice_end - slice_start); continue; } @@ -157,10 +164,10 @@ static int median_frames16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo } AV_QSORT(values, nb_inputs, int, comparei); - if (radius & 1) - dst[x] = values[radius]; + if (nb_inputs & 1) + dst[x] = values[index]; else - dst[x] = (values[radius] + values[radius - 1]) >> 1; + dst[x] = (values[index] + values[index - 1]) >> 1; } dst += out->linesize[p] / 2; @@ -178,6 +185,7 @@ static int median_frames8(AVFilterContext *ctx, void *arg, int jobnr, int nb_job AVFrame *out = td->out; const int nb_inputs = s->nb_inputs; const int radius = s->radius; + const int index = s->index; int values[256]; for (int p = 0; p < s->nb_planes; p++) { @@ -187,8 +195,8 @@ static int median_frames8(AVFilterContext *ctx, void *arg, int jobnr, int nb_job if (!((1 << p) & s->planes)) { av_image_copy_plane(dst, out->linesize[p], - in[0]->data[p] + slice_start * in[0]->linesize[p], - in[0]->linesize[p], + in[radius]->data[p] + slice_start * in[radius]->linesize[p], + in[radius]->linesize[p], s->linesize[p], slice_end - slice_start); continue; } @@ -199,10 +207,10 @@ static int median_frames8(AVFilterContext *ctx, void *arg, int jobnr, int nb_job values[i] = in[i]->data[p][y * in[i]->linesize[p] + x]; AV_QSORT(values, nb_inputs, int, comparei); - if (radius & 1) - dst[x] = values[radius]; + if (nb_inputs & 1) + dst[x] = values[index]; else - dst[x] = (values[radius] + values[radius - 1]) >> 1; + dst[x] = (values[index] + values[index - 1]) >> 1; } dst += out->linesize[p]; @@ -328,6 +336,7 @@ static int activate(AVFilterContext *ctx) static const AVOption xmedian_options[] = { { "inputs", "set number of inputs", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64=3}, 3, 255, .flags = FLAGS }, { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, .flags = FLAGS }, + { "percentile", "set percentile", OFFSET(percentile),AV_OPT_TYPE_FLOAT,{.dbl=0.5}, 0, 1, .flags = FLAGS }, { NULL }, };