summaryrefslogtreecommitdiff
path: root/libavfilter/vf_convolution.c
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2016-09-10 23:34:30 +0200
committerPaul B Mahol <onemda@gmail.com>2016-09-12 14:38:45 +0200
commitafeffd891f58f198dde50ff49e3f8a26b0ede6a8 (patch)
tree0a4878b9e151fce82da1b864bc185ae7e06e1852 /libavfilter/vf_convolution.c
parentb791d0e4e0d148e399a21b3521d4b4a9ed5e8ae1 (diff)
downloadffmpeg-afeffd891f58f198dde50ff49e3f8a26b0ede6a8.tar.gz
avfilter: add sobel and prewitt filter
Signed-off-by: Paul B Mahol <onemda@gmail.com>
Diffstat (limited to 'libavfilter/vf_convolution.c')
-rw-r--r--libavfilter/vf_convolution.c334
1 files changed, 305 insertions, 29 deletions
diff --git a/libavfilter/vf_convolution.c b/libavfilter/vf_convolution.c
index 2cfc3ba62d..7b512677f8 100644
--- a/libavfilter/vf_convolution.c
+++ b/libavfilter/vf_convolution.c
@@ -34,6 +34,9 @@ typedef struct ConvolutionContext {
char *matrix_str[4];
float rdiv[4];
float bias[4];
+ float scale;
+ float delta;
+ int planes;
int size[4];
int depth;
@@ -130,6 +133,196 @@ static inline void line_copy16(uint16_t *line, const uint16_t *srcp, int width,
}
}
+static void filter16_prewitt(ConvolutionContext *s, AVFrame *in, AVFrame *out, int plane)
+{
+ const uint16_t *src = (const uint16_t *)in->data[plane];
+ uint16_t *dst = (uint16_t *)out->data[plane];
+ const int peak = (1 << s->depth) - 1;
+ const int stride = in->linesize[plane] / 2;
+ const int bstride = s->bstride;
+ const int height = s->planeheight[plane];
+ const int width = s->planewidth[plane];
+ const float scale = s->scale;
+ const float delta = s->delta;
+ uint16_t *p0 = (uint16_t *)s->buffer + 16;
+ uint16_t *p1 = p0 + bstride;
+ uint16_t *p2 = p1 + bstride;
+ uint16_t *orig = p0, *end = p2;
+ int y, x;
+
+ line_copy16(p0, src + stride, width, 1);
+ line_copy16(p1, src, width, 1);
+
+ for (y = 0; y < height; y++) {
+ src += stride * (y < height - 1 ? 1 : -1);
+ line_copy16(p2, src, width, 1);
+
+ for (x = 0; x < width; x++) {
+ int suma = p0[x - 1] * -1 +
+ p0[x] * -1 +
+ p0[x + 1] * -1 +
+ p2[x - 1] * 1 +
+ p2[x] * 1 +
+ p2[x + 1] * 1;
+ int sumb = p0[x - 1] * -1 +
+ p0[x + 1] * 1 +
+ p1[x - 1] * -1 +
+ p1[x + 1] * 1 +
+ p2[x - 1] * -1 +
+ p2[x + 1] * 1;
+
+ dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak);
+ }
+
+ p0 = p1;
+ p1 = p2;
+ p2 = (p2 == end) ? orig: p2 + bstride;
+ dst += out->linesize[plane] / 2;
+ }
+}
+
+static void filter16_sobel(ConvolutionContext *s, AVFrame *in, AVFrame *out, int plane)
+{
+ const uint16_t *src = (const uint16_t *)in->data[plane];
+ uint16_t *dst = (uint16_t *)out->data[plane];
+ const int peak = (1 << s->depth) - 1;
+ const int stride = in->linesize[plane] / 2;
+ const int bstride = s->bstride;
+ const int height = s->planeheight[plane];
+ const int width = s->planewidth[plane];
+ const float scale = s->scale;
+ const float delta = s->delta;
+ uint16_t *p0 = (uint16_t *)s->buffer + 16;
+ uint16_t *p1 = p0 + bstride;
+ uint16_t *p2 = p1 + bstride;
+ uint16_t *orig = p0, *end = p2;
+ int y, x;
+
+ line_copy16(p0, src + stride, width, 1);
+ line_copy16(p1, src, width, 1);
+
+ for (y = 0; y < height; y++) {
+ src += stride * (y < height - 1 ? 1 : -1);
+ line_copy16(p2, src, width, 1);
+
+ for (x = 0; x < width; x++) {
+ int suma = p0[x - 1] * -1 +
+ p0[x] * -2 +
+ p0[x + 1] * -1 +
+ p2[x - 1] * 1 +
+ p2[x] * 2 +
+ p2[x + 1] * 1;
+ int sumb = p0[x - 1] * -1 +
+ p0[x + 1] * 1 +
+ p1[x - 1] * -2 +
+ p1[x + 1] * 2 +
+ p2[x - 1] * -1 +
+ p2[x + 1] * 1;
+
+ dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak);
+ }
+
+ p0 = p1;
+ p1 = p2;
+ p2 = (p2 == end) ? orig: p2 + bstride;
+ dst += out->linesize[plane] / 2;
+ }
+}
+
+static void filter_prewitt(ConvolutionContext *s, AVFrame *in, AVFrame *out, int plane)
+{
+ const uint8_t *src = in->data[plane];
+ uint8_t *dst = out->data[plane];
+ const int stride = in->linesize[plane];
+ const int bstride = s->bstride;
+ const int height = s->planeheight[plane];
+ const int width = s->planewidth[plane];
+ const float scale = s->scale;
+ const float delta = s->delta;
+ uint8_t *p0 = s->buffer + 16;
+ uint8_t *p1 = p0 + bstride;
+ uint8_t *p2 = p1 + bstride;
+ uint8_t *orig = p0, *end = p2;
+ int y, x;
+
+ line_copy8(p0, src + stride, width, 1);
+ line_copy8(p1, src, width, 1);
+
+ for (y = 0; y < height; y++) {
+ src += stride * (y < height - 1 ? 1 : -1);
+ line_copy8(p2, src, width, 1);
+
+ for (x = 0; x < width; x++) {
+ int suma = p0[x - 1] * -1 +
+ p0[x] * -1 +
+ p0[x + 1] * -1 +
+ p2[x - 1] * 1 +
+ p2[x] * 1 +
+ p2[x + 1] * 1;
+ int sumb = p0[x - 1] * -1 +
+ p0[x + 1] * 1 +
+ p1[x - 1] * -1 +
+ p1[x + 1] * 1 +
+ p2[x - 1] * -1 +
+ p2[x + 1] * 1;
+
+ dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta);
+ }
+
+ p0 = p1;
+ p1 = p2;
+ p2 = (p2 == end) ? orig: p2 + bstride;
+ dst += out->linesize[plane];
+ }
+}
+
+static void filter_sobel(ConvolutionContext *s, AVFrame *in, AVFrame *out, int plane)
+{
+ const uint8_t *src = in->data[plane];
+ uint8_t *dst = out->data[plane];
+ const int stride = in->linesize[plane];
+ const int bstride = s->bstride;
+ const int height = s->planeheight[plane];
+ const int width = s->planewidth[plane];
+ const float scale = s->scale;
+ const float delta = s->delta;
+ uint8_t *p0 = s->buffer + 16;
+ uint8_t *p1 = p0 + bstride;
+ uint8_t *p2 = p1 + bstride;
+ uint8_t *orig = p0, *end = p2;
+ int y, x;
+
+ line_copy8(p0, src + stride, width, 1);
+ line_copy8(p1, src, width, 1);
+
+ for (y = 0; y < height; y++) {
+ src += stride * (y < height - 1 ? 1 : -1);
+ line_copy8(p2, src, width, 1);
+
+ for (x = 0; x < width; x++) {
+ int suma = p0[x - 1] * -1 +
+ p0[x] * -2 +
+ p0[x + 1] * -1 +
+ p2[x - 1] * 1 +
+ p2[x] * 2 +
+ p2[x + 1] * 1;
+ int sumb = p0[x - 1] * -1 +
+ p0[x + 1] * 1 +
+ p1[x - 1] * -2 +
+ p1[x + 1] * 2 +
+ p2[x - 1] * -1 +
+ p2[x + 1] * 1;
+
+ dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta);
+ }
+
+ p0 = p1;
+ p1 = p2;
+ p2 = (p2 == end) ? orig: p2 + bstride;
+ dst += out->linesize[plane];
+ }
+}
+
static void filter16_3x3(ConvolutionContext *s, AVFrame *in, AVFrame *out, int plane)
{
const uint16_t *src = (const uint16_t *)in->data[plane];
@@ -338,7 +531,8 @@ static void filter_5x5(ConvolutionContext *s, AVFrame *in, AVFrame *out, int pla
static int config_input(AVFilterLink *inlink)
{
- ConvolutionContext *s = inlink->dst->priv;
+ AVFilterContext *ctx = inlink->dst;
+ ConvolutionContext *s = ctx->priv;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
int ret, p;
@@ -356,13 +550,23 @@ static int config_input(AVFilterLink *inlink)
if (!s->buffer)
return AVERROR(ENOMEM);
- if (s->depth > 8) {
- for (p = 0; p < s->nb_planes; p++) {
- if (s->size[p] == 3)
- s->filter[p] = filter16_3x3;
- else if (s->size[p] == 5)
- s->filter[p] = filter16_5x5;
+ if (!strcmp(ctx->filter->name, "convolution")) {
+ if (s->depth > 8) {
+ for (p = 0; p < s->nb_planes; p++) {
+ if (s->size[p] == 3)
+ s->filter[p] = filter16_3x3;
+ else if (s->size[p] == 5)
+ s->filter[p] = filter16_5x5;
+ }
}
+ } else if (!strcmp(ctx->filter->name, "prewitt")) {
+ if (s->depth > 8)
+ for (p = 0; p < s->nb_planes; p++)
+ s->filter[p] = filter16_prewitt;
+ } else if (!strcmp(ctx->filter->name, "sobel")) {
+ if (s->depth > 8)
+ for (p = 0; p < s->nb_planes; p++)
+ s->filter[p] = filter16_sobel;
}
return 0;
@@ -403,34 +607,50 @@ static av_cold int init(AVFilterContext *ctx)
ConvolutionContext *s = ctx->priv;
int i;
- for (i = 0; i < 4; i++) {
- int *matrix = (int *)s->matrix[i];
- char *p, *arg, *saveptr = NULL;
+ if (!strcmp(ctx->filter->name, "convolution")) {
+ for (i = 0; i < 4; i++) {
+ int *matrix = (int *)s->matrix[i];
+ char *p, *arg, *saveptr = NULL;
- p = s->matrix_str[i];
- while (s->matrix_length[i] < 25) {
- if (!(arg = av_strtok(p, " ", &saveptr)))
- break;
+ p = s->matrix_str[i];
+ while (s->matrix_length[i] < 25) {
+ if (!(arg = av_strtok(p, " ", &saveptr)))
+ break;
- p = NULL;
- sscanf(arg, "%d", &matrix[s->matrix_length[i]]);
- s->matrix_length[i]++;
- }
+ p = NULL;
+ sscanf(arg, "%d", &matrix[s->matrix_length[i]]);
+ s->matrix_length[i]++;
+ }
- if (s->matrix_length[i] == 9) {
- s->size[i] = 3;
- if (!memcmp(matrix, same3x3, sizeof(same3x3)))
- s->copy[i] = 1;
+ if (s->matrix_length[i] == 9) {
+ s->size[i] = 3;
+ if (!memcmp(matrix, same3x3, sizeof(same3x3)))
+ s->copy[i] = 1;
+ else
+ s->filter[i] = filter_3x3;
+ } else if (s->matrix_length[i] == 25) {
+ s->size[i] = 5;
+ if (!memcmp(matrix, same5x5, sizeof(same5x5)))
+ s->copy[i] = 1;
+ else
+ s->filter[i] = filter_5x5;
+ } else {
+ return AVERROR(EINVAL);
+ }
+ }
+ } else if (!strcmp(ctx->filter->name, "prewitt")) {
+ for (i = 0; i < 4; i++) {
+ if ((1 << i) & s->planes)
+ s->filter[i] = filter_prewitt;
else
- s->filter[i] = filter_3x3;
- } else if (s->matrix_length[i] == 25) {
- s->size[i] = 5;
- if (!memcmp(matrix, same5x5, sizeof(same5x5)))
s->copy[i] = 1;
+ }
+ } else if (!strcmp(ctx->filter->name, "sobel")) {
+ for (i = 0; i < 4; i++) {
+ if ((1 << i) & s->planes)
+ s->filter[i] = filter_sobel;
else
- s->filter[i] = filter_5x5;
- } else {
- return AVERROR(EINVAL);
+ s->copy[i] = 1;
}
}
@@ -462,6 +682,8 @@ static const AVFilterPad convolution_outputs[] = {
{ NULL }
};
+#if CONFIG_CONVOLUTION_FILTER
+
AVFilter ff_vf_convolution = {
.name = "convolution",
.description = NULL_IF_CONFIG_SMALL("Apply convolution filter."),
@@ -474,3 +696,57 @@ AVFilter ff_vf_convolution = {
.outputs = convolution_outputs,
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
};
+
+#endif /* CONFIG_CONVOLUTION_FILTER */
+
+#if CONFIG_PREWITT_FILTER
+
+static const AVOption prewitt_options[] = {
+ { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, FLAGS},
+ { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 65535, FLAGS},
+ { "delta", "set delta", OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS},
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(prewitt);
+
+AVFilter ff_vf_prewitt = {
+ .name = "prewitt",
+ .description = NULL_IF_CONFIG_SMALL("Apply prewitt operator."),
+ .priv_size = sizeof(ConvolutionContext),
+ .priv_class = &prewitt_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = convolution_inputs,
+ .outputs = convolution_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
+
+#endif /* CONFIG_PREWITT_FILTER */
+
+#if CONFIG_SOBEL_FILTER
+
+static const AVOption sobel_options[] = {
+ { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, FLAGS},
+ { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 65535, FLAGS},
+ { "delta", "set delta", OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS},
+ { NULL }
+};
+
+AVFILTER_DEFINE_CLASS(sobel);
+
+AVFilter ff_vf_sobel = {
+ .name = "sobel",
+ .description = NULL_IF_CONFIG_SMALL("Apply sobel operator."),
+ .priv_size = sizeof(ConvolutionContext),
+ .priv_class = &sobel_class,
+ .init = init,
+ .uninit = uninit,
+ .query_formats = query_formats,
+ .inputs = convolution_inputs,
+ .outputs = convolution_outputs,
+ .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
+};
+
+#endif /* CONFIG_SOBEL_FILTER */