Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
![]() |
#1 | Link |
Registered User
Join Date: Jan 2011
Posts: 121
|
Help debugging recursive runtime script
I have some interlaced VHS captures with jittery/bouncing fields. The fields randomly move up or down a few [whole] pixels vertically, screwing up the interlacing (and potentially making deinterlacing harder). I've tried an AVT-8710 TBC, but it only makes things worse (in addition to compressing some of the upper luma range). Maybe it's broken. I've also tried solutions like Depan/DepanStabilize, Stab, and the function g-force created that preceded Stab, but they don't work nearly as well as a brute force routine.
My naive brute force version does the following:
It's giving me fantastic results, but there are three weaknesses:
In response, I'm trying to create a recursive version that starts with small shifts and moves on to progressively larger shifts when the result seems to be improving. Unfortunately, this requires runtime recursion. According to Gavino's GRunT thread, you should be able to call runtime functions within user functions called by runtime functions, but...I'm getting a crash with this version. Any pointers? Note that this requires Masktools 2 and GRunT. The main function is Stabilize, and it requires planar input due to the mt_edge call. It also assumes TFF order for now, since that's what my captures are...but come to think of it, the AssumeTFF calls are probably unnecessary in this case, regardless of field order. Code:
### MAIN FUNCTION ### function Stabilize(clip orig) { # Get the clip's combed edges and weave them with the clip itself. origedges = orig.GetCombedEdges() origandedgeswoven = Interleave(orig, origedges).AssumeFieldBased.Weave() # Stabilize in "clockwise" and "counterclockwise" directions and choose the best result. # If orig is best, both clockwise and counterclockwise directions will return it. # No additional test is necessary. bestandedgeswoven = ChooseLessCombedFramesWovenEdges(StabilizeClockwise(origandedgeswoven), \ StabilizeCounterclockwise(origandedgeswoven)) # Extract and return the actual clip best = bestandedgeswoven.SeparateFields.SelectEven.AssumeFrameBased() return best } ### STABILIZE SUBROUTINES ### function GetCombedEdges(clip c) { # Vertical edges between adjacent lines are a decent measure of combing. # The Greyscale call is probably useless, so consider removing it. # The levels call could probably use more testing and better parameters, # but it's working pretty well. return c.mt_edge("0 0 0 0 -1 0 0 1 0", 0, 255, 0, 255).Greyscale().Levels(0, 5, 64, 0, 255) } function ChooseLessCombedFramesWovenEdges(clip try1andedgeswoven, clip try2andedgeswoven) { # Separate edges from clips, compare brightness of edges, and return the edge-woven clip # with the dimmest edges. Chances are one or both args are redundant, but whatev. return GConditionalFilter(try1andedgeswoven, try1andedgeswoven, try2andedgeswoven, """ AverageLuma(try1andedgeswoven.SeparateFields.SelectOdd()) < AverageLuma(try2andedgeswoven.SeparateFields.SelectOdd()) """, args = "try1andedgeswoven, try2andedgeswoven", local = true) } # Moving even fields up is almost equivalent to moving odd fields down. # Do them together, and call them "clockwise." function StabilizeClockwise(clip currentandedgeswoven) { # Get clips with odd fields shifted down a line and even fields shifted up a line current = currentandedgeswoven.SeparateFields.SelectEven.AssumeFrameBased().AssumeTFF.SeparateFields() evenup = current.ShiftEvenLumaAndChroma(0.0, 1.0).Weave() odddown = current.ShiftOddLumaAndChroma(0.0, -1.0).Weave() # Get combed edges of the new clips evenupedges = evenup.GetCombedEdges() odddownedges = odddown.GetCombedEdges() # Weave clips with edges evenupandedgeswoven = Interleave(evenup, evenupedges).AssumeFieldBased.Weave() odddownandedgeswoven = Interleave(odddown, odddownedges).AssumeFieldBased.Weave() # Which is better? oddorevenandedgeswoven = ChooseLessCombedFramesWovenEdges(evenupandedgeswoven, odddownandedgeswoven) # Which is best? bestandedgeswoven = ChooseLessCombedFramesWovenEdges(currentandedgeswoven, oddorevenandedgeswoven) # If current is not the best, recurse again using the best return GScriptClip(currentandedgeswoven, """ return AverageLuma(currentandedgeswoven) == AverageLuma(bestandedgeswoven) ? currentandedgeswoven \ : StabilizeClockwise(bestandedgeswoven) """, args = "currentandedgeswoven, bestandedgeswoven", local = True) } # Moving even fields down is almost equivalent to moving odd fields up. # Do them together, and call them "counterclockwise." function StabilizeCounterclockwise(clip currentandedgeswoven) { # Get clips with odd fields shifted down a line and even fields shifted up a line current = currentandedgeswoven.SeparateFields.SelectEven.AssumeFrameBased().AssumeTFF.SeparateFields() evendown = current.ShiftEvenLumaAndChroma(0.0, -1.0).Weave() oddup = current.ShiftOddLumaAndChroma(0.0, 1.0).Weave() # Get combed edges of the new clips evendownedges = evendown.GetCombedEdges() oddupedges = oddup.GetCombedEdges() # Weave clips with edges evendownandedgeswoven = Interleave(evendown, evendownedges).AssumeFieldBased.Weave() oddupandedgeswoven = Interleave(oddup, oddupedges).AssumeFieldBased.Weave() # Which is better? oddorevenandedgeswoven = ChooseLessCombedFramesWovenEdges(evendownandedgeswoven, oddupandedgeswoven) # Which is best? bestandedgeswoven = ChooseLessCombedFramesWovenEdges(currentandedgeswoven, oddorevenandedgeswoven) # If current is not the best, recurse again using the best return GScriptClip(currentandedgeswoven, """ return AverageLuma(currentandedgeswoven) == AverageLuma(bestandedgeswoven) ? currentandedgeswoven \ : StabilizeCounterclockwise(bestandedgeswoven) """, args = "currentandedgeswoven, bestandedgeswoven", local = True) } ### UTILITY FUNCTIONS ### function SubpixelShift(clip input, float deltax, float deltay, bool "sharp") { sharp = Default(sharp, True) return sharp ? Spline36Resize(input, input.Width(), input.Height(), deltax, deltay, input.Width(), input.Height()) \ : BilinearResize(input, input.Width(), input.Height(), deltax, deltay, input.Width(), input.Height()) } function ShiftOddLumaAndChroma(clip c, float deltax, float deltay, bool "sharp") { deltax = Default(deltax, 0.0) deltay = Default(deltay, 0.0) sharp = Default(sharp, True) return Interleave(c.SelectEven(), c.SubpixelShift(deltax, deltay, sharp).SelectOdd()) } Last edited by Mini-Me; 4th April 2011 at 02:41. Reason: Fixed infinite loop. It works now! I'll create a thread once I have a release-ready version. |
![]() |
![]() |
Thread Tools | Search this Thread |
Display Modes | |
|
|