View Full Version : Report sceenshots instead of txt
frenshprince
26th March 2013, 11:11
Hi there,
I use this script to fing bad frame in my videos
AVISource("***.avi", audio=false).AssumeFPS(24000,1001)
ConvertToYV12()
prev=deleteframe(0)
next=duplicateframe(0)
prevdiff=mt_lutxy(last,prev,"x y - 4 / 2 ^")
nextdiff=mt_lutxy(last,next,"x y - 4 / 2 ^")
writefileif("D:\video\***.txt","AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100","current_frame")
And it works nice, except that I would like a report of the bad frame, in screenshot instead of inside a TXT file.
Is that possible to do ?
Thanks for your help :)
fvisagie
26th March 2013, 11:33
Use a runtime filter (http://avisynth.org/mediawiki/Runtime_environment#Runtime_filters) to call Subtitle() on each frame, with your text string as input to Subtitle().
Cheers,
Francois
Gavino
26th March 2013, 11:40
You could use my DeleteFrames() function from this thread to delete all the good frames, leaving just the bad ones, eg
DeleteFrames("AverageLuma(prevdiff) <= 100 || AverageLuma(nextdiff) <= 100")
Incidentally, your code
prev=deleteframe(0)
next=duplicateframe(0)
has prev and next the wrong way round - frame n of prev will be frame n+1 of the original, although it doesn't really matter here since your process treats both directions equally .
frenshprince
26th March 2013, 11:52
You could use my DeleteFrames() function from this thread to delete all the good frames, leaving just the bad ones, eg
DeleteFrames("AverageLuma(prevdiff) <= 100 || AverageLuma(nextdiff) <= 100")
Incidentally, your code
has prev and next the wrong way round - frame n of prev will be frame n+1 of the original, although it doesn't really matter here since your process treats both directions equally .
Hi Gavino,
I used this script this way AVISource("test.avi", audio=false).AssumeFPS(24000,1001)
ConvertToYV12()
prev=deleteframe(0)
next=duplicateframe(0)
prevdiff=mt_lutxy(last,prev,"x y - 4 / 2 ^")
nextdiff=mt_lutxy(last,next,"x y - 4 / 2 ^")
DeleteFrames("AverageLuma(prevdiff) <= 100 || AverageLuma(nextdiff) <= 100")
But Vdub told me that there is no function nemed "delete frames".
frenshprince
26th March 2013, 11:53
Use a runtime filter (http://avisynth.org/mediawiki/Runtime_environment#Runtime_filters) to call Subtitle() on each frame, with your text string as input to Subtitle().
Cheers,
Francois
Hi François,
Thanks for your help, but it seems too complicated to me.:(
Gavino
26th March 2013, 12:14
Vdub told me that there is no function nemed "delete frames".
Your script needs to include the function source code from the thread I linked.
You will also need GScript (http://forum.doom9.org/showthread.php?t=147846).
frenshprince
26th March 2013, 12:29
Thanks for you help Gavino:)
But I'm a total noob; and can't make it works.
I Installed Gscript plugins, but I don't understand your source code.
This is what I tried AVISource("test.avi", audio=false).AssumeFPS(24000,1001)
ConvertToYV12()
GScript("""
function DeleteFrames(clip c, string condition) {
DeleteFrames("AverageLuma(prevdiff) <= 100 || AverageLuma(nextdiff) <= 100")
c
fc = FrameCount()
res = BlankClip(c, length=0)
current_frame = 0
while (current_frame < fc) {
while (Eval(condition) && current_frame < fc) {
current_frame = current_frame+1
}
if (current_frame < fc) { # not at end
start = current_frame # start of wanted section
while (!Eval(condition) && current_frame < fc) {
current_frame = current_frame+1
}
res = res + Trim(start, start-current_frame)
}
}
return res
}
""")
Gavino
26th March 2013, 13:06
Copy the code unchanged from the other thread (which defines the function) before the rest of your script, then add the function call at the end:
GScript("""
function DeleteFrames(clip c, string condition) {
...
""")
AVISource("test.avi", audio=false).AssumeFPS(24000,1001)
ConvertToYV12()
prev=deleteframe(0)
next=duplicateframe(0)
prevdiff=mt_lutxy(last,prev,"x y - 4 / 2 ^")
nextdiff=mt_lutxy(last,next,"x y - 4 / 2 ^")
DeleteFrames("AverageLuma(prevdiff) <= 100 || AverageLuma(nextdiff) <= 100")
fvisagie
26th March 2013, 13:52
Hi François,
Thanks for your help, but it seems too complicated to me.:(
You can replace the WriteFileIf() line at the end of your script with something like
ScriptClip("(AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100) ? Subtitle(String(current_frame)) : last")
to identify the frames considered bad on-screen.
If you want to add string literals to the displayed string, you have to enclose the lot in triple quotes
ScriptClip("""(AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100) ? Subtitle("Bad frame: " + String(current_frame)) : last""")
Hope this helps,
Francois
frenshprince
26th March 2013, 14:06
Thanks Gavino, but I don't get "add the function call at the end"
Remember, I'm an avisynth noob:)
GScript("""
function DeleteFrames(clip c, string condition) {
# DeleteFrames (Gavino, 16 Nov 2011)
# A generic function that will delete all frames satisfying an arbitrary user-defined condition.
# The condition can use any of the Avisynth run-time functions such as AverageLuma(), etc,
# and/or the variable 'current_frame'.
# (Note - Since the condition is evaluated inside the function,
# any variables used (except current_frame) must be global.)
# Example use (delete duplicate frames):
# DeleteFrames("YDifferenceFromPrevious < 0.1 && current_frame > 0")
c
fc = FrameCount()
res = BlankClip(c, length=0)
current_frame = 0
while (current_frame < fc) {
while (Eval(condition) && current_frame < fc) {
current_frame = current_frame+1
}
if (current_frame < fc) { # not at end
start = current_frame # start of wanted section
while (!Eval(condition) && current_frame < fc) {
current_frame = current_frame+1
}
res = res + Trim(start, start-current_frame)
}
}
return res
}
""")
AVISource("test.avi", audio=false).AssumeFPS(24000,1001)
ConvertToYV12()
prev=deleteframe(0)
next=duplicateframe(0)
prevdiff=mt_lutxy(last,prev,"x y - 4 / 2 ^")
nextdiff=mt_lutxy(last,next,"x y - 4 / 2 ^")
DeleteFrames("AverageLuma(prevdiff) <= 100 || AverageLuma(nextdiff) <= 100")
When I try to open it in Vdub, it tells me "I don't know what prediff means"
:thanks:
fvisagie
26th March 2013, 14:11
You can replace the WriteFileIf() line at the end of your script with something like
ScriptClip("(AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100) ? Subtitle(String(current_frame)) : last")
to identify the frames considered bad on-screen.
Or, as Gavino pointed out elsewhere, you could use ShowFrameNumber() instead of Subtitle() in your last line
ScriptClip("(AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100) ? ShowFrameNumber(size=100) : last")
Cheers,
Francois
frenshprince
26th March 2013, 14:16
You can replace the WriteFileIf() line at the end of your script with something like
ScriptClip("(AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100) ? Subtitle(String(current_frame)) : last")
to identify the frames considered bad on-screen.
If you want to add string literals to the displayed string, you have to enclose the lot in triple quotes
ScriptClip("""(AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100) ? Subtitle("Bad frame: " + String(current_frame)) : last""")
Hope this helps,
Francois
Thanks François,
Bad frames are identified, which is great.
But what do I have to add to the script to capture those bad frame automatically on png/jpeg/bmp ?
Gavino
26th March 2013, 14:36
When I try to open it in Vdub, it tells me "I don't know what prediff means"
Sorry, I forgot you need to make the prevdiff and nextdiff variables global for use in DeleteFrames. Change it to:
global prevdiff=mt_lutxy(last,prev,"x y - 4 / 2 ^")
global nextdiff=mt_lutxy(last,next,"x y - 4 / 2 ^")
frenshprince
26th March 2013, 15:20
It works, Thanks Gavino:)
Therefore, I can't make batch with it, since the process is made at the opening of the avs file in VDub.
And it takes twenty minutes to process.
I guess, what I would like is something like this :
AVISource("test.avi", audio=false).AssumeFPS(24000,1001)
ConvertToYV12()
prev=deleteframe(0)
next=duplicateframe(0)
global prevdiff=mt_lutxy(last,prev,"x y - 4 / 2 ^")
global nextdiff=mt_lutxy(last,next,"x y - 4 / 2 ^")
ScriptClip("(AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100) ? ShowFrameNumber(size=100) : last")
then create bmp of those bad frames with imagewriter.
But I can't find the good call.
StainlessS
26th March 2013, 15:35
Twenty mins aint a big problem, go get yourself a beer. Cheers. :)
frenshprince
26th March 2013, 15:40
Twenty mins aint a big problem, go get yourself a beer. Cheers. :)
Not a bad idea :D
But I have more than 200 video to check.
I can't be drunk at work :D
StainlessS
26th March 2013, 16:05
I can't be drunk at work:D
Damn shame.
Global ImgCounter = 0
AVISource("D:\test.avi", audio=false).AssumeFPS(24000,1001)
ConvertToYV12()
prev=deleteframe(0)
next=duplicateframe(0)
global prevdiff=mt_lutxy(last,prev,"x y - 4 / 2 ^")
global nextdiff=mt_lutxy(last,next,"x y - 4 / 2 ^")
ScriptClip("""
TmpC=ShowFrameNumber(size=100).ConvertToRGB24().ImageWriter("d:\TestA_",Start=ImgCounter,End=ImgCounter, type="bmp")
Proc = (AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100)
Global ImgCounter = (Proc) ? ImgCounter+1 : ImgCounter
(Proc) ? RT_TxtWriteFile(String(current_frame),"D:\TESTFILE.TXT",append=True) : NOP
Last.RT_GraphLink(TmpC,Proc) # From RT_Stats
""")
Give above a whirl, not tested, test clip did not fulfill condition to output bmp.
You need RT_Stats for RT_Graphlink().
EDIT: If it dont work on correct frame try " """,After_frame=true) " on scripclip close.
frenshprince
26th March 2013, 16:13
Thanks Stainless.
It doesnt work :
Imagewriter capture every frame, and not only the bad ones.
StainlessS
26th March 2013, 16:18
I think I left in "Proc=True", since removed (almost immediately after posting). Was testing that it worked if condition fulfilled.
frenshprince
26th March 2013, 16:24
It works !
Many thanks to you, and to Gavino and fvisagie as well.
Cheers ;)
StainlessS
26th March 2013, 16:25
See also edit on post #17
EDIT: From RT_Stats docs
RT_GraphLink(clip source, clip c1, ... , clip cn, bool b1, ... , bool bn)
Standard filter function.
This function is a standard filter graph function, not a runtime/compile time function.
It takes a compulsory source clip which it will return unchanged.
The clips, c1 to cn (one or more, at least one of them) are by default forcibly linked into
the filter graph. The bools b1 to bn are optional (zero or more) and would default to True
if not supplied. These bools will if false, switch OFF the forcible linking into the filter graph
for the corresponding clip c1 to cn.
Avisynth does not normally process any filter chains that do not contribute to the output clip,
this filter allows you to select graph chains that you wish to forcibly process.
The usual way to force process an unused chain is to do a stackHorizontal/Vertical and a crop.
The forced clips should all be same length as the source clip (but no error if not), only frame numbers contained
in both source and forced clips will be forcibly accessed when frame n of source clip is accessed.
All args un-named.
Example: [will only render the TestA" and TestC images]
a=ImageSource("d:\avs\1.jpg",end=0) # Single frame
TmpA = a.subtitle("TestA").ImageWriter("d:\avs\TestA_", type="png") # Written
TmpB = a.subtitle("TestB").ImageWriter("d:\avs\TestB_", type="png") # Skipped
TmpC = a.subtitle("TestC").ImageWriter("d:\avs\TestC_", type="png") # Written
RT_GraphLink(a,TmpA,TmpB,TmpC,True,false) # 3rd bool defaults true
return Last
Very similar to this solution.
StainlessS
26th March 2013, 16:51
Addendum, added line (EDIT: Post #17) to output frame numbers to text file,
(Proc) ? RT_TxtWriteFile(String(current_frame),"D:\TESTFILE.TXT",append=True) : NOP
Should work I think, perhaps more convenient, or not.
fvisagie
26th March 2013, 17:11
Therefore, I can't make batch with it
If you want to make a fast batch process, use a command-line encoder like ffmpeg to read the Avisynth output. In Windows, create a batch file called, say, batch.bat containing
ffmpeg -i "%1" -vcodec copy -an -f null NUL
and from the command prompt invoke it with
batch your.avs
This will only process the single input file specified in your.avs. To process all AVI files in the directory,
remove the AVISource() line in your.avs
modify batch.bat as below, and
from the command line, invoke batch.bat so: for %i in (*.avi) do batch "%i"
batch.bat
echo AVISource("%1", audio=false).AssumeFPS(24000,1001) >input.avs
type your.avs >>input.avs
ffmpeg -i input.avs -vcodec copy -an -f null NUL
del input.avs
I didn't specifically test the above now, but this approach does work. At worst you'll have to contend with a slip-up on my part ;).
Cheers,
Francois
StainlessS
26th March 2013, 17:17
One too many closing parenthesis. (Delete last character).
EDIT: how about text file, any more than 1 line output ?
frenshprince
26th March 2013, 17:17
Addendum, added line (EDIT: Post #17) to output frame numbers to text file,
(Proc) ? RT_TxtWriteFile(String(current_frame),"D:\TESTFILE.TXT",append=True) : NOP
Should work I think, perhaps more convenient, or not.
I spoke too quickly.
Only the first bad frame is exported.
I tried with your edit Global ImgCounter = 0
AVISource("Fractale 01.avi", audio=false).AssumeFPS(24000,1001)
#return info()
ConvertToYV12()
prev=deleteframe(0)
next=duplicateframe(0)
global prevdiff=mt_lutxy(last,prev,"x y - 4 / 2 ^")
global nextdiff=mt_lutxy(last,next,"x y - 4 / 2 ^")
ScriptClip("""
TmpC=ShowFrameNumber(size=100).ConvertToRGB24().ImageWriter("D:\Fractale01_",Start=ImgCounter,End=ImgCounter, type="bmp")
Proc = (AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100)
Global ImgCounter = (Proc) ? ImgCounter+1 : ImgCounter
Last.RT_GraphLink(TmpC,Proc) # From RT_Stats
""",After_frame=true))
but same results.
One too many closing parenthesis.
Saw that and corrected it :D
Gavino
26th March 2013, 17:22
You could also use ConditionalFilter (http://avisynth.org/mediawiki/ConditionalFilter)() to select the frames for ImageWriter() (IMHO simpler).
AVISource("D:\test.avi", audio=false).AssumeFPS(24000,1001)
ConvertToYV12()
prev=deleteframe(0)
next=duplicateframe(0)
prevdiff=mt_lutxy(last,prev,"x y - 4 / 2 ^")
nextdiff=mt_lutxy(last,next,"x y - 4 / 2 ^")
ConvertToRGB24()
img = ImageWriter("d:\TestA_", type="bmp")
ConditionalFilter(last, img, last, "AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100", "=", "true")
StainlessS
26th March 2013, 17:26
Nice, would the bmp's be sequentially numbered or as frame number ?
frenshprince
26th March 2013, 17:28
You could also use ConditionalFilter (http://avisynth.org/mediawiki/ConditionalFilter)() to select the frames for ImageWriter() (IMHO simpler).
AVISource("D:\test.avi", audio=false).AssumeFPS(24000,1001)
ConvertToYV12()
prev=deleteframe(0)
next=duplicateframe(0)
prevdiff=mt_lutxy(last,prev,"x y - 4 / 2 ^")
nextdiff=mt_lutxy(last,next,"x y - 4 / 2 ^")
ConvertToRGB24()
img = ImageWriter("d:\TestA_", type="bmp")
ConditionalFilter(last, img, last, "AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100", "=", "true")
Works perfectly :thanks:
kolak
26th March 2013, 17:32
Hi there,
I use this script to fing bad frame in my videos
And it works nice, except that I would like a report of the bad frame, in screenshot instead of inside a TXT file.
Is that possible to do ?
Thanks for your help :)
Bad in this case means?
Gavino
26th March 2013, 17:38
Nice, would the bmp's be sequentially numbered or as frame number ?
As frame number (hence no need to have the frame number showing on the image).
frenshprince
26th March 2013, 17:42
Bad in this case means?
http://forum.doom9.org/showthread.php?t=167494
StainlessS
26th March 2013, 18:18
As frame number (hence no need to have the frame number showing on the image).
Ooops, guess one of the benefits of having a test clip is seeing whether or not summick works. I for some reason thought start and end args were for output file names, hence the daft ImgCounter Global :(
anyway, corrected here together with test clip creation,
think that there is a script called InsertEvery or similar, but as I
know ClipClop, used that.
AVISource("D:\test.avi", audio=false).AssumeFPS(24000,1001)
# Create test clip, insert white frame every 10
# Trim(0,199)
# WHT=Last.BlankClip(color=$ffffff)
# ClipClop(Last,WHT,SCMD="1 10;1 20;1 30;1 40;1 50;1 60;1 70;1 80;1 90;1 100;1 110;1 120;1 130;1 140;1 150;1 160;1 170;1 180;1 190")
ConvertToYV12()
prev=deleteframe(0)
next=duplicateframe(0)
prevdiff=mt_lutxy(last,prev,"x y - 4 / 2 ^")
nextdiff=mt_lutxy(last,next,"x y - 4 / 2 ^")
TmpC=ShowFrameNumber(size=100).ConvertToRGB24().ImageWriter("d:\TestA_",type="bmp")
ScriptClip("""
Proc = (AverageLuma(prevdiff) > 100 && AverageLuma(nextdiff) > 100)
(Proc) ? RT_TxtWriteFile(String(current_frame),"D:\TESTFILE.TXT",append=True) : NOP
Last.RT_GraphLink(TmpC,Proc) # From RT_Stats
#(Proc) ? Last.Echo(TmpC) : Last # Alternative to RT_GraphLink() for v2.6Alpha4
""")
EDIT: I guess TmpC could be made Global and moved outside of Scriptclip.
FIXED
Gavino
27th March 2013, 00:15
I guess TmpC could be made Global and moved outside of Scriptclip.
Yes, it can be moved outside, but it doesn't need to be global - variables at outer script level are visible within run-time scripts.
See Scope and lifetime of variables (http://avisynth.org/mediawiki/The_script_execution_model/Scope_and_lifetime_of_variables).
Similarly, prevdiff and nextdiff don't need to be global here either (they were previously made global to be visible inside the DeleteFrames() function).
StainlessS
27th March 2013, 09:42
Fixed. Must get real tedious, always being right. :)
frenshprince
11th April 2013, 13:27
Hi there,
Your AVS scripts work very well.
Thanks again for that.
Therefore, I have a new picture issue.
Sometimes, there is some block like these which appears :
http://img534.imageshack.us/img534/2223/issue2i.jpg
Do you think it's possible to make a script who can identify and report those kind of issues ?
Thank you
kolak
26th April 2013, 19:47
Anyone, Didee?
StainlessS
27th April 2013, 16:12
Are the above frames isolated, at scene change, or just anywhere ?
Post a small sample please.
kolak
27th April 2013, 16:37
It can be 1 frame or few continuous and has not much to do with scene change.
Problem which I think about (and looks bout the same) is from digibeta tape ( http://en.wikipedia.org/wiki/Betacam , Digital Betacam section) and "dropouts" are always in form of blocks. Sometimes it's much less visible, but most likely affects whole frame. There are not many solutions which can detect such a problems.
fvisagie
29th April 2013, 08:05
Could these drop-outs be characterised by:
1. They appear and disappear suddenly (i.e. few to no preceding and succeeding frames have them)
2. Most importantly, they're regular in shape - rectangular in general, with squares as a few special cases
If you can find a way to characterise the drop-outs, a detection method can be scripted/coded, I would guess.
The question then would become: once you can detect them, do you have a good way in mind of using that knowledge? Replacing frames with motion-compensated ones, multi-capturing, ?
Cheers,
Francois
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.