[FFmpeg-devel] [PATCH] avfilter: add morpho filter

Lynne dev at lynne.ee
Mon Sep 20 23:00:31 EEST 2021




Sep 20, 2021, 19:33 by onemda at gmail.com:

> Signed-off-by: Paul B Mahol <onemda at gmail.com>
> ---
>  doc/filters.texi         |  32 ++
>  libavfilter/Makefile     |   1 +
>  libavfilter/allfilters.c |   1 +
>  libavfilter/vf_morpho.c  | 865 +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 899 insertions(+)
>  create mode 100644 libavfilter/vf_morpho.c
>
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 0c45fb710d..b46556c12c 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -10225,6 +10225,7 @@ A number representing position of the first frame with respect to the telecine
>  pattern. This is to be used if the stream is cut. The default value is @code{0}.
>  @end table
>  
> + at anchor{dilation}
>  @section dilation
>  
>  Apply dilation effect to the video.
> @@ -11541,6 +11542,7 @@ value.
>  
>  @end table
>  
> + at anchor{erosion}
>  @section erosion
>  
>  Apply erosion effect to the video.
> @@ -15316,6 +15318,36 @@ Default value is 0.
>  
>  This filter supports the all above options as @ref{commands}.
>  
> + at section morpho
> +
> +This filter allows to apply main morphological grayscale transforms,
> +erode and dilate with arbitrary structures set in second input stream.
> +
> +Unlike naive implementation and much slower performance in @ref{erosion}
> +and @ref{dilation} filters, when speed is critical @code{morpho} filter
> +should be used instead.
> +
> +A description of accepted options follows,
> +
> + at table @option
> + at item mode
> +Set morphological transform to apply, can be @code{erode} or @code{dilate}.
> +Default is @code{erode}.
> +
> + at item planes
> +Set planes to filter, by default all planes except alpha are filtered.
> +
> + at item structure
> +Set which structure video frames will be processed from second input stream,
> +can be @var{first} or @var{all}. Default is @var{all}.
> + at end table
> +
> +The @code{morpho} filter also supports the @ref{framesync} options.
> +
> + at subsection Commands
> +
> +This filter supports same @ref{commands} as options.
> +
>  @section mpdecimate
>  
>  Drop frames that do not differ greatly from the previous frame in
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index 272f876c07..06e01da38e 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -350,6 +350,7 @@ OBJS-$(CONFIG_MIDEQUALIZER_FILTER)           += vf_midequalizer.o framesync.o
>  OBJS-$(CONFIG_MINTERPOLATE_FILTER)           += vf_minterpolate.o motion_estimation.o
>  OBJS-$(CONFIG_MIX_FILTER)                    += vf_mix.o framesync.o
>  OBJS-$(CONFIG_MONOCHROME_FILTER)             += vf_monochrome.o
> +OBJS-$(CONFIG_MORPHO_FILTER)                 += vf_morpho.o
>  OBJS-$(CONFIG_MPDECIMATE_FILTER)             += vf_mpdecimate.o
>  OBJS-$(CONFIG_NEGATE_FILTER)                 += vf_lut.o
>  OBJS-$(CONFIG_NLMEANS_FILTER)                += vf_nlmeans.o
> diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
> index 1283d124b8..10dfe72131 100644
> --- a/libavfilter/allfilters.c
> +++ b/libavfilter/allfilters.c
> @@ -335,6 +335,7 @@ extern const AVFilter ff_vf_midequalizer;
>  extern const AVFilter ff_vf_minterpolate;
>  extern const AVFilter ff_vf_mix;
>  extern const AVFilter ff_vf_monochrome;
> +extern const AVFilter ff_vf_morpho;
>  extern const AVFilter ff_vf_mpdecimate;
>  extern const AVFilter ff_vf_msad;
>  extern const AVFilter ff_vf_negate;
> diff --git a/libavfilter/vf_morpho.c b/libavfilter/vf_morpho.c
> new file mode 100644
> index 0000000000..46c641c4b9
> --- /dev/null
> +++ b/libavfilter/vf_morpho.c
> @@ -0,0 +1,865 @@
> +/*
> + * Copyright (c) 2016 ReneBrals
> + * Copyright (c) 2021 Paul B Mahol
> + *
> + * This file is part of FFmpeg.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in all
> + * copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> + * SOFTWARE.
> + */
> +
> +#include "avfilter.h"
> +#include "formats.h"
> +#include "internal.h"
> +#include "libavutil/intreadwrite.h"
> +#include "libavutil/imgutils.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/pixdesc.h"
> +#include "video.h"
> +#include "framesync.h"
> +
> +typedef struct IPlane {
> +    uint8_t **img;
> +    size_t W;
> +    size_t H;
> +    size_t range;
> +    int type_size;
> +
> +    void (*max)(uint8_t *c, uint8_t *a, uint8_t *b, size_t x);
> +    void (*min)(uint8_t *c, uint8_t *a, uint8_t *b, size_t x);
> +    void (*max_in_place)(uint8_t *a, uint8_t *b, size_t x);
> +    void (*min_in_place)(uint8_t *a, uint8_t *b, size_t x);
> +} IPlane;
> +
> +typedef struct LUT {
> +    uint8_t ***arr;
> +    int minR;
> +    int maxR;
> +    size_t I;
> +    size_t X;
> +    int padX;
> +} LUT;
> +
> +typedef struct chord {
> +    int x;
> +    int y;
> +    int l;
> +    int i;
> +} chord;
> +
> +typedef struct chordSet {
> +    chord *C;
> +    size_t size;
> +    size_t cap;
> +
> +    int *R;
> +    size_t Lnum;
> +
> +    int minX;
> +    int maxX;
> +    int minY;
> +    int maxY;
> +} chordSet;
> +
> +typedef struct MorphoContext {
> +    const AVClass *class;
> +    FFFrameSync fs;
> +
> +    chordSet SE[4];
> +    IPlane SEimg[4];
> +    IPlane g[4], f[4];
> +    LUT Ty[4];
> +
> +    int mode;
> +    int planes;
> +    int structures;
> +
> +    int planewidth[4];
> +    int planeheight[4];
> +    int splanewidth[4];
> +    int splaneheight[4];
> +    int depth;
> +    int type_size;
> +    int nb_planes;
> +
> +    int got_structure[4];
> +} MorphoContext;
> +
> +#define OFFSET(x) offsetof(MorphoContext, x)
> +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_RUNTIME_PARAM
> +
> +static const AVOption morpho_options[] = {
> +    { "mode",  "set morphological transform",                 OFFSET(mode),       AV_OPT_TYPE_INT,   {.i64=0}, 0,  1, FLAGS, "mode" },
> +    { "erode",  NULL,                                         0,                  AV_OPT_TYPE_CONST, {.i64=0}, 0,  0, FLAGS, "mode" },
> +    { "dilate", NULL,                                         0,                  AV_OPT_TYPE_CONST, {.i64=1}, 0,  0, FLAGS, "mode" },
> +    { "planes",  "set planes to filter",                      OFFSET(planes),     AV_OPT_TYPE_INT,   {.i64=7}, 0, 15, FLAGS },
> +    { "structure", "when to process structures",              OFFSET(structures), AV_OPT_TYPE_INT,   {.i64=1}, 0,  1, FLAGS, "str" },
> +    {   "first", "process only first structure, ignore rest", 0,                  AV_OPT_TYPE_CONST, {.i64=0}, 0,  0, FLAGS, "str" },
> +    {   "all",   "process all structure",                     0,                  AV_OPT_TYPE_CONST, {.i64=1}, 0,  0, FLAGS, "str" },
> +    { NULL }
> +};
> +
> +FRAMESYNC_DEFINE_CLASS(morpho, MorphoContext, fs);
> +
> +static int query_formats(AVFilterContext *ctx)
> +{
> +    static const enum AVPixelFormat pix_fmts[] = {
> +        AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
> +        AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
> +        AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P,
> +        AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
> +        AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
> +        AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9,
> +        AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, AV_PIX_FMT_GBRP9,
> +        AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
> +        AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
> +        AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12,
> +        AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14,
> +        AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
> +        AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
> +        AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA444P12,
> +        AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16,
> +        AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
> +        AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16,
> +        AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16,
> +        AV_PIX_FMT_NONE
> +    };
> +
> +    return ff_set_common_formats_from_list(ctx, pix_fmts);
> +}
> +
> +static void Min(uint8_t *c, uint8_t *a, uint8_t *b, size_t x)
> +{
> +    for (size_t i = 0; i < x; i++)
> +        c[i] = FFMIN(b[i], a[i]);
> +}
> +
> +static void MinInPlace(uint8_t *a, uint8_t *b, size_t x)
> +{
> +    for (size_t i = 0; i < x; i++)
> +        a[i] = FFMIN(a[i], b[i]);
> +}
> +
> +static void Max(uint8_t *c, uint8_t *a, uint8_t *b, size_t x)
> +{
> +    for (size_t i = 0; i < x; i++)
> +        c[i] = FFMAX(a[i], b[i]);
> +}
> +
> +static void MaxInPlace(uint8_t *a, uint8_t *b, size_t x)
> +{
> +    for (size_t i = 0; i < x; i++)
> +        a[i] = FFMAX(a[i], b[i]);
> +}
> +
> +static void Min16(uint8_t *cc, uint8_t *aa, uint8_t *bb, size_t x)
> +{
> +    uint16_t *a = (uint16_t *)aa;
> +    uint16_t *b = (uint16_t *)bb;
> +    uint16_t *c = (uint16_t *)cc;
> +
> +    for (size_t i = 0; i < x; i++)
> +        c[i] = FFMIN(b[i], a[i]);
> +}
> +
> +static void MinInPlace16(uint8_t *aa, uint8_t *bb, size_t x)
> +{
> +    uint16_t *a = (uint16_t *)aa;
> +    uint16_t *b = (uint16_t *)bb;
> +
> +    for (size_t i = 0; i < x; i++)
> +        a[i] = FFMIN(a[i], b[i]);
> +}
> +
> +static void Max16(uint8_t *cc, uint8_t *aa, uint8_t *bb, size_t x)
> +{
> +    uint16_t *a = (uint16_t *)aa;
> +    uint16_t *b = (uint16_t *)bb;
> +    uint16_t *c = (uint16_t *)cc;
> +
> +    for (size_t i = 0; i < x; i++)
> +        c[i] = FFMAX(a[i], b[i]);
> +}
> +
> +static void MaxInPlace16(uint8_t *aa, uint8_t *bb, size_t x)
> +{
> +    uint16_t *a = (uint16_t *)aa;
> +    uint16_t *b = (uint16_t *)bb;
> +
> +    for (size_t i = 0; i < x; i++)
> +        a[i] = FFMAX(a[i], b[i]);
> +}
>

Remove the pointless wrapper functions and remove the CamelCase
naming convention.



More information about the ffmpeg-devel mailing list