annotate ffmpeg/libavfilter/vf_histeq.c @ 13:844d341cf643 tip

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