FFmpeg
edge_common.c
Go to the documentation of this file.
1 /*
2  * This file is part of FFmpeg.
3  *
4  * FFmpeg is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * FFmpeg is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with FFmpeg; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "edge_common.h"
20 
21 // Internal helper for ff_sobel()
22 static int get_rounded_direction(int gx, int gy)
23 {
24  /* reference angles:
25  * tan( pi/8) = sqrt(2)-1
26  * tan(3pi/8) = sqrt(2)+1
27  * Gy/Gx is the tangent of the angle (theta), so Gy/Gx is compared against
28  * <ref-angle>, or more simply Gy against <ref-angle>*Gx
29  *
30  * Gx and Gy bounds = [-1020;1020], using 16-bit arithmetic:
31  * round((sqrt(2)-1) * (1<<16)) = 27146
32  * round((sqrt(2)+1) * (1<<16)) = 158218
33  */
34  if (gx) {
35  int tanpi8gx, tan3pi8gx;
36 
37  if (gx < 0)
38  gx = -gx, gy = -gy;
39  gy *= (1 << 16);
40  tanpi8gx = 27146 * gx;
41  tan3pi8gx = 158218 * gx;
42  if (gy > -tan3pi8gx && gy < -tanpi8gx) return DIRECTION_45UP;
43  if (gy > -tanpi8gx && gy < tanpi8gx) return DIRECTION_HORIZONTAL;
44  if (gy > tanpi8gx && gy < tan3pi8gx) return DIRECTION_45DOWN;
45  }
46  return DIRECTION_VERTICAL;
47 }
48 
49 // Simple sobel operator to get rounded gradients
50 void ff_sobel(int w, int h,
51  uint16_t *dst, int dst_linesize,
52  int8_t *dir, int dir_linesize,
53  const uint8_t *src, int src_linesize)
54 {
55  int i, j;
56 
57  for (j = 1; j < h - 1; j++) {
58  dst += dst_linesize;
59  dir += dir_linesize;
60  src += src_linesize;
61  for (i = 1; i < w - 1; i++) {
62  const int gx =
63  -1*src[-src_linesize + i-1] + 1*src[-src_linesize + i+1]
64  -2*src[ i-1] + 2*src[ i+1]
65  -1*src[ src_linesize + i-1] + 1*src[ src_linesize + i+1];
66  const int gy =
67  -1*src[-src_linesize + i-1] + 1*src[ src_linesize + i-1]
68  -2*src[-src_linesize + i ] + 2*src[ src_linesize + i ]
69  -1*src[-src_linesize + i+1] + 1*src[ src_linesize + i+1];
70 
71  dst[i] = FFABS(gx) + FFABS(gy);
72  dir[i] = get_rounded_direction(gx, gy);
73  }
74  }
75 }
76 
77 // Filters rounded gradients to drop all non-maxima
78 // Expects gradients generated by ff_sobel()
79 // Expects zero's destination buffer
81  uint8_t *dst, int dst_linesize,
82  const int8_t *dir, int dir_linesize,
83  const uint16_t *src, int src_linesize)
84 {
85  int i, j;
86 
87 #define COPY_MAXIMA(ay, ax, by, bx) do { \
88  if (src[i] > src[(ay)*src_linesize + i+(ax)] && \
89  src[i] > src[(by)*src_linesize + i+(bx)]) \
90  dst[i] = av_clip_uint8(src[i]); \
91 } while (0)
92 
93  for (j = 1; j < h - 1; j++) {
94  dst += dst_linesize;
95  dir += dir_linesize;
96  src += src_linesize;
97  for (i = 1; i < w - 1; i++) {
98  switch (dir[i]) {
99  case DIRECTION_45UP: COPY_MAXIMA( 1, -1, -1, 1); break;
100  case DIRECTION_45DOWN: COPY_MAXIMA(-1, -1, 1, 1); break;
101  case DIRECTION_HORIZONTAL: COPY_MAXIMA( 0, -1, 0, 1); break;
102  case DIRECTION_VERTICAL: COPY_MAXIMA(-1, 0, 1, 0); break;
103  }
104  }
105  }
106 }
107 
108 // Filter to keep all pixels > high, and keep all pixels > low where all surrounding pixels > high
109 void ff_double_threshold(int low, int high, int w, int h,
110  uint8_t *dst, int dst_linesize,
111  const uint8_t *src, int src_linesize)
112 {
113  int i, j;
114 
115  for (j = 0; j < h; j++) {
116  for (i = 0; i < w; i++) {
117  if (src[i] > high) {
118  dst[i] = src[i];
119  continue;
120  }
121 
122  if (!(!i || i == w - 1 || !j || j == h - 1) &&
123  src[i] > low &&
124  (src[-src_linesize + i-1] > high ||
125  src[-src_linesize + i ] > high ||
126  src[-src_linesize + i+1] > high ||
127  src[ i-1] > high ||
128  src[ i+1] > high ||
129  src[ src_linesize + i-1] > high ||
130  src[ src_linesize + i ] > high ||
131  src[ src_linesize + i+1] > high))
132  dst[i] = src[i];
133  else
134  dst[i] = 0;
135  }
136  dst += dst_linesize;
137  src += src_linesize;
138  }
139 }
140 
141 // Applies gaussian blur, using 5x5 kernels, sigma = 1.4
142 void ff_gaussian_blur(int w, int h,
143  uint8_t *dst, int dst_linesize,
144  const uint8_t *src, int src_linesize)
145 {
146  int i, j;
147 
148  memcpy(dst, src, w); dst += dst_linesize; src += src_linesize;
149  memcpy(dst, src, w); dst += dst_linesize; src += src_linesize;
150  for (j = 2; j < h - 2; j++) {
151  dst[0] = src[0];
152  dst[1] = src[1];
153  for (i = 2; i < w - 2; i++) {
154  /* Gaussian mask of size 5x5 with sigma = 1.4 */
155  dst[i] = ((src[-2*src_linesize + i-2] + src[2*src_linesize + i-2]) * 2
156  + (src[-2*src_linesize + i-1] + src[2*src_linesize + i-1]) * 4
157  + (src[-2*src_linesize + i ] + src[2*src_linesize + i ]) * 5
158  + (src[-2*src_linesize + i+1] + src[2*src_linesize + i+1]) * 4
159  + (src[-2*src_linesize + i+2] + src[2*src_linesize + i+2]) * 2
160 
161  + (src[ -src_linesize + i-2] + src[ src_linesize + i-2]) * 4
162  + (src[ -src_linesize + i-1] + src[ src_linesize + i-1]) * 9
163  + (src[ -src_linesize + i ] + src[ src_linesize + i ]) * 12
164  + (src[ -src_linesize + i+1] + src[ src_linesize + i+1]) * 9
165  + (src[ -src_linesize + i+2] + src[ src_linesize + i+2]) * 4
166 
167  + src[i-2] * 5
168  + src[i-1] * 12
169  + src[i ] * 15
170  + src[i+1] * 12
171  + src[i+2] * 5) / 159;
172  }
173  dst[i ] = src[i ];
174  dst[i + 1] = src[i + 1];
175 
176  dst += dst_linesize;
177  src += src_linesize;
178  }
179  memcpy(dst, src, w); dst += dst_linesize; src += src_linesize;
180  memcpy(dst, src, w);
181 }
ff_gaussian_blur
void ff_gaussian_blur(int w, int h, uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize)
Applies gaussian blur.
Definition: edge_common.c:142
w
uint8_t w
Definition: llviddspenc.c:38
edge_common.h
ff_sobel
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)
Simple sobel operator to get rounded gradients.
Definition: edge_common.c:50
DIRECTION_VERTICAL
@ DIRECTION_VERTICAL
Definition: edge_common.h:36
get_rounded_direction
static int get_rounded_direction(int gx, int gy)
Definition: edge_common.c:22
DIRECTION_45DOWN
@ DIRECTION_45DOWN
Definition: edge_common.h:34
COPY_MAXIMA
#define COPY_MAXIMA(ay, ax, by, bx)
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:64
DIRECTION_HORIZONTAL
@ DIRECTION_HORIZONTAL
Definition: edge_common.h:35
ff_non_maximum_suppression
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 rounded gradients to drop all non-maxima pixels in the magnitude image Expects gradients gene...
Definition: edge_common.c:80
ff_double_threshold
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)
Filters all pixels in src to keep all pixels > high, and keep all pixels > low where all surrounding ...
Definition: edge_common.c:109
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
DIRECTION_45UP
@ DIRECTION_45UP
Definition: edge_common.h:33
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
h
h
Definition: vp9dsp_template.c:2038