Log in

View Full Version : Automatic clip alignment script - need help


zambelli
13th July 2007, 03:04
I have a frequent need for generating Avisynth scripts that load two videos and compare them either for PSNR/SSIM calculation or A/B evalution (Interleave or StackVertical). My problem is that it's often very difficult to predict how the video clips will align temporally, making automation very cumbersome. Adding to the mess is the fact that formats supporting VFR often need to be loaded with the ConvertFPS=true parameter in DirectShowSource.

I tried writing a script that would take two videos and find the best alignment by calculating LumaDifference for 3 points in the clip (25%, 50% and 75% timeline marks) and picking the frame offset that has the smallest sum of luma difference points. I used ConditionalFilter and I must admit I quickly got lost in the strange reverse logic of Avisynth's conditional execution.

Here's my script so far:
target = "test.wmv"

original = AVISource("source.avi", audio=false)


function BestAlignedVideo(clip s, string filename, float fr)
{
global VFR = DirectShowSource(filename, fps=fr, convertfps=true, audio=false)
global CFR = DirectShowSource(filename, fps=fr, convertfps=false, audio=false)
global src = s
global fc = s.Framecount

CFR = ConditionalFilter(CFR, CFR, CFR.Trim(1,0), \
"diff1 = LumaDifference(src.Trim(Round(fc * 0.25), -1), CFR.Trim(Round(fc * 0.25), -1) )"+chr(13)+ \
"diff2 = LumaDifference(src.Trim(Round(fc * 0.5), -1), CFR.Trim(Round(fc * 0.5), -1) )"+chr(13)+ \
"diff3 = LumaDifference(src.Trim(Round(fc * 0.75), -1), CFR.Trim(Round(fc * 0.75), -1) )"+chr(13)+ \
"return diff1 + diff2 + diff3", \
"<", \
"diff1 = LumaDifference(src.Trim(Round(fc * 0.25), -1), CFR.Trim(Round(fc * 0.25)+1, -1) )"+chr(13)+ \
"diff2 = LumaDifference(src.Trim(Round(fc * 0.5), -1), CFR.Trim(Round(fc * 0.5)+1, -1) )"+chr(13)+ \
"diff3 = LumaDifference(src.Trim(Round(fc * 0.75), -1), CFR.Trim(Round(fc * 0.75)+1, -1) )"+chr(13)+ \
"return diff1 + diff2 + diff3", show=false)

VFR = ConditionalFilter(VFR, VFR, VFR.Trim(1,0), \
"diff1 = LumaDifference(src.Trim(Round(fc * 0.25), -1), VFR.Trim(Round(fc * 0.25), -1) )"+chr(13)+ \
"diff2 = LumaDifference(src.Trim(Round(fc * 0.5), -1), VFR.Trim(Round(fc * 0.5), -1) )"+chr(13)+ \
"diff3 = LumaDifference(src.Trim(Round(fc * 0.75), -1), VFR.Trim(Round(fc * 0.75), -1) )"+chr(13)+ \
"return diff1 + diff2 + diff3", \
"<", \
"diff1 = LumaDifference(src.Trim(Round(fc * 0.25), -1), VFR.Trim(Round(fc * 0.25)+1, -1) )"+chr(13)+ \
"diff2 = LumaDifference(src.Trim(Round(fc * 0.5), -1), VFR.Trim(Round(fc * 0.5)+1, -1) )"+chr(13)+ \
"diff3 = LumaDifference(src.Trim(Round(fc * 0.75), -1), VFR.Trim(Round(fc * 0.75)+1, -1) )"+chr(13)+ \
"return diff1 + diff2 + diff3", show=false)


return ConditionalFilter(CFR, VFR, CFR, \
"diff1 = LumaDifference(src.Trim(Round(fc * 0.25), -1), VFR.Trim(Round(fc * 0.25), -1) )"+chr(13)+ \
"diff2 = LumaDifference(src.Trim(Round(fc * 0.5), -1), VFR.Trim(Round(fc * 0.5), -1) )"+chr(13)+ \
"diff3 = LumaDifference(src.Trim(Round(fc * 0.75), -1), VFR.Trim(Round(fc * 0.75), -1) )"+chr(13)+ \
"return diff1 + diff2 + diff3", \
"<", \
"diff1 = LumaDifference(src.Trim(Round(fc * 0.25), -1), CFR.Trim(Round(fc * 0.25), -1) )"+chr(13)+ \
"diff2 = LumaDifference(src.Trim(Round(fc * 0.5), -1), CFR.Trim(Round(fc * 0.5), -1) )"+chr(13)+ \
"diff3 = LumaDifference(src.Trim(Round(fc * 0.75), -1), CFR.Trim(Round(fc * 0.75), -1) )"+chr(13)+ \
"return diff1 + diff2 + diff3", show=false)
}



encoded = BestAlignedVideo(original, target, 29.97)

fc = (original.Framecount > encoded.Framecount) ? (encoded.Framecount - 5) : (original.Framecount - 5)
original = original.Trim(0, -fc)
encoded = encoded.Trim(0, -fc)


Interleave(original, encoded)

I'm pretty sure there's a much cleaner and more flexible way of doing this. I'm open to throwing this script out the window entirely and starting from scratch again. Here are the goals:

Load two videos. Ideally both could be DShow types, but if one is AVI source for easier comparison, that's fine. We'll call one of them "source".
Load the target video twice, once with ConvertFPS set to True and once set to False.
For each version of the video, compare it to the source video at frame offset -1, 0 and +1.
Return the video that most closely resembles the source.


Any ideas?