Log in

View Full Version : TweakYPlaneNoiseThresh() - script


StainlessS
20th September 2021, 01:01
Might come in useful.

TweakYPlaneNoiseThresh.avsi

# TweakYPlaneNoiseThresh.avsi

/*
TweakYPlaneNoiseThresh() v0.04, by StainlessS @ Doom9. # https://forum.doom9.org/showthread.php?p=1952709#post1952709
Req AVS+, RT_Stats, Grunt.
Any Planar Y/YUV/A. [depth 8 -> 32].

Shows results of some YPlane operation [YPlaneMin, YPlaneMax, YPlaneMinMaxDifference] on sampled clip, with multiple simultaneous Threshold settings.

TweakYPlaneNoiseThresh(clip c,int "YPlaneOp"=0,Float "NoiseBase"=0.0,Float "NoiseStep"=0.005,Int "Rows"=21)

eg YPlaneMin(Threshold=NoiseTh)
Threshold is a percentage, the maximum percent population of the pixels that are allowed to be ignored below minimum (ignore extreme pixels ie noise).
YPlaneMin first creates a pixel population count array of the current frame, and then it creates a running total of pixel population stepping from 0 upwards.
When the running total pixel population % is greater or equal to threshold arg, it returns the index of the array element that it has so far reached.
If the lowest populated array elements total less than Threshold, they are ignored. If the lowest populated element % population is greater or equal to Threshold, then nothing
is ignored and that lowest poplated pixel element index is returned.
YPlaneMin(threshold=0.0) ignores nothing and returns the index of the lowest populated element in the count array.
You might use eg YPlaneMin(Threshold=0.1) to ignore (at most) the darkest 0.1% of pixels when finding minimum pixel luma.
YplaneMax(Threshold=0.2), ignores lightest (at most) 0.2% of pixels.
YplaneMinMaxDifference(Threshold=0.3), ignores (at most) the darkest 0.3% and lightest 0.3% of pixels.
YPlaneMedian(), is implemented as YPlaneMin(Threshold=50.0).

Metrics: (only 5 lines of results out of 21)

0] TweakYPlaneNoiseThresh: YPlaneMin @ NoiseTh % (1280x720P10)
Ignore up to Ignore single
NoiseTh OneInXPixels Square of Pixels YPlaneMin(NoiseTh)
0.000 % 0 0x0 152
0.050 % 2000 21x21 168
0.100 % 1000 30x30 172
0.150 % 666 37x37 172
0.200 % 500 43x43 172

To specify to ignore at most 1 in every 500 darkest pixels in a frame, you can use YPlaneMin(Threshold=100.0/500.0) [as the 5th result line above].
The "Ignore single Square of pixels" entry shows the approx max size of a non noise object that could potentially be ignored by mistake [when no other lower level noise is on frame].
"Ignore single Square of pixels" size shown will vary with frame size.
The rightmost "YPlaneMin(NoiseTh)" column shows the actual result from (in this case) YPlaneMin().

Args:
YPlaneOp, default 0, 0->2, 0=YPlaneMin(), 1=YPlaneMax(), 2=YPlaneMinMaxDifference().
NoiseBase, default 0.00, 0.0->1.0, Lowest Noise Threshold tested.
NoiseStep default 0.005, 0.0<NoiseStep<=1.0, Noise Theshold step between 21 different Noise Thresholds, relative to NoiseBase.
Rows, default 21, 1 -> max allowed by frame height (silent limit). Number of rows displayed. [the more rows, the slower]
*/

Function TweakYPlaneNoiseThresh(clip c,int "YPlaneOp",Float "NoiseBase",Float "NoiseStep",Int "Rows") {
c myName="TweakYPlaneNoiseThresh: "
YPlaneOp = Default(YPlaneOp,0)
NoiseBase = Default(NoiseBase,0.0)
NoiseStep = Default(NoiseStep,0.005)
Assert(0 <= YPlaneOp <= 2,myName+"0 <= YPlaneOp <= 2")
Assert(0.0 <= NoiseBase <= 1.0,myName+"0.0 <= NoiseBase <= 1.0")
Assert(0.0 < NoiseStep <= 1.0,myName+"0.0 < NoiseStep <= 1.0")
W=Width H=Height RowMax=(H/18)-3 bpc=BitsPerComponent
Rows=Default(Rows,21).Max(1).Min(RowMax)
Assert(!IsRGB&&IsPlanar,myName+"Planar with Y only")
YOP=Select(YPLaneOp,"YPlaneMin","YPLaneMax","YPlaneMinMaxDifference")
evS="T%d=NoiseBase+(i*NoiseStep) I%d=(T%d>0.0?100.0/T%d:0).Int S%d=(T%d>0.0?SqRt(P*T%d/100).Round:0).Int Y%d="+YOP+"(T%d)"
# Newlines are a PITA, gotta leave "\\n" for Scriptclip Eval("S=RT_string..."), so using here "\\\\n" to leave "\\n" in Scriptclip. [Same for "%%%%"="%%"]
dhS=RT_String("""RT_String("%%d] TweakYPlaneNoiseThresh: %s @ NoiseTh %%%% (%dx%dP%d)\\\\n Ignore up to Ignore single\\\\n""" +
\ "NoiseTh%%%% OneInXPixels Square of pixels %s(NoiseTh)\\\\n",YOP,W,H,bpc,YOP)
drS="%.6f %10d %5dx%-5d " + (bpc==32?"%f":"%5d")
dvS="\ T%d,I%d,S%d,S%d,Y%d"
vS=","+Chr(10)+"\ n,"+chr(10)
for(i=0,Rows-1) { dhS=RT_String("%s%s%s",dhS,drS,(i==Rows-1?Chr(34):"\\n")) vS=RT_String("%s%s%s",vS,RT_String(dvS,i,i,i,i,i),(i==Rows-1)?")":","+Chr(10)) }
rtS=dhS+vS
# DbgS=rts.RT_StrReplace("\\n",Chr(10)) RT_WriteFile(".\TweakYPlaneNoiseThresh_DEBUG.txt","%s",DbgS) RT_Debug(DbgS) # Output Debugging to file and DebugView
SSS="""
n=current_frame W=Width H=Height P=W*H
For(i=0,Rows-1) { Eval(RT_String(evS,i,i,i,i,i,i,i,i,i)) }
Return Subtitle(Eval(rtS),lsp=0,Font="Courier New")
"""
Return GScriptClip(SSS,Args="NoiseBase,NoiseStep,Rows,evS,rtS",Local=True)
}


Client

##### CONFIG #######
#Avisource(".\OUT\TEST1.avi")
#FfVideoSource(".\OUT\TEST1.avi")
AviSource(".\BP-KTL.AVI")
#ConvertBits(10)

YPlaneOp = 0 # 0) 0->2, 0=YPlaneMin(), 1=YPlaneMax(), 2=YPlaneMinMaxDifference().
NoiseBase = 0.00 # 0.0) 0.0->1.0, Lowest Noise Threshold shown.
NoiseStep = 0.005 # 0.005) 0.0<NoiseStep<=1.0, Noise Theshold stepping.
Rows = 9999 # 9999, All of em' (silent limited to frame height).
##### END CONFIG ######

Return TweakYPlaneNoiseThresh(YPlaneOp,NoiseBase,NoiseStep,Rows)


What it looks like [not selected to demo anything, just a clip I had at hand]
https://i.postimg.cc/4ncpCNcZ/Tweak-YPlane-Noise-Thresh-01.jpg (https://postimg.cc/4ncpCNcZ)

ChaosKing
20th September 2021, 07:56
I don't see the wives! 😤

But usefull script 😁

real.finder
20th September 2021, 11:33
I don't see the wives! ��


maybe you will say "why not both?" :D but more wives will destroy your life

anyway, StainlessS, "Req AVS+" but you still use old grun instead of http://avisynth.nl/index.php/Function_objects :rolleyes:

see here https://github.com/Dogway/Avisynth-Scripts/blob/a881360e22c21dbf6c7fa0d497cb821f24ac5a9b/SMDegrain%20v3.3.0d/SMDegrain%20v3.3.0d.avsi#L173 and https://github.com/Dogway/Avisynth-Scripts/pull/11/commits/36b554ae17de1b1f9c473eecef0c5f4747704439

StainlessS
20th September 2021, 14:13
I don't see the wives! ��
I had to puzzle over that for quite a time, A picture is worth a thousand words.


"Req AVS+" but you still use old grun instead of ... :rolleyes:

Old Dog, Old Tricks. (Dogway [EDIT: And Real.Finder] must be just a puppy).
AVS+ req, for native HBD YPlane...(), and builtin GScript stuff.

I should really show bit depth on frame too.
Currently modding to make user selectable number of rows [maybe 21 rows too much for some, have not tested on slow machine, only i7-8700].
Will repost original script [maybe showing bit depth] later in thread, so it can be seen what the update is doing.
[The update will be very cryptic gobble-de-gook (to make the variable rows stuff work)].


EDIT: Original script, updates will be more cryptic to understand.

# TweakYPlaneNoiseThresh.avsi

/*
TweakYPlaneNoiseThresh(), by StainlessS @ Doom9. # https://forum.doom9.org/showthread.php?p=1952709#post1952709
Req AVS+, RT_Stats, Grunt.
Any PLanar Y/YUV/A. [depth 8 -> 16].

Shows results of some YPlane operation [YPlaneMin, YPlaneMax, YPlaneMinMaxDifference] on sampled clip, with 21 simultaneous Threshold settings.

TweakYPlaneNoiseThresh(clip c,int "YPlaneOp"=0,Float "NoiseBase"=0.0,Float "NoiseStep"=0.05)

eg YPlaneMin(Threshold=NoiseTh)
Threshold is a percentage, the maximum percent population of the pixels that are allowed to be ignored below minimum (ignore extreme pixels ie noise).
YPlaneMin first creates a pixel population count array of the current frame, and then it creates a running total of pixel population stepping from 0 upwards.
When the running total pixel population % is greater or equal to threshold arg, it returns the index of the array element that it has so far reached.
If the lowest populated array elements total less than Threshold, they are ignored. If the lowest populated element % population is greater or equal to Threshold, then nothing
is ignored and that lowest poplated pixel element index is returned.
YPlaneMin(threshold=0.0) ignores nothing and returns the index of the lowest populated element in the count array.
You might use eg YPlaneMin(Threshold=0.1) to ignore (at most) the darkest 0.1% of pixels when finding minimum pixel luma.
YplaneMax(Threshold=0.2), ignores lightest (at most) 0.2% of pixels.
YplaneMinMaxDifference(Threshold=0.3), ignores (at most) the darkest and lightest 0.3% of pixels.
YPlaneMedian, is implemented as YPlaneMin(Threshold=50.0).

Metrics: (only 5 lines of results out of 21)

0] TweakYPlaneNoiseThresh: YPlaneMin @ NoiseTh % (1280x720P10)
Ignore up to Ignore single
NoiseTh OneInXPixels Square of Pixels YPlaneMin(NoiseTh)
0.000 % 0 0x0 152
0.050 % 2000 21x21 168
0.100 % 1000 30x30 172
0.150 % 666 37x37 172
0.200 % 500 43x43 172

To specify to ignore at most 1 in every 500 darkest pixels in a frame, you can use YPlaneMin(Threshold=100.0/500.0) [as the 5th result line above].
The "Ignore single Square of pixels" entry shows the approx max size of a non noise object that could potentially be ignored by mistake [when no other noise is on frame].
The rightmost "YPlaneMin(NoiseTh)" column shows the actual result from (in this case) YPlaneMin().

Args:
YPlaneOp, default 0, 0->2, 0=YPlaneMin(), 1=YPlaneMax(), 2=YPlaneMinMaxDifference().
NoiseBase, default 0.00, 0.0->1.0, Lowest Noise Threshold tested.
NoiseStep default 0.05, 0.0<NoiseStep<=1.0, Noise Theshold step between 21 different Noise Thresholds, relative to NoiseBase.
*/

Function TweakYPlaneNoiseThresh(clip c,int "YPlaneOp",Float "NoiseBase",Float "NoiseStep") {
c
myName = "TweakYPlaneNoiseThresh: "
YPlaneOp = Default(YPlaneOp,0)
NoiseBase = Default(NoiseBase,0.0)
NoiseStep = Default(NoiseStep,0.05)
Assert(0 <= YPlaneOp <= 2,myName+"0 <= YPlaneOp <= 2")
Assert(0.0 <= NoiseBase <= 1.0,myName+"0.0 <= NoiseBase <= 1.0")
Assert(0.0 < NoiseStep <= 1.0,myName+"0.0 < NoiseStep <= 1.0")
YOP = Select(YPLaneOp,"YPlaneMin","YPLaneMax","YPlaneMinMaxDifference")
evS="T%d=NoiseBase+(i*NoiseStep) I%d=(T%d>0.0?100.0/T%d:0).Int S%d=(T%d>0.0?SqRt(P*T%d/100).Round:0).Int Y%d="+YOP+"(T%d)"
SSS=("""
n = current_frame W=Width H=Height P=W*H bpc=BitsPerComponent
For(i=0,20) { Eval(RT_String(evS,i,i,i,i,i,i,i,i,i)) }
S=RT_String(
\ "%d] TweakYPlaneNoiseThresh: %s @ NoiseTh %% (%dx%dP%d)\\n" +
\ " Ignore up to Ignore single\\n" +
\ "NoiseTh OneInXPixels Square of pixels %s(NoiseTh)\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n" +
\ "%.3f %% %6d %4dx%-4d %5d\\n"
\ ,n,YOP,W,H,bpc,YOP,
\ T0,I0,S0,S0,Y0,T1,I1,S1,S1,Y1,T2,I2,S2,S2,Y2,T3,I3,S3,S3,Y3,T4,I4,S4,S4,Y4,T5,I5,S5,S5,
\ Y5,T6,I6,S6,S6,Y6,T7,I7,S7,S7,Y7,T8,I8,S8,S8,Y8,T9,I9,S9,S9,Y9,T10,I10,S10,S10,Y10,
\ T11,I11,S11,S11,Y11,T12,I12,S12,S12,Y12,T13,I13,S13,S13,Y13,T14,I14,S14,S14,Y14,
\ T15,I15,S15,S15,Y15,T16,I16,S16,S16,Y16,T17,I17,S17,S17,Y17,T18,I18,S18,S18,Y18,
\ T19,I19,S19,S19,Y19,T20,I20,S20,S20,Y20)
Return Subtitle(S,lsp=0,Font="Courier New")
""")
Return GScriptClip(SSS,Args="YOP,NoiseBase,NoiseStep,evS",Local=True)
}


Client

##### CONFIG #######
#Avisource(".\OUT\TEST1.avi")
FfVideoSource(".\OUT\TEST1.avi")

YPlaneOp = 0 # 0) 0->2, 0=YPlaneMin(), 1=YPlaneMax(), 2=YPlaneMinMaxDifference().
NoiseBase = 0.00 # 0.0) 0.0->1.0, Lowest Noise Threshold shown.
NoiseStep = 0.05 # 0.05) 0.0<NoiseStep<=1.0, Noise Theshold stepping.
##### END CONFIG ######

Return TweakYPlaneNoiseThresh(YPlaneOp,NoiseBase,NoiseStep)

https://i.postimg.cc/mcwsZYnV/Tweak-YPlane-Noise-Thresh-00.jpg (https://postimg.cc/mcwsZYnV)

StainlessS
20th September 2021, 15:44
First post updated with display of bit depth on frame, [ Just shows eg (1280x720P10) ]
Above post added this update and will leave there when further updated as is simpler to see what it does.

StainlessS
20th September 2021, 19:37
Update to post 1.
Now can select Rows (default 21), 1 -> height of frame (silent limit).
Where possible, template strings are now constructed outside of scriptclip, should use less memory [although I dont see anybody scanning a 200,000 frame clip with it].


FfVideoSource(".\OUT\TEST1.avi")
ConvertBits(16)
TweakYPlaneNoiseThresh(Rows=999999999)

https://i.postimg.cc/90bHLctv/Tweak-YPlane-Noise-Thresh-00.jpg (https://postimages.org/)

EDIT: Above, 16 bit.

EDIT: Zooming in a bit, changing NoiseStep from 0.05 to 0.01.

https://i.postimg.cc/k4KL1WdV/Tweak-YPlane-Noise-Thresh-01.jpg (https://postimages.org/)

StainlessS
21st September 2021, 01:54
OK, here v0.03, supports 32 bit Float, see 1st post.
Was
drS="%.3f %% %6d %4dx%-4d %5d"
Now,
drS="%.3f %% %6d %4dx%-4d " + (bpc==32?"%f":"%5d")

God I'm good!, just came back from pub and there it was, easy peasy, I should go more often, helps get me in that genius zen mode.

https://i.postimg.cc/nr23PMy4/Tweak-YPlane-Noise-Thresh-WIP-00.jpg (https://postimages.org/)

EDIT: Not tested much, [not much to test :) ]

EDIT: Above with NoiseStep 0.01 instead of default 0.05 (same as prev image), [thought it was borked for a few seconds]


FfVideoSource(".\OUT\TEST1.avi")
ConvertBits(32)
TweakYPlaneNoiseThresh(NoiseStep=0.01,Rows=999999999)

StainlessS
29th September 2021, 21:02
1st post updeted, v0.04.
Allowed for smaller thresholds [more digits], changed default NoiseStep from 0.05 to 0.005.
Fixed RowMax=(H/18)-3 [was RowMax=H/20]

used client

##### CONFIG #######
#Avisource(".\OUT\TEST1.avi")
#FfVideoSource(".\OUT\TEST1.avi")
AviSource(".\BP-KTL.AVI")
#ConvertBits(10)

YPlaneOp = 0 # 0) 0->2, 0=YPlaneMin(), 1=YPlaneMax(), 2=YPlaneMinMaxDifference().
NoiseBase = 0.00 # 0.0) 0.0->1.0, Lowest Noise Threshold shown.
NoiseStep = 0.005 # 0.005) 0.0<NoiseStep<=1.0, Noise Theshold stepping.
Rows = 9999 # 9999, All of em' (silent limited to frame height).
##### END CONFIG ######

Return TweakYPlaneNoiseThresh(YPlaneOp,NoiseBase,NoiseStep,Rows)


https://i.postimg.cc/zDt7gyXL/Tweak-YPlane-Noise-Thresh-01.jpg (https://postimg.cc/4ncpCNcZ)

VoodooFX
4th October 2021, 18:01
Where this could be useful or for what purpose you wrote this func?

StainlessS
4th October 2021, 20:10
Where this could be useful or for what purpose you wrote this func?
Dont know, you decide.

However, this was the thread that prompted script function:- https://forum.doom9.org/showthread.php?p=1952621#post1952621

anton_foy
14th July 2022, 22:55
Maybe I will sound dumb here but the pixels it is allowed to ignore is considered noise. So would this be suitable to use for realtime (ScriptClip) to estimate how noisy the frame is? I guess the output value is rather how much "noise free" the image is?
Would be interested to try this in my script where I dynamically adjust Thsad and Tradius with temporal denoisers.
As for now I use a combo of averageLuma and rgbDifference to get some kind of noise estimation value but it has some problems.

StainlessS
15th July 2022, 12:39
pixels it is allowed to ignore is considered noise.
Extreme outliers, maybe noise.

So would this be suitable to use for realtime (ScriptClip) to estimate how noisy the frame is?
Not really. Is visual feedback only.
FranceBB in thread prompting the script, wanted to detect black sequence at end of clip,

Hi there,
my colleagues in another floor are capturing losslessly our whole archive using several VTRs and a BlackMagic DeckLink that saves the file as 4:2:2 10bit v210 lossless with PCM audio.
Unfortunately, timecode jumps so it's not possible to set TCin and TCout to make the recording stop automatically.
What they're doing is trying to set up alarm clocks in their phones and stop tapes manually, but since they have to do plenty of other things at the same time, sometimes they forget.
This leads to several minutes of black frames at the end of a tape recording and, sometimes, the tape goes back to the beginning.
Of course, I see everything that is recorded and I've been using Virtual Dub with Direct Stream Copy to trim out everything since v210 is lossless and all intra as every frame is a keyframe, so I can trim out easily without re-encoding, however we're getting to a point in which I can't trim out as many files.
The other day alone I've been trimming out 37 files...
The day before that it was 53 files...
I have other things to do in my job of course, I can't spend the whole day trimming out black frames in several files...
I can't go on like this and my boss response was: "Automatize it!"
so... here I am: is there a way (either in Avisynth or FFMpeg) to detect black frames at the end of a file and trim them out automatically?

(I know, I know, levels might come into play as tapes don't have a perfect black sitting at 64, so 0.0V, however is there anything that has a tweakable threshold and can do this?)

This script only purpose was to visually examine FranceBB black frames to see what theshold might be best in a "black frames detector".

Here is the script function that it was intended to help find best NoiseTh noise threshold for [I did not have any idea if was digital Black, or had some/much noise]
From here:- https://forum.doom9.org/showthread.php?p=1952526#post1952526

Function FindNonBlackFramesAtEnd(clip c,Int YMaxTh,Float "NoiseTh",bool "Debug") {
myName="FindNonBlackFramesAtEnd: "
c
Debug=Default(debug,False)
FC = FrameCount
result = 0
NoiseTh=Float(Default(NoiseTh,0.4))
for(n=FC-1,0,-1) {
current_frame = n
Y = YPlaneMax(Last,Threshold=NoiseTh)
(Debug) ? RT_DebugF("%d] Y=%f",n,Y,name=myName) : NOP
if(Y>YMaxTh) {result = n+1 n = -1 }
}
return result
}


I tried to make it a bit more flexible [TweakYPlaneNoiseThresh()], but have no idea what other uses it could have.

EDIT: We did not want to trim off black at end of clip that was actually part of the video, (maybe with audio), only the extra artificially added frames that should be stripped off.

EDIT: That function FindNonBlackFramesAtEnd() actually returns the frame number of the first artificial black frame, OR, the length of the NON Black clip.
[probably a misleading function name - I'm shit at thinking of function names, they all start out as Fred(), or Bill() or similar]