avfilter/vf_vectorscope: add threshold option
authorPaul B Mahol <onemda@gmail.com>
Thu, 3 Mar 2016 19:44:38 +0000 (20:44 +0100)
committerPaul B Mahol <onemda@gmail.com>
Thu, 3 Mar 2016 20:05:39 +0000 (21:05 +0100)
Useful to only display lows/mids/highs.

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

index a1591c6..4ec7507 100644 (file)
@@ -12639,6 +12639,20 @@ Draw graticule for black point.
 
 @item bgopacity, b
 Set background opacity.
+
+@item lthreshold, l
+Set low threshold for color component not represented on X or Y axis.
+Values lower than this value will be ignored. Default is 0.
+Note this value is multiplied with actual max possible value one pixel component
+can have. So for 8-bit input and low threshold value of 0.1 actual threshold
+is 0.1 * 255 = 25.
+
+@item hthreshold, h
+Set high threshold for color component not represented on X or Y axis.
+Values higher than this value will be ignored. Default is 1.
+Note this value is multiplied with actual max possible value one pixel component
+can have. So for 8-bit input and high threshold value of 0.9 actual threshold
+is 0.9 * 255 = 230.
 @end table
 
 @anchor{vidstabdetect}
index 4a53bf0..35e6eb6 100644 (file)
@@ -56,6 +56,10 @@ typedef struct VectorscopeContext {
     int graticule;
     float opacity;
     float bgopacity;
+    float lthreshold;
+    float hthreshold;
+    int tmin;
+    int tmax;
     int flags;
     int cs;
     uint8_t peak[1024][1024];
@@ -101,6 +105,10 @@ static const AVOption vectorscope_options[] = {
     {   "black", "draw black point", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "flags" },
     { "bgopacity", "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.3}, 0, 1, FLAGS},
     { "b",         "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.3}, 0, 1, FLAGS},
+    { "lthreshold", "set low threshold",  OFFSET(lthreshold), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 1, FLAGS},
+    { "l",          "set low threshold",  OFFSET(lthreshold), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 1, FLAGS},
+    { "hthreshold", "set high threshold", OFFSET(hthreshold), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, FLAGS},
+    { "h",          "set high threshold", OFFSET(hthreshold), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, FLAGS},
     { NULL }
 };
 
@@ -371,6 +379,8 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int
     uint16_t *dpd = dst[pd];
     const int max = s->size - 1;
     const int mid = s->size / 2;
+    const int tmin = s->tmin;
+    const int tmax = s->tmax;
     int i, j, k;
 
     for (k = 0; k < 4 && dst[k]; k++) {
@@ -388,11 +398,16 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int
             for (i = 0; i < h; i++) {
                 const int iwx = i * slinesizex;
                 const int iwy = i * slinesizey;
+                const int iwd = i * slinesized;
                 for (j = 0; j < w; j++) {
                     const int x = FFMIN(spx[iwx + j], max);
                     const int y = FFMIN(spy[iwy + j], max);
+                    const int z = spd[iwd + j];
                     const int pos = y * dlinesize + x;
 
+                    if (z < tmin || z > tmax)
+                        continue;
+
                     dpd[pos] = FFMIN(dpd[pos] + intensity, max);
                     if (dst[3])
                         dst[3][pos] = max;
@@ -402,11 +417,16 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int
             for (i = 0; i < h; i++) {
                 const int iwx = i * slinesizex;
                 const int iwy = i * slinesizey;
+                const int iwd = i * slinesized;
                 for (j = 0; j < w; j++) {
                     const int x = FFMIN(spx[iwx + j], max);
                     const int y = FFMIN(spy[iwy + j], max);
+                    const int z = spd[iwd + j];
                     const int pos = y * dlinesize + x;
 
+                    if (z < tmin || z > tmax)
+                        continue;
+
                     dst[0][pos] = FFMIN(dst[0][pos] + intensity, max);
                     dst[1][pos] = FFMIN(dst[1][pos] + intensity, max);
                     dst[2][pos] = FFMIN(dst[2][pos] + intensity, max);
@@ -421,11 +441,16 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int
             for (i = 0; i < h; i++) {
                 const int iw1 = i * slinesizex;
                 const int iw2 = i * slinesizey;
+                const int iwd = i * slinesized;
                 for (j = 0; j < w; j++) {
                     const int x = FFMIN(spx[iw1 + j], max);
                     const int y = FFMIN(spy[iw2 + j], max);
+                    const int z = spd[iwd + j];
                     const int pos = y * dlinesize + x;
 
+                    if (z < tmin || z > tmax)
+                        continue;
+
                     if (!dpd[pos])
                         dpd[pos] = FFABS(mid - x) + FFABS(mid - y);
                     dpx[pos] = x;
@@ -438,11 +463,16 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int
             for (i = 0; i < h; i++) {
                 const int iw1 = i * slinesizex;
                 const int iw2 = i * slinesizey;
+                const int iwd = i * slinesized;
                 for (j = 0; j < w; j++) {
                     const int x = FFMIN(spx[iw1 + j], max);
                     const int y = FFMIN(spy[iw2 + j], max);
+                    const int z = spd[iwd + j];
                     const int pos = y * dlinesize + x;
 
+                    if (z < tmin || z > tmax)
+                        continue;
+
                     if (!dpd[pos])
                         dpd[pos] = FFMIN(x + y, max);
                     dpx[pos] = x;
@@ -457,11 +487,16 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int
         for (i = 0; i < h; i++) {
             const int iw1 = i * slinesizex;
             const int iw2 = i * slinesizey;
+            const int iwd = i * slinesized;
             for (j = 0; j < w; j++) {
                 const int x = FFMIN(spx[iw1 + j], max);
                 const int y = FFMIN(spy[iw2 + j], max);
+                const int z = spd[iwd + j];
                 const int pos = y * dlinesize + x;
 
+                if (z < tmin || z > tmax)
+                    continue;
+
                 dpd[pos] = FFMIN(max, dpd[pos] + intensity);
                 dpx[pos] = x;
                 dpy[pos] = y;
@@ -478,9 +513,13 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int
             for (j = 0; j < in->width; j++) {
                 const int x = FFMIN(spx[iwx + (j >> hsub)], max);
                 const int y = FFMIN(spy[iwy + (j >> hsub)], max);
+                const int z = spd[iwd + j];
                 const int pos = y * dlinesize + x;
 
-                dpd[pos] = FFMAX(spd[iwd + j], dpd[pos]);
+                if (z < tmin || z > tmax)
+                    continue;
+
+                dpd[pos] = FFMAX(z, dpd[pos]);
                 dpx[pos] = x;
                 dpy[pos] = y;
                 if (dst[3])
@@ -537,6 +576,8 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p
     uint8_t *dpx = dst[px];
     uint8_t *dpy = dst[py];
     uint8_t *dpd = dst[pd];
+    const int tmin = s->tmin;
+    const int tmax = s->tmax;
     int i, j, k;
 
     for (k = 0; k < 4 && dst[k]; k++)
@@ -552,11 +593,16 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p
             for (i = 0; i < h; i++) {
                 const int iwx = i * slinesizex;
                 const int iwy = i * slinesizey;
+                const int iwd = i * slinesized;
                 for (j = 0; j < w; j++) {
                     const int x = spx[iwx + j];
                     const int y = spy[iwy + j];
+                    const int z = spd[iwd + j];
                     const int pos = y * dlinesize + x;
 
+                    if (z < tmin || z > tmax)
+                        continue;
+
                     dpd[pos] = FFMIN(dpd[pos] + intensity, 255);
                     if (dst[3])
                         dst[3][pos] = 255;
@@ -566,11 +612,16 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p
             for (i = 0; i < h; i++) {
                 const int iwx = i * slinesizex;
                 const int iwy = i * slinesizey;
+                const int iwd = i * slinesized;
                 for (j = 0; j < w; j++) {
                     const int x = spx[iwx + j];
                     const int y = spy[iwy + j];
+                    const int z = spd[iwd + j];
                     const int pos = y * dlinesize + x;
 
+                    if (z < tmin || z > tmax)
+                        continue;
+
                     dst[0][pos] = FFMIN(dst[0][pos] + intensity, 255);
                     dst[1][pos] = FFMIN(dst[1][pos] + intensity, 255);
                     dst[2][pos] = FFMIN(dst[2][pos] + intensity, 255);
@@ -585,11 +636,16 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p
             for (i = 0; i < h; i++) {
                 const int iw1 = i * slinesizex;
                 const int iw2 = i * slinesizey;
+                const int iwd = i * slinesized;
                 for (j = 0; j < w; j++) {
                     const int x = spx[iw1 + j];
                     const int y = spy[iw2 + j];
+                    const int z = spd[iwd + j];
                     const int pos = y * dlinesize + x;
 
+                    if (z < tmin || z > tmax)
+                        continue;
+
                     if (!dpd[pos])
                         dpd[pos] = FFABS(128 - x) + FFABS(128 - y);
                     dpx[pos] = x;
@@ -602,11 +658,16 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p
             for (i = 0; i < h; i++) {
                 const int iw1 = i * slinesizex;
                 const int iw2 = i * slinesizey;
+                const int iwd = i * slinesized;
                 for (j = 0; j < w; j++) {
                     const int x = spx[iw1 + j];
                     const int y = spy[iw2 + j];
+                    const int z = spd[iwd + j];
                     const int pos = y * dlinesize + x;
 
+                    if (z < tmin || z > tmax)
+                        continue;
+
                     if (!dpd[pos])
                         dpd[pos] = FFMIN(x + y, 255);
                     dpx[pos] = x;
@@ -621,11 +682,16 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p
         for (i = 0; i < h; i++) {
             const int iw1 = i * slinesizex;
             const int iw2 = i * slinesizey;
+            const int iwd = i * slinesized;
             for (j = 0; j < w; j++) {
                 const int x = spx[iw1 + j];
                 const int y = spy[iw2 + j];
+                const int z = spd[iwd + j];
                 const int pos = y * dlinesize + x;
 
+                if (z < tmin || z > tmax)
+                    continue;
+
                 dpd[pos] = FFMIN(255, dpd[pos] + intensity);
                 dpx[pos] = x;
                 dpy[pos] = y;
@@ -642,9 +708,13 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p
             for (j = 0; j < in->width; j++) {
                 const int x = spx[iwx + (j >> hsub)];
                 const int y = spy[iwy + (j >> hsub)];
+                const int z = spd[iwd + j];
                 const int pos = y * dlinesize + x;
 
-                dpd[pos] = FFMAX(spd[iwd + j], dpd[pos]);
+                if (z < tmin || z > tmax)
+                    continue;
+
+                dpd[pos] = FFMAX(z, dpd[pos]);
                 dpx[pos] = x;
                 dpy[pos] = y;
                 if (dst[3])
@@ -963,12 +1033,20 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 static int config_input(AVFilterLink *inlink)
 {
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
-    VectorscopeContext *s = inlink->dst->priv;
+    AVFilterContext *ctx = inlink->dst;
+    VectorscopeContext *s = ctx->priv;
 
     s->is_yuv = !(desc->flags & AV_PIX_FMT_FLAG_RGB);
     s->size = 1 << desc->comp[0].depth;
     s->mult = s->size / 256;
     s->depth = desc->comp[0].depth;
+    s->tmin = s->lthreshold * (s->size - 1);
+    s->tmax = s->hthreshold * (s->size - 1);
+
+    if (s->tmin > s->tmax) {
+        av_log(ctx, AV_LOG_ERROR, "low threshold should be less than high threshold\n");
+        return AVERROR(EINVAL);
+    }
 
     if (s->mode == GRAY && s->is_yuv)
         s->pd = 0;