> 2021年5月10日 下午9:42,Xuewei Meng <928826...@qq.com> 写道: > > From: Xuewei Meng <xwmen...@gmail.com> > > 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 <xwmen...@gmail.com> > --- > doc/filters.texi | 20 +++++++--- > libavfilter/vf_guided.c | 104 ++++++++++++++++++++++++++++++++---------------- > 2 files changed, 85 insertions(+), 39 deletions(-) > > diff --git a/doc/filters.texi b/doc/filters.texi > index 03ca9ae..eb747cb 100644 > --- a/doc/filters.texi > +++ b/doc/filters.texi > @@ -12963,12 +12963,22 @@ Apply guided filter for edge-preserving smoothing, > dehazing and so on. > The filter accepts the following options: > @table @option > @item radius > -Set the radius in pixels. > +Set the box radius in pixels. > Allowed range is 1 to 20. Default is 3. > > @item eps > -Set regularization parameter. > -Allowed range is 0 to 1. Default is 0.1. > +Set regularization parameter (with square). > +Allowed range is 0 to 1. Default is 0.01. > + > +@item mode > +Set filter mode. Can be @code{basic} or @code{fast}. > +Default is @code{basic}. > + > +@item sub > +Set subsampling ratio. > +Allowed range is 1 to 64. > +Default is always 1 for @code{basic} value of @var{mode} option, > +and 4 for @code{fast} value of @var{mode} option. > > @item planes > Set planes to filter. Default is first only. > @@ -12987,8 +12997,8 @@ ffmpeg -i in.png -i in.png -filter_complex guided > out.png > > @item > Dehazing, structure-transferring filtering, detail enhancement with guided > filter. > -For the generation of guidance image, > -see @url{http://kaiminghe.com/publications/pami12guidedfilter.pdf}. > +For the generation of guidance image, refer to paper "Guided Image > Filtering". > +See: @url{http://kaiminghe.com/publications/pami12guidedfilter.pdf}. > @example > ffmpeg -i in.png -i guidance.png -filter_complex guided out.png > @end example > diff --git a/libavfilter/vf_guided.c b/libavfilter/vf_guided.c > index 86c0db5..230fb7b 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; > \ > } > \ > -- > 1.9.1 > > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe". >
Pushed Thanks Steven Liu _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".