diff --git a/doc/filters.texi b/doc/filters.texi index 86feebccdc..f59926a05e 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -3219,7 +3219,7 @@ curves=psfile='MyCurvesPresets/purple.asv':green='0.45/0.53' Denoise frames using 2D DCT (frequency domain filtering). -This filter is not designed for real time and can be extremely slow. +This filter is not designed for real time. The filter accepts the following options: @@ -3235,14 +3235,14 @@ If you need a more advanced filtering, see @option{expr}. Default is @code{0}. @item overlap -Set number overlapping pixels for each block. Each block is of size -@code{16x16}. Since the filter can be slow, you may want to reduce this value, -at the cost of a less effective filter and the risk of various artefacts. +Set number overlapping pixels for each block. Since the filter can be slow, you +may want to reduce this value, at the cost of a less effective filter and the +risk of various artefacts. If the overlapping value doesn't allow to process the whole input width or height, a warning will be displayed and according borders won't be denoised. -Default value is @code{15}. +Default value is @var{blocksize}-1, which is the best possible setting. @item expr, e Set the coefficient factor expression. @@ -3254,6 +3254,15 @@ If this is option is set, the @option{sigma} option will be ignored. The absolute value of the coefficient can be accessed through the @var{c} variable. + +@item n +Set the @var{blocksize} using the number of bits. @code{1<<@var{n}} defines the +@var{blocksize}, which is the width and height of the processed blocks. + +The default value is @var{3} (8x8) and can be raised to @var{4} for a +@var{blocksize} of 16x16. Note that changing this setting has huge consequences +on the speed processing. Also, a larger block size does not necessarily means a +better de-noising. @end table @subsection Examples @@ -3268,6 +3277,11 @@ The same operation can be achieved using the expression system: dctdnoiz=e='gte(c, 4.5*3)' @end example +Violent denoise using a block size of @code{16x16}: +@example +dctdnoiz=15:n=4 +@end example + @anchor{decimate} @section decimate diff --git a/libavfilter/version.h b/libavfilter/version.h index 1a43dc51a9..dfc305b4ed 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -31,7 +31,7 @@ #define LIBAVFILTER_VERSION_MAJOR 4 #define LIBAVFILTER_VERSION_MINOR 11 -#define LIBAVFILTER_VERSION_MICRO 102 +#define LIBAVFILTER_VERSION_MICRO 103 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ LIBAVFILTER_VERSION_MINOR, \ diff --git a/libavfilter/vf_dctdnoiz.c b/libavfilter/vf_dctdnoiz.c index 45cd476930..1e2d2b7ac9 100644 --- a/libavfilter/vf_dctdnoiz.c +++ b/libavfilter/vf_dctdnoiz.c @@ -19,7 +19,7 @@ */ /** - * A simple, relatively efficient and extremely slow DCT image denoiser. + * A simple, relatively efficient and slow DCT image denoiser. * * @see http://www.ipol.im/pub/art/2011/ys-dct/ * @@ -28,14 +28,12 @@ * Tasche (DOI: 10.1016/j.laa.2004.07.015). */ +#include "libavutil/avassert.h" #include "libavutil/eval.h" #include "libavutil/opt.h" #include "drawutils.h" #include "internal.h" -#define NBITS 4 -#define BSIZE (1<<(NBITS)) - static const char *const var_names[] = { "c", NULL }; enum { VAR_C, VAR_VARS_NB }; @@ -55,32 +53,122 @@ typedef struct DCTdnoizContext { float *weights; // dct coeff are cumulated with overlapping; these values are used for averaging int p_linesize; // line sizes for color and weights int overlap; // number of block overlapping pixels - int step; // block step increment (BSIZE - overlap) + int step; // block step increment (blocksize - overlap) + int n; // 1<th); \ +} \ + \ +static void filter_freq_expr_##bsize(DCTdnoizContext *s, \ + const float *src, int src_linesize, \ + float *dst, int dst_linesize) \ +{ \ + filter_freq_##bsize(src, src_linesize, dst, dst_linesize, s->expr, s->var_values, 0); \ } -static void filter_freq_sigma(DCTdnoizContext *s, - const float *src, int src_linesize, - float *dst, int dst_linesize) -{ - filter_freq(src, src_linesize, dst, dst_linesize, NULL, NULL, s->th); -} - -static void filter_freq_expr(DCTdnoizContext *s, - const float *src, int src_linesize, - float *dst, int dst_linesize) -{ - filter_freq(src, src_linesize, dst, dst_linesize, s->expr, s->var_values, 0); -} +DEF_FILTER_FREQ_FUNCS(8) +DEF_FILTER_FREQ_FUNCS(16) static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; DCTdnoizContext *s = ctx->priv; int i, x, y, bx, by, linesize, *iweights; + const int bsize = 1 << s->n; const float dct_3x3[3][3] = { { 1./sqrt(3), 1./sqrt(3), 1./sqrt(3) }, { 1./sqrt(2), 0, -1./sqrt(2) }, @@ -317,8 +410,8 @@ static int config_input(AVFilterLink *inlink) for (x = 0; x < 3; x++) s->color_dct[y][x] = dct_3x3[rgba_map[y]][rgba_map[x]]; - s->pr_width = inlink->w - (inlink->w - BSIZE) % s->step; - s->pr_height = inlink->h - (inlink->h - BSIZE) % s->step; + s->pr_width = inlink->w - (inlink->w - bsize) % s->step; + s->pr_height = inlink->h - (inlink->h - bsize) % s->step; if (s->pr_width != inlink->w) av_log(ctx, AV_LOG_WARNING, "The last %d horizontal pixels won't be denoised\n", inlink->w - s->pr_width); @@ -341,10 +434,10 @@ static int config_input(AVFilterLink *inlink) iweights = av_calloc(s->pr_height, linesize * sizeof(*iweights)); if (!iweights) return AVERROR(ENOMEM); - for (y = 0; y < s->pr_height - BSIZE + 1; y += s->step) - for (x = 0; x < s->pr_width - BSIZE + 1; x += s->step) - for (by = 0; by < BSIZE; by++) - for (bx = 0; bx < BSIZE; bx++) + for (y = 0; y < s->pr_height - bsize + 1; y += s->step) + for (x = 0; x < s->pr_width - bsize + 1; x += s->step) + for (by = 0; by < bsize; by++) + for (bx = 0; bx < bsize; bx++) iweights[(y + by)*linesize + x + bx]++; for (y = 0; y < s->pr_height; y++) for (x = 0; x < s->pr_width; x++) @@ -358,18 +451,37 @@ static av_cold int init(AVFilterContext *ctx) { DCTdnoizContext *s = ctx->priv; + s->bsize = 1 << s->n; + if (s->overlap == -1) + s->overlap = s->bsize - 1; + + if (s->overlap > s->bsize - 1) { + av_log(s, AV_LOG_ERROR, "Overlap value can not except %d " + "with a block size of %dx%d\n", + s->bsize - 1, s->bsize, s->bsize); + return AVERROR(EINVAL); + } + if (s->expr_str) { int ret = av_expr_parse(&s->expr, s->expr_str, var_names, NULL, NULL, NULL, NULL, 0, ctx); if (ret < 0) return ret; - s->filter_freq_func = filter_freq_expr; + switch (s->n) { + case 3: s->filter_freq_func = filter_freq_expr_8; break; + case 4: s->filter_freq_func = filter_freq_expr_16; break; + default: av_assert0(0); + } } else { - s->filter_freq_func = filter_freq_sigma; + switch (s->n) { + case 3: s->filter_freq_func = filter_freq_sigma_8; break; + case 4: s->filter_freq_func = filter_freq_sigma_16; break; + default: av_assert0(0); + } } s->th = s->sigma * 3.; - s->step = BSIZE - s->overlap; + s->step = s->bsize - s->overlap; return 0; } @@ -445,8 +557,8 @@ static void filter_plane(AVFilterContext *ctx, memset(dst, 0, h * dst_linesize * sizeof(*dst)); // block dct sums - for (y = 0; y < h - BSIZE + 1; y += s->step) { - for (x = 0; x < w - BSIZE + 1; x += s->step) + for (y = 0; y < h - s->bsize + 1; y += s->step) { + for (x = 0; x < w - s->bsize + 1; x += s->step) s->filter_freq_func(s, src + x, src_linesize, dst + x, dst_linesize); src += s->step * src_linesize;