Useful to only display lows/mids/highs.
Signed-off-by: Paul B Mahol <onemda@gmail.com>
... | ... |
@@ -12639,6 +12639,20 @@ Draw graticule for black point. |
12639 | 12639 |
|
12640 | 12640 |
@item bgopacity, b |
12641 | 12641 |
Set background opacity. |
12642 |
+ |
|
12643 |
+@item lthreshold, l |
|
12644 |
+Set low threshold for color component not represented on X or Y axis. |
|
12645 |
+Values lower than this value will be ignored. Default is 0. |
|
12646 |
+Note this value is multiplied with actual max possible value one pixel component |
|
12647 |
+can have. So for 8-bit input and low threshold value of 0.1 actual threshold |
|
12648 |
+is 0.1 * 255 = 25. |
|
12649 |
+ |
|
12650 |
+@item hthreshold, h |
|
12651 |
+Set high threshold for color component not represented on X or Y axis. |
|
12652 |
+Values higher than this value will be ignored. Default is 1. |
|
12653 |
+Note this value is multiplied with actual max possible value one pixel component |
|
12654 |
+can have. So for 8-bit input and high threshold value of 0.9 actual threshold |
|
12655 |
+is 0.9 * 255 = 230. |
|
12642 | 12656 |
@end table |
12643 | 12657 |
|
12644 | 12658 |
@anchor{vidstabdetect} |
... | ... |
@@ -56,6 +56,10 @@ typedef struct VectorscopeContext { |
56 | 56 |
int graticule; |
57 | 57 |
float opacity; |
58 | 58 |
float bgopacity; |
59 |
+ float lthreshold; |
|
60 |
+ float hthreshold; |
|
61 |
+ int tmin; |
|
62 |
+ int tmax; |
|
59 | 63 |
int flags; |
60 | 64 |
int cs; |
61 | 65 |
uint8_t peak[1024][1024]; |
... | ... |
@@ -101,6 +105,10 @@ static const AVOption vectorscope_options[] = { |
101 | 101 |
{ "black", "draw black point", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "flags" }, |
102 | 102 |
{ "bgopacity", "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.3}, 0, 1, FLAGS}, |
103 | 103 |
{ "b", "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.3}, 0, 1, FLAGS}, |
104 |
+ { "lthreshold", "set low threshold", OFFSET(lthreshold), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 1, FLAGS}, |
|
105 |
+ { "l", "set low threshold", OFFSET(lthreshold), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 1, FLAGS}, |
|
106 |
+ { "hthreshold", "set high threshold", OFFSET(hthreshold), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, FLAGS}, |
|
107 |
+ { "h", "set high threshold", OFFSET(hthreshold), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, FLAGS}, |
|
104 | 108 |
{ NULL } |
105 | 109 |
}; |
106 | 110 |
|
... | ... |
@@ -371,6 +379,8 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int |
371 | 371 |
uint16_t *dpd = dst[pd]; |
372 | 372 |
const int max = s->size - 1; |
373 | 373 |
const int mid = s->size / 2; |
374 |
+ const int tmin = s->tmin; |
|
375 |
+ const int tmax = s->tmax; |
|
374 | 376 |
int i, j, k; |
375 | 377 |
|
376 | 378 |
for (k = 0; k < 4 && dst[k]; k++) { |
... | ... |
@@ -388,11 +398,16 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int |
388 | 388 |
for (i = 0; i < h; i++) { |
389 | 389 |
const int iwx = i * slinesizex; |
390 | 390 |
const int iwy = i * slinesizey; |
391 |
+ const int iwd = i * slinesized; |
|
391 | 392 |
for (j = 0; j < w; j++) { |
392 | 393 |
const int x = FFMIN(spx[iwx + j], max); |
393 | 394 |
const int y = FFMIN(spy[iwy + j], max); |
395 |
+ const int z = spd[iwd + j]; |
|
394 | 396 |
const int pos = y * dlinesize + x; |
395 | 397 |
|
398 |
+ if (z < tmin || z > tmax) |
|
399 |
+ continue; |
|
400 |
+ |
|
396 | 401 |
dpd[pos] = FFMIN(dpd[pos] + intensity, max); |
397 | 402 |
if (dst[3]) |
398 | 403 |
dst[3][pos] = max; |
... | ... |
@@ -402,11 +417,16 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int |
402 | 402 |
for (i = 0; i < h; i++) { |
403 | 403 |
const int iwx = i * slinesizex; |
404 | 404 |
const int iwy = i * slinesizey; |
405 |
+ const int iwd = i * slinesized; |
|
405 | 406 |
for (j = 0; j < w; j++) { |
406 | 407 |
const int x = FFMIN(spx[iwx + j], max); |
407 | 408 |
const int y = FFMIN(spy[iwy + j], max); |
409 |
+ const int z = spd[iwd + j]; |
|
408 | 410 |
const int pos = y * dlinesize + x; |
409 | 411 |
|
412 |
+ if (z < tmin || z > tmax) |
|
413 |
+ continue; |
|
414 |
+ |
|
410 | 415 |
dst[0][pos] = FFMIN(dst[0][pos] + intensity, max); |
411 | 416 |
dst[1][pos] = FFMIN(dst[1][pos] + intensity, max); |
412 | 417 |
dst[2][pos] = FFMIN(dst[2][pos] + intensity, max); |
... | ... |
@@ -421,11 +441,16 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int |
421 | 421 |
for (i = 0; i < h; i++) { |
422 | 422 |
const int iw1 = i * slinesizex; |
423 | 423 |
const int iw2 = i * slinesizey; |
424 |
+ const int iwd = i * slinesized; |
|
424 | 425 |
for (j = 0; j < w; j++) { |
425 | 426 |
const int x = FFMIN(spx[iw1 + j], max); |
426 | 427 |
const int y = FFMIN(spy[iw2 + j], max); |
428 |
+ const int z = spd[iwd + j]; |
|
427 | 429 |
const int pos = y * dlinesize + x; |
428 | 430 |
|
431 |
+ if (z < tmin || z > tmax) |
|
432 |
+ continue; |
|
433 |
+ |
|
429 | 434 |
if (!dpd[pos]) |
430 | 435 |
dpd[pos] = FFABS(mid - x) + FFABS(mid - y); |
431 | 436 |
dpx[pos] = x; |
... | ... |
@@ -438,11 +463,16 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int |
438 | 438 |
for (i = 0; i < h; i++) { |
439 | 439 |
const int iw1 = i * slinesizex; |
440 | 440 |
const int iw2 = i * slinesizey; |
441 |
+ const int iwd = i * slinesized; |
|
441 | 442 |
for (j = 0; j < w; j++) { |
442 | 443 |
const int x = FFMIN(spx[iw1 + j], max); |
443 | 444 |
const int y = FFMIN(spy[iw2 + j], max); |
445 |
+ const int z = spd[iwd + j]; |
|
444 | 446 |
const int pos = y * dlinesize + x; |
445 | 447 |
|
448 |
+ if (z < tmin || z > tmax) |
|
449 |
+ continue; |
|
450 |
+ |
|
446 | 451 |
if (!dpd[pos]) |
447 | 452 |
dpd[pos] = FFMIN(x + y, max); |
448 | 453 |
dpx[pos] = x; |
... | ... |
@@ -457,11 +487,16 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int |
457 | 457 |
for (i = 0; i < h; i++) { |
458 | 458 |
const int iw1 = i * slinesizex; |
459 | 459 |
const int iw2 = i * slinesizey; |
460 |
+ const int iwd = i * slinesized; |
|
460 | 461 |
for (j = 0; j < w; j++) { |
461 | 462 |
const int x = FFMIN(spx[iw1 + j], max); |
462 | 463 |
const int y = FFMIN(spy[iw2 + j], max); |
464 |
+ const int z = spd[iwd + j]; |
|
463 | 465 |
const int pos = y * dlinesize + x; |
464 | 466 |
|
467 |
+ if (z < tmin || z > tmax) |
|
468 |
+ continue; |
|
469 |
+ |
|
465 | 470 |
dpd[pos] = FFMIN(max, dpd[pos] + intensity); |
466 | 471 |
dpx[pos] = x; |
467 | 472 |
dpy[pos] = y; |
... | ... |
@@ -478,9 +513,13 @@ static void vectorscope16(VectorscopeContext *s, AVFrame *in, AVFrame *out, int |
478 | 478 |
for (j = 0; j < in->width; j++) { |
479 | 479 |
const int x = FFMIN(spx[iwx + (j >> hsub)], max); |
480 | 480 |
const int y = FFMIN(spy[iwy + (j >> hsub)], max); |
481 |
+ const int z = spd[iwd + j]; |
|
481 | 482 |
const int pos = y * dlinesize + x; |
482 | 483 |
|
483 |
- dpd[pos] = FFMAX(spd[iwd + j], dpd[pos]); |
|
484 |
+ if (z < tmin || z > tmax) |
|
485 |
+ continue; |
|
486 |
+ |
|
487 |
+ dpd[pos] = FFMAX(z, dpd[pos]); |
|
484 | 488 |
dpx[pos] = x; |
485 | 489 |
dpy[pos] = y; |
486 | 490 |
if (dst[3]) |
... | ... |
@@ -537,6 +576,8 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p |
537 | 537 |
uint8_t *dpx = dst[px]; |
538 | 538 |
uint8_t *dpy = dst[py]; |
539 | 539 |
uint8_t *dpd = dst[pd]; |
540 |
+ const int tmin = s->tmin; |
|
541 |
+ const int tmax = s->tmax; |
|
540 | 542 |
int i, j, k; |
541 | 543 |
|
542 | 544 |
for (k = 0; k < 4 && dst[k]; k++) |
... | ... |
@@ -552,11 +593,16 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p |
552 | 552 |
for (i = 0; i < h; i++) { |
553 | 553 |
const int iwx = i * slinesizex; |
554 | 554 |
const int iwy = i * slinesizey; |
555 |
+ const int iwd = i * slinesized; |
|
555 | 556 |
for (j = 0; j < w; j++) { |
556 | 557 |
const int x = spx[iwx + j]; |
557 | 558 |
const int y = spy[iwy + j]; |
559 |
+ const int z = spd[iwd + j]; |
|
558 | 560 |
const int pos = y * dlinesize + x; |
559 | 561 |
|
562 |
+ if (z < tmin || z > tmax) |
|
563 |
+ continue; |
|
564 |
+ |
|
560 | 565 |
dpd[pos] = FFMIN(dpd[pos] + intensity, 255); |
561 | 566 |
if (dst[3]) |
562 | 567 |
dst[3][pos] = 255; |
... | ... |
@@ -566,11 +612,16 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p |
566 | 566 |
for (i = 0; i < h; i++) { |
567 | 567 |
const int iwx = i * slinesizex; |
568 | 568 |
const int iwy = i * slinesizey; |
569 |
+ const int iwd = i * slinesized; |
|
569 | 570 |
for (j = 0; j < w; j++) { |
570 | 571 |
const int x = spx[iwx + j]; |
571 | 572 |
const int y = spy[iwy + j]; |
573 |
+ const int z = spd[iwd + j]; |
|
572 | 574 |
const int pos = y * dlinesize + x; |
573 | 575 |
|
576 |
+ if (z < tmin || z > tmax) |
|
577 |
+ continue; |
|
578 |
+ |
|
574 | 579 |
dst[0][pos] = FFMIN(dst[0][pos] + intensity, 255); |
575 | 580 |
dst[1][pos] = FFMIN(dst[1][pos] + intensity, 255); |
576 | 581 |
dst[2][pos] = FFMIN(dst[2][pos] + intensity, 255); |
... | ... |
@@ -585,11 +636,16 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p |
585 | 585 |
for (i = 0; i < h; i++) { |
586 | 586 |
const int iw1 = i * slinesizex; |
587 | 587 |
const int iw2 = i * slinesizey; |
588 |
+ const int iwd = i * slinesized; |
|
588 | 589 |
for (j = 0; j < w; j++) { |
589 | 590 |
const int x = spx[iw1 + j]; |
590 | 591 |
const int y = spy[iw2 + j]; |
592 |
+ const int z = spd[iwd + j]; |
|
591 | 593 |
const int pos = y * dlinesize + x; |
592 | 594 |
|
595 |
+ if (z < tmin || z > tmax) |
|
596 |
+ continue; |
|
597 |
+ |
|
593 | 598 |
if (!dpd[pos]) |
594 | 599 |
dpd[pos] = FFABS(128 - x) + FFABS(128 - y); |
595 | 600 |
dpx[pos] = x; |
... | ... |
@@ -602,11 +658,16 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p |
602 | 602 |
for (i = 0; i < h; i++) { |
603 | 603 |
const int iw1 = i * slinesizex; |
604 | 604 |
const int iw2 = i * slinesizey; |
605 |
+ const int iwd = i * slinesized; |
|
605 | 606 |
for (j = 0; j < w; j++) { |
606 | 607 |
const int x = spx[iw1 + j]; |
607 | 608 |
const int y = spy[iw2 + j]; |
609 |
+ const int z = spd[iwd + j]; |
|
608 | 610 |
const int pos = y * dlinesize + x; |
609 | 611 |
|
612 |
+ if (z < tmin || z > tmax) |
|
613 |
+ continue; |
|
614 |
+ |
|
610 | 615 |
if (!dpd[pos]) |
611 | 616 |
dpd[pos] = FFMIN(x + y, 255); |
612 | 617 |
dpx[pos] = x; |
... | ... |
@@ -621,11 +682,16 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p |
621 | 621 |
for (i = 0; i < h; i++) { |
622 | 622 |
const int iw1 = i * slinesizex; |
623 | 623 |
const int iw2 = i * slinesizey; |
624 |
+ const int iwd = i * slinesized; |
|
624 | 625 |
for (j = 0; j < w; j++) { |
625 | 626 |
const int x = spx[iw1 + j]; |
626 | 627 |
const int y = spy[iw2 + j]; |
628 |
+ const int z = spd[iwd + j]; |
|
627 | 629 |
const int pos = y * dlinesize + x; |
628 | 630 |
|
631 |
+ if (z < tmin || z > tmax) |
|
632 |
+ continue; |
|
633 |
+ |
|
629 | 634 |
dpd[pos] = FFMIN(255, dpd[pos] + intensity); |
630 | 635 |
dpx[pos] = x; |
631 | 636 |
dpy[pos] = y; |
... | ... |
@@ -642,9 +708,13 @@ static void vectorscope8(VectorscopeContext *s, AVFrame *in, AVFrame *out, int p |
642 | 642 |
for (j = 0; j < in->width; j++) { |
643 | 643 |
const int x = spx[iwx + (j >> hsub)]; |
644 | 644 |
const int y = spy[iwy + (j >> hsub)]; |
645 |
+ const int z = spd[iwd + j]; |
|
645 | 646 |
const int pos = y * dlinesize + x; |
646 | 647 |
|
647 |
- dpd[pos] = FFMAX(spd[iwd + j], dpd[pos]); |
|
648 |
+ if (z < tmin || z > tmax) |
|
649 |
+ continue; |
|
650 |
+ |
|
651 |
+ dpd[pos] = FFMAX(z, dpd[pos]); |
|
648 | 652 |
dpx[pos] = x; |
649 | 653 |
dpy[pos] = y; |
650 | 654 |
if (dst[3]) |
... | ... |
@@ -963,12 +1033,20 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
963 | 963 |
static int config_input(AVFilterLink *inlink) |
964 | 964 |
{ |
965 | 965 |
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); |
966 |
- VectorscopeContext *s = inlink->dst->priv; |
|
966 |
+ AVFilterContext *ctx = inlink->dst; |
|
967 |
+ VectorscopeContext *s = ctx->priv; |
|
967 | 968 |
|
968 | 969 |
s->is_yuv = !(desc->flags & AV_PIX_FMT_FLAG_RGB); |
969 | 970 |
s->size = 1 << desc->comp[0].depth; |
970 | 971 |
s->mult = s->size / 256; |
971 | 972 |
s->depth = desc->comp[0].depth; |
973 |
+ s->tmin = s->lthreshold * (s->size - 1); |
|
974 |
+ s->tmax = s->hthreshold * (s->size - 1); |
|
975 |
+ |
|
976 |
+ if (s->tmin > s->tmax) { |
|
977 |
+ av_log(ctx, AV_LOG_ERROR, "low threshold should be less than high threshold\n"); |
|
978 |
+ return AVERROR(EINVAL); |
|
979 |
+ } |
|
972 | 980 |
|
973 | 981 |
if (s->mode == GRAY && s->is_yuv) |
974 | 982 |
s->pd = 0; |