nonoitall
8th May 2008, 08:02
Wherever there's a weird problem to be found, I seem to stumble upon it. I've written a fairly complicated and slow but theoretically effective script for cleaning up bad splices in my clip. It replaces bad frames at the scene end with the previous frame if the previous frame is similar to the bad frame. Likewise it replaces bad frames at the scene start with the next frame if the next frame is similar to the bad frame.
# Next frame
next = clip.Trim(1, 0)
# Previous frame
prev = clip.Trim(0, -1) + clip
# Difference where gray is no difference and above or below that is the luma
# difference divided by 2
diffGray = clip.mt_lutxy(prev, "x y - 2 / 128 +", u=-128, v=-128)
# Absolute difference where black is no difference and above that is the luma
# difference
diffAbs = clip.mt_lutxy(prev, "x y - abs", u=-128, v=-128)
# A white clip (this represents true)
white = clip.BlankClip(width=16, height=16, pixel_type="YV12", color=$ffffff)
# A black clip (this represents false)
black = clip.BlankClip(width=16, height=16, pixel_type="YV12", color=$000000)
# This detects what could potentially be a bad end of a scene and returns a
# white frame for bad frames and a black frame for good frames
badEnd = diffGray.ConditionalFilter(white, black, \
"Crop(0, 0, 0, -8).AverageLuma() - Crop(0, 472, 0, 0).AverageLuma()", \
">", "20", false)
# This detects the end of a scene, returning white for scene ends, black
# otherwise
sceneEnd = diffAbs.ConditionalFilter(white, black, "AverageLuma()", \
">", "45", false).Trim(1, 0)
# This 'AND's the scene end and the bad end together, returning a white
# frame for bad scene ends and a black frame otherwise
badSceneEnd = sceneEnd.ConditionalFilter(badEnd, black, "AverageLuma()", \
">", "128", false)
# In this clip we can assume that all bad scene ends are followed by bad
# scene beginnings
badSceneBegin = black.Trim(0, -1) + badSceneEnd
# This detects whether this frame has noteworthy differences from the next
# frame and returns black if it does, white if it doesn't
safeBegin = diffAbs.ConditionalFilter(white, black, "AverageLuma()", \
"<", "2.5", false).Trim(1, 0)
# This detects whether this frame has noteworthy differences from the previous
# frame and returns black if it does, white if it doesn't
safeEnd = diffAbs.Crop(0, 0, 0, -120).ConditionalFilter(white, black, \
"AverageLuma()", "<", "2.6", false)
# The point of those two 'safe' clips is that even if a frame is bad, I don't want
# to throw it away if it has a lot of unique information in it
# This 'AND's safe begin and bad scene begin together, returning white if this is
# a bad scene beginning that is similar to the next frame, black otherwise
replaceBegin = safeBegin.ConditionalFilter(badSceneBegin, black, \
"AverageLuma()", ">", "128", false)
# This 'AND's safe end and bad scene end together, returning white if this is a
# bad scene ending that is similar to the previous frame, black otherwise
replaceEnd = safeEnd.ConditionalFilter(badSceneEnd, black, "AverageLuma()", \
">", "128", false)
# This replaces the current frame with the next frame when a safe-to-change
# bad scene beginning is detected
fixed1 = replaceBegin.ConditionalFilter(next, denoised, "AverageLuma()", \
">", "128", true)
# This replaces the current frame with the previous frame when a safe-to-change
# bad scene ending is detected
fixed2 = replaceEnd.ConditionalFilter(prev, fixed1, "AverageLuma()", ">", \
"128", true)
I've already tuned all of the numbers to my source material and they are accurate enough. Sometimes, though, frames that should be replaced don't get replaced. For example, let's say frame #1000 is white in badEnd, sceneEnd and safeEnd. Logically, 'AND'ing together badEnd and sceneEnd should produce white in badSceneEnd, and 'AND'ing that with safeEnd should produce white in replaceEnd. But, for some bizarre reason, frame #1000 ends up being black in badSceneEnd and replaceEnd.
This only happens on some frames - on other frames it will work the way it's supposed to. Is there some special way I have to use ConditionalFilter to make it work properly or is this a bug?
# Next frame
next = clip.Trim(1, 0)
# Previous frame
prev = clip.Trim(0, -1) + clip
# Difference where gray is no difference and above or below that is the luma
# difference divided by 2
diffGray = clip.mt_lutxy(prev, "x y - 2 / 128 +", u=-128, v=-128)
# Absolute difference where black is no difference and above that is the luma
# difference
diffAbs = clip.mt_lutxy(prev, "x y - abs", u=-128, v=-128)
# A white clip (this represents true)
white = clip.BlankClip(width=16, height=16, pixel_type="YV12", color=$ffffff)
# A black clip (this represents false)
black = clip.BlankClip(width=16, height=16, pixel_type="YV12", color=$000000)
# This detects what could potentially be a bad end of a scene and returns a
# white frame for bad frames and a black frame for good frames
badEnd = diffGray.ConditionalFilter(white, black, \
"Crop(0, 0, 0, -8).AverageLuma() - Crop(0, 472, 0, 0).AverageLuma()", \
">", "20", false)
# This detects the end of a scene, returning white for scene ends, black
# otherwise
sceneEnd = diffAbs.ConditionalFilter(white, black, "AverageLuma()", \
">", "45", false).Trim(1, 0)
# This 'AND's the scene end and the bad end together, returning a white
# frame for bad scene ends and a black frame otherwise
badSceneEnd = sceneEnd.ConditionalFilter(badEnd, black, "AverageLuma()", \
">", "128", false)
# In this clip we can assume that all bad scene ends are followed by bad
# scene beginnings
badSceneBegin = black.Trim(0, -1) + badSceneEnd
# This detects whether this frame has noteworthy differences from the next
# frame and returns black if it does, white if it doesn't
safeBegin = diffAbs.ConditionalFilter(white, black, "AverageLuma()", \
"<", "2.5", false).Trim(1, 0)
# This detects whether this frame has noteworthy differences from the previous
# frame and returns black if it does, white if it doesn't
safeEnd = diffAbs.Crop(0, 0, 0, -120).ConditionalFilter(white, black, \
"AverageLuma()", "<", "2.6", false)
# The point of those two 'safe' clips is that even if a frame is bad, I don't want
# to throw it away if it has a lot of unique information in it
# This 'AND's safe begin and bad scene begin together, returning white if this is
# a bad scene beginning that is similar to the next frame, black otherwise
replaceBegin = safeBegin.ConditionalFilter(badSceneBegin, black, \
"AverageLuma()", ">", "128", false)
# This 'AND's safe end and bad scene end together, returning white if this is a
# bad scene ending that is similar to the previous frame, black otherwise
replaceEnd = safeEnd.ConditionalFilter(badSceneEnd, black, "AverageLuma()", \
">", "128", false)
# This replaces the current frame with the next frame when a safe-to-change
# bad scene beginning is detected
fixed1 = replaceBegin.ConditionalFilter(next, denoised, "AverageLuma()", \
">", "128", true)
# This replaces the current frame with the previous frame when a safe-to-change
# bad scene ending is detected
fixed2 = replaceEnd.ConditionalFilter(prev, fixed1, "AverageLuma()", ">", \
"128", true)
I've already tuned all of the numbers to my source material and they are accurate enough. Sometimes, though, frames that should be replaced don't get replaced. For example, let's say frame #1000 is white in badEnd, sceneEnd and safeEnd. Logically, 'AND'ing together badEnd and sceneEnd should produce white in badSceneEnd, and 'AND'ing that with safeEnd should produce white in replaceEnd. But, for some bizarre reason, frame #1000 ends up being black in badSceneEnd and replaceEnd.
This only happens on some frames - on other frames it will work the way it's supposed to. Is there some special way I have to use ConditionalFilter to make it work properly or is this a bug?