From patchwork Tue Nov 30 13:12:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thilo Borgmann X-Patchwork-Id: 31845 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:d206:0:0:0:0:0 with SMTP id q6csp7629022iob; Tue, 30 Nov 2021 05:13:07 -0800 (PST) X-Google-Smtp-Source: ABdhPJwbDsYhIq7dUSkVXgRBirONjftq8XN1ii07Yd5eQBJCN/ZUSB9+Tzf5wmAOvXCSKHORkG0u X-Received: by 2002:aa7:c301:: with SMTP id l1mr83432571edq.20.1638277986793; Tue, 30 Nov 2021 05:13:06 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1638277986; cv=none; d=google.com; s=arc-20160816; b=LDcERo4CjgGG0TtTMRDSTHn8Rw+p6xjA/LHU8Cp76vA3i8F8vx1RYpayAQmunAVcVC AR+Eej+BPmubo3BODt69Hb9ZVH/pwpuRIW2kPNiOSJxMDTzaShahFSry8UMcpC62CCL1 JDsUJeoeW9S2vOdR37W/xOwHzswPHsmUTyzq1VpdFRt7RUuPGZkUdPDdYSCf4wDNXhz6 sgWw55Lq6vxUkkNzCe7MRmiZ40Bp83qr3WxXgZcH/GKnISAmA9cXHLMdZuO5Ft11HCPS /oNj4o0oR4gbP71+bRpYELsCBXTsKc+9LuhD+k+gGPElcUg3tg7puwdYAPFgC4IA9fUG FLbA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject :content-language:mime-version:date:message-id:from:to :dkim-signature:delivered-to; bh=lx0xhUyinXAxUwSFwIZCOSgw4RYI2kZEY17pGBVkf/8=; b=i53rq1G3evFEE6x24f5JhfuM5J7wzpPxjDLPoJS4P3nbfbCtAnyl/ft7vr4lwxM9hY fqcBYgLm8U4l7V+BSGGTTnOjeSdrRPbB4ytksUTceEQSEv4lvnzeh8rZcYpKN7JnoQ8t dHirNNADX7fXpbpC6CNjNIWZYqMSToVm7m2KUs3h/XuyGcPeARLb3oOIj0CZqLX4/A4V m4F/pw0djBL+Ui00NXGu/LTqqdfWGIjOAA7QN4V0efGP4+AI+YClfgb+97/LOB3ZhPr1 imVAdZLdMiVoRSI7APU7Vlo5uUKEP/ohC2Hf3k7RRMNpvu4/qKGgiMsHOCtt/+JIHtRJ kRZA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@mail.de header.s=mailde202009 header.b=IkkVsaO6; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=mail.de Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id aq9si26293533ejc.340.2021.11.30.05.13.06; Tue, 30 Nov 2021 05:13:06 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@mail.de header.s=mailde202009 header.b=IkkVsaO6; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=mail.de Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 68D4D68AE4A; Tue, 30 Nov 2021 15:13:03 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from shout02.mail.de (shout02.mail.de [62.201.172.25]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id D899268AC75 for ; Tue, 30 Nov 2021 15:12:56 +0200 (EET) Received: from postfix01.mail.de (postfix01.bt.mail.de [10.0.121.125]) by shout02.mail.de (Postfix) with ESMTP id 54C06A38D1 for ; Tue, 30 Nov 2021 14:12:56 +0100 (CET) Received: from smtp02.mail.de (smtp02.bt.mail.de [10.0.121.212]) by postfix01.mail.de (Postfix) with ESMTP id 38AD58015B for ; Tue, 30 Nov 2021 14:12:56 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=mail.de; s=mailde202009; t=1638277976; bh=tRMgEZEfKDUQMgzbmYFmLdGkBG6yGt5fJiKEczoG6iM=; h=To:From:Subject:Date:From; b=IkkVsaO6Q2OAkjywQleNfo0XSX4q/4zrJoyv//nT2qpsRP9PxEye8VxvonKVr2oIZ ucDmlieQi/zmv+7QoEUbLC4gZIh0w1RFU6ULdFaMIP6wfgRzKDWE/PPpLP8VD2nLuA NfOOJH+JoTDzbxj1LRB+eeofg4nARyg6yqz42k/LKDC25krjylqr40ab62Ipf7MfEp FfyLGvbe1oq5Pa7oUh6rW4lW6CsUrfiPbIiRgxG/Tgre19/Dpw9ZsmFt9ba2B/FFSF fcrwsd8TQUT12umTsOIacasdyMTclwxuXjGDMJmdHVS/ItYT7vlyMWuyfzXcrWImWd cADxIaX9YRG+w== Received: from [127.0.0.1] (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by smtp02.mail.de (Postfix) with ESMTPSA id 04264A0299 for ; Tue, 30 Nov 2021 14:12:55 +0100 (CET) To: FFmpeg development discussions and patches From: Thilo Borgmann Message-ID: Date: Tue, 30 Nov 2021 14:12:55 +0100 MIME-Version: 1.0 Content-Language: en-US X-purgate: clean X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate-type: clean X-purgate-Ad: Categorized by eleven eXpurgate (R) http://www.eleven.de X-purgate: This mail is considered clean (visit http://www.eleven.de for further information) X-purgate: clean X-purgate-size: 29820 X-purgate-ID: 154282::1638277976-0000429D-63451031/0/0 Subject: [FFmpeg-devel] [PATCH 1/2] lafi/vf_edgedetect: Move some common functions into seperate file X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 5CU+y5yELcE6 Hi, v2, common functions moved into lavfi/edge_common.{c,h}. Also moved gaussian_blur() into the same. -Thilo From 0599b15e109cd6d0e1452663eb45b8b70b428444 Mon Sep 17 00:00:00 2001 From: Thilo Borgmann Date: Tue, 30 Nov 2021 00:16:52 +0100 Subject: [PATCH 1/2] lafi/vf_edgedetect: Move some common functions into seperate file --- libavfilter/Makefile | 2 +- libavfilter/edge_common.c | 181 +++++++++++++++++++++++++++++++++++ libavfilter/edge_common.h | 107 +++++++++++++++++++++ libavfilter/vf_edgedetect.c | 183 ++---------------------------------- 4 files changed, 296 insertions(+), 177 deletions(-) create mode 100644 libavfilter/edge_common.c create mode 100644 libavfilter/edge_common.h diff --git a/libavfilter/Makefile b/libavfilter/Makefile index 08edc92d8c..1b559539ba 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -258,7 +258,7 @@ OBJS-$(CONFIG_DRAWBOX_FILTER) += vf_drawbox.o OBJS-$(CONFIG_DRAWGRAPH_FILTER) += f_drawgraph.o OBJS-$(CONFIG_DRAWGRID_FILTER) += vf_drawbox.o OBJS-$(CONFIG_DRAWTEXT_FILTER) += vf_drawtext.o -OBJS-$(CONFIG_EDGEDETECT_FILTER) += vf_edgedetect.o +OBJS-$(CONFIG_EDGEDETECT_FILTER) += vf_edgedetect.o edge_common.o OBJS-$(CONFIG_ELBG_FILTER) += vf_elbg.o OBJS-$(CONFIG_ENTROPY_FILTER) += vf_entropy.o OBJS-$(CONFIG_EPX_FILTER) += vf_epx.o diff --git a/libavfilter/edge_common.c b/libavfilter/edge_common.c new file mode 100644 index 0000000000..d72e8521cd --- /dev/null +++ b/libavfilter/edge_common.c @@ -0,0 +1,181 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "edge_common.h" + +// Internal helper for ff_sobel() +static int get_rounded_direction(int gx, int gy) +{ + /* reference angles: + * tan( pi/8) = sqrt(2)-1 + * tan(3pi/8) = sqrt(2)+1 + * Gy/Gx is the tangent of the angle (theta), so Gy/Gx is compared against + * , or more simply Gy against *Gx + * + * Gx and Gy bounds = [-1020;1020], using 16-bit arithmetic: + * round((sqrt(2)-1) * (1<<16)) = 27146 + * round((sqrt(2)+1) * (1<<16)) = 158218 + */ + if (gx) { + int tanpi8gx, tan3pi8gx; + + if (gx < 0) + gx = -gx, gy = -gy; + gy *= (1 << 16); + tanpi8gx = 27146 * gx; + tan3pi8gx = 158218 * gx; + if (gy > -tan3pi8gx && gy < -tanpi8gx) return DIRECTION_45UP; + if (gy > -tanpi8gx && gy < tanpi8gx) return DIRECTION_HORIZONTAL; + if (gy > tanpi8gx && gy < tan3pi8gx) return DIRECTION_45DOWN; + } + return DIRECTION_VERTICAL; +} + +// Simple sobel operator to get rounded gradients +void ff_sobel(int w, int h, + uint16_t *dst, int dst_linesize, + int8_t *dir, int dir_linesize, + const uint8_t *src, int src_linesize) +{ + int i, j; + + for (j = 1; j < h - 1; j++) { + dst += dst_linesize; + dir += dir_linesize; + src += src_linesize; + for (i = 1; i < w - 1; i++) { + const int gx = + -1*src[-src_linesize + i-1] + 1*src[-src_linesize + i+1] + -2*src[ i-1] + 2*src[ i+1] + -1*src[ src_linesize + i-1] + 1*src[ src_linesize + i+1]; + const int gy = + -1*src[-src_linesize + i-1] + 1*src[ src_linesize + i-1] + -2*src[-src_linesize + i ] + 2*src[ src_linesize + i ] + -1*src[-src_linesize + i+1] + 1*src[ src_linesize + i+1]; + + dst[i] = FFABS(gx) + FFABS(gy); + dir[i] = get_rounded_direction(gx, gy); + } + } +} + +// Filters rounded gradients to drop all non-maxima +// Expects gradients generated by ff_sobel() +// Expects zero's destination buffer +void ff_non_maximum_suppression(int w, int h, + uint8_t *dst, int dst_linesize, + const int8_t *dir, int dir_linesize, + const uint16_t *src, int src_linesize) +{ + int i, j; + +#define COPY_MAXIMA(ay, ax, by, bx) do { \ + if (src[i] > src[(ay)*src_linesize + i+(ax)] && \ + src[i] > src[(by)*src_linesize + i+(bx)]) \ + dst[i] = av_clip_uint8(src[i]); \ +} while (0) + + for (j = 1; j < h - 1; j++) { + dst += dst_linesize; + dir += dir_linesize; + src += src_linesize; + for (i = 1; i < w - 1; i++) { + switch (dir[i]) { + case DIRECTION_45UP: COPY_MAXIMA( 1, -1, -1, 1); break; + case DIRECTION_45DOWN: COPY_MAXIMA(-1, -1, 1, 1); break; + case DIRECTION_HORIZONTAL: COPY_MAXIMA( 0, -1, 0, 1); break; + case DIRECTION_VERTICAL: COPY_MAXIMA(-1, 0, 1, 0); break; + } + } + } +} + +// Filter to keep all pixels > high, and keep all pixels > low where all surrounding pixels > high +void ff_double_threshold(int low, int high, int w, int h, + uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize) +{ + int i, j; + + for (j = 0; j < h; j++) { + for (i = 0; i < w; i++) { + if (src[i] > high) { + dst[i] = src[i]; + continue; + } + + if (!(!i || i == w - 1 || !j || j == h - 1) && + src[i] > low && + (src[-src_linesize + i-1] > high || + src[-src_linesize + i ] > high || + src[-src_linesize + i+1] > high || + src[ i-1] > high || + src[ i+1] > high || + src[ src_linesize + i-1] > high || + src[ src_linesize + i ] > high || + src[ src_linesize + i+1] > high)) + dst[i] = src[i]; + else + dst[i] = 0; + } + dst += dst_linesize; + src += src_linesize; + } +} + +// Applies gaussian blur, using 5x5 kernels, sigma = 1.4 +void ff_gaussian_blur(int w, int h, + uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize) +{ + int i, j; + + memcpy(dst, src, w); dst += dst_linesize; src += src_linesize; + memcpy(dst, src, w); dst += dst_linesize; src += src_linesize; + for (j = 2; j < h - 2; j++) { + dst[0] = src[0]; + dst[1] = src[1]; + for (i = 2; i < w - 2; i++) { + /* Gaussian mask of size 5x5 with sigma = 1.4 */ + dst[i] = ((src[-2*src_linesize + i-2] + src[2*src_linesize + i-2]) * 2 + + (src[-2*src_linesize + i-1] + src[2*src_linesize + i-1]) * 4 + + (src[-2*src_linesize + i ] + src[2*src_linesize + i ]) * 5 + + (src[-2*src_linesize + i+1] + src[2*src_linesize + i+1]) * 4 + + (src[-2*src_linesize + i+2] + src[2*src_linesize + i+2]) * 2 + + + (src[ -src_linesize + i-2] + src[ src_linesize + i-2]) * 4 + + (src[ -src_linesize + i-1] + src[ src_linesize + i-1]) * 9 + + (src[ -src_linesize + i ] + src[ src_linesize + i ]) * 12 + + (src[ -src_linesize + i+1] + src[ src_linesize + i+1]) * 9 + + (src[ -src_linesize + i+2] + src[ src_linesize + i+2]) * 4 + + + src[i-2] * 5 + + src[i-1] * 12 + + src[i ] * 15 + + src[i+1] * 12 + + src[i+2] * 5) / 159; + } + dst[i ] = src[i ]; + dst[i + 1] = src[i + 1]; + + dst += dst_linesize; + src += src_linesize; + } + memcpy(dst, src, w); dst += dst_linesize; src += src_linesize; + memcpy(dst, src, w); +} diff --git a/libavfilter/edge_common.h b/libavfilter/edge_common.h new file mode 100644 index 0000000000..87c143f2b8 --- /dev/null +++ b/libavfilter/edge_common.h @@ -0,0 +1,107 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common functions for edge detection + */ + +#ifndef AVFILTER_EDGE_COMMON_H +#define AVFILTER_EDGE_COMMON_H + +#include "avfilter.h" + +/** + * @brief Rounded directions used in av_image_sobel() + */ +enum AVRoundedDirection { + DIRECTION_45UP, + DIRECTION_45DOWN, + DIRECTION_HORIZONTAL, + DIRECTION_VERTICAL, +}; + +/** + * Simple sobel operator to get rounded gradients + * + * @param w the width of the image in pixels + * @param h the height of the image in pixels + * @param dst data pointers to magnitude image + * @param dst_linesize linesizes for the magnitude image + * @param dir data pointers to direction image + * @param dir_linesize linesizes for the direction image + * @param src data pointers to source image + * @param src_linesize linesizes for the source image + */ +void ff_sobel(int w, int h, + uint16_t *dst, int dst_linesize, + int8_t *dir, int dir_linesize, + const uint8_t *src, int src_linesize); + +/** + * Filters rounded gradients to drop all non-maxima pixels in the magnitude image + * Expects gradients generated by av_image_sobel() + * Expects zero's in the destination buffer dst + * + * @param w the width of the image in pixels + * @param h the height of the image in pixels + * @param dst data pointers to magnitude image + * @param dst_linesize linesizes for the magnitude image + * @param dir data pointers to direction image + * @param dir_linesize linesizes for the direction image + * @param src data pointers to source image + * @param src_linesize linesizes for the source image + */ +void ff_non_maximum_suppression(int w, int h, + uint8_t *dst, int dst_linesize, + const int8_t *dir, int dir_linesize, + const uint16_t *src, int src_linesize); + +/** + * Filters all pixels in src to keep all pixels > high, + * and keep all pixels > low where all surrounding pixels > high + * + * @param low the low threshold value + * @param high the hegh threshold value + * @param w the width of the image in pixels + * @param h the height of the image in pixels + * @param dst data pointers to destination image + * @param dst_linesize linesizes for the destination image + * @param src data pointers to source image + * @param src_linesize linesizes for the source image + */ +void ff_double_threshold(int low, int high, int w, int h, + uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize); + +/** + * Applies gaussian blur. + * 5x5 kernels, sigma = 1.4 + * + * @param w the width of the image in pixels + * @param h the height of the image in pixels + * @param dst data pointers to destination image + * @param dst_linesize linesizes for the destination image + * @param src data pointers to source image + * @param src_linesize linesizes for the source image + */ +void ff_gaussian_blur(int w, int h, + uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize); + +#endif diff --git a/libavfilter/vf_edgedetect.c b/libavfilter/vf_edgedetect.c index 3eea34e325..90390ceb3e 100644 --- a/libavfilter/vf_edgedetect.c +++ b/libavfilter/vf_edgedetect.c @@ -32,6 +32,7 @@ #include "formats.h" #include "internal.h" #include "video.h" +#include "edge_common.h" #define PLANE_R 0x4 #define PLANE_G 0x1 @@ -139,176 +140,6 @@ static int config_props(AVFilterLink *inlink) return 0; } -static void gaussian_blur(AVFilterContext *ctx, int w, int h, - uint8_t *dst, int dst_linesize, - const uint8_t *src, int src_linesize) -{ - int i, j; - - memcpy(dst, src, w); dst += dst_linesize; src += src_linesize; - if (h > 1) { - memcpy(dst, src, w); dst += dst_linesize; src += src_linesize; - } - for (j = 2; j < h - 2; j++) { - dst[0] = src[0]; - if (w > 1) - dst[1] = src[1]; - for (i = 2; i < w - 2; i++) { - /* Gaussian mask of size 5x5 with sigma = 1.4 */ - dst[i] = ((src[-2*src_linesize + i-2] + src[2*src_linesize + i-2]) * 2 - + (src[-2*src_linesize + i-1] + src[2*src_linesize + i-1]) * 4 - + (src[-2*src_linesize + i ] + src[2*src_linesize + i ]) * 5 - + (src[-2*src_linesize + i+1] + src[2*src_linesize + i+1]) * 4 - + (src[-2*src_linesize + i+2] + src[2*src_linesize + i+2]) * 2 - - + (src[ -src_linesize + i-2] + src[ src_linesize + i-2]) * 4 - + (src[ -src_linesize + i-1] + src[ src_linesize + i-1]) * 9 - + (src[ -src_linesize + i ] + src[ src_linesize + i ]) * 12 - + (src[ -src_linesize + i+1] + src[ src_linesize + i+1]) * 9 - + (src[ -src_linesize + i+2] + src[ src_linesize + i+2]) * 4 - - + src[i-2] * 5 - + src[i-1] * 12 - + src[i ] * 15 - + src[i+1] * 12 - + src[i+2] * 5) / 159; - } - if (w > 2) - dst[i ] = src[i ]; - if (w > 3) - dst[i + 1] = src[i + 1]; - - dst += dst_linesize; - src += src_linesize; - } - if (h > 2) { - memcpy(dst, src, w); dst += dst_linesize; src += src_linesize; - } - if (h > 3) - memcpy(dst, src, w); -} - -enum { - DIRECTION_45UP, - DIRECTION_45DOWN, - DIRECTION_HORIZONTAL, - DIRECTION_VERTICAL, -}; - -static int get_rounded_direction(int gx, int gy) -{ - /* reference angles: - * tan( pi/8) = sqrt(2)-1 - * tan(3pi/8) = sqrt(2)+1 - * Gy/Gx is the tangent of the angle (theta), so Gy/Gx is compared against - * , or more simply Gy against *Gx - * - * Gx and Gy bounds = [-1020;1020], using 16-bit arithmetic: - * round((sqrt(2)-1) * (1<<16)) = 27146 - * round((sqrt(2)+1) * (1<<16)) = 158218 - */ - if (gx) { - int tanpi8gx, tan3pi8gx; - - if (gx < 0) - gx = -gx, gy = -gy; - gy *= (1 << 16); - tanpi8gx = 27146 * gx; - tan3pi8gx = 158218 * gx; - if (gy > -tan3pi8gx && gy < -tanpi8gx) return DIRECTION_45UP; - if (gy > -tanpi8gx && gy < tanpi8gx) return DIRECTION_HORIZONTAL; - if (gy > tanpi8gx && gy < tan3pi8gx) return DIRECTION_45DOWN; - } - return DIRECTION_VERTICAL; -} - -static void sobel(int w, int h, - uint16_t *dst, int dst_linesize, - int8_t *dir, int dir_linesize, - const uint8_t *src, int src_linesize) -{ - int i, j; - - for (j = 1; j < h - 1; j++) { - dst += dst_linesize; - dir += dir_linesize; - src += src_linesize; - for (i = 1; i < w - 1; i++) { - const int gx = - -1*src[-src_linesize + i-1] + 1*src[-src_linesize + i+1] - -2*src[ i-1] + 2*src[ i+1] - -1*src[ src_linesize + i-1] + 1*src[ src_linesize + i+1]; - const int gy = - -1*src[-src_linesize + i-1] + 1*src[ src_linesize + i-1] - -2*src[-src_linesize + i ] + 2*src[ src_linesize + i ] - -1*src[-src_linesize + i+1] + 1*src[ src_linesize + i+1]; - - dst[i] = FFABS(gx) + FFABS(gy); - dir[i] = get_rounded_direction(gx, gy); - } - } -} - -static void non_maximum_suppression(int w, int h, - uint8_t *dst, int dst_linesize, - const int8_t *dir, int dir_linesize, - const uint16_t *src, int src_linesize) -{ - int i, j; - -#define COPY_MAXIMA(ay, ax, by, bx) do { \ - if (src[i] > src[(ay)*src_linesize + i+(ax)] && \ - src[i] > src[(by)*src_linesize + i+(bx)]) \ - dst[i] = av_clip_uint8(src[i]); \ -} while (0) - - for (j = 1; j < h - 1; j++) { - dst += dst_linesize; - dir += dir_linesize; - src += src_linesize; - for (i = 1; i < w - 1; i++) { - switch (dir[i]) { - case DIRECTION_45UP: COPY_MAXIMA( 1, -1, -1, 1); break; - case DIRECTION_45DOWN: COPY_MAXIMA(-1, -1, 1, 1); break; - case DIRECTION_HORIZONTAL: COPY_MAXIMA( 0, -1, 0, 1); break; - case DIRECTION_VERTICAL: COPY_MAXIMA(-1, 0, 1, 0); break; - } - } - } -} - -static void double_threshold(int low, int high, int w, int h, - uint8_t *dst, int dst_linesize, - const uint8_t *src, int src_linesize) -{ - int i, j; - - for (j = 0; j < h; j++) { - for (i = 0; i < w; i++) { - if (src[i] > high) { - dst[i] = src[i]; - continue; - } - - if (!(!i || i == w - 1 || !j || j == h - 1) && - src[i] > low && - (src[-src_linesize + i-1] > high || - src[-src_linesize + i ] > high || - src[-src_linesize + i+1] > high || - src[ i-1] > high || - src[ i+1] > high || - src[ src_linesize + i-1] > high || - src[ src_linesize + i ] > high || - src[ src_linesize + i+1] > high)) - dst[i] = src[i]; - else - dst[i] = 0; - } - dst += dst_linesize; - src += src_linesize; - } -} - static void color_mix(int w, int h, uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize) @@ -360,12 +191,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } /* gaussian filter to reduce noise */ - gaussian_blur(ctx, width, height, - tmpbuf, width, - in->data[p], in->linesize[p]); + ff_gaussian_blur(width, height, + tmpbuf, width, + in->data[p], in->linesize[p]); /* compute the 16-bits gradients and directions for the next step */ - sobel(width, height, + ff_sobel(width, height, gradients, width, directions,width, tmpbuf, width); @@ -373,13 +204,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) /* non_maximum_suppression() will actually keep & clip what's necessary and * ignore the rest, so we need a clean output buffer */ memset(tmpbuf, 0, width * height); - non_maximum_suppression(width, height, + ff_non_maximum_suppression(width, height, tmpbuf, width, directions,width, gradients, width); /* keep high values, or low values surrounded by high values */ - double_threshold(edgedetect->low_u8, edgedetect->high_u8, + ff_double_threshold(edgedetect->low_u8, edgedetect->high_u8, width, height, out->data[p], out->linesize[p], tmpbuf, width);