redfordxx
10th January 2012, 20:30
I made a script which can be helpful to estimate blending pattern of some video, where was change framerate via blending. However, at least sample of source clip is necessary to make the analysis. There are two outputs. Visual and information in the file.
Function:
#function EstimateWeights v0.1
#by redfordxx
#Needed:
#Blendweight plugin by mg262
#RedAverage by redfordxx
function EstimateWeights (clip src, clip dst, float fps_src, float fps_dst, int "shift") {
#src ......clip before the framerate change (for example nonblended 24/1.001 clip)
#dst ......clip after the framerate change (for example blended 25fps clip)
#fps_src...framerate of source (for example 24000.0/1001)
#fps_dst...target framerate (for example 25)
#shift..... positive or negative number of frames needed to shift the source clip to match the destination
shift=default(shift,0)
global sep1=" -- "
global LabelNumbers="Estimated frame: "
file="BlendWeight log.txt"
src=src.AssumeFPS(fps_src)#.ScriptClip("Subtitle(String(current_frame))")
dst=dst.AssumeFPS(fps_dst)
sh_cnt=(shift>=0) ? shift+1 : 0
sh_rng=(shift>=0) ? -1 : -shift
prev=src.FrameEvaluate( "global frp=current_frame").loop(sh_cnt,0,sh_rng).ChangeFPS(fps_dst,1).loop(2,0,-1)
curr=src.FrameEvaluate( "global frc=current_frame").loop(sh_cnt,0,sh_rng).ChangeFPS(fps_dst,1).loop(1,0,-1)
next=src.FrameEvaluate( "global frn=current_frame").loop(sh_cnt,0,sh_rng).ChangeFPS(fps_dst,1).loop(0,0,-1)
iii=Interleave(prev,dst,curr,dst,next, prev,curr,next, curr,dst)
blendprev=iii.ScriptClip("BlendWeight(current_frame)").SelectEvery(10,1)
blendnext=iii.ScriptClip("BlendWeight(current_frame)").SelectEvery(10,3)
blendsrc=iii.ScriptClip("BlendWeight(current_frame)").SelectEvery(10,6)
tmp=Interleave(blendprev,dst,blendnext)
eval1="""
global q_n=YDifferenceToNext
global q_p=YDifferenceFromPrevious
"""
dx=10
s1=StackHorizontal(prev,curr,next)
s2=StackHorizontal(blendprev,tmp.FrameEvaluate(eval1).SelectEvery(3,1),blendnext)
dp=RAverageW(blendprev,dx,dst,-dx,bias=128)
dc=RAverageW(curr,dx,iii.FrameEvaluate("global q_c=YDifferenceFromPrevious").SelectEvery(10,9),-dx,bias=128)
dn=RAverageW(blendnext,dx,dst,-dx,bias=128)
s3=StackHorizontal(dp,dc,dn).Greyscale()
sp=RAverageW(curr,dx,iii.FrameEvaluate("global s_p=YDifferenceToNext").SelectEvery(10,5),-dx,bias=128)
sn=RAverageW(curr,-dx,iii.FrameEvaluate("global s_n=YDifferenceFromPrevious").SelectEvery(10,7),dx,bias=128)
s4=StackHorizontal(sp,blendsrc,sn).Greyscale()
StackVertical(s1,s2,s3,s4)
WriteFile(file, "LabelNumbers", "current_frame", """" <== """", "frp","sep1","frc","sep1","frn","""" Quality("""","q_p","sep1","q_c","sep1","q_n","""") Flow("""","s_p","sep1","s_n","""")"""")
WriteFile(file, "Chr(32)")
}
Usage example:
black=BlankClip(pixel_type="YV12", color=$000000,width=160,height=160)
white=BlankClip(pixel_type="YV12", color=$FAFAFA,width=160,height=160)
s1=StackVertical(StackHorizontal(black,white),StackHorizontal(white,white))
s2=StackVertical(StackHorizontal(white,black),StackHorizontal(white,white))
s3=StackVertical(StackHorizontal(white,white),StackHorizontal(white,black))
s4=StackVertical(StackHorizontal(white,white),StackHorizontal(black,white))
bbb=Interleave(s1,s2,s3,s4).AssumeFPS(4,1)
bbb2=bbb.ConvertFPS(5,1)
EstimateWeights(bbb,bbb2,4,5)
You can use real live clips, but this is test clip to see how does conversion from 4 to 5 fps look like. As expected, the coefficient are increasing by 0.2, which is shown in the logfile.
To understand the meaning of the output clip better use one real life clip instead of bbb first, but just shortly, what you will see Stacked:
previous, current, next source
first pair estimation, current destination, second pair est
difference of current destination to 1st est, current src, 2nd est
src different to previous, current dst estimation, src difference to next
Logfile sample:
Frame 1001 = 0.0000 x prev. Frame + 1.0000 x next Frame
Frame 1003 = -1.#IND x prev. Frame + -1.#IND x next Frame
Frame 1006 = 0.0000 x prev. Frame + 1.0000 x next Frame
Estimated frame: 100 <== 79 -- 80 -- 80 Quality(0.000000 -- 0.000000 -- 177.250000) Flow(107.500000 -- 0.000000)
Frame 1011 = -1.#IND x prev. Frame + -1.#IND x next Frame
Frame 1013 = 0.2000 x prev. Frame + 0.8000 x next Frame
Frame 1016 = 1.0000 x prev. Frame + 0.0000 x next Frame
Estimated frame: 101 <== 80 -- 80 -- 81 Quality(177.250000 -- 86.000000 -- 0.250000) Flow(0.000000 -- 107.500000)
Frame 1021 = 0.3000 x prev. Frame + 0.7000 x next Frame
Frame 1023 = 0.4000 x prev. Frame + 0.6000 x next Frame
Frame 1026 = 0.5000 x prev. Frame + 0.5000 x next Frame
Estimated frame: 102 <== 80 -- 81 -- 82 Quality(64.750000 -- 64.500000 -- 0.250000) Flow(107.500000 -- 107.500000)
Frame 1031 = 0.2000 x prev. Frame + 0.8000 x next Frame
Frame 1033 = 0.6000 x prev. Frame + 0.4000 x next Frame
Frame 1036 = 0.5000 x prev. Frame + 0.5000 x next Frame
Estimated frame: 103 <== 81 -- 82 -- 83 Quality(43.250000 -- 43.000000 -- 0.250000) Flow(107.500000 -- 107.500000)
Frame 1041 = 0.1000 x prev. Frame + 0.9000 x next Frame
Frame 1043 = 0.8000 x prev. Frame + 0.2000 x next Frame
Frame 1046 = 0.5000 x prev. Frame + 0.5000 x next Frame
Estimated frame: 104 <== 82 -- 83 -- 84 Quality(21.750000 -- 21.500000 -- 0.250000) Flow(107.500000 -- 107.500000)
Frame 1051 = 0.0000 x prev. Frame + 1.0000 x next Frame
Frame 1053 = -1.#IND x prev. Frame + -1.#IND x next Frame
Frame 1056 = 0.0000 x prev. Frame + 1.0000 x next Frame
Estimated frame: 105 <== 83 -- 84 -- 84 Quality(0.000000 -- 0.000000 -- 177.250000) Flow(107.500000 -- 0.000000)
Where for example the second block means:
for the output (dst) frame were three input (src) frames tested: 80, 80 and 81
However, it can happen like for example here, that because there was framerate change in order to match the destination clip, some frame can be duplicated.
These three frames (say, f1,f2,f3) were tested in two couples to find the weight (f1,f2) and (f2,f3)
For each couple were found best possible coefficients to calculate destination frame, see above:
For first couple it was not successful for second couple it was 0.2*f2+0.8*f3.
This information you can find in the lines with caption "Frame <framenumber>1" or "Frame <framenumber>3".
The line "Frame <framenumber>6" shows the coefficients c1,c3 for calculation of the f2=c1*f1+c3*f3. Here, c1=1 and c3=0. c1 close to one tells us that f1 and f2 are close to identical.
There are three Quality values q1,q2,q3 which tell us how well the destination frame is estimation by the source frames by means of LumaDifference function. More exactly:
q1=LumaDifference(dst,c1*f1+c2*f2)
q2=LumaDifference(dst,f2) #if this is the lowest value, the frame is probably not blended but exactly the original.
q3=LumaDifference(dst,c2*f2+c3*f3)
Finally, Flow values are luma differences from previous and to next frames in the source file. For good estimation this should be high, i.e.there should be lot of motion and scenechanges.
For the correct blend values you have to choose the low and possibly lowest quality number with high Flow value and coeficients in the interval (0,1)
If the first resp second Flow value is very low (even lower than the quality value), then the first resp second pair of frames are not good predictors.
If the quality value is high, the estimation is not sufficient (it was not possible to find coefficients for that particular couple which would create destination frame.
So here is reading the logfile:
Frame 100: q1 is low flow1 is high=>we can use first interpolation which says dst100=src80 (same info comes from q2=0...which means dst=src)
Frame 101: q3 is low flow2 is high=> we can use second interpolation:dst101=0.2*src80+0.8*src81
Next:
dst102=0.4*src81+0.6*src82
dst103=0.6*src82+0.4*src83
dst104=0.8*src83+0.2*src84
....
We cannot use for example values in line 1021 for frame 102 calculation, coz q1 is too high
Function:
#function EstimateWeights v0.1
#by redfordxx
#Needed:
#Blendweight plugin by mg262
#RedAverage by redfordxx
function EstimateWeights (clip src, clip dst, float fps_src, float fps_dst, int "shift") {
#src ......clip before the framerate change (for example nonblended 24/1.001 clip)
#dst ......clip after the framerate change (for example blended 25fps clip)
#fps_src...framerate of source (for example 24000.0/1001)
#fps_dst...target framerate (for example 25)
#shift..... positive or negative number of frames needed to shift the source clip to match the destination
shift=default(shift,0)
global sep1=" -- "
global LabelNumbers="Estimated frame: "
file="BlendWeight log.txt"
src=src.AssumeFPS(fps_src)#.ScriptClip("Subtitle(String(current_frame))")
dst=dst.AssumeFPS(fps_dst)
sh_cnt=(shift>=0) ? shift+1 : 0
sh_rng=(shift>=0) ? -1 : -shift
prev=src.FrameEvaluate( "global frp=current_frame").loop(sh_cnt,0,sh_rng).ChangeFPS(fps_dst,1).loop(2,0,-1)
curr=src.FrameEvaluate( "global frc=current_frame").loop(sh_cnt,0,sh_rng).ChangeFPS(fps_dst,1).loop(1,0,-1)
next=src.FrameEvaluate( "global frn=current_frame").loop(sh_cnt,0,sh_rng).ChangeFPS(fps_dst,1).loop(0,0,-1)
iii=Interleave(prev,dst,curr,dst,next, prev,curr,next, curr,dst)
blendprev=iii.ScriptClip("BlendWeight(current_frame)").SelectEvery(10,1)
blendnext=iii.ScriptClip("BlendWeight(current_frame)").SelectEvery(10,3)
blendsrc=iii.ScriptClip("BlendWeight(current_frame)").SelectEvery(10,6)
tmp=Interleave(blendprev,dst,blendnext)
eval1="""
global q_n=YDifferenceToNext
global q_p=YDifferenceFromPrevious
"""
dx=10
s1=StackHorizontal(prev,curr,next)
s2=StackHorizontal(blendprev,tmp.FrameEvaluate(eval1).SelectEvery(3,1),blendnext)
dp=RAverageW(blendprev,dx,dst,-dx,bias=128)
dc=RAverageW(curr,dx,iii.FrameEvaluate("global q_c=YDifferenceFromPrevious").SelectEvery(10,9),-dx,bias=128)
dn=RAverageW(blendnext,dx,dst,-dx,bias=128)
s3=StackHorizontal(dp,dc,dn).Greyscale()
sp=RAverageW(curr,dx,iii.FrameEvaluate("global s_p=YDifferenceToNext").SelectEvery(10,5),-dx,bias=128)
sn=RAverageW(curr,-dx,iii.FrameEvaluate("global s_n=YDifferenceFromPrevious").SelectEvery(10,7),dx,bias=128)
s4=StackHorizontal(sp,blendsrc,sn).Greyscale()
StackVertical(s1,s2,s3,s4)
WriteFile(file, "LabelNumbers", "current_frame", """" <== """", "frp","sep1","frc","sep1","frn","""" Quality("""","q_p","sep1","q_c","sep1","q_n","""") Flow("""","s_p","sep1","s_n","""")"""")
WriteFile(file, "Chr(32)")
}
Usage example:
black=BlankClip(pixel_type="YV12", color=$000000,width=160,height=160)
white=BlankClip(pixel_type="YV12", color=$FAFAFA,width=160,height=160)
s1=StackVertical(StackHorizontal(black,white),StackHorizontal(white,white))
s2=StackVertical(StackHorizontal(white,black),StackHorizontal(white,white))
s3=StackVertical(StackHorizontal(white,white),StackHorizontal(white,black))
s4=StackVertical(StackHorizontal(white,white),StackHorizontal(black,white))
bbb=Interleave(s1,s2,s3,s4).AssumeFPS(4,1)
bbb2=bbb.ConvertFPS(5,1)
EstimateWeights(bbb,bbb2,4,5)
You can use real live clips, but this is test clip to see how does conversion from 4 to 5 fps look like. As expected, the coefficient are increasing by 0.2, which is shown in the logfile.
To understand the meaning of the output clip better use one real life clip instead of bbb first, but just shortly, what you will see Stacked:
previous, current, next source
first pair estimation, current destination, second pair est
difference of current destination to 1st est, current src, 2nd est
src different to previous, current dst estimation, src difference to next
Logfile sample:
Frame 1001 = 0.0000 x prev. Frame + 1.0000 x next Frame
Frame 1003 = -1.#IND x prev. Frame + -1.#IND x next Frame
Frame 1006 = 0.0000 x prev. Frame + 1.0000 x next Frame
Estimated frame: 100 <== 79 -- 80 -- 80 Quality(0.000000 -- 0.000000 -- 177.250000) Flow(107.500000 -- 0.000000)
Frame 1011 = -1.#IND x prev. Frame + -1.#IND x next Frame
Frame 1013 = 0.2000 x prev. Frame + 0.8000 x next Frame
Frame 1016 = 1.0000 x prev. Frame + 0.0000 x next Frame
Estimated frame: 101 <== 80 -- 80 -- 81 Quality(177.250000 -- 86.000000 -- 0.250000) Flow(0.000000 -- 107.500000)
Frame 1021 = 0.3000 x prev. Frame + 0.7000 x next Frame
Frame 1023 = 0.4000 x prev. Frame + 0.6000 x next Frame
Frame 1026 = 0.5000 x prev. Frame + 0.5000 x next Frame
Estimated frame: 102 <== 80 -- 81 -- 82 Quality(64.750000 -- 64.500000 -- 0.250000) Flow(107.500000 -- 107.500000)
Frame 1031 = 0.2000 x prev. Frame + 0.8000 x next Frame
Frame 1033 = 0.6000 x prev. Frame + 0.4000 x next Frame
Frame 1036 = 0.5000 x prev. Frame + 0.5000 x next Frame
Estimated frame: 103 <== 81 -- 82 -- 83 Quality(43.250000 -- 43.000000 -- 0.250000) Flow(107.500000 -- 107.500000)
Frame 1041 = 0.1000 x prev. Frame + 0.9000 x next Frame
Frame 1043 = 0.8000 x prev. Frame + 0.2000 x next Frame
Frame 1046 = 0.5000 x prev. Frame + 0.5000 x next Frame
Estimated frame: 104 <== 82 -- 83 -- 84 Quality(21.750000 -- 21.500000 -- 0.250000) Flow(107.500000 -- 107.500000)
Frame 1051 = 0.0000 x prev. Frame + 1.0000 x next Frame
Frame 1053 = -1.#IND x prev. Frame + -1.#IND x next Frame
Frame 1056 = 0.0000 x prev. Frame + 1.0000 x next Frame
Estimated frame: 105 <== 83 -- 84 -- 84 Quality(0.000000 -- 0.000000 -- 177.250000) Flow(107.500000 -- 0.000000)
Where for example the second block means:
for the output (dst) frame were three input (src) frames tested: 80, 80 and 81
However, it can happen like for example here, that because there was framerate change in order to match the destination clip, some frame can be duplicated.
These three frames (say, f1,f2,f3) were tested in two couples to find the weight (f1,f2) and (f2,f3)
For each couple were found best possible coefficients to calculate destination frame, see above:
For first couple it was not successful for second couple it was 0.2*f2+0.8*f3.
This information you can find in the lines with caption "Frame <framenumber>1" or "Frame <framenumber>3".
The line "Frame <framenumber>6" shows the coefficients c1,c3 for calculation of the f2=c1*f1+c3*f3. Here, c1=1 and c3=0. c1 close to one tells us that f1 and f2 are close to identical.
There are three Quality values q1,q2,q3 which tell us how well the destination frame is estimation by the source frames by means of LumaDifference function. More exactly:
q1=LumaDifference(dst,c1*f1+c2*f2)
q2=LumaDifference(dst,f2) #if this is the lowest value, the frame is probably not blended but exactly the original.
q3=LumaDifference(dst,c2*f2+c3*f3)
Finally, Flow values are luma differences from previous and to next frames in the source file. For good estimation this should be high, i.e.there should be lot of motion and scenechanges.
For the correct blend values you have to choose the low and possibly lowest quality number with high Flow value and coeficients in the interval (0,1)
If the first resp second Flow value is very low (even lower than the quality value), then the first resp second pair of frames are not good predictors.
If the quality value is high, the estimation is not sufficient (it was not possible to find coefficients for that particular couple which would create destination frame.
So here is reading the logfile:
Frame 100: q1 is low flow1 is high=>we can use first interpolation which says dst100=src80 (same info comes from q2=0...which means dst=src)
Frame 101: q3 is low flow2 is high=> we can use second interpolation:dst101=0.2*src80+0.8*src81
Next:
dst102=0.4*src81+0.6*src82
dst103=0.6*src82+0.4*src83
dst104=0.8*src83+0.2*src84
....
We cannot use for example values in line 1021 for frame 102 calculation, coz q1 is too high