diff options
author | Paul B Mahol <onemda@gmail.com> | 2016-09-10 23:34:30 +0200 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2016-09-12 14:38:45 +0200 |
commit | afeffd891f58f198dde50ff49e3f8a26b0ede6a8 (patch) | |
tree | 0a4878b9e151fce82da1b864bc185ae7e06e1852 /libavfilter/vf_convolution.c | |
parent | b791d0e4e0d148e399a21b3521d4b4a9ed5e8ae1 (diff) | |
download | ffmpeg-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.c | 334 |
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 */ |