From patchwork Sat Jan 23 14:33:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 25122 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id DBD4C4491C6 for ; Sat, 23 Jan 2021 17:00:20 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id AAD4168803B; Sat, 23 Jan 2021 17:00:20 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-lf1-f41.google.com (mail-lf1-f41.google.com [209.85.167.41]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id A952468088D for ; Sat, 23 Jan 2021 17:00:13 +0200 (EET) Received: by mail-lf1-f41.google.com with SMTP id o10so11615744lfl.13 for ; Sat, 23 Jan 2021 07:00:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=oiVC9XwbSXZoUa+mxN2/lnN37S368t5BxcCzgBC7Zsg=; b=k5y7c1ncKCpbaEoIjfRdKUDXIDP/16Z+3cxrsImFXBrcUbPL58JevrPoSoT1e4NQyN KF6qcJ1sQXNnrxFP3P52/t7Mi/5YZJUZXxqZs9OJOYn1KHrKdX4lBXGhCwMaH0SKTDIc KGdakh4k2wjdN/U6g+jOYrBauXrR+R+4FHtYOiW+rGoLrI9+kBmBSIDw4hH9Qq3H/ZS5 p174GyYjY4BrgOwnKIKIFbq/AH28jnCtGydxIwRQZJ4Wy+3OlB7/z2Ot661EfQ1XC4RZ /esjMACEr2jGJH0K8SOhr1xtz3Wfyc9/+lViR6/yViEVtY5izOZkj3DGvkn6rAEbEV1S Qezg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=oiVC9XwbSXZoUa+mxN2/lnN37S368t5BxcCzgBC7Zsg=; b=TPwmmXvZJfwYrsjOIazXo2HXeEU585mI67+W5Xv/yOg5EEVuUtUqxH2JeFegWhBKBn 5Giga6wwBH/Ufic63LMiPMdoRTvsQt/7X1MV2UmZygzyZWLy355ix88k78sCXrSbYKP7 oteFSC0IICVNAaXmMGMKI3USiMBz2Jndv9WIGB97flFUYQn0mVSUYcsY39CQVscSbyXG DBvRQnSFAAglleD9J21kYvPuEi0QwTbcxXFC55W8enUG3fAvgiDlIPbRpX7cQxIcbzrz N0SA/3JXSnzHIfxLeWPTmDzpCVWFvNnEe6ZdVb5E/LS70FvMFUMBqH/9TJjaJT1j+tI2 IOCg== X-Gm-Message-State: AOAM533GmbjRUyWoln0SIAxZI09V6NJgf8NXS08UDR40PxmSBjW2BCrV e82wvmzX8s9gJfIUmJ5v9QeVBD21vn0= X-Google-Smtp-Source: ABdhPJxdTd2m34CDt6QhLO/tyBJcrGVNy9I9o8fIHHhPFYJk1YQjXlfNuj/Wj7Tw86X2D4Zmtd1c0A== X-Received: by 2002:a50:d88c:: with SMTP id p12mr321595edj.370.1611412431793; Sat, 23 Jan 2021 06:33:51 -0800 (PST) Received: from localhost.localdomain ([31.45.254.141]) by smtp.gmail.com with ESMTPSA id j25sm7376807edy.13.2021.01.23.06.33.50 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 23 Jan 2021 06:33:51 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Sat, 23 Jan 2021 15:33:43 +0100 Message-Id: <20210123143343.2476-1-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH] avfilter: add kirsch video filter X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- doc/filters.texi | 21 ++++++ libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/vf_convolution.c | 133 +++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+) diff --git a/doc/filters.texi b/doc/filters.texi index c2d7bac51d..00f5d38406 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -13396,6 +13396,27 @@ kerndeint=map=1 @end example @end itemize +@section kirsch +Apply kirsch operator to input video stream. + +The filter accepts the following option: + +@table @option +@item planes +Set which planes will be processed, unprocessed planes will be copied. +By default value 0xf, all planes will be processed. + +@item scale +Set value which will be multiplied with filtered result. + +@item delta +Set value which will be added to filtered result. +@end table + +@subsection Commands + +This filter supports the all above options as @ref{commands}. + @section lagfun Slowly update darker pixels. diff --git a/libavfilter/Makefile b/libavfilter/Makefile index b930a00d8b..fbb4e29bd0 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -298,6 +298,7 @@ OBJS-$(CONFIG_INFLATE_FILTER) += vf_neighbor.o OBJS-$(CONFIG_INTERLACE_FILTER) += vf_tinterlace.o OBJS-$(CONFIG_INTERLEAVE_FILTER) += f_interleave.o OBJS-$(CONFIG_KERNDEINT_FILTER) += vf_kerndeint.o +OBJS-$(CONFIG_KIRSCH_FILTER) += vf_convolution.o OBJS-$(CONFIG_LAGFUN_FILTER) += vf_lagfun.o OBJS-$(CONFIG_LENSCORRECTION_FILTER) += vf_lenscorrection.o OBJS-$(CONFIG_LENSFUN_FILTER) += vf_lensfun.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 616962690b..d9d36554c4 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -283,6 +283,7 @@ extern AVFilter ff_vf_inflate; extern AVFilter ff_vf_interlace; extern AVFilter ff_vf_interleave; extern AVFilter ff_vf_kerndeint; +extern AVFilter ff_vf_kirsch; extern AVFilter ff_vf_lagfun; extern AVFilter ff_vf_lenscorrection; extern AVFilter ff_vf_lensfun; diff --git a/libavfilter/vf_convolution.c b/libavfilter/vf_convolution.c index c238dae925..7b655ae25b 100644 --- a/libavfilter/vf_convolution.c +++ b/libavfilter/vf_convolution.c @@ -159,6 +159,55 @@ static void filter16_sobel(uint8_t *dstp, int width, } } +static void filter16_kirsch(uint8_t *dstp, int width, + float scale, float delta, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) +{ + uint16_t *dst = (uint16_t *)dstp; + const uint16_t *c0 = (const uint16_t *)c[0], *c1 = (const uint16_t *)c[1], *c2 = (const uint16_t *)c[2]; + const uint16_t *c3 = (const uint16_t *)c[3], *c5 = (const uint16_t *)c[5]; + const uint16_t *c6 = (const uint16_t *)c[6], *c7 = (const uint16_t *)c[7], *c8 = (const uint16_t *)c[8]; + int x; + + for (x = 0; x < width; x++) { + int sum0 = c0[x] * 5 + c1[x] * 5 + c2[x] * 5 + + c3[x] * -3 + c5[x] * -3 + + c6[x] * -3 + c7[x] * -3 + c8[x] * -3; + int sum1 = c0[x] * -3 + c1[x] * 5 + c2[x] * 5 + + c3[x] * 5 + c5[x] * -3 + + c6[x] * -3 + c7[x] * -3 + c8[x] * -3; + int sum2 = c0[x] * -3 + c1[x] * -3 + c2[x] * 5 + + c3[x] * 5 + c5[x] * 5 + + c6[x] * -3 + c7[x] * -3 + c8[x] * -3; + int sum3 = c0[x] * -3 + c1[x] * -3 + c2[x] * -3 + + c3[x] * 5 + c5[x] * 5 + + c6[x] * 5 + c7[x] * -3 + c8[x] * -3; + int sum4 = c0[x] * -3 + c1[x] * -3 + c2[x] * -3 + + c3[x] * -3 + c5[x] * 5 + + c6[x] * 5 + c7[x] * 5 + c8[x] * -3; + int sum5 = c0[x] * -3 + c1[x] * -3 + c2[x] * -3 + + c3[x] * -3 + c5[x] * -3 + + c6[x] * 5 + c7[x] * 5 + c8[x] * 5; + int sum6 = c0[x] * 5 + c1[x] * -3 + c2[x] * -3 + + c3[x] * -3 + c5[x] * -3 + + c6[x] * -3 + c7[x] * 5 + c8[x] * 5; + int sum7 = c0[x] * 5 + c1[x] * 5 + c2[x] * -3 + + c3[x] * -3 + c5[x] * -3 + + c6[x] * -3 + c7[x] * -3 + c8[x] * 5; + + sum0 = FFMAX(sum0, sum1); + sum2 = FFMAX(sum2, sum3); + sum4 = FFMAX(sum4, sum5); + sum6 = FFMAX(sum6, sum7); + sum0 = FFMAX(sum0, sum2); + sum4 = FFMAX(sum4, sum6); + sum0 = FFMAX(sum0, sum4); + + dst[x] = av_clip(FFABS(sum0) * scale + delta, 0, peak); + } +} + static void filter_prewitt(uint8_t *dst, int width, float scale, float delta, const int *const matrix, const uint8_t *c[], int peak, int radius, @@ -214,6 +263,54 @@ static void filter_sobel(uint8_t *dst, int width, } } +static void filter_kirsch(uint8_t *dst, int width, + float scale, float delta, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) +{ + const uint8_t *c0 = c[0], *c1 = c[1], *c2 = c[2]; + const uint8_t *c3 = c[3], *c5 = c[5]; + const uint8_t *c6 = c[6], *c7 = c[7], *c8 = c[8]; + int x; + + for (x = 0; x < width; x++) { + int sum0 = c0[x] * 5 + c1[x] * 5 + c2[x] * 5 + + c3[x] * -3 + c5[x] * -3 + + c6[x] * -3 + c7[x] * -3 + c8[x] * -3; + int sum1 = c0[x] * -3 + c1[x] * 5 + c2[x] * 5 + + c3[x] * 5 + c5[x] * -3 + + c6[x] * -3 + c7[x] * -3 + c8[x] * -3; + int sum2 = c0[x] * -3 + c1[x] * -3 + c2[x] * 5 + + c3[x] * 5 + c5[x] * 5 + + c6[x] * -3 + c7[x] * -3 + c8[x] * -3; + int sum3 = c0[x] * -3 + c1[x] * -3 + c2[x] * -3 + + c3[x] * 5 + c5[x] * 5 + + c6[x] * 5 + c7[x] * -3 + c8[x] * -3; + int sum4 = c0[x] * -3 + c1[x] * -3 + c2[x] * -3 + + c3[x] * -3 + c5[x] * 5 + + c6[x] * 5 + c7[x] * 5 + c8[x] * -3; + int sum5 = c0[x] * -3 + c1[x] * -3 + c2[x] * -3 + + c3[x] * -3 + c5[x] * -3 + + c6[x] * 5 + c7[x] * 5 + c8[x] * 5; + int sum6 = c0[x] * 5 + c1[x] * -3 + c2[x] * -3 + + c3[x] * -3 + c5[x] * -3 + + c6[x] * -3 + c7[x] * 5 + c8[x] * 5; + int sum7 = c0[x] * 5 + c1[x] * 5 + c2[x] * -3 + + c3[x] * -3 + c5[x] * -3 + + c6[x] * -3 + c7[x] * -3 + c8[x] * 5; + + sum0 = FFMAX(sum0, sum1); + sum2 = FFMAX(sum2, sum3); + sum4 = FFMAX(sum4, sum5); + sum6 = FFMAX(sum6, sum7); + sum0 = FFMAX(sum0, sum2); + sum4 = FFMAX(sum4, sum6); + sum0 = FFMAX(sum0, sum4); + + dst[x] = av_clip_uint8(FFABS(sum0) * scale + delta); + } +} + static void filter16_3x3(uint8_t *dstp, int width, float rdiv, float bias, const int *const matrix, const uint8_t *c[], int peak, int radius, @@ -604,6 +701,10 @@ static int config_input(AVFilterLink *inlink) if (s->depth > 8) for (p = 0; p < s->nb_planes; p++) s->filter[p] = filter16_sobel; + } else if (!strcmp(ctx->filter->name, "kirsch")) { + if (s->depth > 8) + for (p = 0; p < s->nb_planes; p++) + s->filter[p] = filter16_kirsch; } return 0; @@ -744,6 +845,17 @@ static av_cold int init(AVFilterContext *ctx) s->rdiv[i] = s->scale; s->bias[i] = s->delta; } + } else if (!strcmp(ctx->filter->name, "kirsch")) { + for (i = 0; i < 4; i++) { + if ((1 << i) & s->planes) + s->filter[i] = filter_kirsch; + else + s->copy[i] = 1; + s->size[i] = 3; + s->setup[i] = setup_3x3; + s->rdiv[i] = s->scale; + s->bias[i] = s->delta; + } } return 0; @@ -864,4 +976,25 @@ AVFilter ff_vf_roberts = { }; #endif /* CONFIG_ROBERTS_FILTER */ + +#if CONFIG_KIRSCH_FILTER + +#define kirsch_options prewitt_roberts_sobel_options +AVFILTER_DEFINE_CLASS(kirsch); + +AVFilter ff_vf_kirsch = { + .name = "kirsch", + .description = NULL_IF_CONFIG_SMALL("Apply kirsch operator."), + .priv_size = sizeof(ConvolutionContext), + .priv_class = &kirsch_class, + .init = init, + .query_formats = query_formats, + .inputs = convolution_inputs, + .outputs = convolution_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, + .process_command = process_command, +}; + +#endif /* CONFIG_KIRSCH_FILTER */ + #endif /* CONFIG_PREWITT_FILTER || CONFIG_ROBERTS_FILTER || CONFIG_SOBEL_FILTER */