lavfi/histogram: make waveform mode more useful
authorPaul B Mahol <onemda@gmail.com>
Sat, 9 Feb 2013 16:05:28 +0000 (16:05 +0000)
committerPaul B Mahol <onemda@gmail.com>
Sat, 9 Feb 2013 16:05:28 +0000 (16:05 +0000)
Now it displays all color components (not just luma)
either in parade or overlay and also works with RGB colorspace.

Signed-off-by: Paul B Mahol <onemda@gmail.com>
doc/filters.texi
libavfilter/vf_histogram.c

index 0a2a374..da80ff5 100644 (file)
@@ -3146,9 +3146,9 @@ chroma values in vectorscope, similar as @code{color} but actual chroma values
 are displayed.
 
 @item waveform
-per row/column luminance graph. In row mode the left side represents luma = 0
-and right side represents luma = 255. In column mode top side represends
-luma = 0 and bottom side represents luma = 255.
+per row/column color component graph. In row mode graph in the left side represents
+color component value 0 and right side represents value = 255. In column mode top
+side represents color component value = 0 and bottom side represents value = 255.
 @end table
 Default value is @code{levels}.
 
@@ -3168,6 +3168,33 @@ Default value is @code{10}. Allowed range is [1, 255].
 @item waveform_mode
 Set mode for @code{waveform}. Can be either @code{row}, or @code{column}.
 Default is @code{row}.
+
+@item display_mode
+Set display mode for @code{waveform}.
+It accepts the following values:
+@table @samp
+@item parade
+Display separate waveforms for the color components side by side in
+@code{row} mode or one below other in @code{column} mode.
+
+In this display mode it is easy to spot color casts in the highlights and
+shadows of an image, by comparing the contours of the top and the bottom
+of each waveform. Since whites, grays, and blacks are characterized by
+exactly equal amounts of red, green, and blue, neutral areas of the
+picture should display three waveforms of roughly equal height.
+If not, the correction is easy to make by making adjustments to level the
+three waveforms.
+
+@item overlay
+Presents information that's identical to that in the @code{parade}, except
+that the waveforms representing color components are superimposed directly
+over one another.
+
+This display mode can make it easier to spot the relative differences or
+similarities in overlapping areas of the color components that are supposed
+to be identical, such as neutral whites, grays, or blacks.
+@end table
+Default is @code{parade}.
 @end table
 
 @subsection Examples
index 22de387..ee9689f 100644 (file)
@@ -47,6 +47,7 @@ typedef struct HistogramContext {
     int            scale_height;
     int            step;
     int            waveform_mode;
+    int            display_mode;
 } HistogramContext;
 
 #define OFFSET(x) offsetof(HistogramContext, x)
@@ -64,6 +65,9 @@ static const AVOption histogram_options[] = {
     { "waveform_mode", "set waveform mode", OFFSET(waveform_mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "waveform_mode"},
     { "row",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "waveform_mode" },
     { "column", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "waveform_mode" },
+    { "display_mode", "set display mode", OFFSET(display_mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "display_mode"},
+    { "parade",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "display_mode" },
+    { "overlay", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "display_mode" },
     { NULL },
 };
 
@@ -99,10 +103,10 @@ static int query_formats(AVFilterContext *ctx)
     const enum AVPixelFormat *pix_fmts;
 
     switch (h->mode) {
+    case MODE_WAVEFORM:
     case MODE_LEVELS:
         pix_fmts = levels_pix_fmts;
         break;
-    case MODE_WAVEFORM:
     case MODE_COLOR:
     case MODE_COLOR2:
         pix_fmts = color_pix_fmts;
@@ -153,9 +157,9 @@ static int config_output(AVFilterLink *outlink)
         break;
     case MODE_WAVEFORM:
         if (h->waveform_mode)
-            outlink->h = 256;
+            outlink->h = 256 * FFMAX(h->ncomp * h->display_mode, 1);
         else
-            outlink->w = 256;
+            outlink->w = 256 * FFMAX(h->ncomp * h->display_mode, 1);
         break;
     case MODE_COLOR:
     case MODE_COLOR2:
@@ -223,23 +227,31 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
         break;
     case MODE_WAVEFORM:
         if (h->waveform_mode) {
-            for (i = 0; i < inlink->w; i++) {
-                for (j = 0; j < inlink->h; j++) {
-                    int pos = in->data[0][j * in->linesize[0] + i] * out->linesize[0] + i;
-                    unsigned value = out->data[0][pos];
-                    value = FFMIN(value + h->step, 255);
-                    out->data[0][pos] = value;
+            for (k = 0; k < h->ncomp; k++) {
+                int offset = k * 256 * h->display_mode;
+                for (i = 0; i < inlink->w; i++) {
+                    for (j = 0; j < inlink->h; j++) {
+                        int pos = (offset +
+                                   in->data[k][j * in->linesize[k] + i]) *
+                                  out->linesize[k] + i;
+                        unsigned value = out->data[k][pos];
+                        value = FFMIN(value + h->step, 255);
+                        out->data[k][pos] = value;
+                    }
                 }
             }
         } else {
-            for (i = 0; i < inlink->h; i++) {
-                src = in ->data[0] + i * in ->linesize[0];
-                dst = out->data[0] + i * out->linesize[0];
-                for (j = 0; j < inlink->w; j++) {
-                    int pos = src[j];
-                    unsigned value = dst[pos];
-                    value = FFMIN(value + h->step, 255);
-                    dst[pos] = value;
+            for (k = 0; k < h->ncomp; k++) {
+                int offset = k * 256 * h->display_mode;
+                for (i = 0; i < inlink->h; i++) {
+                    src = in ->data[k] + i * in ->linesize[k];
+                    dst = out->data[k] + i * out->linesize[k];
+                    for (j = 0; j < inlink->w; j++) {
+                        int pos = src[j] + offset;
+                        unsigned value = dst[pos];
+                        value = FFMIN(value + h->step, 255);
+                        dst[pos] = value;
+                    }
                 }
             }
         }