LCOV - code coverage report
Current view: top level - libavfilter - vf_histeq.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 90 0.0 %
Date: 2017-12-15 18:13:28 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2012 Jeremy Tran
       3             :  * Copyright (c) 2001 Donald A. Graft
       4             :  *
       5             :  * This file is part of FFmpeg.
       6             :  *
       7             :  * FFmpeg is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 2 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * FFmpeg is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License along
      18             :  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
      19             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      20             :  */
      21             : 
      22             : /**
      23             :  * @file
      24             :  * Histogram equalization filter, based on the VirtualDub filter by
      25             :  * Donald A. Graft  <neuron2 AT home DOT com>.
      26             :  * Implements global automatic contrast adjustment by means of
      27             :  * histogram equalization.
      28             :  */
      29             : 
      30             : #include "libavutil/common.h"
      31             : #include "libavutil/internal.h"
      32             : #include "libavutil/opt.h"
      33             : #include "libavutil/pixdesc.h"
      34             : 
      35             : #include "avfilter.h"
      36             : #include "drawutils.h"
      37             : #include "formats.h"
      38             : #include "internal.h"
      39             : #include "video.h"
      40             : 
      41             : // #define DEBUG
      42             : 
      43             : // Linear Congruential Generator, see "Numerical Recipes"
      44             : #define LCG_A 4096
      45             : #define LCG_C 150889
      46             : #define LCG_M 714025
      47             : #define LCG(x) (((x) * LCG_A + LCG_C) % LCG_M)
      48             : #define LCG_SEED 739187
      49             : 
      50             : enum HisteqAntibanding {
      51             :     HISTEQ_ANTIBANDING_NONE   = 0,
      52             :     HISTEQ_ANTIBANDING_WEAK   = 1,
      53             :     HISTEQ_ANTIBANDING_STRONG = 2,
      54             :     HISTEQ_ANTIBANDING_NB,
      55             : };
      56             : 
      57             : typedef struct HisteqContext {
      58             :     const AVClass *class;
      59             :     float strength;
      60             :     float intensity;
      61             :     int antibanding;               ///< HisteqAntibanding
      62             :     int in_histogram [256];        ///< input histogram
      63             :     int out_histogram[256];        ///< output histogram
      64             :     int LUT[256];                  ///< lookup table derived from histogram[]
      65             :     uint8_t rgba_map[4];           ///< components position
      66             :     int bpp;                       ///< bytes per pixel
      67             : } HisteqContext;
      68             : 
      69             : #define OFFSET(x) offsetof(HisteqContext, x)
      70             : #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
      71             : #define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, INT_MIN, INT_MAX, FLAGS, unit }
      72             : 
      73             : static const AVOption histeq_options[] = {
      74             :     { "strength",    "set the strength", OFFSET(strength), AV_OPT_TYPE_FLOAT, {.dbl=0.2}, 0, 1, FLAGS },
      75             :     { "intensity",   "set the intensity", OFFSET(intensity), AV_OPT_TYPE_FLOAT, {.dbl=0.21}, 0, 1, FLAGS },
      76             :     { "antibanding", "set the antibanding level", OFFSET(antibanding), AV_OPT_TYPE_INT, {.i64=HISTEQ_ANTIBANDING_NONE}, 0, HISTEQ_ANTIBANDING_NB-1, FLAGS, "antibanding" },
      77             :     CONST("none",    "apply no antibanding",     HISTEQ_ANTIBANDING_NONE,   "antibanding"),
      78             :     CONST("weak",    "apply weak antibanding",   HISTEQ_ANTIBANDING_WEAK,   "antibanding"),
      79             :     CONST("strong",  "apply strong antibanding", HISTEQ_ANTIBANDING_STRONG, "antibanding"),
      80             :     { NULL }
      81             : };
      82             : 
      83             : AVFILTER_DEFINE_CLASS(histeq);
      84             : 
      85           0 : static av_cold int init(AVFilterContext *ctx)
      86             : {
      87           0 :     HisteqContext *histeq = ctx->priv;
      88             : 
      89           0 :     av_log(ctx, AV_LOG_VERBOSE,
      90             :            "strength:%0.3f intensity:%0.3f antibanding:%d\n",
      91           0 :            histeq->strength, histeq->intensity, histeq->antibanding);
      92             : 
      93           0 :     return 0;
      94             : }
      95             : 
      96           0 : static int query_formats(AVFilterContext *ctx)
      97             : {
      98             :     static const enum AVPixelFormat pix_fmts[] = {
      99             :         AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA,
     100             :         AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
     101             :         AV_PIX_FMT_NONE
     102             :     };
     103           0 :     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
     104           0 :     if (!fmts_list)
     105           0 :         return AVERROR(ENOMEM);
     106           0 :     return ff_set_common_formats(ctx, fmts_list);
     107             : }
     108             : 
     109           0 : static int config_input(AVFilterLink *inlink)
     110             : {
     111           0 :     AVFilterContext *ctx = inlink->dst;
     112           0 :     HisteqContext *histeq = ctx->priv;
     113           0 :     const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
     114             : 
     115           0 :     histeq->bpp = av_get_bits_per_pixel(pix_desc) / 8;
     116           0 :     ff_fill_rgba_map(histeq->rgba_map, inlink->format);
     117             : 
     118           0 :     return 0;
     119             : }
     120             : 
     121             : #define R 0
     122             : #define G 1
     123             : #define B 2
     124             : #define A 3
     125             : 
     126             : #define GET_RGB_VALUES(r, g, b, src, map) do { \
     127             :     r = src[x + map[R]];                       \
     128             :     g = src[x + map[G]];                       \
     129             :     b = src[x + map[B]];                       \
     130             : } while (0)
     131             : 
     132           0 : static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
     133             : {
     134           0 :     AVFilterContext   *ctx     = inlink->dst;
     135           0 :     HisteqContext     *histeq  = ctx->priv;
     136           0 :     AVFilterLink      *outlink = ctx->outputs[0];
     137           0 :     int strength  = histeq->strength  * 1000;
     138           0 :     int intensity = histeq->intensity * 1000;
     139             :     int x, y, i, luthi, lutlo, lut, luma, oluma, m;
     140             :     AVFrame *outpic;
     141             :     unsigned int r, g, b, jran;
     142             :     uint8_t *src, *dst;
     143             : 
     144           0 :     outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
     145           0 :     if (!outpic) {
     146           0 :         av_frame_free(&inpic);
     147           0 :         return AVERROR(ENOMEM);
     148             :     }
     149           0 :     av_frame_copy_props(outpic, inpic);
     150             : 
     151             :     /* Seed random generator for antibanding. */
     152           0 :     jran = LCG_SEED;
     153             : 
     154             :     /* Calculate and store the luminance and calculate the global histogram
     155             :        based on the luminance. */
     156           0 :     memset(histeq->in_histogram, 0, sizeof(histeq->in_histogram));
     157           0 :     src = inpic->data[0];
     158           0 :     dst = outpic->data[0];
     159           0 :     for (y = 0; y < inlink->h; y++) {
     160           0 :         for (x = 0; x < inlink->w * histeq->bpp; x += histeq->bpp) {
     161           0 :             GET_RGB_VALUES(r, g, b, src, histeq->rgba_map);
     162           0 :             luma = (55 * r + 182 * g + 19 * b) >> 8;
     163           0 :             dst[x + histeq->rgba_map[A]] = luma;
     164           0 :             histeq->in_histogram[luma]++;
     165             :         }
     166           0 :         src += inpic->linesize[0];
     167           0 :         dst += outpic->linesize[0];
     168             :     }
     169             : 
     170             : #ifdef DEBUG
     171             :     for (x = 0; x < 256; x++)
     172             :         ff_dlog(ctx, "in[%d]: %u\n", x, histeq->in_histogram[x]);
     173             : #endif
     174             : 
     175             :     /* Calculate the lookup table. */
     176           0 :     histeq->LUT[0] = histeq->in_histogram[0];
     177             :     /* Accumulate */
     178           0 :     for (x = 1; x < 256; x++)
     179           0 :         histeq->LUT[x] = histeq->LUT[x-1] + histeq->in_histogram[x];
     180             : 
     181             :     /* Normalize */
     182           0 :     for (x = 0; x < 256; x++)
     183           0 :         histeq->LUT[x] = (histeq->LUT[x] * intensity) / (inlink->h * inlink->w);
     184             : 
     185             :     /* Adjust the LUT based on the selected strength. This is an alpha
     186             :        mix of the calculated LUT and a linear LUT with gain 1. */
     187           0 :     for (x = 0; x < 256; x++)
     188           0 :         histeq->LUT[x] = (strength * histeq->LUT[x]) / 255 +
     189           0 :                          ((255 - strength) * x)      / 255;
     190             : 
     191             :     /* Output the equalized frame. */
     192           0 :     memset(histeq->out_histogram, 0, sizeof(histeq->out_histogram));
     193             : 
     194           0 :     src = inpic->data[0];
     195           0 :     dst = outpic->data[0];
     196           0 :     for (y = 0; y < inlink->h; y++) {
     197           0 :         for (x = 0; x < inlink->w * histeq->bpp; x += histeq->bpp) {
     198           0 :             luma = dst[x + histeq->rgba_map[A]];
     199           0 :             if (luma == 0) {
     200           0 :                 for (i = 0; i < histeq->bpp; ++i)
     201           0 :                     dst[x + i] = 0;
     202           0 :                 histeq->out_histogram[0]++;
     203             :             } else {
     204           0 :                 lut = histeq->LUT[luma];
     205           0 :                 if (histeq->antibanding != HISTEQ_ANTIBANDING_NONE) {
     206           0 :                     if (luma > 0) {
     207           0 :                         lutlo = histeq->antibanding == HISTEQ_ANTIBANDING_WEAK ?
     208           0 :                                 (histeq->LUT[luma] + histeq->LUT[luma - 1]) / 2 :
     209           0 :                                  histeq->LUT[luma - 1];
     210             :                     } else
     211           0 :                         lutlo = lut;
     212             : 
     213           0 :                     if (luma < 255) {
     214           0 :                         luthi = (histeq->antibanding == HISTEQ_ANTIBANDING_WEAK) ?
     215           0 :                             (histeq->LUT[luma] + histeq->LUT[luma + 1]) / 2 :
     216           0 :                              histeq->LUT[luma + 1];
     217             :                     } else
     218           0 :                         luthi = lut;
     219             : 
     220           0 :                     if (lutlo != luthi) {
     221           0 :                         jran = LCG(jran);
     222           0 :                         lut = lutlo + ((luthi - lutlo + 1) * jran) / LCG_M;
     223             :                     }
     224             :                 }
     225             : 
     226           0 :                 GET_RGB_VALUES(r, g, b, src, histeq->rgba_map);
     227           0 :                 if (((m = FFMAX3(r, g, b)) * lut) / luma > 255) {
     228           0 :                     r = (r * 255) / m;
     229           0 :                     g = (g * 255) / m;
     230           0 :                     b = (b * 255) / m;
     231             :                 } else {
     232           0 :                     r = (r * lut) / luma;
     233           0 :                     g = (g * lut) / luma;
     234           0 :                     b = (b * lut) / luma;
     235             :                 }
     236           0 :                 dst[x + histeq->rgba_map[R]] = r;
     237           0 :                 dst[x + histeq->rgba_map[G]] = g;
     238           0 :                 dst[x + histeq->rgba_map[B]] = b;
     239           0 :                 oluma = av_clip_uint8((55 * r + 182 * g + 19 * b) >> 8);
     240           0 :                 histeq->out_histogram[oluma]++;
     241             :             }
     242             :         }
     243           0 :         src += inpic->linesize[0];
     244           0 :         dst += outpic->linesize[0];
     245             :     }
     246             : #ifdef DEBUG
     247             :     for (x = 0; x < 256; x++)
     248             :         ff_dlog(ctx, "out[%d]: %u\n", x, histeq->out_histogram[x]);
     249             : #endif
     250             : 
     251           0 :     av_frame_free(&inpic);
     252           0 :     return ff_filter_frame(outlink, outpic);
     253             : }
     254             : 
     255             : static const AVFilterPad histeq_inputs[] = {
     256             :     {
     257             :         .name         = "default",
     258             :         .type         = AVMEDIA_TYPE_VIDEO,
     259             :         .config_props = config_input,
     260             :         .filter_frame = filter_frame,
     261             :     },
     262             :     { NULL }
     263             : };
     264             : 
     265             : static const AVFilterPad histeq_outputs[] = {
     266             :     {
     267             :         .name = "default",
     268             :         .type = AVMEDIA_TYPE_VIDEO,
     269             :     },
     270             :     { NULL }
     271             : };
     272             : 
     273             : AVFilter ff_vf_histeq = {
     274             :     .name          = "histeq",
     275             :     .description   = NULL_IF_CONFIG_SMALL("Apply global color histogram equalization."),
     276             :     .priv_size     = sizeof(HisteqContext),
     277             :     .init          = init,
     278             :     .query_formats = query_formats,
     279             :     .inputs        = histeq_inputs,
     280             :     .outputs       = histeq_outputs,
     281             :     .priv_class    = &histeq_class,
     282             :     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
     283             : };

Generated by: LCOV version 1.13