diff options
author | Paul B Mahol <onemda@gmail.com> | 2019-01-15 11:32:49 +0100 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2019-10-29 10:56:04 +0100 |
commit | 1c3b70e2e078bf0901b3af5491f923818809de37 (patch) | |
tree | b97e20f26684a6859c03a1ea52f8ad74ef14729c /libavfilter/median_template.c | |
parent | 68f623d64451a6ee8c81b6071ec68d6097c0f213 (diff) |
avfilter: add median filter
Diffstat (limited to 'libavfilter/median_template.c')
-rw-r--r-- | libavfilter/median_template.c | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/libavfilter/median_template.c b/libavfilter/median_template.c new file mode 100644 index 0000000000..6953a23a5b --- /dev/null +++ b/libavfilter/median_template.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2019 Paul B Mahol + * + * 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 + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + */ + +#include "libavutil/avassert.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +#undef pixel +#if DEPTH == 8 +#define pixel uint8_t +#else +#define pixel uint16_t +#endif + +#undef htype +#define htype uint16_t + +#undef fn +#undef fn2 +#undef fn3 +#define SHIFT ((DEPTH + 1) / 2) +#define BINS (1 << SHIFT) +#define MASK (BINS - 1) +#define fn3(a,b) a##_##b +#define fn2(a,b) fn3(a,b) +#define fn(a) fn2(a, DEPTH) + +#define PICK_COARSE_BIN(x, y) (BINS * (x) + ((y) >> SHIFT)) +#define PICK_FINE_BIN(x, y, z) (BINS * ((x) * ((y) >> SHIFT) + (z)) + ((y) & MASK)) + +static void fn(filter_plane)(AVFilterContext *ctx, const uint8_t *ssrc, int src_linesize, + uint8_t *ddst, int dst_linesize, int width, int height, + int slice_h_start, int slice_h_end, int jobnr) +{ + MedianContext *s = ctx->priv; + htype *ccoarse = s->coarse[jobnr]; + htype *cfine = s->fine[jobnr]; + const int radius = s->radius; + const int t = s->t; + const pixel *src = (const pixel *)ssrc; + pixel *dst = (pixel *)ddst; + const pixel *srcp; + const pixel *p; + + src_linesize /= sizeof(pixel); + dst_linesize /= sizeof(pixel); + + memset(cfine, 0, s->fine_size * sizeof(*cfine)); + memset(ccoarse, 0, s->coarse_size * sizeof(*ccoarse)); + + srcp = src + FFMAX(0, slice_h_start - radius) * src_linesize; + if (jobnr == 0) { + for (int i = 0; i < width; i++) { + cfine[PICK_FINE_BIN(width, srcp[i], i)] += radius + 1; + ccoarse[PICK_COARSE_BIN(i, srcp[i])] += radius + 1; + } + } + + srcp = src + FFMAX(0, slice_h_start - radius - (jobnr != 0)) * src_linesize; + for (int i = 0; i < radius + (jobnr != 0) * (1 + radius); i++) { + for (int j = 0; j < width; j++) { + cfine[PICK_FINE_BIN(width, srcp[j], j)]++; + ccoarse[PICK_COARSE_BIN(j, srcp[j])]++; + } + srcp += src_linesize; + } + + srcp = src; + + for (int i = slice_h_start; i < slice_h_end; i++) { + htype coarse[BINS] = { 0 }; + htype fine[BINS][BINS] = { { 0 } }; + htype luc[BINS] = { 0 }; + + p = srcp + src_linesize * FFMAX(0, i - radius - 1); + for (int j = 0; j < width; j++) { + cfine[PICK_FINE_BIN(width, p[j], j)]--; + ccoarse[PICK_COARSE_BIN(j, p[j])]--; + } + + p = srcp + src_linesize * FFMIN(height - 1, i + radius); + for (int j = 0; j < width; j++) { + cfine[PICK_FINE_BIN(width, p[j], j)]++; + ccoarse[PICK_COARSE_BIN(j, p[j])]++; + } + + s->hmuladd(coarse, &ccoarse[0], radius, BINS); + for (int j = 0; j < radius; j++) + s->hadd(coarse, &ccoarse[BINS * j], BINS); + for (int k = 0; k < BINS; k++) + s->hmuladd(&fine[k][0], &cfine[BINS * width * k], 2 * radius + 1, BINS); + + for (int j = 0; j < width; j++) { + int sum = 0, k, b; + htype *segment; + + s->hadd(coarse, &ccoarse[BINS * FFMIN(j + radius, width - 1)], BINS); + + for (k = 0; k < BINS; k++) { + sum += coarse[k]; + if (sum > t) { + sum -= coarse[k]; + break; + } + } + av_assert0(k < BINS); + + if (luc[k] <= j - radius) { + memset(&fine[k], 0, BINS * sizeof(htype)); + for (luc[k] = j - radius; luc[k] < FFMIN(j + radius + 1, width); luc[k]++) + s->hadd(fine[k], &cfine[BINS * (width * k + luc[k])], BINS); + if (luc[k] < j + radius + 1) { + s->hmuladd(&fine[k][0], &cfine[BINS * (width * k + width - 1)], j + radius + 1 - width, BINS); + luc[k] = j + radius + 1; + } + } else { + for (; luc[k] < j + radius + 1; luc[k]++) { + s->hsub(fine[k], &cfine[BINS * (width * k + FFMAX(luc[k] - 2 * radius - 1, 0))], BINS); + s->hadd(fine[k], &cfine[BINS * (width * k + FFMIN(luc[k], width - 1))], BINS); + } + } + + s->hsub(coarse, &ccoarse[BINS * FFMAX(j - radius, 0)], BINS); + + segment = fine[k]; + for (b = 0; b < BINS; b++) { + sum += segment[b]; + if (sum > t) { + dst[j] = BINS * k + b; + break; + } + } + av_assert0(b < BINS); + } + + dst += dst_linesize; + } +} |