[FFmpeg-devel] [PATCH 1/2 v2] delogo: Use weighted interpolation
Stefano Sabatini
stefasab at gmail.com
Thu Jun 27 23:12:45 CEST 2013
On date Wednesday 2013-06-26 14:50:37 +0200, Jean Delvare encoded:
> The original delogo algorithm interpolates both horizontally and
> vertically and uses the average to compute the resulting sample. This
> works reasonably well when the logo area is almost square. However
> when the logo area is significantly larger than high or higher than
> large, the result is largely suboptimal.
>
> The issue can be clearly seen by testing the delogo filter with a fake
> logo area that is 200 pixels large and 2 pixels high. Vertical
> interpolation gives a very good result in that case, horizontal
> interpolation gives a very bad result, and the overall result is poor,
> because both are given the same weight.
>
> Even when the logo is roughly square, the current algorithm gives poor
> results on the borders of the logo area, because it always gives
> horizontal and vertical interpolations an equal weight, and this is
> suboptimal on borders. For example, in the middle of the left hand
> side border of the logo, you want to trust the left known point much
> more than the right known point (which the current algorithm already
> does) but also much more than the top and bottom known points (which
> the current algorithm doesn't do.)
>
> By properly weighting each known point when computing the value of
> each interpolated pixel, the visual result is much better, especially
> on borders and/or for high or large logo areas.
>
> The algorithm I implemented guarantees that the weight of each of the
> 4 known points directly depends on its distance to the interpolated
> point. It is largely inspired from the original algorithm, the key
> difference being that it computes the relative weights globally
> instead of separating the vertical and horizontal interpolations and
> combining them afterward.
>
> Signed-off-by: Jean Delvare <khali at linux-fr.org>
> ---
> I am using unsigned long long here because the computations would
> otherwise possibly overflow when the logo area is big.
>
> Changes since v1:
> * Stop claiming the new algorithm is slower, it isn't.
> * Handle clipping properly.
> * Fix an off-by-one error on right and bottom distances.
>
> libavfilter/vf_delogo.c | 25 +++-
> tests/ref/fate/filter-delogo | 218 +++++++++++++++++++++----------------------
> 2 files changed, 126 insertions(+), 117 deletions(-)
>
> --- ffmpeg.orig/libavfilter/vf_delogo.c 2013-06-26 10:16:22.716508202 +0200
> +++ ffmpeg/libavfilter/vf_delogo.c 2013-06-26 10:31:12.102268045 +0200
> @@ -1,6 +1,7 @@
> /*
> * Copyright (c) 2002 Jindrich Makovicka <makovick at gmail.com>
> * Copyright (c) 2011 Stefano Sabatini
> + * Copyright (c) 2013 Jean Delvare <khali at linux-fr.org>
> *
> * This file is part of FFmpeg.
> *
> @@ -22,7 +23,8 @@
> /**
> * @file
> * A very simple tv station logo remover
> - * Ported from MPlayer libmpcodecs/vf_delogo.c.
> + * Originally imported from MPlayer libmpcodecs/vf_delogo.c,
> + * the algorithm was later improved.
> */
>
> #include "libavutil/common.h"
> @@ -58,8 +60,8 @@ static void apply_delogo(uint8_t *dst, i
> int logo_x, int logo_y, int logo_w, int logo_h,
> int band, int show, int direct)
> {
> - int x, y;
> - int interp, dist;
> + int x, y, dist;
> + uint64_t interp, weightl, weightr, weightt, weightb;
> uint8_t *xdst, *xsrc;
>
> uint8_t *topleft, *botleft, *topright;
> @@ -90,23 +92,30 @@ static void apply_delogo(uint8_t *dst, i
> for (x = logo_x1+1,
> xdst = dst+logo_x1+1,
> xsrc = src+logo_x1+1; x < logo_x2-1; x++, xdst++, xsrc++) {
> +
> + /* Weighted interpolation based on relative distances */
> + weightl = (uint64_t) (logo_x2-1-x) * (y-logo_y1) * (logo_y2-1-y);
> + weightr = (uint64_t)(x-logo_x1) * (y-logo_y1) * (logo_y2-1-y);
> + weightt = (uint64_t)(x-logo_x1) * (logo_x2-1-x) * (logo_y2-1-y);
> + weightb = (uint64_t)(x-logo_x1) * (logo_x2-1-x) * (y-logo_y1);
> +
> interp =
> (topleft[src_linesize*(y-logo_y -yclipt)] +
> topleft[src_linesize*(y-logo_y-1-yclipt)] +
> - topleft[src_linesize*(y-logo_y+1-yclipt)]) * (logo_w-(x-logo_x))/logo_w
> + topleft[src_linesize*(y-logo_y+1-yclipt)]) * weightl
> +
> (topright[src_linesize*(y-logo_y-yclipt)] +
> topright[src_linesize*(y-logo_y-1-yclipt)] +
> - topright[src_linesize*(y-logo_y+1-yclipt)]) * (x-logo_x)/logo_w
> + topright[src_linesize*(y-logo_y+1-yclipt)]) * weightr
> +
> (topleft[x-logo_x-xclipl] +
> topleft[x-logo_x-1-xclipl] +
> - topleft[x-logo_x+1-xclipl]) * (logo_h-(y-logo_y))/logo_h
> + topleft[x-logo_x+1-xclipl]) * weightt
> +
> (botleft[x-logo_x-xclipl] +
> botleft[x-logo_x-1-xclipl] +
> - botleft[x-logo_x+1-xclipl]) * (y-logo_y)/logo_h;
> - interp /= 6;
> + botleft[x-logo_x+1-xclipl]) * weightb;
> + interp /= (weightl + weightr + weightt + weightb) * 3U;
[...]
LGTM and nice idea.
Another possibility would be to consider generalized barycentric
coordinates with respect to the logo rectangle vertexes, but this
would be a completely different algorithm.
I assume that the algorithm has been tested, and will push it in a day
(or let Michael push it) if there are no other comments.
--
FFmpeg = Funny & Fostering Mastering Pitiless Erotic Gnome
More information about the ffmpeg-devel
mailing list