[FFmpeg-devel] [PATCH 1/2] lafi/vf_edgedetect: Move some functions to lavu/imgutils
Thilo Borgmann
thilo.borgmann at mail.de
Tue Nov 16 14:55:54 EET 2021
Hi,
shared code with vf_blurriness.c in patch 2/2.
RFC: is there a better place to put these?
-Thilo
-------------- next part --------------
From b4e3701b2ed034b8d60aeff5d5ed75e4d4332a9f Mon Sep 17 00:00:00 2001
From: Thilo Borgmann <thilo.borgmann at mail.de>
Date: Tue, 16 Nov 2021 13:35:02 +0100
Subject: [PATCH 1/2] lafi/vf_edgedetect: Move some functions to lavu/imgutils
---
libavfilter/vf_edgedetect.c | 127 +-----------------------------------
libavutil/imgutils.c | 120 ++++++++++++++++++++++++++++++++++
libavutil/imgutils.h | 63 ++++++++++++++++++
3 files changed, 186 insertions(+), 124 deletions(-)
diff --git a/libavfilter/vf_edgedetect.c b/libavfilter/vf_edgedetect.c
index 3eea34e325..9750ba5f98 100644
--- a/libavfilter/vf_edgedetect.c
+++ b/libavfilter/vf_edgedetect.c
@@ -188,127 +188,6 @@ static void gaussian_blur(AVFilterContext *ctx, int w, int h,
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
- * <ref-angle>, or more simply Gy against <ref-angle>*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)
@@ -365,7 +244,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
in->data[p], in->linesize[p]);
/* compute the 16-bits gradients and directions for the next step */
- sobel(width, height,
+ av_image_sobel(width, height,
gradients, width,
directions,width,
tmpbuf, width);
@@ -373,13 +252,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,
+ av_image_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,
+ av_image_double_threshold(edgedetect->low_u8, edgedetect->high_u8,
width, height,
out->data[p], out->linesize[p],
tmpbuf, width);
diff --git a/libavutil/imgutils.c b/libavutil/imgutils.c
index 9ab5757cf6..fdb1331077 100644
--- a/libavutil/imgutils.c
+++ b/libavutil/imgutils.c
@@ -690,3 +690,123 @@ int av_image_fill_black(uint8_t *dst_data[4], const ptrdiff_t dst_linesize[4],
return 0;
}
+
+// Internal helper for av_image_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
+ * <ref-angle>, or more simply Gy against <ref-angle>*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 av_image_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 av_image_sobel()
+// Expects zero's destination buffer
+void av_image_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 av_image_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;
+ }
+}
diff --git a/libavutil/imgutils.h b/libavutil/imgutils.h
index cb2d74728e..a0514a67f0 100644
--- a/libavutil/imgutils.h
+++ b/libavutil/imgutils.h
@@ -301,6 +301,69 @@ int av_image_fill_black(uint8_t *dst_data[4], const ptrdiff_t dst_linesize[4],
enum AVPixelFormat pix_fmt, enum AVColorRange range,
int width, int height);
+/**
+ * @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 av_image_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 av_image_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 av_image_double_threshold(int low, int high, int w, int h,
+ uint8_t *dst, int dst_linesize,
+ const uint8_t *src, int src_linesize);
+
/**
* @}
*/
--
2.20.1 (Apple Git-117)
More information about the ffmpeg-devel
mailing list