View Full Version : automate static removal
greymouse
3rd August 2018, 21:53
hi film friends
I need some help, i'm currently working on this video, which has static noise going often through my video,
I am at this time dropping the frames but i'm doing this manually and theres a lot of noise every and so many frames in an hour of footage
I was using morph() but that again due to the number of frames that need fixing is a laborious task
is there a way to automate this?
I know there's black lines going through the video as well but I know how to fix that
the noise I refer to are on frames
71,88,94,116,167
sample Video:
https://www.sendspace.com/file/1o6sp0
any help would be great in the mean time i'll keep plodding along
Thanks!
Gordon
greymouse
3rd August 2018, 22:02
this is my drop frame list so far
22371
22483
22519
22529
22765
23329,23330
24624
24987
25045
25063
25153
25200
25260,25261
25310
25324
25366
25419,25420
25460,25461
25490
25552,25554
25596,25597
25712
25777
26017
26174
26249
26656
26892
27021
27686,27687
27703
27764
27790
27932,27933
28081
28128
28164,28173
28321,28323
28410
28455
28473
28611
28691 ,28692
28872
28885
28923
28974,28984
29036
29051
29181
29210
29318
29324
29531,29538
29849
29876
29946
29962
30028
30208
30214
30237
30418
30546,30547
30970
31008
31015
31024
31102
31113
31504
31609
31842
31876,31884
31957
32010
32123
32156
32225
32325
32553,32554
32830 ,32831
32946
32987
33138
33445
33483,33491
33562
33830
34044
34573
34663
34692
34705
34750
34798
34805
34807
34861
34868,34875
34934,34944
34948
34985
35140
35346
35411,35412
35483,35492
35506,35526
35530,35538
35553
35581
35677 ,35685
35688,35689
35761
36163
36163
36276
36333
36356,36365
36407,36415
36598
36739
36773
37156,37164
37186
37306,37322
37331
37336,37337
37374
37569,37570
37602,37610
37610
37653
37681,37689
37730
37794,37802
37957,37965
38020,38021
38147
38165,38166
38311,38312
38343
38385,38393
38421
38436,38437
38463
38531
38649
38853
39103
39186
39321,39331
39598
39603
39819
39863,39874
39883
39951,39952
39954,39956
40250,40251
40301
40479
40707,40708
41003
41654,41662
41868
42074
42132,42134
42237,42238
42278
43590
43774
43995,44002
44189
44444
44468
44492
44509
44511
44557
44574
44643
44646
44647
44650
44694
44723
44749
44775
44868
44926
44953
44985,44986
45041
45047
45182
45385
45442,45443
45448
45462
45500
45532,45534
45730
45737
45765
45868,45870
45883
45906
45984
45989
45992,46003
46016
46028
46058
46062
46093,46094
46096
46152
46281
46297
46430
46555
46703
46721
46744
46782
46801
46811,46813
46849
46866
46974
47029
47062
47141
47182
47201,47202
47222
47270,47271
47278
47366
47533
47573
47615
47620
47631
47653
47699
47755
47843
47851,47853
47892,49156
49233,49235
49322
49394,49395
49417
49448
49471,49472
49497
49510
49545
49573
49596
49601
49619
49653,49656
49660
49666
49675
49687
49690,49691
49696
49724
49734
49760
49838
49871
49927
49948
49974
49989
50012
50128
50136,50137
50189
50207,50208
50237
50265
50278
50312
50363
50397,50398
50401
50407
50420
50425,50426
50456
50494
50572,50573
50591
50593
50606
50615
50682
50711
50736
50949,50952
50965
50976
50996
51082
51085
51089
51119
51136
51146
51174,51175
51255,51256
51308
51358
51406
51410
51473,51475
51501
51510
51532,51534
51591
51797
51947
52119
52155
52180
52302,52303
52319
52329,52330
52346,52347
52671
52674
52682
52699
52810
52821,52822
52826,52837
52840
52846
52900,52902
52918
53006
53011
53025
53062
53287
53395
53492
53514
53564 ,53565
53703
53715
53746
53798
53829
53901
53911
53957
54072
54140
54147
this is me going frame by frame and dropping those frames
johnmeyer
3rd August 2018, 23:04
I developed a script, and posted it here:
Finding individual "bad" frames in video; save frame number; or repair (https://forum.doom9.org/showthread.php?p=1789584#post1789584)
This will replace any bad frame with a motion estimated version, created using adjacent frames.
The bad frame detection logic might be able to notice the noise frames, and handle everything for you automatically.
[edit]OK, I tried it on your video. My "bad frame" detection logic needs to be modified to better detect only the frames with the break up (StainlessS??). This should be easy to do because the tearing is mostly pure white. However, even with the existing logic, the following code does a pretty good job of fixing the problems, and it does so automatically. If you use it exactly as posted, it will automatically replace frames, and will show a few dots in the upper left corner on any frame that has been synthesized from adjacent frames. By changing the TRUE/FALSE values in the control section, you can change the script to output frame numbers, or actually write new video to a file.
Feel free to play around with it, especially the threshold.
#Find And (Optionally) Fix Bad Frames
#John Meyer - December 13, 2016
#Rev. 2.0
#Thanks to Gavino and StainlessS for making the script more professional.
#This script detects single bad frames.
#You can configure the script to write, to a file, the frame numbers of all frames which are detected as "bad".
#You can also configure it to automatically replace each bad frame with a new
#frame interpolated from its neighbors.
#This script will fail if the bad frame happens immediately before or after a scene change.
#This script will also fail to find a bad frame if there is more than one bad frame in a row.
#It works very well for finding both blank frames and also "flash" frames (like those caused
#by a photographer's flash). It will also find single frames which have lots of
#static or pixels. It can also find a frame with large x or y displacement from adjacent frames, like
#a film frame that wasn't properly registered in the film gate, or an analog
#video frame that lost vertical sync.
#When using VirtualDub, to create the text file containing the bad frame numbers,
#select "Run Video Analysis Pass" in the VirtualDub File menu. If you are simultaneously
#creating a fixed video file, you don't need to do this because the file will
#be created simultaneously as the fixed video file is created.
#The script uses ratios of the metrics for the current frame to the same metrics
#on the two adjacent frames. Under normal circumstances, the metrics should be quite
#similar, and therefore the ratio should be very near to unity (i.e., 1.00).
#Run through the video with the "METRICS" variable set to "True" and look at the metrics
#in order to determine an optimum threshold value. A larger threshhold will
#catch fewer bad frames, and a lower threshold will eventually create false positives.
#The replacement code works well enough that if you end up replacing a few frames that are
#actually good, you probably won't notice it.
#-----------------------------
loadplugin("C:\Program Files\AviSynth 2.5\plugins\MVTools\mvtools2.dll")
#Control script operation by changing the following values :
#=====================================================================
VideoFile = "E:\Documents\Dnload\UNPACK\Rollaine_Noise_Sample_Pass1_huffy.avi"
global badthreshold = 1.2 # Set METRICS=TRUE to determine best value
METRICS = FALSE # TRUE will show Metrics ONLY (i.e., TRUE overrides all other selctions)
SHOWDOT = TRUE # TRUE will add "***" to each replacment frame (for troubleshooting)
REPLACE = TRUE # TRUE will replace each bad frame with a one that is interpolated from adjacent frames
FILEWRITE = FALSE # TRUE will create a file which contains the frame numbers of all bad frames
filename = "E:\Bad.txt" # Set to name and location where you want the frame numbers stored
#=====================================================================
source = AVISource(VideoFile).convertTOYV12().killaudio()
script = """Subtitle("\nPrevious Ratio = " + String( YDifferenceFromPrevious(source) /
\ Max(YDifferenceFromPrevious( selectevery(source, 1, -1)),0.00001) ) +
\ "\nNext Ratio = " + String( YDifferenceToNext(source) /
\ Max(YDifferenceToNext(selectevery(source, 1, 1)),0.00001)), lsp=0)"""
MetClip = Scriptclip(source, script)
FileFixed = (FILEWRITE)
\ ? WriteFileIf(source, filename, "
\ YDifferenceFromPrevious() / Max(YDifferenceFromPrevious( selectevery(1, -1)),0.00001)
\ > badthreshold && YDifferenceToNext() / Max(YDifferenceToNext(selectevery(1, 1)),0.00001)
\ > badthreshold", "current_frame", append = false) : Source
output = (METRICS) ? MetClip : (REPLACE) ? ReplaceBadI(FileFixed,showdot) : FileFixed
return output
#------------------------------
function ReplaceBadI (clip c, bool SHOWDOT)
{
even = c.SeparateFields().SelectEven()
super_even = SHOWDOT ? even.subtitle("***").MSuper(pel=2) : even.MSuper(pel=2)
vfe = manalyse(super_even,truemotion=true,isb=false,delta=2)
vbe = manalyse(super_even,truemotion=true,isb=true,delta=2)
filldrops_e = mflowinter(even,super_even,vbe,vfe,time=50)
odd = c.SeparateFields().SelectOdd()
super_odd = SHOWDOT ? odd.subtitle("***").MSuper(pel=2) : odd.MSuper(pel=2)
vfo = manalyse(super_odd,truemotion=true,isb=false,delta=2)
vbo = manalyse(super_odd,truemotion=true,isb=true,delta=2)
filldrops_o = mflowinter(odd,super_odd,vbo,vfo,time=50)
Interleave(filldrops_e,filldrops_o)
Replacement = Weave()
fixed = ConditionalSelect(c, "
Prev = YDifferenceFromPrevious()
Prev1 = Max(YDifferenceFromPrevious(SelectEvery(1,-1)),0.00001)
Next = YDifferenceToNext()
Next1 = Max(YDifferenceToNext(SelectEvery(1,1)),0.00001)
Prev/Prev1 < badthreshold && Next/Next1 < badthreshold ? 0 : 1", \
c, selectevery(Replacement,1,-1))
return fixed
}
greymouse
3rd August 2018, 23:16
:thanks: I'll give it ago, this noise is running through the whole 3 hour tape, I've tried to re-record it but the noise is still in the same place on the time line
johnmeyer
3rd August 2018, 23:23
Note that I edited my post above after you posted. You might want to re-read it.
greymouse
3rd August 2018, 23:42
Note that I edited my post above after you posted. You might want to re-read it.
ah! thanks will read again
greymouse
4th August 2018, 00:03
thank you very much! i'll have tinker
StainlessS
4th August 2018, 10:09
Greymouse, Post result of your tinker ['result'=success/failure].
Bit busy at the mo, but may be able to take a peek in a few days.
Mounir
5th August 2018, 10:07
For the automation part i don't know but to interpolate frames i always found svpflow work better than morph in most cases, see below
LoadPlugin("C:\Program Files (x86)\AviSynth 2.6\plugins\svpflow-1.0.6\svpflow1.dll")
LoadPlugin("C:\Program Files (x86)\AviSynth 2.6\plugins\svpflow-1.0.6\svpflow2.dll")
AVISource("Rollaine_Noise_Sample_Pass1_huffy.avi")
assumetff()
converttoyv12(interlaced=true)
# syntax: ReplaceFramesSVPFlow(number of the frame, duration 1 frame or more)
# Replacing frames below:
ReplaceFramesSVPFlow(88,1)
ReplaceFramesSVPFlow(116,1)
ReplaceFramesSVPFlow(152,1)
ReplaceFramesSVPFlow(166,2) # 2 frames here !
function ReplaceFramesSVPFlow(clip Source, int N, int X)
{
# N is number of the 1st frame in Source that needs replacing.
# X is total number of frames to replace
#e.g. ReplaceFramesSVPFLow(101, 5) would replace 101,102,103,104,105 , by using 100 and 106 as reference points for SVPFlow interpolation
start=Source.trim(N-1,-1) #one good frame before, used for interpolation reference point
end=Source.trim(N+X,-1) #one good frame after, used for interpolation reference point
start+end
AssumeFPS(1) #temporarily FPS=1 to use mflowfps
super=SVSuper("{gpu:1}")
vectors=SVAnalyse(super, "{}")
SVSmoothFps(super, vectors, "{rate:{num:"+String(X+1)+", den:1}}", url="www.svp-team.com", mt=1).Subtitle("SVPFlow")
AssumeFPS(FrameRate(Source)) #return back to normal source framerate for joining
Trim(1, framecount-1) #trim ends, leaving replacement frames
Source.trim(0,-N) ++ last ++ Source.trim(N+X+1,0)
}
StainlessS
5th August 2018, 10:43
GreyMouse,
I thought 118 MB for an 8 seconds clip of 720x576@25 was a bit high, seems is HuffYUV RGB.
Assuming source was YUV then suggest next time in VDub2,
Video/Fast Recompress/
Video/Compression/HuffYUV/Configure/RGB Compression Method/ = Convert To YUY2
Video/Compression/HuffYUV/Configure/YUY2 Compression Method/ = Predict Median(Best)
Should be somewhat smaller and without YUV to RGB conversion. [EDIT: Or without even YUV -> RGB -> YUV conversion]
EDIT: John,
Maybe below a little bit simpler to understand (just format change really of part of your script [EDIT: but inside 'script' changed source to Last])
original
script = """Subtitle("\nPrevious Ratio = " + String( YDifferenceFromPrevious(source) /
\ Max(YDifferenceFromPrevious( selectevery(source, 1, -1)),0.00001) ) +
\ "\nNext Ratio = " + String( YDifferenceToNext(source) /
\ Max(YDifferenceToNext(selectevery(source, 1, 1)),0.00001)), lsp=0)"""
MetClip = Scriptclip(source, script)
FileFixed = (FILEWRITE)
\ ? WriteFileIf(source, filename, "
\ YDifferenceFromPrevious() / Max(YDifferenceFromPrevious( selectevery(1, -1)),0.00001)
\ > badthreshold && YDifferenceToNext() / Max(YDifferenceToNext(selectevery(1, 1)),0.00001)
\ > badthreshold", "current_frame", append = false) : Source
mod
INTERLACED = FALSE # You decide
filename = "E:\Bad.txt" # Set to name and location where you want the frame numbers stored
#=====================================================================
source = AVISource(VideoFile).convertTOYV12(Interlaced=INTERLACED).killaudio()
script = """
PrevRatio = YDifferenceFromPrevious / Max(YDifferenceFromPrevious( selectevery(1, -1)),0.00001)
NextRatio = YDifferenceToNext / Max(YDifferenceToNext ( selectevery(1, 1 )),0.00001)
ScriptDot = (PrevRatio > badthreshold && NextRatio > badthreshold) ? "***" : ""
Subtitle(ScriptDot+"\nPrevious Ratio = " + String(PrevRatio) + "\nNext Ratio = " + String(NextRatio), lsp=0)
"""
MetClip = Scriptclip(source, script)
FileFixed = (FILEWRITE)
\ ? WriteFileIf(source, filename,
\ "
\ YDifferenceFromPrevious() / Max(YDifferenceFromPrevious( selectevery(1, -1)),0.00001) > badthreshold &&
\ YDifferenceToNext() / Max(YDifferenceToNext ( selectevery(1, 1 )),0.00001) > badthreshold
\ "
\ , "current_frame", append = false)
\ : Source
output = (METRICS) ? MetClip : (REPLACE) ? ReplaceBadI(FileFixed,showdot) : FileFixed
return output#.StackVertical(Source)
EDIT: Also, the ConvertToYV12 might want an Interlaced=True if appropriate.
eg
INTERLACED = FALSE # You decide
filename = "E:\Bad.txt" # Set to name and location where you want the frame numbers stored
#=====================================================================
source = AVISource(VideoFile).convertTOYV12(Interlaced=INTERLACED).killaudio()
EDIT: Modified scipt a bit more. Added ScriptDot
StainlessS
5th August 2018, 15:40
John, Spotted a pretty bad error in your script, as was a little 'messy' prior to above suggested mods, was difficult for anyone to spot it,
(probably just assumed that logic was correct without examining too closely).
Relates to detection logic
FileFixed = (FILEWRITE)
\ ? WriteFileIf(source, filename, "
\ YDifferenceFromPrevious() / Max(YDifferenceFromPrevious( selectevery(1, -1)),0.00001)
\ > badthreshold && YDifferenceToNext() / Max(YDifferenceToNext(selectevery(1, 1)),0.00001)
\ > badthreshold", "current_frame", append = false) : Source
and this (does not produce same results as per above)
fixed = ConditionalSelect(c, "
Prev = YDifferenceFromPrevious()
Prev1 = Max(YDifferenceFromPrevious(SelectEvery(1,-1)),0.00001)
Next = YDifferenceToNext()
Next1 = Max(YDifferenceToNext(SelectEvery(1,1)),0.00001)
Prev/Prev1 < badthreshold && Next/Next1 < badthreshold ? 0 : 1", \
c, selectevery(Replacement,1,-1))
WriteFile stuff is like this
BADFRAME = (A > badthresh && B > badthresh) # both have to be greater than badthresh to be bad (if either is smaller or equal to badthresh then NOT bad)
Whereas in ReplaceBadI is not same logic
GOODFRAME = (A < badthresh && B < badthresh) # ie selects source frame if good else interpolates
Assuming that Writefile stuff is correct then ReplaceBadI should be [EDIT: Have not yet figured out which is correct]
GOODFRAME = (A <= badthresh || B <= badthresh) # ie selects source frame if good else interpolates
Tis a bit dangerous reversing logic, (invert conditions ie > to <=) and invert logic operator (ie && to ||),
a lot safer in this case to use exact same logic and ConditionalSelect return '? 1 : 0' instead of '? 0 : 1'.
EDIT: Think this is the guy, Augustus De Morgan:- https://en.wikipedia.org/wiki/De_Morgan%27s_laws
https://s15.postimg.cc/vc4bpbmcr/De_Morgan.jpg (https://postimages.org/)
EDIT: I really should brush up on this stuff, List of Boolean algebra topics:- https://en.wikipedia.org/wiki/List_of_Boolean_algebra_topics
EDIT: Which one is as intended, WriteFileIf, or ReplaceBadI ???
johnmeyer
5th August 2018, 17:12
StainlessS,
Thanks for taking such a detailed look at my script. As you can see from the comments in my script and also the link I provided to the thread where I initially developed this, you looked at it quite a bit back then.
I like the easier-to-understand versions, but I'm not sure all the changes are going to work (I'm not in my office right now). First, I don't see any logic to turn "showdot" on and off. I had a SHOWDOT true/false variable at the beginning of my script and, when set to FALSE, no dots were shown. The whole idea of having the dots is to be able to study those frames that are now interpolated, and take action if you see too many frames which contain motion estimation artifacts. You obviously do not want the dots in the final rendered output.
So you have to be able to turn off the dots.
The "interlaced=true" addition is a good one, and something I need to remember, since color conversions can get screwed up without it.
The replace logic bug has me scratching my head, however. I've used this script on multiple occasions and I am pretty sure the ReplaceBadI function works correctly, even if my script formatting is a little crude. So I think my "less than" and "greater than" logic is OK, as is the "AND" vs. "OR" logic (and of course Boolean logic lets you get the same result if you negate and simultaneously change from AND to OR). Thus, if there is an error, it must be in the WriteFile logic. I'm not sure I have saved frame numbers (which is what the WriteFile section does) since I first developed the script. So, when I get back to my office computer, I'll check that and see if it is indeed backwards, as you say.
Thanks!
StainlessS
5th August 2018, 17:26
The added Showdot stuff is only in the Metrics display, your showdots is for ReplaceBadI only,
Not really necessary to switch it on/off in metrics.
When you can, tell which is the correct one (I suspect that I assumed wrong and ReplaceBadI was actually correct).
I'll check that and see if it is indeed backwards, as you say.
Guaranteed, although dont know for sure which is correct. (I stopped as soon as I saw the error).
EDIT:
if there is an error, it must be in the WriteFile
OK, I'll continue with that assumption, however I shall mod to detect BADFRAMES as detecting GOODFRAMES dont feel right.
Currently attempting to make a much more understandable version of the entire script, with more differences available eg n-1 <-> n+1
so script can be hacked much more easily for some specific requirment.
EDIT: Question, Do you does, or do you doesn't use Avs+, GScript, Grunt ???
EDIT: "Is you is or is you ain't my baby ..." :)
EDIT: If you use above mentioned avs+, GScript, Grunt, then could make contained functions, less problems interfering between them
eg Local and private args courtesy of Grunt [EDIT: and without globals].
EDIT:
As you can see from the comments in my script and also the link I provided to the thread where I initially developed this, you looked at it quite a bit back then.
Yep, and so did Gavino, so that probably vindicates/mitigates me a lil bit [Big G will probably pop up soon with some similar excuse :) ]
johnmeyer
5th August 2018, 22:50
StainlessS,
I won't be able to look at this until tomorrow, but I can say with certainty that the ReplaceBadI function works as intended because I used that yesterday on the OP's video and it worked. And, it worked not only when I originally posted the script, but also when I've used it since I created it a few years ago.
Even though I included the logic to write the frame numbers to a file, I haven't used that since I did the testing when I originally wrote the script. So if there is a problem, it is probably there. In my defense, I may have wanted to write the numbers of the good frames rather than the bad ones, but I can't remember at this point. If that was my intent, I certainly failed to document it correctly.
EDIT: Question, Do you does, or do you doesn't use Avs+, GScript, Grunt ???
EDIT: "Is you is or is you ain't my baby ..." I am, of course, a StainlessS acolyte, so yes I do have all of those and, if you remember the NFL "kinescope" film beat bars that you helped me with, it was the functions in GScript that let me create a mask from the overexposure created by the noise bars, and then correct the exposure, a restoration result of which I am quite proud and which I could not have done without both your excellent functions, and also your help:
1955 NFL Football "Kinescope" (https://www.youtube.com/watch?v=qx26T6WOZ_4)
The only reason I brought your name up in this thread is that I thought perhaps you would have a more clever, or at least a more effective way to detect the noise bars. YDifference should have nailed it, but it didn't catch all of them, and didn't produce large, obvious metrics as I thought it would. The noise is pretty massive and should be easy to detect, but my approach isn't good enough.
A better comparison between the the two adjacent frames should be able to catch them all.
Your idea for handling two frame glitches would be very welcome (see my original post for the problems dealing with still photographer's "pre-flashes"), but the logic for doing motion estimation from frames which are more distant would be mildly complicated and therefore not a ten-minute exercise.
StainlessS
5th August 2018, 23:18
What I got so far.
#loadplugin("C:\Program Files\AviSynth 2.5\plugins\MVTools\mvtools2.dll")
#Control script operation by changing the following values :
#=====================================================================
VideoFile = "E:\Documents\Dnload\UNPACK\Rollaine_Noise_Sample_Pass1_huffy.avi"
VideoFile = ".\GreyMouse_Rollaine_Noise_Sample_Pass1_huffy.avi"
INTERLACED = FALSE # Source is Interlaced, You decide.
BADTHRESHOLD = 1.3 # Set METRICS=TRUE to determine best value
METRICS = TRUE # TRUE will show Metrics ONLY (i.e., TRUE overrides all other selections)
REPLACE = TRUE # TRUE will replace each bad frame with a one that is interpolated from adjacent frames
SHOWDOT = TRUE # TRUE will add "***" to each replacment frame (for troubleshooting)
FILEWRITE = FALSE # TRUE will create a file which contains the frame numbers of all bad frames
filename = "E:\Bad.txt" # Set to name and location where you want the frame numbers stored
#=====================================================================
source = AVISource(VideoFile).convertTOYV12(Interlaced=INTERLACED).killaudio()
Met_Script = """ # Where n = current_frame
###################
P1C = selectevery(1, -1) # Clip where n-1 Frame shifted to frame n
N1C = selectevery(1, +1) # Clip where n+1 Frame shifted to frame n
P2C = selectevery(1, -2) # Clip where n-2 Frame shifted to frame n
N2C = selectevery(1, +2) # Clip where n+2 Frame shifted to frame n
P3C = selectevery(1, -3) # Clip where n-3 Frame shifted to frame n
N3C = selectevery(1, +3) # Clip where n+3 Frame shifted to frame n
###
P3Ave = AverageLuma(P3C) # AverageLuma(n-3)
N3Ave = AverageLuma(N3C) # AverageLuma(n+3)
P2Ave = AverageLuma(P2C) # AverageLuma(n-2)
N2Ave = AverageLuma(N2C) # AverageLuma(n+2)
P1Ave = AverageLuma(P1C) # AverageLuma(n-1)
N1Ave = AverageLuma(N1C) # AverageLuma(n+1)
Ave = AverageLuma # AverageLuma(n+0)
###
P3P2Dif = LumaDifference(P3C,P2C) # Dif(n-3, n-2)
N2N3Dif = LumaDifference(N2C,N3C) # Dif(n+2, n+3)
##
P2P1Dif = YDifferenceFromPrevious(P1C) # Dif(n-2, n-1)
N1N2Dif = YDifferenceToNext(N1C) # Dif(n+1, n+2)
P1Dif = YDifferenceFromPrevious # Dif(n-1, n+0)
N1Dif = YDifferenceToNext # Dif(n+0, n+1)
P1Alt = Lumadifference(P2C) # Dif(n-2, n+0) # Difference between frames either side of n - 1
N1Alt = Lumadifference(N2C) # Dif(n+0, n+2) # Difference between frames either side of n + 1
Alt = Lumadifference(P1C,N1C) # Dif(n-1, n+1) # Difference between frames either side of n
PRatio = P1Dif / Max(P2P1Dif,0.00001) # Dif(n-1, n+0) / Max(Dif(n-2,n-1),0.00001)
NRatio = N1Dif / Max(N1N2Dif,0.00001) # Dif(n+0, n+1) / Max(Dif(n+1,n+2),0.00001)
# P1P2Rat = P1Dif / Max(P2P1Dif,0.00001) # Dif(n-1, n+0) / Max(Dif(n-2,n-1),0.00001)
# N1N2Rat = N1Dif / Max(N1N2Dif,0.00001) # Dif(n+0, n+1) / Max(Dif(n-2,n-1),0.00001)
# EDIT: Should not be here, stumbling over good unique names at the moment
###
FoundBad = (PRatio >= badthreshold || NRatio >= badthreshold) # True if FoundBad (bad if either is bad)
###################
ScriptDot = (FoundBad) ? "***" : ""
Met_Script_S =
\ ScriptDot +
\ String(P3Ave, "\nP3Ave = %f") +
\ String(N3Ave, "\nN3Ave = %f") +
\ String(P2Ave, "\nP2Ave = %f") +
\ String(N2Ave, "\nN2Ave = %f") +
\ String(P1Ave, "\nP1Ave = %f") +
\ String(N1Ave, "\nN1Ave = %f") +
\ String(Ave, "\nAve = %f") +
\ String(P3P2Dif, "\nP3P2Dif = %f") +
\ String(N2N3Dif, "\nN2N3Dif = %f") +
\ String(P2P1Dif, "\nP2P1Dif = %f") +
\ String(N1N2Dif, "\nN1N2Dif = %f") +
\ String(P1Dif, "\nP1Dif = %f") +
\ String(N1Dif, "\nN1Dif = %f") +
\ String(P1Alt, "\nP1Alt = %f") +
\ String(N1Alt, "\nN1Alt = %f") +
\ String(Alt, "\nAlt = %f") +
\ String(PRatio, "\nPRatio = %f") +
\ String(NRatio, "\nNRatio = %f")
Return Subtitle(Met_Script_S, lsp=0,Font="Courier New",Size=28)
"""
MetClip = Scriptclip(source, Met_Script)
return MetClip
The 1st bit can have some lines commented out, same with subtitle metrics part.
If I can use GSCript/avs+, Grunt, and RT_Stats (older v1.43 should be fine), then I can make functions that can take a USER expression that returns
bool (final probably return int, above returns clip rather than bool or int, but that is sort of incidental).
Expression will have to use Standardised names (as in 1st part of above script, [not finalized at all yet]),
and function could create an eval string that implements only the user used variables eg P1Dif etc . Same type of thing for above Subtitle part.
In essence, user supplies a Script using named variables, and utility function returns a script string to ascertain eg dif(n-1,n+0) [for P1Dif], etc,
similar setup to create subtitle string. Depending upon some args, will concatenate scripts producing final funtionality for whatever required.
Thats the idea anyways. Question remains, do you use Gscript/avs+ Grunt ? [EDIT: Already answered]
User Supplied script might look something like
(PRatio >= Thresh1 || NRatio >= Thresh1)
and then together with some user supplied args (like ShowSubtitle, or whatever) will create function that behaves as required.
Above snippet works ok with Greymouse clip, all it does is show subtitled variables.
EDIT: Well then WriteFile stuff broken
if replace stuff,
GOODFRAME = (A < badthresh && B < badthresh) # ie selects source frame if good else interpolates
Return (GOODFRAME) ? 0 : 1
Then below should be correct for WriteFile
BADFRAME = (A >= badthresh || B >= badthresh) # was, BADFRAME = (A > badthresh && B > badthresh)
EDIT: My lil idea at start of this post is a bit hazy just now, but we will get it working just fine with
conditions that can be user knocked up reasonably easily.
EDIT:
Thats the idea anyways. Question remains, do you use Gscript/avs+ Grunt ?
Sorry, I saw your answer now.
johnmeyer
6th August 2018, 04:37
I had to go to my office computer this evening, so I spent a few minutes on this. As I surmised, my ReplaceBadI function works as expected, although because of my poor detection logic, it is not as reliable as I'd like with this test clip. However you are correct that the WriteFileIf is dodgy. But, I don't think it is for the reasons you think. The logic itself actually works as written, and if I change the ">" to "<" it outputs almost every frame number, meaning that it is saving the good frame numbers.
I then tried changing ">" to ">=", and this made a big difference. What?? This makes absolutely no sense to me because the chances of two metrics actually being equal are virtually zero, unless you have a perfect duplicate. Therefore, I should have not seen any difference whatsoever.
So, I think my WriteIf problems are far deeper than just a mistake in boolean logic and are probably related to some of the mysteries of how conditional logic in AVISynth works.
If GScript or GRunT can solve these problems, I'm willing to try it out, although we should remember that it is the OP who asked for help, not me.
StainlessS
6th August 2018, 12:26
BADFRAME = (A >= badthresh || B >= badthresh) # was, BADFRAME = (A > badthresh && B > badthresh)
Was not just > oposed to >= that was wrong, also the logic operator, in red above.
(and no matter how remote a possibility, >= is opposite <).
EDIT: And opposite of != is not != (as == is unlikely to happen) https://www.cosgan.de/images/smilie/teufel/d020.gif https://www.cosgan.de/images/smilie/teufel/a045.gif
it is the OP who asked for help
Yep, and the demo metrics thing could help spot what is required for OP problem. [which is what started me on it]
A lot of the problem is that the clip pans erratically, with periods where stationary, so its hard to detect the crap.
johnmeyer
6th August 2018, 15:58
A lot of the problem is that the clip pans erratically, with periods where stationary, so its hard to detect the crap.One idea that has worked for me with other similar situations is to create a moving average of the metric and then scale the difference metrics according to the moving average. This makes it easier to detect anomalies that happen during fast panning.
StainlessS
6th August 2018, 17:21
Wanna play with this anybody, (not really attempted to tweak thresh), additional errors within 2 frames of current will affect result.
the MC ratios, maybe could be replaced with comparison source(n-1)->Mc(n) and source(n+1)->Mc(n)
AVISource("D:\GreyMouse_Rollaine_Noise_Sample_Pass1_huffy.avi").ConvertToYV12
ORG=Last
SelectEvery(1,-1) # Shift Forward 1
super=MSuper()
prefilt = RemoveGrain(22)
super = MSuper(hpad=16,vpad=16,levels=1,sharp=1,rfilter=4) # One level is enough for MRecalculate
superfilt = prefilt.MSuper(hpad=16,vpad=16,sharp=1,rfilter=4) # All levels for MAnalyse
bv = superfilt.MAnalyse(isb=true, blksize=16,overlap=4,search=3,delta=2)
fv = superfilt.MAnalyse(isb=false,blksize=16,overlap=4,search=3,delta=2)
bv = super.MRecalculate(bv,blksize=8,overlap=2,thSAD=100)
fv = super.MRecalculate(fv,blksize=8,overlap=2,thSAD=100)
MFlowInter(super,bv,fv,time=50,ml=200)
MC=Last
ORG
BadThreshold=1.3
GoodThreshold=BadThreshold
SHOWSUBS=true
ShowDot=true
STACK=true
Met_Script = """ # Where n = current_frame
###################
P1C = selectevery(1, -1) # Clip where n-1 Frame shifted to frame n
N1C = selectevery(1, +1) # Clip where n+1 Frame shifted to frame n
P2C = selectevery(1, -2) # Clip where n-2 Frame shifted to frame n
N2C = selectevery(1, +2) # Clip where n+2 Frame shifted to frame n
P2P1Dif = YDifferenceFromPrevious(P1C) # Dif(n-2, n-1)
N1N2Dif = YDifferenceToNext(N1C) # Dif(n+1, n+2)
P1Dif = YDifferenceFromPrevious # Dif(n-1, n+0)
N1Dif = YDifferenceToNext # Dif(n+0, n+1)
P1Alt = Lumadifference(P2C) # Dif(n-2, n+0) # Difference between frames either side of n - 1
N1Alt = Lumadifference(N2C) # Dif(n+0, n+2) # Difference between frames either side of n + 1
Alt = Lumadifference(P1C,N1C) # Dif(n-1, n+1) # Difference between frames either side of n
PRatio = P1Dif / Max(P2P1Dif,0.00001) # Dif(n-1, n+0) / Max(Dif(n-2,n-1),0.00001)
NRatio = N1Dif / Max(N1N2Dif,0.00001) # Dif(n+0, n+1) / Max(Dif(n+1,n+2),0.00001)
###
MC_P1Dif = Lumadifference(P1C,MC) # Dif(n-1, MC(n+0))
MC_N1Dif = Lumadifference(MC,N1C) # Dif(MC(n+0),n+1)
MC_PRatio = MC_P1Dif / Max(P2P1Dif,0.00001) # Dif(n-1, MC(n+0)) / Max(Dif(n-2,n-1),0.00001)
MC_NRatio = MC_N1Dif / Max(N1N2Dif,0.00001) # Dif(MC(n+0), n+1) / Max(Dif(n+1,n+2),0.00001)
SrcIsBad = (PRatio >= badthreshold || NRatio >= badthreshold) # True if Source frame bad (bad if either is bad)
MCIsGood = (MC_PRatio < GoodThreshold && MC_NRatio < GoodThreshold) # True if MC frame Good (good only if both good)
UseMC = SrcIsBad && MCIsGood
###
ScriptDot = String(SrcIsBad) + " " + String(MCIsGood) + " " + String(UseMC)
Met_Script_S =
\ ScriptDot +
\ String(P2P1Dif, "\nP2P1Dif = %f") +
\ String(N1N2Dif, "\nN1N2Dif = %f") +
\ String(P1Dif, "\nP1Dif = %f") +
\ String(N1Dif, "\nN1Dif = %f") +
\ String(P1Alt, "\nP1Alt = %f") +
\ String(N1Alt, "\nN1Alt = %f") +
\ String(Alt, "\nAlt = %f") +
\ String(PRatio, "\nPRatio = %f") +
\ String(NRatio, "\nNRatio = %f") +
\ String(MC_P1Dif, "\nMC_P1Dif = %f") +
\ String(MC_N1Dif, "\nMC_N1Dif = %f") +
\ String(MC_PRatio, "\nMC_PRatio = %f") +
\ String(MC_NRatio, "\nMC_NRatio = %f")
Return SHOWSUBS ? Subtitle(Met_Script_S, lsp=0,Font="Courier New",Size=28) : !UseMC ? Last : ShowDot ? MC.Subtitle("***") : MC
"""
Scriptclip(Met_Script)
return STACK ? StackVertical(Last,(SHOWDOT&&!SHOWSUBS)?ORG.Subtitle("Source"):MC.Subtitle("MC")) : Last
I've left some non used vars available, maybe nudge into better solution.
Not perfect, but it does work to some degree (sometimes replaces non bad frames, but results dont look much different to the non bad).
johnmeyer
6th August 2018, 19:48
The good news is that I simply copied the script and it worked. The bad news is that it doesn't seem to do anything. The lower screen seems to be nothing more than the upper screen offset by one frame, with some of the noise removed, but not much, and in many cases no noise removed at all.
Also, in looking at all the metrics, the four main "ratio" metrics, which appear to be the heart of the detection logic, don't seem to change all that much for the frames containing lots of noise.
http://i177.photobucket.com/albums/w208/johnmeyer/Screen%20Shot_zpsqcuqcnll.jpg
StainlessS
6th August 2018, 22:24
Also, in looking at all the metrics, the four main "ratio" metrics, which appear to be the heart of the detection logic, don't seem to change all that much for the frames containing lots of noise.
Yes well, as I recall you did your inital script to detect Flash Frames, aint no flashes here, just crap.
PRatio and NRatio in you image were though still over BadThresh of 1.3 (actually about 1.57),
and the MC ratios need both be lo-ish.
EDIT: If you set GoodThreshold very high, then will sort of behave pretty much as your detector would (assuming same Badthresh).
The purpose of GoodThreshold is to limit replacement where would be clearly detrimental.
The shown MC frame is synthesized from those either side of the (upper) source frame, ie src(n-1 and n+1).
The MC frame aligning with src(n-1) was synthesized from source frames src(n-2 and n) and as src(n) is the current crap
frame, so it is bad [which actually means it is less likely to be chosen to replace src(n-1), if good GoodThreshold can be found].
Exact same thing for MC frame aligning with src+1.
Anyways, make ShowSubs=False, and leave ShowDot and STACK at true, and play, you should see the clip being fixed
(source will move to bottom and fixed without subs to top, but showing the DOT on fixed frames).
Not perfect I know, but is better, I was kinda hoping that you might improve whilst I was off doing stuff.
Well I shall try maybe recreate src(n) by (as well as using n-1 and n+1 as MC interp sources) using n-2 and n+1, and another from n-1 and n+2,
and try chose least worst of the bunch.
I'm probably off doing stuff again for a lil bit but should get back within the hour probably (and then try do it).
Where there was two consecutive crud frames in source, both result MC frames will likely look bad
(probably not as bad as original, unless 3 or 4 consecutive crap frames, where would probably look worse
especially where crap coincides) .
EDIT: OK, I see what you misunderstood, the MC clip is a test comparison clip, it is not the fixed clip, where
numbers are good, the current MC frame will be chosen to replace the crud source frame. (MC is created at top
of script and it dont change). It is both part of the detection whatsit, and where appropriate the source of individual
frames used in fixing crud, but only for fixing single bad frames.
Every frame in the MC clip is the result of interpolating the two frames either side of it in the source clip.
In your script, ReplaceBadFramesI just blindly replaces bad frames when bad
source is detected, here we use the MC clip (the source of frames that will repair crud frames) within the detector,
to see if replacment frames are likely better than the crud they are to fix, that is what GoodThreshold thing is about.
johnmeyer
7th August 2018, 01:45
StainlessS,
Thanks for the lengthy explanation. It answers all my questions and gives me enough information that I should be able to play around and, who knows, I might actually do something useful.
I'll be able to get to this tomorrow. I have a vested interest in this, beyond just helping the OP, because the problem of fixing individual bad frames happens ALL the time, in countless different ways. Having a better script would be welcome.
johnmeyer
7th August 2018, 21:41
Played around with ShowSubs=False, as you suggested and except for the two-frame corruption at frames 166 & 167, the script works flawlessly.
I'm still trying to fully understand the way you've done comparisons using n-2, n-1, n+1, n+2, but if I ask questions about that, we'll go down the same long rat hole (see this (https://forum.doom9.org/showthread.php?t=175373)) about how motion estimation deltas work, etc. No need to re-hash that now.
So, with this test clip, the script seems to work almost flawlessly for single corrupt frames, and your logic does a better job detecting them than did my simple, single YDifference ratios. Your attempt to make it also work when there are two flawed frames in a row doesn't appear to work on that one pair I mentioned above.
I'll keep looking at this, as time permits.
[edit] The script does replace about 2x the number of frames that it needs to (i.e., it is replacing quite a few good frames). My script did that as well.
In looking some more at 166 & 167, your script does detect and then replace them both, but since the only motion compensation clip you create is "MC", that doesn't give good results when an adjacent frame is also corrupt.
StainlessS
7th August 2018, 22:57
EDIT:
and your logic does a better job detecting them than did my simple, single YDifference ratios. Your attempt to make it also work when there are two flawed frames in a row doesn't appear to work
Not my logic John, thats your logic, messed about a bit but doing same thing.
Have not implemented 2 crud frame stuff yet, that is what I am currently struggling with, only improvement over yours really is in the Goodthresh thing.
End_EDIT:
I have not as yet been able to figure out a way of using the additional MC fix clips (n-2,n+1, etc) and weighting so as to be able to compare with each other,
but have not as yet given up.
As for GoodThreshold, I think that a fixed thresh is not the best thing here.
Reason,
1st of all, to detect bad, instead of using PRatio and NRatio, we could simplify to just 1 ratio ie Ratio = Max(PRatio,NRatio).
In detector, if EITHER P or N ratio is greater or equal to BadThreshold, then is bad, so decision is really governed by the greater of the two.
Similarly, to detect if MC candidate fix frame is good, BOTH MC_P AND MC_N ratios should be less than GoodThreshold, so decision is really again
governed by the greater of the two MC ratio's, so MC_Ratio = Max(MC_PRatio,MC_NRatio).
So now I can just use terms Ratio and MC_Ratio.
The bad Ratio could be significantly greater than BadThreshold, and so by using GoodThreshold = Badthreshold as default, might be expecting too great an improvment
via the candidate MC fix frame, perhaps we need self calibrating GoodThreshold.
My first idea was to remove GoodThreshold from user setting and inside script for each frame make it, GoodThreshold=(Ratio-1)/2.0 + 1.0, so
it would be set half way between 1.0 and detected numbers for the crud frame. this seems quite reasonable, but it could be that anything
below Ratio would (by the numbers) be an improvment, where could be set as GoodThreshold=Ratio.
So next (and current best) idea, is allow user set option of Goodthreshold, and depending upon user setting, either use fixed GoodThreshold, or
self calibrating.
If user sets GoodThreshold > 1.0, then is non self calibrating fixed threshold.
If 0.0 < GoodThreshold <= 1.0, then self calibrating, where for each frame Goodthr = (Ratio - 1.0) * GoodThreshold + 1.0,
so a GoodThreshold of eg 0.5, would set GoodThr for each frame to half way between 1.0 and Ratio, 0.666 to 2/3 of the way, 1.0 to Ratio.
[EDIT: GoodThreshold <= 0.0 error]
Anyways, if doubts then shout up.
EDIT: Above in Red Perhaps Wrong, see next post.
Here shifted clips.
[Actually using RT_Stats RT_LumaDifference(clip1,clip2, n=i n2=j) (or delta=k, delta2=l) could avoid all of the shifting stuff (but implementing as raw avs script).]
############ Shifted Source Clips #######
P2C = ORG.selectevery(1, -2) # src n-2 Frame shifted to frame n
P1C = ORG.selectevery(1, -1) # src n-1 Frame shifted to frame n
N1C = ORG.selectevery(1, +1) # src n+1 Frame shifted to frame n
N2C = ORG.selectevery(1, +2) # src n+2 Frame shifted to frame n
############ Shifted MC Clips #######
Prefilt = ORG.RemoveGrain(22)
Super = ORG.MSuper(hpad=16,vpad=16,levels=1,sharp=1,rfilter=4) # One level is enough for MRecalculate
Superfilt = Prefilt.MSuper(hpad=16,vpad=16,sharp=1,rfilter=4) # All levels for MAnalyse
bv = Superfilt.MAnalyse(isb=true, blksize=16,overlap=4,search=3,delta=2)# DELTA 2, (distance between interpolate source frames)
fv = Superfilt.MAnalyse(isb=false,blksize=16,overlap=4,search=3,delta=2)
bv = Super.MRecalculate(bv,blksize=8,overlap=2,thSAD=100)
fv = Super.MRecalculate(fv,blksize=8,overlap=2,thSAD=100)
MC11 = ORG.MFlowInter(Super,bv,fv,time=50.0,ml=200).SelectEvery(1,-1) # n interplated from src n-1 & n+1 @ 50.0% (n-1 shifted to n)
#
bv = Superfilt.MAnalyse(isb=true, blksize=16,overlap=4,search=3,delta=3)# DELTA 3
fv = Superfilt.MAnalyse(isb=false,blksize=16,overlap=4,search=3,delta=3)
bv = Super.MRecalculate(bv,blksize=8,overlap=2,thSAD=100)
fv = Super.MRecalculate(fv,blksize=8,overlap=2,thSAD=100)
MC21 = ORG.MFlowInter(Super,bv,fv,time=200.0/3,ml=200).SelectEvery(1,-2) # n interplated from src n-2 & n+1 @ 66.67% (n-2 shifted to n)
MC12 = ORG.MFlowInter(Super,bv,fv,time=100.0/3,ml=200).SelectEvery(1,-1) # n interplated from src n-1 & n+2 @ 33.33% (n-1 shifted to n)
#
bv = Superfilt.MAnalyse(isb=true, blksize=16,overlap=4,search=3,delta=4)# DELTA 4
fv = Superfilt.MAnalyse(isb=false,blksize=16,overlap=4,search=3,delta=4)
bv = Super.MRecalculate(bv,blksize=8,overlap=2,thSAD=100)
fv = Super.MRecalculate(fv,blksize=8,overlap=2,thSAD=100)
MC22 = ORG.MFlowInter(Super,bv,fv,time=50.0,ml=200).SelectEvery(1,-2) # n interplated from src n-2 & n+2 @ 50.0% (n-2 shifted to n)
#####################################
EDIT: the (n-1 shifted to n) in blue above aligns the interpolated MC frame to align with the src frame that is intended to fix.
EDIT: MC interpolated frames are not created at the same frame number as the frame they are intended to fix, they are created at the same frame number of the lower of the two source frame numbers used as interpolate source frames, and so need to be shifted to align with fix target frame in source clip.
EDIT: eg YDifferencetoNext can be used to get dif between a clip frame current_frame and same clip current_frame+1, but if current and n+2, then must use
something else. LumaDifference allows for two clips (which could be same clip), but both frames compared are at current frame, this is the reason for clip alignment (also same type thing used to compare n+1, n+2, shifted clip can still use YDifferencetoNext with shifted clip).
LumaDifference allows eg clip1, n+x to clip2 n+y, but both clips need be aligned by -x and -y. (avs 2.60 allows for offset arg which can avoid some shifting if both x and y are same).
EDIT: Talking B*ll*cks above, AverageLuma et al have offset arg, YDifferenceToNext and LumaDifference do NOT have Offset args in v2.60.
RT_Stats funcs for same stuff can use current_frame (by default) or 'n=x' for frame x or delta=y (default 0, offset from current_frame or specified frame number) and where two clips (eg RT_LumaDifference) can specify all (or default) for each clip.
EDIT: Thanx John, revisited your link in prev post and found a broken PostImage link, now fixed.
EDIT: MC21 and MC12 MFlowInter times fixed (was eg 1.0/3 instead of 100.0/3)
StainlessS
8th August 2018, 02:50
Prev posted self calibrating GoodThreshold is perhaps wrong, was Goodthr = (Ratio - 1.0) * GoodThreshold + 1.0, but should maybe be as below.
Below correction.
If user sets GoodThreshold > 1.0, then is non self calibrating fixed threshold.
If 0.0 <= GoodThreshold <= 1.0, then self calibrating, where for each frame Goodthr = (Ratio - BadThreshold) * GoodThreshold + BadThreshold,
so a GoodThreshold of eg 0.5, would set GoodThr for each frame to half way between BadThreshold and Ratio, 0.666 to 2/3 of the way, 1.0 to Ratio.
GoodThreshold < 0.0 error. [EDIT: was GoodThreshold <= 0.0 error. if 0.0 then GoodTh set to BadThreshold]
Seem more sensible ? (or not, I aint sure)
Here, prev posted script modded as per prev post corrected GoodThreshold stuff.
AVISource("D:\GreyMouse_Rollaine_Noise_Sample_Pass1_huffy.avi").ConvertToYV12
ORG=Last
SelectEvery(1,-1) # Shift Forward 1
super=MSuper()
prefilt = RemoveGrain(22)
super = MSuper(hpad=16,vpad=16,levels=1,sharp=1,rfilter=4) # One level is enough for MRecalculate
superfilt = prefilt.MSuper(hpad=16,vpad=16,sharp=1,rfilter=4) # All levels for MAnalyse
bv = superfilt.MAnalyse(isb=true, blksize=16,overlap=4,search=3,delta=2)
fv = superfilt.MAnalyse(isb=false,blksize=16,overlap=4,search=3,delta=2)
bv = super.MRecalculate(bv,blksize=8,overlap=2,thSAD=100)
fv = super.MRecalculate(fv,blksize=8,overlap=2,thSAD=100)
MFlowInter(super,bv,fv,time=50,ml=200)
MC=Last
ORG
BadThreshold = 1.3
GoodThreshold = 1.0/3 # 0.333, self calibrating threshold. [EDIT: Was 0.666]
SHOWSUBS=True
ShowDot=true
STACK=true
Met_Script = """ # Where n = current_frame
###################
P1C = selectevery(1, -1) # Clip where n-1 Frame shifted to frame n
N1C = selectevery(1, +1) # Clip where n+1 Frame shifted to frame n
P2C = selectevery(1, -2) # Clip where n-2 Frame shifted to frame n
N2C = selectevery(1, +2) # Clip where n+2 Frame shifted to frame n
P2P1Dif = YDifferenceFromPrevious(P1C) # Dif(n-2, n-1)
N1N2Dif = YDifferenceToNext(N1C) # Dif(n+1, n+2)
P1Dif = YDifferenceFromPrevious # Dif(n-1, n+0)
N1Dif = YDifferenceToNext # Dif(n+0, n+1)
PRatio = P1Dif / Max(P2P1Dif,0.00001) # Dif(n-1, n+0) / Max(Dif(n-2,n-1),0.00001)
NRatio = N1Dif / Max(N1N2Dif,0.00001) # Dif(n+0, n+1) / Max(Dif(n+1,n+2),0.00001)
###
MC_P1Dif = Lumadifference(P1C,MC) # Dif(n-1, MC(n+0))
MC_N1Dif = Lumadifference(MC,N1C) # Dif(MC(n+0),n+1)
MC_PRatio = MC_P1Dif / Max(P2P1Dif,0.00001) # Dif(n-1, MC(n+0)) / Max(Dif(n-2,n-1),0.00001)
MC_NRatio = MC_N1Dif / Max(N1N2Dif,0.00001) # Dif(MC(n+0), n+1) / Max(Dif(n+1,n+2),0.00001)
Ratio = Max(PRatio,NRatio)
MC_Ratio = Max(MC_PRatio,MC_NRatio)
SrcIsBad = (Ratio >= badthreshold) # True if Source frame bad (bad if either is bad)
GoodTh = GoodThreshold > 1.0
\ ? GoodThreshold
\ : (Ratio - BadThreshold) * GoodThreshold + BadThreshold
MCIsGood = (MC_Ratio < GoodTh) # True if MC frame Good (good only if both good)
UseMC = SrcIsBad && MCIsGood
###
ScriptDot = "Bad="+String(SrcIsBad) + " GoodFix=" + String(MCIsGood) + " " + (UseMC ? "***" : "")
Met_Script_S =
\ ScriptDot +
\ String(P2P1Dif, "\nP2P1Dif = %f") +
\ String(N1N2Dif, "\nN1N2Dif = %f") +
\ String(P1Dif, "\nP1Dif = %f") +
\ String(N1Dif, "\nN1Dif = %f") +
\ String(MC_P1Dif, "\nMC_P1Dif = %f") +
\ String(MC_N1Dif, "\nMC_N1Dif = %f") +
\ String(Ratio, "\nRatio = %f") +
\ String(MC_Ratio, "\nMC_Ratio = %f")
SHOWSUBS ? Subtitle(Met_Script_S, lsp=0,Font="Courier New",Size=28) : NOP
SHOWSUBS ? Subtitle(String(GoodTh, "GoodTh = %f"),Font="Courier New",Size=28,Align=1) : NOP
Return SHOWSUBS ? Last : !UseMC ? Last : ShowDot ? MC.Subtitle("***") : MC
"""
Scriptclip(Met_Script)
return STACK ? StackVertical(Last,(SHOWDOT&&!SHOWSUBS)?ORG.Subtitle("Source"):MC.Subtitle("MC")) : Last
Still no attempt to find best thresholds for this specific clip.
StainlessS
14th August 2018, 11:27
GreyMouse,
I thought 118 MB for an 8 seconds clip of 720x576@25 was a bit high, seems is HuffYUV RGB.
Assuming source was YUV then suggest next time in VDub2,
Video/Fast Recompress/
Video/Compression/HuffYUV/Configure/RGB Compression Method/ = Convert To YUY2
Video/Compression/HuffYUV/Configure/YUY2 Compression Method/ = Predict Median(Best)
Should be somewhat smaller and without YUV to RGB conversion.
Greymouse, can you post a bigger sample than originally supplied, more than 8 seconds and as per above, but preferably as YV12
and encoded with UT_Video ("ULY0") and minus the audio, can re-encode via AVS and VDub2, as in quote but using UT_Video.
Are all of your sources non interlaced ?
Avisource("...")
ConvertToYV12(Interlaced=False)
Killaudio
Return Last
Feed into VD2, and UT_Video ULY0, Fast Recompress.
EDIT: Max about 1GB.
StainlessS
1st September 2018, 21:21
GreyMouse (not online since Aug 4th), here fixer-upper, fixes all seriously bad frames in your source.
Part #1 of 3
DirtBox_MI.Avs
Function DirtBox_MI(clip c,clip "dc",Float "Th",Float "ThMin",Int "MinLen",Int "MaxLen",Bool "ProcSingles",
\ bool "Show",Int "Chop",String "SurgeonFile") {
/*
DirtBox_MI(). [ Take your time saying the name out aloud when in public place ].
Req:- GScript OR Avs+, Grunt, MvTools2, Masktools2, RemoveGrain, CallCmd, RT_Stats v1.43.
CallCmd() optional, will auto delete DBase on clip closure if present.
YUV Only (well whatever MvTools2 supports).
Args:-
c, Source clip.
dc, Detection Clip, Default c. Must have same number of frames as Src c, no other requirement.
Intent to use eg Zebra Bands to better tune for detection, Used only for primary detect of
leftmost and rightmost frames where damage occurs.
Th, Bad Ratio Threshold, default 1.3. If eg Cur->Nxt / Max(Prv->Cur,0.001) > Th then Nxt
frame is possble 1st of damaged frames (but Cur->Nxt must also be >= ThMin as described below).
ThMin, Difference of current frame to next must be at least this to detect Left 'breakup'. default 0.5.
(Avoid detection where prev frame is a duplicate and Cur->Nxt diff is very small.)
MinLen, Minimum length of damaged sequence to fix, default 1.
MaxLen, Maximum length of damaged sequence to fix, default 2 (1 <= MinLen <= MaxLen <= 5).
ProcSingles, Default True, Process single frame scene as noise. (where detected as both EOS and SOS).
Show, Show Metrics, default True.
Chop, Show Mode if Show=True,
0 Normal
1 Left half of frame is fixed, Right original.
2 Top half of frame is fixed, Bottom original.
SurgeonFile, Default "FrameSurgeonCmd.txt". If Non "", then writes a FrameSurgeon() command file to
recreate result, so can manually edit the result file and re-render in FrameSurgeon.
[part of the Sawbones/FrameSurgeon combo which also requires ClipClop()].
If using Multi-instances, each instance should have its own SurgeonFile file.
Dc clip implemented to assist in detection, where can use eg Zebra() to create a 'tuned to error' diagnostic clip.
Most damage will likely occur horizontally (in eg VHS tracking gunk), and so we might use Zebra Default Row=true
to create a vertical set of Zebra bars (same height as clip c), and can use the Zebra args, Threshold, Lo and Hi,
to tune some of the bars to better reveal where errors occur. If any of the bars seem of no use, then best
get rid of those bars so as not to 'water down' the detection metrics.
May be able to detect several kinds of frame corruption, including flash frames, up to five frames catered for.
Dc clip probably not needed for flash photography flashes.
To deal with Interlaced clip, can eg SeparateFields / SelectEven/Odd and handle each separately, then weave them
back together again afterwards. Is multi-instance capable and so (despite use of global vars) will work just fine.
Probably better to only seek forwards, as jumping into middle of bad sequence will start detect from jump point.
Shows Flags where hi-lited,
E=End Of Scene, S=Start Of Scene, L=Left Intep Src frame, R=Right Interpolate Src frame, *=Interpolated frame.
*/
c myName="DirtBox_MI: " # v0.0
IsAvsPlus=(FindStr(UCase(versionString),"AVISYNTH+")!=0) HasGScript=RT_FunctionExist("GScript")
HasGRunt =RT_FunctionExist("GScriptClip") HasMvTools=RT_FunctionExist("MSuper")
HasMaskTools=RT_FunctionExist("MT_Lutxy")
HasRemoveGrain=RT_FunctionExist("RemoveGrain") HasCallCmd = RT_FunctionExist("CallCmd")
IsAvs26=(VersionNumber>=2.6)
Assert(IsAvsPlus || HasGScript,RT_String("%sNeed either GScript or AVS+",myName))
Assert(HasGRunt,RT_String("%sNeed GRunt:-https://forum.doom9.org/showthread.php?t=139337 ",myName))
Assert(HasMVTools,RT_String("%sNeed MvTools2:-http://forum.doom9.org/showthread.php?t=131033",myName))
Assert(HasMaskTools,RT_String("%sNeed MaskTools",myName))
Assert(HasRemoveGrain,RT_String("%sNeed RemoveGrain",myName))
dc = Default(dc,c)
Th = Default(Th,1.3)
ThMin = Default(ThMin,0.5)
MinLen = Default(MinLen,1)
MaxLen = Default(MaxLen,2)
ProcSingles = Default(ProcSingles,True)
Show = Default(Show, True)
Chop = Default(Chop, 0)
SurgeonFile = Default(SurgeonFile, "FrameSurgeonCmd.txt")
Assert(dc.Framecount==c.FrameCount,RT_String("%sdc.FrameCount does not match",myName))
Assert(1 <= MinLen <= MaxLen <= 5,RT_String("%s1 <= MinLen(%d) <= MaxLen(%d) <= 5",myName,MinLen,MaxLen))
Chop = Show ? Min(Max(Chop,0),2) : 0
StainlessS
1st September 2018, 21:22
Part #2 of 3 [append to part #1]
Func_S="""
Function Fn@@@(clip c,clip dc,String DB,Float Th,Float ThMin,Int MinLen,Int MaxLen,Bool ProcSingles,
\ Bool Show,Int Chop,String SurgeonFile) {
c i=current_frame # Using i, (avoid confusion with n of Next)
Status=RT_DBaseGetField(DB,i,0)
if(Show || Status == 0) { # In here if Show or unvisited
iPrv = RT_LumaDifference(dc,dc,delta=-1,delta2=0) # dc(i-1), dc(i)
iNxt = RT_LumaDifference(dc,dc,delta= 0,delta2=1) # dc(i), dc(i+1)
LftRat = iNxt / Max(iPrv,0.001)
if(Status==0) {
Status=1 IpLen=0 IpIx=0 # Default to Src
EOSOS = Int(EOSOS@@@.RT_AverageLuma(n=i,w=1,h=1)) # 0=Norm, 1=EOS, 2=SOS, 3=EOS & SOS
Proc = EOSOS!=1||(ProcSingles&&Int(EOSOS@@@.RT_AverageLuma(n=i+1,w=1,h=1))==3)?1:0
if (Proc==1 && iNxt >= ThMin && LftRat >= Th) { # Got Left suspect breakup
TstLen=0
ETerm=Min(i+MaxLen,FrameCount-3) # Last possible INTERPOLATED frame
for(j=i+1,ETerm) { # Determine unknown length (checking for EOS)
if(RT_DBaseGetField(DB,j,0)<=1) { # Unknown or Src
ES=Int(EOSOS@@@.RT_AverageLuma(n=j,w=1,h=1))==1 # Is EOS ?
if(ES) { # EOS
j = Eterm # Break
} Else {
TstLen=TstLen+1
}
} Else { j = Eterm } # Break
}
if(TstLen>=MinLen) {
CL_d = 0 # Init to Int, ie not yet tested
ETerm = i + TstLen
IpLen=0 BestMax=256.0
for(j=i+MinLen,ETerm) {
dcP_d = RT_LumaDifference(dc,dc,n=j,n2=j,delta=0,delta2=1) # dc(j ),dc(j+1)
dcN_d = RT_LumaDifference(dc,dc,n=j,n2=j,delta=1,delta2=2) # dc(j+1),dc(j+2)
RgtRat = dcP_d / Max(dcN_d,0.001)
if(dcP_d >= ThMin && RgtRat >= Th) {
# We have possible bad frames as tested via DC detection clip (at least MinLen).
# i = Left Interp Src frame. j = possible Right Interp Src frame - 1.
BadLen = j - i # Suspect badlen
ML_c = BadLen==1?M1@@@:BadLen==2?M21@@@:BadLen==3?M31@@@:BadLen==4?M41@@@:M51@@@
# Now test whether 1st Interp better matches 1st InterpSrc (NOT using dc clip)
CL_d=CL_d.IsInt ? RT_LumaDifference(c,c,n=i,n2=i,delta=0,delta2=1): CL_d # c(i),c(i+1)
ML_d=RT_Lumadifference(c,ML_c,n=i,n2=i,delta=0,delta2=1) # c(i),ML_c(i+1)
if(ML_d < CL_d && ML_d < BestMax) {
MR_c = BadLen==1?M1@@@:BadLen==2?M22@@@:BadLen==3?M33@@@:BadLen==4?M44@@@:M55@@@
# Now test whether last Interp better matches Last InterpSrc (NOT using dc clip)
CR_d = RT_LumaDifference(c,c, n=j,n2=j,delta=0,delta2=1) # c(j), c(j+1)
MR_d = RT_Lumadifference(MR_c,c,n=j,n2=j,delta=0,delta2=1) # MR_c(j),c(j+1)
if(MR_d < CR_d && MR_d < BesTMax) {
BestMax=Max(ML_d,MR_d) IpLen=BadLen
}
}
}
} # End, for j
if(IpLen>0) {
Status=2 # Left Interp Src
RT_DBaseSet(DB,i,Status,EOSOS,IpLen,0)
BadStart=IpLen==1?4:IpLen==2?5:IpLen==3?7:IpLen==4?10:14
for(k=0,IpLen-1) {
EOSOS = Int(EOSOS@@@.RT_AverageLuma(n=i+1+k,w=1,h=1)) # 0=Norm, 1=EOS, 2=SOS, 3=EOS & SOS
RT_DBaseSet(DB,i+1+k,BadStart+k,EOSOS,IpLen,k+1)
}
EOSOS = Int(EOSOS@@@.RT_AverageLuma(n=i+1+k,w=1,h=1)) # 0=Norm, 1=EOS, 2=SOS, 3=EOS & SOS
RT_DBaseSet(DB,i+1+IpLen,3,EOSOS,IpLen,0) # Right Interp Src
if(SurgeonFile!="") { RT_WriteFile(SurgeonFile,"I%d %d",IpLen,i+1,Append=True) }
}
} # End if TstLen >= MinLen
}
(Status == 1) ? RT_DBaseSet(DB,i,Status,EOSOS,IpLen,IpIx) : NOP # Defaulted Src
} # End if Status == 0
} # End, if(Show || Status == 0)
Assert(1 <= Status <= 18,RT_String("Error bad Status=%d",Status))
Status<=3?Last
\ : Status <= 9 ? (Status==4?M1@@@:Status==5?M21@@@:Status==6?M22@@@:Status==7?M31@@@:Status==8?M32@@@:M33@@@)
\ : Status <= 13 ? (Status==10?M41@@@:Status==11?M42@@@:Status==12?M43@@@:M44@@@)
\ : Status == 14 ? M51@@@ : Status==15 ? M52@@@ : Status==16 ? M53@@@ : Status==17 ? M54@@@ : M55@@@
if(Show) {
if(Chop==1) { W=Last.Width/8*4 StackHorizontal(Last.Crop(0,0,W,0),c.Crop(Last.Width-W,0,0,0)) }
Else if (Chop==2) { H=Last.Height/8*4 StackVertical(Last.Crop(0,0,0,H),c.Crop(0,Last.Height-H,0,0)) }
HiLite=45 LoLite=76
EOSOS = RT_DBaseGetField(DB,i,1)
EOS_C = RT_BitTST(EOSOS,0) ? Hilite : LoLite
SOS_C = RT_BitTST(EOSOS,1) ? Hilite : LoLite
if(Status == 1) {
RT_Subtitle("%d] \a%cE\a%cS\aLLR*\a- D(n-1)=%.3f : D(n+1)=%.3f\nLftRat=%.3f",i,EOS_C,SOS_C,iPrv,iNxt,LftRat)
} Else {
IpLen = RT_DBaseGetField(DB,i,2)
IpIx = RT_DBaseGetField(DB,i,3)
if(Status==2) { # Left InterpSrc
Pdf = RT_LumaDifference(dc,dc,n=i+IpLen+1,n2=i+IpLen+1,delta=-1,delta2=0)
Ndf = RT_LumaDifference(dc,dc,n=i+IpLen+1,n2=i+IpLen+1,delta=0,delta2=1)
RgtRat=Pdf/Max(Ndf,0.001)
RT_Subtitle("%d] \a%cE\a%cS\a-L\aLR*\a- D(n-1)=%.3f : D(n+1)=%.3f\nLftRat=%.3f (RgtRat=%.3f)",
\ i,EOS_C,SOS_C,iPrv,iNxt,LftRat,RgtRat)
} Else if(Status==3) { # Right InterpSrc
RgtRat = iPrv / Max(iNxt,0.001)
Pdf = RT_LumaDifference(dc,dc,n=i-IpLen-1,n2=i-IpLen-1,delta=0,delta2=-1)
Ndf = RT_LumaDifference(dc,dc,n=i-IpLen-1,n2=i-IpLen-1,delta=0,delta2=1)
LftRat=Ndf/Max(Pdf,0.001)
RT_Subtitle("%d] \a%cE\a%cS\aL\a-R\aL*\a- D(n-1)=%.3f : D(n+1)=%.3f\nRgtRat=%.3f (LftRat=%.3f)",
\ i,EOS_C,SOS_C,iPrv,iNxt,RgtRat,LftRat)
} Else {
RT_Subtitle("%d] \a%cE\a%cS\aLLR\a-*\a*\a- [%d/%d] D(n-1)=%.3f : D(n+1)=%.3f",
\ i,EOS_C,SOS_C,IpIx,IpLen,iPrv,iNxt)
}
}
}
Return Last
}
if(SurgeonFile!="") {
SurgeonFile=RT_GetFullPathName(SurgeonFile)
RT_FileDelete(SurgeonFile)
RT_WriteFile(SurgeonFile,"###\n# FrameSurgeon() Command file [ Generated by DirtBox() ]\n###\n\n")
}
DB=RT_GetFullPathName("~@@@_"+RT_LocalTimeString+".DB") RT_DBaseAlloc(DB,FrameCount,"iiii")
/* DBase Fields:-
0) Status,
0 = UnKnown
1 = Src
2 = Left Interp Src
3 = Right Interp Src
4 = Interp[1/1]
5 = Interp[1/2] : 6 = Interp[2/2]
7 = Interp[1/3] : 8 = Interp[2/3] : 9 = Interp[3/3]
10 = Inter[(1/4) : 11 = Inter[(2/4) : 12 = Inter[(3/4) : 13 = Inter[(4/4)
14 = Inter[(1/5) : 15 = Inter[(2/5) : 16 = Inter[(3/5) : 17 = Inter[(4/5) : 18 = Inter[(5/5)
1) EOS/SOS
0 Normal Source
1 EOS (End Of Scene)
2 SOS
3 SOS and EOS (ie single frame scene)
2) InperpLen 0 Src, or 1 to 5
3) InterpIx, 1 to InterpLen if if Not Src.
*/
RT_DBaseSet(DB,0, 1,2,0,0) # Set SOS for 1st frame
RT_DBaseSet(DB,FrameCount-1, 1,1,0,0) # Set EOS for last frame
Prefilt = c.RemoveGrain(22)
Super = c.MSuper(hpad=16,vpad=16,levels=1,sharp=1,rfilter=4) # One level is enough for MRecalculate
Superfilt = Prefilt.MSuper(hpad=16,vpad=16,sharp=1,rfilter=4) # All levels for MAnalyse
bv = Superfilt.MAnalyse(isb=true, blksize=16,overlap=4,search=3,delta=2)# DELTA 2, (distance between interpolate source frames)
fv = Superfilt.MAnalyse(isb=false,blksize=16,overlap=4,search=3,delta=2)
bv = Super.MRecalculate(bv,blksize=8,overlap=2,thSAD=100)
fv = Super.MRecalculate(fv,blksize=8,overlap=2,thSAD=100)
Global M1@@@=c.MFlowInter(Super,bv,fv,time=50.0,ml=200).SelectEvery(1,-1) # n interp from src n-1 & n+1 @ 50.0% (n-1 shifted to n)
#
bv = Superfilt.MAnalyse(isb=true, blksize=16,overlap=4,search=3,delta=3)# DELTA 3
fv = Superfilt.MAnalyse(isb=false,blksize=16,overlap=4,search=3,delta=3)
bv = Super.MRecalculate(bv,blksize=8,overlap=2,thSAD=100)
fv = Super.MRecalculate(fv,blksize=8,overlap=2,thSAD=100)
Global M21@@@=c.MFlowInter(Super,bv,fv,time=100.0/3,ml=200).SelectEvery(1,-1) # n interp from src n-1 & n+2 @ 33.33% (n-1 shifted to n)
Global M22@@@=c.MFlowInter(Super,bv,fv,time=200.0/3,ml=200).SelectEvery(1,-2) # n interp from src n-2 & n+1 @ 66.67% (n-2 shifted to n)
#
bv = Superfilt.MAnalyse(isb=true, blksize=16,overlap=4,search=3,delta=4)# DELTA 4
fv = Superfilt.MAnalyse(isb=false,blksize=16,overlap=4,search=3,delta=4)
bv = Super.MRecalculate(bv,blksize=8,overlap=2,thSAD=100)
fv = Super.MRecalculate(fv,blksize=8,overlap=2,thSAD=100)
Global M31@@@=c.MFlowInter(Super,bv,fv,time=25.0,ml=200).SelectEvery(1,-1) # n interp from src n-1 & n+3 @ 25.0% (n-1 shifted to n)
Global M32@@@=c.MFlowInter(Super,bv,fv,time=50.0,ml=200).SelectEvery(1,-2) # n interp from src n-2 & n+2 @ 50.0% (n-2 shifted to n)
Global M33@@@=c.MFlowInter(Super,bv,fv,time=75.0,ml=200).SelectEvery(1,-3) # n interp from src n-3 & n+1 @ 75.0% (n-3 shifted to n)
#
bv = Superfilt.MAnalyse(isb=true, blksize=16,overlap=4,search=3,delta=5)# DELTA 5
fv = Superfilt.MAnalyse(isb=false,blksize=16,overlap=4,search=3,delta=5)
bv = Super.MRecalculate(bv,blksize=8,overlap=2,thSAD=100)
fv = Super.MRecalculate(fv,blksize=8,overlap=2,thSAD=100)
Global M41@@@=c.MFlowInter(Super,bv,fv,time=20.0,ml=200).SelectEvery(1,-1) # n interp from src n-1 & n+4 @ 20.0% (n-1 shifted to n)
Global M42@@@=c.MFlowInter(Super,bv,fv,time=40.0,ml=200).SelectEvery(1,-2) # n interp from src n-2 & n+3 @ 40.0% (n-2 shifted to n)
Global M43@@@=c.MFlowInter(Super,bv,fv,time=60.0,ml=200).SelectEvery(1,-3) # n interp from src n-3 & n+2 @ 60.0% (n-3 shifted to n)
Global M44@@@=c.MFlowInter(Super,bv,fv,time=80.0,ml=200).SelectEvery(1,-4) # n interp from src n-4 & n+1 @ 80.0% (n-4 shifted to n)
#
bv = Superfilt.MAnalyse(isb=true, blksize=16,overlap=4,search=3,delta=6)# DELTA 6
fv = Superfilt.MAnalyse(isb=false,blksize=16,overlap=4,search=3,delta=6)
bv = Super.MRecalculate(bv,blksize=8,overlap=2,thSAD=100)
fv = Super.MRecalculate(fv,blksize=8,overlap=2,thSAD=100)
Global M51@@@=c.MFlowInter(Super,bv,fv,time=100.0/6,ml=200).SelectEvery(1,-1) # n interp from src n-1 & n+5 @ 16.67% (n-1 shifted to n)
Global M52@@@=c.MFlowInter(Super,bv,fv,time=200.0/6,ml=200).SelectEvery(1,-2) # n interp from src n-2 & n+4 @ 33.33% (n-2 shifted to n)
Global M53@@@=c.MFlowInter(Super,bv,fv,time=300.0/6,ml=200).SelectEvery(1,-3) # n inter from src n-3 & n+3 @50.00% (n-3 shifted to n)
Global M54@@@=c.MFlowInter(Super,bv,fv,time=400.0/6,ml=200).SelectEvery(1,-4) # n inter from src n-4 & n+2 @ 66.67% (n-4 shifted to n)
Global M55@@@=c.MFlowInter(Super,bv,fv,time=500.0/6,ml=200).SelectEvery(1,-5) # n inter from src n-5 & n+1 @ 83.33% (n-4 shifted to n)
#
SupEos = c.MSuper(pel=1,sharp=0,rfilter=2,hpad=16, vpad=16)
BvEos = SupEos.MAnalyse(isb=True, delta=1,blksize=16)
FvSos = SupEos.MAnalyse(isb=False, delta=1,blksize=16)
EOS = c.MSCDetection(BvEos,thSCD1=400,thSCD2=130).Crop(0,0,16,16) EOS=(IsAvs26)?EOS.ConvertToY8:EOS.ConvertToYV12
SOS = c.MSCDetection(FvSos,thSCD1=400,thSCD2=130).Crop(0,0,16,16) SOS=(IsAvs26)?SOS.ConvertToY8:SOS.ConvertToYV12
Global EOSOS@@@ = MT_Lutxy(EOS,SOS,yexpr="y 0 == x 0 == 0 1 ? x 0 == 2 3 ? ?",u=-128,v=-128)
ARGS = "dc,DB,Th,ThMin,MinLen,MaxLen,ProcSingles,Show,Chop,SurgeonFile"
ScriptLine="Fn@@@(last, "+ARGS+")"
c.GScriptClip(ScriptLine, local=true, args=ARGS)
Return Last
"""
GIFunc="DirtBox_MI" # Function Name, Supply unique name for your multi-instance function.
GIName=GIFunc+"_InstanceNumber" # Name of the Instance number Global
RT_IncrGlobal(GIName) # Increment Instance Global (init to 1 if not already exists)
GID = GIFunc + "_" + String(Eval(GIName))
InstS = RT_StrReplace(Func_S,"@@@","_"+GID)
# RT_WriteFile("DEBUG_"+GID+".TXT","%s",InstS)
HasGScript ? GScript(InstS) : Eval(InstS) # Use GSCript if installed (loaded plugs override builtin)
# if CallCmd available, Auto delete DBase file on clip closure.
HasCallCmd?CallCmd(close=RT_String("""CMD /C chcp 1252 && del "%s" """,DB), hide=true, Synchronous=7):NOP
Return Last
}
StainlessS
1st September 2018, 21:22
Part #3 of 3 (client script)
ORG=AVISource("D:\GreyMouse.avi").ConvertToYV12
############ Config ################
TH = 1.3 # If either DC LRat or RRat greater or equal this then frame is bad.
THMIN = 0.5
MINLEN = 1
MAXLEN = 2
PROCSINGLES = True # Process single frame scene/cut
SHOW = True
CHOP = 0 # 0)=fix whole frame, 1) Fix only Left half of frame (Only when Show=true)
STACK = True
USE_DC = True # Use Zebra Bars as DC detect clip
###
DC_PIXELS = 16 # Zebra Bar width, multiple of 4 (Used only if STACK and USE_DC, else 4)
DC_SKIPBARS = 1 # Skip YPlaneMin Bars (2 also skips YPLaneMax bar)
DC_THRESHOLD = 0 # As Zebra Default
DC_LO = 128 # As Zebra Default
DC_HI = 255 # As Zebra Default
#########################################
ORG
# Dont use YPlaneMin Bar (on Greymouse clip is always near black, watering down metrics).
# Zebra:- https://forum.doom9.org/showthread.php?t=167663
DC=ORG.Zebra(pix=STACK&&USE_DC?DC_PIXELS:4,Threshold=DC_THRESHOLD,lo=DC_Lo,hi=DC_HI).Crop(DC_SKIPBARS*DC_PIXELS,0,0,0)
SEP=DC.BlankClip(Width=4,Color=$FF00FF)
Clean = Last.DirtBox_MI(dc=USE_DC?DC:ORG,Th=TH,ThMin=THMIN,MinLen=MINLEN,MaxLen=MAXLEN,ProcSingles=PROCSINGLES,Show=SHOW,Chop=CHOP)
Return (STACK && USE_DC)
\ ? StackHorizontal(Clean,SEP,DC,SEP,ORG.RT_Subtitle("BadSrc"))
\ : STACK ? StackHorizontal(Clean,SEP,ORG.RT_Subtitle("BadSrc"))
\ : Clean
EDIT: If set MaxLen to 4, then luckily fixes seq at 51, where jumping pretty bad, sort of de-shakes it.
EDIT: Not too sprightly, getting ~20FPS on Core Duo 2.4Ghz.
EDIT:
the noise I refer to are on frames
71,88,94,116,167
Actually, 167 should be 166 and 167, 2 frame bad pair.
Results in FrameSurgeonCmd.txt
###
# FrameSurgeon() Command file [ Generated by DirtBox() ]
###
I1 71
I1 88
I1 94
I1 116
I2 166 # EDIT: I2 = 2 bad frames starting at 166
https://s20.postimg.cc/m7w9umwll/Dirt_Box_MI_166.jpg (https://postimg.cc/image/m7w9umwll/)
https://s20.postimg.cc/yip8es37t/Dirt_Box_MI.jpg (https://postimg.cc/image/yip8es37t/)
EDIT: On 2nd thoughts, probably will not work OK with flash frames, as will likely be detected as End Of Scene / Start of Scene
and screw things up. I'll try to figure out what the rules are.
EDIT: See new thread and updated script here DirtBox_MI_v0.01 :- https://forum.doom9.org/showthread.php?t=175708
StainlessS
5th September 2018, 18:27
John, here your posted script converted to Script function, think it works exactly the same, but fixed the WriteFile logic.
Also note, I've made available arg AND, so can use either AND or OR logic.
You might want to change defaults or something. (NOTE, Metrics=True, will output metrics, otherwise, Filename = "" will output the fixed clip, else frame numbers)
DirtyJohn.avs
Function DirtyJohn(clip c,Float "Th",Float "ThMin",Bool "Metrics",Bool "ShowDot",String "FileName",Bool "AND") {
c
Th = Default(th,1.3)
ThMin = Default(ThMin,0.5)
Metrics = Default(Metrics,True)
ShowDot = Default(ShowDot,False)
FileName = Default(FileName,"")
And = Default(And,False) # NOTE, Default is 'either bad' for badframe, ie OR logic
###
Even = c.SeparateFields().SelectEven()
Super_Even = ShowDot ? Even.Subtitle("***").MSuper(pel=2) : Even.MSuper(pel=2)
vfe = MAnalyse(Super_Even,truemotion=true,isb=false,delta=2)
vbe = MAnalyse(Super_Even,truemotion=true,isb=true,delta=2)
Filldrops_E = MFlowInter(Even,Super_Even,vbe,vfe,Time=50)
#
Odd = c.SeparateFields().SelectOdd()
Super_Odd = ShowDot ? Odd.Subtitle("***").MSuper(pel=2) : Odd.MSuper(pel=2)
vfo = MAnalyse(Super_Odd,truemotion=true,isb=false,delta=2)
vbo = MAnalyse(Super_Odd,truemotion=true,isb=true,delta=2)
Filldrops_O = MFlowInter(Odd,Super_Odd,vbo,vfo,Time=50)
###
Script_Init= """
PrvDif = YDifferenceFromPrevious
PPrvDif = YDifferenceFromPrevious(Selectevery(1, -1))
PrvRatio = PrvDif / Max(PPrvDif,0.001)
NxtDif = YDifferenceToNext
NNxtDif = YDifferenceToNext(Selectevery(1, 1))
NxtRatio = NxtDif / Max(NNxtDif,0.001)
PBad = PrvDif > ThMin && PrvRatio > Th
NBad = NxtDif > ThMin && NxtRatio > Th
"""
Bad_Logic = (AND) ? "BadFrame = PBad && NBad" : "BadFrame = PBad || NBad"
Script_Base = Script_Init + Bad_Logic + Chr(10)
Script_Met = """
S1=String(current_frame,"%.0f] ")
S2=BadFrame ? "***\n" : "\n"
S3=String(PrvDif ,"PrevDiff = %f") + String(NxtDif, " : NextDiff = %f\n")
S4=String(PrvRatio,"PrevRatio= %f") + String(NxtRatio," : NextRatio= %f")
Return Subtitle(S1+S2+S3+S4,lsp=0,font="CourierNew",size=20)
"""
Script_Wr = Script_Base+"BadFrame"
Script_Cond = Script_Base+"BadFrame ? 1 : 0"
###
Replacement_Clip = Interleave(Filldrops_E,Filldrops_O).Weave
Return
\ (Metrics) ? ScriptClip(Script_Base+Script_Met)
\ : (FileName!="") ? WriteFileIf(FileName,Script_Wr,"Current_frame",Append=False)
\ : ConditionalSelect(Script_Cond,c,Replacement_Clip.SelectEvery(1,-1))
}
DirtyJohn_Client.avs
############ Config ################
VideoFile = "GreyMouse.avi"
INTERLACED = FALSE # You decide
TH = 1.2 # Set METRICS=TRUE to determine best value
THMIN = 0.5 # 0.5,
SHOWDOT = True # TRUE will add "***" to each replacment frame (for troubleshooting)
METRICS = True # TRUE will show Metrics ONLY (i.e., TRUE overrides all other selctions)
FILENAME = "" # Set to name and location where you want the frame numbers stored, If "" then fix clip instead of Write.
AND = False # True uses && logic instead of || logic in detector.
STACK = True # Return Stacked Window
##########################################
AVISource("D:\"+VideoFile).ConvertToYV12(Interlaced=INTERLACED)#.killaudio()
ORG=Last
DirtyJohn(Th=Th,ThMin=ThMin,Metrics=Metrics,ShowDot=ShowDot,FileName=FileName,And=AND)
Return STACK ? StackVertical(Last,ORG) : Last
EDIT: Oops, AND logic was OR for both AND=True and AND=False, fixed.
EDIT: Added STACK setting to client
EDIT: Can call with ThMin=0.0 if not required, but almost certainly better having it above 0.0
johnmeyer
5th September 2018, 19:59
Thanks for giving me the "DirtyJohn" moniker. :)
I don't have any current project on which to use it, but replacing bad frames is such a common problem that I'm sure I'll get around to testing the in the near future.
Thansk!!
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.