Log in

View Full Version : Rolling picture: Any plugin or script solution ?


Emulgator
28th June 2010, 18:20
In some hard cases it may happen that a film scan delivers
a rolling picture because film transport jammed or perforation is slashed.
In cases where a rescan is impossible:
Is there any solution to reassemble the picture
using something in the league of motion analysis and retransformation,
finally resplicing along the moving border ?

A sample of a rolling scan is here: http://www.dvd-manufactur.de/files/roll.mpg

rfmmars
28th June 2010, 19:27
In some hard cases it may happen that a film scan delivers
a rolling picture because film transort jammed or perforation is slashed.
In cases where a rescan is impossible:
Is there any solution to reassemble the picture
using something in the league of motion analysis and retransformation,
finally resplicing along the moving border ?

A sample of a rolling scan is here: http://www.dvd-manufactur.de/files/roll.mpg

It looks to me that it was a transfer by a person who didn't check the projector framing before capture. It wasn't a defective projector because the coreection is smooth, You could decapture into jpgs and hand edit those frames and then reasemble to avi.

Richard

Emulgator
1st July 2010, 21:24
Yes, the hand editing is still a final approach.
In between i tried to find a bit of an automated way of assuming frame shifting at constant speed,
trimming, then cropping the rolling part with increasingly shifted borders and finally StackVertical and Aligned Splice.


(sourcefilter)
rollstart=51#input roll start frame number
rollend=106#input roll end frame number
rollrange=rollend-rollstart
start=Trim(0,rollstart-1)
roll=Trim(rollstart,rollend)
end=Trim(rollend+1,0)
picoffsetperframe=(height/rollrange)+((height/rollrange) % 2)


rollframecount=5#GetFramenumber(roll)# Hm, how to get the framenumber?

picoffset=rollframecount*picoffsetperframe
rolltop=Crop(roll, 0, 0, 0, height-picoffset)
rollbottom=Crop(roll, 0, height-picoffset, 0, 0)
deroll=StackVertical(rollbottom, rolltop)
AlignedSplice(start, deroll, end)
/*
Subtitle("Rollframecount = "+String(rollframecount)+"", size=12, align=1, x=(width/2)-20, y=60, first_frame=0, font="Verdana", text_color=$FFFF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset "+String(picoffset)+" pixels vertical", size=12, align=1, x=(width/2)-20, y=40, first_frame=0, font="Verdana", text_color=$FFFF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset per frame = + "+String(picoffsetperframe)+" pixels vertical", size=12, align=1, x=(width/2)-40, y=20, first_frame=0, font="Verdana", text_color=$FFFF00, halo_color=$000000, interlaced=false)
*/

Here I found a small script (by Wilbert) that indeed delivers the framenumber rendered in the upper left corner of the video frame,
but I am a bit helpless in getting this thing to deliver a simple integer for my script instead of printing a string...

function PrintFrameNumber(clip c)
{
c2 = ScriptClip(c, "subtitle(framecount)")
c3 = FrameEvaluate(c2, "me()")
c4 = FrameEvaluate(c3, "global text = current_frame")
return c4
}

function me()
{
global framecount = String(text)
}


testvideo = roll
PrintFrameNumber(testvideo)

Gavino
1st July 2010, 22:49
Here I found a small script (by Wilbert) that indeed delivers the framenumber rendered in the upper left corner of the video frame, but I am a bit helpless in getting this thing to deliver a simple integer for my script instead of printing a string...
Your PrintFrameNumber function is a very roundabout way of doing the following:
function PrintFrameNumber(clip c) {
ScriptClip(c, "subtitle(string(current_frame))")
}
Getting it to deliver an integer is even simpler, it's just current_frame. So you need to put the frame-dependent part of your code inside ScriptClip:
...
deroll=ScriptClip(roll, """
rollframecount=current_frame

picoffset=rollframecount*picoffsetperframe
rolltop=Crop(0, 0, 0, height-picoffset)
rollbottom=Crop(0, height-picoffset, 0, 0)
StackVertical(rollbottom, rolltop)
""")
AlignedSplice(start, deroll, end)

Emulgator
1st July 2010, 23:35
Wow. Thank you, Gavino. It begins to work.
Syntax is it. And i am so stuck sometimes... Three quotes.
Again, many thanks go to: España !

Emulgator
2nd July 2010, 00:06
And here the improved results, Lanczos4 instead of simple crop, some paddings to acommodate frame number 0 offsets...

#----------------------Emulgators DeRolling Simple 1.0 (Assumption : constant rolling speed upwards)----------
#Comment subtitles out when proper working is confirmed. 2x within deroll and 2x outside...
#/*
rollstart=51#input roll start frame number -> first frame that is offset
rollend=106#input roll end frame number -> last frame that is offset
rollrange=rollend-rollstart+1
start=Trim(0,rollstart-1)
roll=Trim(rollstart,rollend)
end=Trim(rollend+1,0)
picoffsetperframe=(height/(rollrange+1))
deroll=ScriptClip(roll, """
rollframecount=current_frame+1
picoffset=rollframecount*picoffsetperframe
rolltop=Lanczos4Resize(roll, width, height-picoffset, 0, 0, 0, (height-picoffset))
rollbottom=Lanczos4Resize(roll, width, picoffset, 0, (height-picoffset), 0, 0)
StackVertical(rollbottom, rolltop)
Subtitle("Rollframecount = "+String(rollframecount)+"", size=12, align=1, x=(width/2)-40, y=60, first_frame=0, font="Verdana", text_color=$FFFF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset for this frame: "+String(picoffset)+" pixels vertical", size=12, align=1, x=(width/2)-40, y=80, first_frame=0, font="Verdana", text_color=$FFFF00, halo_color=$000000, interlaced=false)
""")
AlignedSplice(start, deroll, end)
Subtitle("Rollrange = "+String(rollrange)+" Frames", size=12, align=1, x=(width/2)-40, y=20, first_frame=0, font="Verdana", text_color=$FFFF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset increase per frame = + "+String(picoffsetperframe)+" pixels vertical", size=12, align=1, x=(width/2)-40, y=40, first_frame=0, font="Verdana", text_color=$FFFF00, halo_color=$000000, interlaced=false)
#*/

Gavino
2nd July 2010, 00:47
Again, many thanks go to: España !
¡De nada, hombre!
Now you know who to cheer for in the World Cup. :)

In your revised script, I think maybe you want

picoffsetperframe=float(height)/(rollrange+1)

to avoid integer truncation in the calculation and to get the offset right on the last frame.

EDIT: Ah, I see you've already incorporated the 'rollrange+1' part of the correction.
EDIT2: And if using float you would also need
picoffset=round(rollframecount*picoffsetperframe)

Emulgator
2nd July 2010, 01:47
Yes!Yes!Yes!
Exactly where i stumbled next: the truncation would lead to incorrect calculation for the last frames.
I had to introduce a further float here as well:
rollrange=float(rollend-rollstart+1)
Although the result is an integer anyway, this finally helped to print out the offset with 6 decimals.
Some frames come out allright now, some are complaining: "Resize YV12 destination height must be a multiple of 2."
Now I gonna have to fix the resizer with some mod2 here and there, I guess...

Emulgator
2nd July 2010, 01:56
Now with improved float offset, rounding and mod2 height calculation:

#--------------------------------------Emulgators DeRolling Simple 1.1 (Assumption : constant rolling speed upwards)------
#Comment subtitles out when proper working is confirmed. 2x within deroll and 2x outside...
#/*
rollstart=74#input roll start frame number -> first frame that is offset
rollend=125#input roll end frame number -> last frame that is offset
rollrange=float(rollend-rollstart+1)
start=Trim(0,rollstart-1)
roll=Trim(rollstart,rollend)
end=Trim(rollend+1,0)
picoffsetperframe=float(height/(rollrange+1))
deroll=ScriptClip(roll, """
rollframecount=current_frame+1
picoffset=round(rollframecount*picoffsetperframe)+(round(rollframecount*picoffsetperframe)% 2)
rolltop=Lanczos4Resize(roll, width, (height-picoffset), 0, 0, 0, (height-picoffset))
rollbottom=Lanczos4Resize(roll, width, (picoffset), 0, (height-picoffset), 0, 0)
StackVertical(rollbottom, rolltop)
Subtitle("Rollframecount = "+String(rollframecount)+"", size=12, align=1, x=(width/2)-40, y=height-40, first_frame=0, font="Verdana", text_color=$FFFF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset for this frame: "+String(picoffset)+" pixels vertical", size=12, align=1, x=(width/2)-40, y=height-20, first_frame=0, font="Verdana", text_color=$FFFF00, halo_color=$000000, interlaced=false)
""")
AlignedSplice(start, deroll, end)
Subtitle("Rollrange = "+String(rollrange)+" Frames", size=12, align=1, x=(width/2)-40, y=height-80, first_frame=0, font="Verdana", text_color=$FFFF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset increase per frame = + "+String(picoffsetperframe)+" pixels vertical", size=12, align=1, x=(width/2)-40, y=height-60, first_frame=0, font="Verdana", text_color=$FFFF00, halo_color=$000000, interlaced=false)
#*/

Gavino
2nd July 2010, 09:55
Now with improved float offset, rounding and mod2 height calculation:
...
picoffset=round(rollframecount*picoffsetperframe)+(round(rollframecount*picoffsetperframe)% 2)
...
This results in a multiple of 2, but not always the nearest multiple, eg 2.6 becomes 4. Better would be
picoffset=2*round(rollframecount*picoffsetperframe/2.0)

Emulgator
2nd July 2010, 12:31
Yes, this rounds better! Mine was rather rounding up.
Now improved rounding, Aligning before DeRolling, Stabilisation after Derolling.
Still looking for a stitching idea. Some Aligning introduces black borders...

#---Before DeRoll, Align first ! VCMohan's Grid, Perspective, Spinner, Reform=deskew+skew. VCMohan's plugins needed------------
#grid(sf=0, ef=framecount, lineint=10, bold=5, vbold=2, grid=true, axis=true)#Comment grid in to see where the transformations end up
ConvertToRGB#(RGB is needed for Perspective only)
perspective(a=-0.00001, b=0.0, x=+1400, y=0)#these were the KungFu Scan 2 perspective corrections, very smooth !
ConvertToYV12#(interlaced=true)#(RGB was needed for Perspective only)
#spinner(check=false, angle=+0.7, q=4)#these were the KungFu Scan 2 angle corrections, sometimes exceptions thrown...
#-----deskew transforms a Quadrilateral (at least 1 pixel per side smaller than frame) into a Rectangle (at least 1 pixel per side smaller than frame) Result shows stairstepping !
#deskew(last, blankclip, ltopx=2, ltopy=2, lbotx=12, lboty=height-2, rtopx=width-2, rtopy=2, rbotx=width-2, rboty=height-2, resize="cubic")#these were the KungFu Scan 2 deskewer settings
#--------------------------------------Emulgators DeRolling Simple 1.2 (Assumption : constant rolling speed upwards)------
#Comment subtitles out when proper working is confirmed. 2x within deroll and 2x outside...
#/*
rollstart=74#input roll start frame number -> first frame that is offset
rollend=125#input roll end frame number -> last frame that is offset
rollrange=float(rollend-rollstart+1)
start=Trim(0,rollstart-1)
roll=Trim(rollstart,rollend)
end=Trim(rollend+1,0)
picoffsetperframe=float(height/(rollrange+1))
deroll=ScriptClip(roll, """
rollframecount=current_frame+1
#picoffset=round(rollframecount*picoffsetperframe)+(round(rollframecount*picoffsetperframe)% 2)#this round up only
picoffset=2*round(rollframecount*picoffsetperframe/2.0)#Gavinos improvement to round to nearest neighbor
rolltop=Lanczos4Resize(roll, width, (height-picoffset), 0, 0, 0, (height-picoffset))
rollbottom=Lanczos4Resize(roll, width, (picoffset), 0, (height-picoffset), 0, 0)
StackVertical(rollbottom, rolltop)
Subtitle("Rollframecount = "+String(rollframecount)+"", size=12, align=1, x=(width/2)-80, y=height-40, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset for this frame: "+String(picoffset)+" pixels vertical", size=12, align=1, x=(width/2)-80, y=height-20, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
""")
AlignedSplice(start, deroll, end)
Stab()
Subtitle("Rollrange = "+String(rollrange)+" Frames", size=12, align=1, x=(width/2)-80, y=height-80, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset increase per frame = + "+String(picoffsetperframe)+" pixels vertical", size=12, align=1, x=(width/2)-80, y=height-60, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
#*/

A derolling sample, yet not properly decimated and colour corrected before derolling is here:

http://dvd-manufactur.de/files/deroll1.m2v

johnmeyer
2nd July 2010, 19:23
A much better way to handle this problem is to just use an editing program. I put the clip in Vegas on two timelines, and keyframed the upper and lower halves of the frame. However, this immediately showed me that you may not be very happy with the results. The reason? The gate in the projector blocks about 10-15% of the image edge. As a result, when you try to line up the upper and lower images, the point at which they meet, which will at times be right in the middle of the picture, will have a huge amount missing. You can leave a big black gap and then try to fill that in, or you will just have to live with a very fractured image.

Emulgator
5th July 2010, 17:23
And this is the place where i put my hope on Avisynth.

With perspective plugin it looks like some 4 pixels would be left to fill.

Right now I am adding pre-resizing + 4 pixels height
and later cropping back 2 black lines bottom + 2 black lines top

Next step will be adding primary roll offset.

As further step I hope for some inspiration regarding line repair algorithms.

johnmeyer
5th July 2010, 18:19
I think you may find that there are a LOT more than four lines of video missing. I didn't measure, but I think it might be closer to twenty lines.

Emulgator
6th July 2010, 16:43
Here is a screenshot with grid applied before transformation.

While counting I see close to 572-574 vertical lines.
The skewing is from trying to fix the lens/scanner/gate offset.

My approach is suffering from trying to weld a picture from two frames shot at different times,
so any thoughts to introduce motion-based repairs are definitely welcome.

http://dvd-manufactur.de/files/deroll_1-3.jpg

Emulgator
6th July 2010, 17:33
Shortly after I wrote this
I found that I could derive both parts to be assemble from the same time.

start=Trim(0, rollstart-1)
rolltopsrc=Trim(rollstart, rollend)
rollbottomsrc=Trim(rollstart-1, rollend-1)
end=Trim(rollend+1, 0)

johnmeyer
6th July 2010, 17:49
Shortly after I wrote this
I found that I could derive both parts to be assemble from the same timeI'll repeat what I said in my previous post: this could be MUCH more easily done in an editing program. I use Vegas, which is expensive, but Sony has a $50 version that can easily do what you want. It takes about one minute. If you want to combine the top half of a frame from one frame earlier with the bottom half of the earlier frame, you simply put a copy of the film on one track, and the put the same film on the track immediately below. Move the video on one track one frame to the left (earlier in time), and with one second of effort you now can combine video from two adjacent frames.

Use pan/crop or track motion to align the two frames, and keyframes to do the movement. Since the movement may not be linear, you can add more keyframes, as necessary, to get the two frames to track. If the exposure doesn't match because the projector had a "hot spot," you can apply exposure correction to one of the two copies of the film.

I can't imagine trying to do this sort of thing without being able to move the frame and see results in real time. Doing this via a script is going to be torture.

If you use an editing program, you could be done with this project in less time that it took me to write this.

Your choice, of course. I'm just trying to suggest a much faster way. AVISynth and its plugins are brilliant, but some problems are much better handled with other tools.

Emulgator
6th July 2010, 22:24
John, your suggestion is of course good.
And I could switch to it easily.
I have bought Vegas 8.0c and 9.0d and Edius 4.61 and Edius 5.12 and AdobeCS3PP and EditStudio 5.0.1 and 6.0.5
and of course I may come out much faster using one of those.
Yes, the scripting may be a torture and consumes much more time.
The things I am after are yet to come. I cannot do these in an NLE, I guess.
Varying decimation (Hard EuroPulldown removal from edited material, with bad scanner skips),
sophisticated repair methods for frame repair, TGMC, MCTD.
What comes before and after in my whole script is a bit more than I showed here...
Still, many thanks for your thoughts. I will keep on developing my bergwerk ;-)

poisondeathray
6th July 2010, 22:50
There is no reason why you cannot combine the best of tools. For example, you can import .avs scripts directly into premiere pro (avs import plugin, or avfs - avisynth virtual file system) . Or you can use lossless intermediates for import into NLE's

You do have bands of missing pixels , they are too large just to fill in with "something" , and your before/after frames in your example do not have enough information to fill in the gaps

Emulgator
7th July 2010, 12:23
Yes, there will anyway be lossles intermediates and NLE work.
Color wheel correction has to be done as well and this is were Edius and / or Vegas will come in for this job.

BTW, the gaps in my examples are coming from suboptimal hard decimation of film
scanned with not completely locked gate and on-the fly hard-Euro-pulldowned or the like.
This can not be mended by this script alone of course, rather i tend to test with "impossible" sources anyway.
Version 1.4 will cater for padding before perspective and cropping afterwards to have all scanned video lines in the output.

Version 1.3

#--------------------------------------Emulgators DeRolling Simple 1.3 (Assumption : constant rolling speed upwards)----------
# DeRoller alpha : proof of concept, no automation, integer calculations only.
# DeRoller 1.0 : First release, Lanczos instead of Crop,
# DeRoller 1.1 : Introduced offset calculation in float, then rounding up.
# DeRoller 1.2 : Added geometrical pre-alignment of the two parts to be assembled. Added Stab afterwards. Rounding improvement,
# DeRoller 1.3 : Derives the two parts to be assembled from the same time now. Pre-Upsizer added.
# Rounding introduced in 1.2 could lead to undersized height <4 pixels for the first derolled frame. Back to rounding up only by mod2
#/*#--------------------------------------------------------------------Pre-Alignment-------------------------------------------------------
# Before DeRolling a film scan, you may have to align the cutlines first ! Often film scans are skewed !
# VCMohan's plugins needed here: Grid, Perspective, Spinner, Reform=deskew+skew. Avoid Reform, poor resizer !
#grid(sf=0, ef=framecount, lineint=10, bold=5, vbold=2, grid=true, axis=true)#Comment grid in to see where the transformations end up
ConvertToRGB#(RGB is needed for Perspective only)
perspective(a=-0.00001, b=0.0, x=+1400, y=0)#these were the KungFu Scan 2 perspective corrections, very smooth !
ConvertToYV12#(interlaced=true)#(RGB was needed for Perspective only)
#spinner(check=false, angle=+0.7, q=4)#these were the KungFu Scan 2 angle corrections, sometimes exceptions thrown...
# Deskew transforms a Quadrilateral part of the frame (source at least 1 pixel per side smaller than frame)
# into a Rectangle within the frame (at least 1 pixel per side smaller than frame) Result shows stairstepping ! Poor resizer (point??)
#deskew(last, blankclip, ltopx=2, ltopy=2, lbotx=12, lboty=height-2, rtopx=width-2, rtopy=2, rbotx=width-2, rboty=height-2, resize="cubic")
# (these were the KungFu Scan 2 deskewer settings)
#*/#------------------------------------------------------------End of Pre-alignment-------------------------------------------------------
#/*#-------------------------------------------------------Start of Emulgator's DeRoller 1.3----------------------------------------------
# Comment subtitles out when proper working is confirmed. 2x within deroll and 2x past deroll...
rollstart=49#first frame to be considered as rolling
rollend=100#last frame to be considered as rolling
vertstartoffset=0#Vertical offset of the first frame to be derolled
vertendoffset=height#Vertical offset of the last frame to be derolled
beforevertoffset=0#Vertical offset to be compensated globally for all frames before deroll. Not used at the moment !
aftervertoffset=0#Vertical offset to be compensated globally for all frames after deroll. Not used at the moment !
bordercomp=0#Set to 4 if perspective is used, 0 if spinner or deskew or no alignment is used. Not used at the moment !
#
rollrange=float(rollend-rollstart+1)
start=Trim(0, rollstart-1)
rolltopsrc=Trim(rollstart, rollend)
rollbottomsrc=Trim(rollstart-1, rollend-1)#The -1 ensures that the lower rolling picture part which will be stacked on top comes from the same shooting time as the upper rolling picture part.
end=Trim(rollend+1, 0)
picoffsetperframe=float(height/(rollrange+1))
deroll=ScriptClip(rolltopsrc, """
Lanczos4Resize(rolltopsrc, width, height+bordercomp)
rollframecount=current_frame+1
picoffset=round(rollframecount*picoffsetperframe)+(round(rollframecount*picoffsetperframe)%2)
##My version, this rounds up only
#picoffset=2*round(rollframecount*picoffsetperframe/2.0)
##Gavinos improvement to round to nearest neighbour, but rolltopresizer chokes if this yields less than 4 pixels height
rolltop=Lanczos4Resize(rolltopsrc, width, ((height-picoffset)-(bordercomp/2)), 0, 2, -0, (height-picoffset))
rollbottom=Lanczos4Resize(rollbottomsrc, width, (picoffset-(bordercomp/2)), 0, (height-picoffset), -0, -2)
StackVertical(rollbottom, rolltop)
Subtitle("Rollframecount = "+String(rollframecount)+"", size=12, align=1, x=(width/2)-80, y=height-40, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset for this frame: "+String(picoffset)+" pixels vertical", size=12, align=1, x=(width/2)-80, y=height-20, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
""")
AlignedSplice(start, deroll, end)
#Stab()
Subtitle("Rollrange = "+String(rollrange)+" Frames", size=12, align=1, x=(width/2)-80, y=height-80, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset increase per frame = + "+String(picoffsetperframe)+" pixels vertical", size=12, align=1, x=(width/2)-80, y=height-60, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
#*/#-----------------------------------------------End of Emulgator's DeRoller 1.3-----------------------------------------------------

2Bdecided
7th July 2010, 16:28
There is no reason why you cannot combine the best of tools. For example, you can import .avs scripts directly into premiere pro (avs import plugin, or avfs - avisynth virtual file system) . Or you can use lossless intermediates for import into NLE's

You do have bands of missing pixels , they are too large just to fill in with "something" , and your before/after frames in your example do not have enough information to fill in the gapsThere are a couple of video in-painting plug-ins for AVIsynth which might help.

But unless this is being done as a challenge, I think the obvious answer is "just" to find a better copy of the film - whatever it is, I can't believe this is the only version available! The film print and transfer are atrocious.

Cheers,
David.

Emulgator
8th July 2010, 19:18
Oh yes ! It is definitely to be seen as a challenge.
All I got from the guy is this transfer and the expressed hope to mend it.
This may have been the (to him) very last available clips of a copy that has been projected over and over to death.
I cannot tell, I do not know better, I only work on it.

DeRoller Version 1.4 is out:

#/*#-------------------------------------------------------Start of Emulgator's DeRoller 1.4----------------------------------------------
# Comment subtitles out when proper working is confirmed. 2x within deroll and 2x past deroll...
rollstart=49#first frame to be considered as rolling
rollend=100#last frame to be considered as rolling
vertstartoffset=550#Vertical offset (line number) of the lower frame border of the first frame to be derolled.
# In case of standard rolling (Lower frame border moves up from the bottom): vertstartoffset is usually a bit less than height.
# Reverse DeRolling can be accomodated ! vertstartoffset is then less than vertendoffset.
vertendoffset=6#Vertical offset (line number) of the lower frame border of the last frame to be derolled.
# In case of standard rolling (Lower frame border moves up from the bottom): vertendoffset is usually a bit greater than zero.
# Reverse DeRolling can be accomodated ! vertendoffset is then greater than vertstartoffset.
beforevertoffsetline=556#Vertical offset to be compensated globally for all frames before deroll. Wiil be applied in cliprange "before" only.
aftervertoffsetline=0#Vertical offset to be compensated globally for all frames after deroll. Will be applied in cliprange "after" only.
topbottomcrop=0#This sets the amount to crop before the splicing resizer sets in. Gets rid of half scanned lines. Was experimental Leave at 0.
#
bordercomp=0# Default = 0 ! To be kept at 0 at this moment ! Outcome of my fantasies...
# bordercomp values may be -64...0..+64. 0 = Neutral. Something experimental.
# Stretches or squeezes the upper vs the lower part over time.
# -64 makes the upper part come down vertically squeezed, the lower part descending vertically stretched.
# Upper/lower part are equally resized when splice line has arrived at half height.
# Then the upper part comes further down, now stretched more than the descending lower part,
# which is now further squeezed until it disappears.
# +64 is vice versa. The upper part starts to come down vertically stretched, while the lower part is sqeezed right from the beginning,
# Lower Part is expanding as descending, the upper part squeezing as descending,
# Upper/lower part are equally resizied when splice line has arrived at half height
# Not of real use at this moment !
rollrange=float((rollend-rollstart)+1)#If there is only 1 frame to deroll, then the framenumber difference would deliver 0, but there is still 1 frame to deroll.
before=Trim(0, rollstart-1)
rolltopsrc=Trim(rollstart, rollend+1)
# One frame was missing (frame nr <rollend>) It should be the last split frame.
# Lengthening the ends of rolltopsrc and rollbottomsrc +1 helped here.
rollbottomsrc=Trim(rollstart-1, rollend)
# The -1 offset of rollbottomsrc ensures that the lower rolling picture part which will be stacked on top
# comes from the same shooting time as the upper part, so 1 frame duration before the split scan.
after=Trim(rollend+1, 0)
picoffsetperframe=float((vertstartoffset-vertendoffset)/(rollrange+1))
deroll=ScriptClip(rolltopsrc, """
Lanczos4Resize(rolltopsrc, width, height+bordercomp)
rollframecount=current_frame+1
picoffset=2*round((height-vertstartoffset-vertendoffset)/2)+(round(rollframecount*picoffsetperframe))+(round(rollframecount*picoffsetperframe)%2)
##My version, this rounds up only...
#picoffset=2*round(rollframecount*picoffsetperframe/2.0)
##Gavinos improvement to round to nearest neighbour, but rolltopresizer chokes if this yields less than 4 pixels height
rolltop=Lanczos4Resize(rolltopsrc, width, ((height-picoffset)-(bordercomp/2)), 0, topbottomcrop, -0, (height-picoffset))
rollbottom=Lanczos4Resize(rollbottomsrc, width, (picoffset-(bordercomp/2)), 0, (height-picoffset), -0, -topbottomcrop)
#rolltop=Spline36Resize(rolltopsrc, width, ((height-picoffset)-(bordercomp/2)), 0, 0, -0, (height-picoffset))
#rollbottom=Spline36Resize(rollbottomsrc, width, (picoffset-(bordercomp/2)), 0, (height-picoffset), -0, -0)
StackVertical(rollbottom, rolltop)
Subtitle("Rollframecount = "+String(rollframecount)+"", size=12, align=1, x=(width/2)-80, y=height-40, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
Subtitle("Applied Moving Picoffset for this frame: "+String(picoffset)+" pixels vertical", size=12, align=1, x=(width/2)-80, y=height-20, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
""")
beforevertoffset=2*((height-beforevertoffsetline%(height))/2)
aftervertoffset=2*((height-aftervertoffsetline%(height))/2)
beforetopsrc=Trim(0, rollstart-1)
beforebottomsrc=Trim(0,-1)++Trim(0, rollstart-2)#Because there is no predecessor for frame 0, this has to be given for its own reconstruction
aftertopsrc=Trim(rollend+1, framecount-1)
afterbottomsrc=Trim(rollend, framecount-2)
beforetop= (beforevertoffsetline!=0) ? Lanczos4Resize(beforetopsrc, width, height-beforevertoffset, 0, topbottomcrop, -0, height-beforevertoffset) : NOP
beforebottom= (beforevertoffsetline!=0) ? Lanczos4Resize(beforebottomsrc, width, beforevertoffset, 0, height-beforevertoffset, -0, -topbottomcrop) : NOP
aftertop= (aftervertoffsetline!=0) ? Lanczos4Resize(aftertopsrc, width, height-aftervertoffset, 0, topbottomcrop, -0, height-aftervertoffset) : NOP
afterbottom= (aftervertoffsetline!=0) ? Lanczos4Resize(afterbottomsrc, width, aftervertoffset, 0, height-aftervertoffset, -0, -topbottomcrop) : NOP
beforecomp= (beforevertoffsetline==0) ? before : StackVertical(beforebottom, beforetop)
aftercomp= (aftervertoffsetline==0) ? after : StackVertical(afterbottom, aftertop)
AlignedSplice(beforecomp, deroll, aftercomp)
#Stab()
Subtitle("Rollrange = "+String(rollrange)+" Frames", size=12, align=1, x=(width/2)-80, y=height-80, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset increase per frame = + "+String(picoffsetperframe)+" pixels vertical", size=12, align=1, x=(width/2)-80, y=height-60, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
Subtitle("Applied Picoffset before/after= + "+String(beforevertoffset)+" / "+String(aftervertoffset)+" pixels vertical", size=12, align=1, x=(width/2)-80, y=height-0, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
#*/#-----------------------------------------------End of Emulgator's DeRoller 1.4-----------------------------------------------------

Next to come: the half scan lines will have to be inpainted, the black delogoed, whatever.
Right now I am resizing these out, losing 2 or 4lines.

By the way, it is fun to have a script handy for such occasions.

Another outcome will be : Rolling decimation.

This script may help people who have PAL or NTSC rota-prism video scans from arbitrary framerate film.
and want to decimate these back to full frames.

Emulgator
9th July 2010, 11:01
Version 1.5 is out, introducing repair of half top/bottom scanlines by ExInpaint)

#-----Emulgators DeRoller Simple 1.5 (Assumption : constant rolling speed upwards or downwards, steady offset before and after possible)-
# DeRoller alpha : proof of concept, no automation, integer calculations only.
# DeRoller 1.0 : First release, Lanczos instead of Crop,
# DeRoller 1.1 : Introduced offset calculation in float, then rounding up.
# DeRoller 1.2 : Added geometrical pre-alignment of the two parts to be assembled. Added Stab afterwards. Rounding improvement,
# DeRoller 1.3 : Derives the two parts to be assembled from the same time now. Pre-Upsizer added.
# Rounding introduced in 1.2 could lead to undersized height <4 pixels for the first derolled frame. Back to rounding up only by mod2
# DeRoller 1.4 : Introduced vertical start offset and vertical end offset to compensate bad splices
# where the rolling offset vs. time is not a slope, but a ramp or ramp/slope, slope/ramp or ramp/slope/ramp combination
# Reverse Rolling (from top to bottom) is thereby accomodated as well !
# DeRoller 1.5 : Introduced repair of top/bottom half scanlines by adding ExInpaint
#/*#--------------------------------------------------------------------Pre-Alignment-------------------------------------------------------
# Before DeRolling a film scan, you may have to align the borders first ! Often film scans are skewed !
# VCMohan's plugins needed here: Grid, Perspective, Spinner, Reform=deskew+skew. Avoid Reform, poor resizer !
#grid(sf=0, ef=framecount, lineint=10, bold=5, vbold=2, grid=true, axis=true)#Comment grid in to see where the transformations end up
# to repair top/bottom half scanlines that would destroy de-rolling, these have to be repaired by ExInpaint first.
ConvertToRGB#exinpaint needs RGB to work correctly with a mask colour of 000000, Perspective needs RGB too
ExInpaint(last, last.letterbox(2, 2, 0, 0, color=$000000), color=$000000, xsize=11, ysize=11)#x/ysize=11 was the sweet spot
#If SeparateFields and 2x vertical resizer have to be used, be sure to move ExInpaint before the sepfields and resizer. Looks better.
Addborders(2, 2, 2, 2)#Perspective has to discard 2 border pixels for calculations and makes these black, we pad up borders before with 2 pixels black
perspective(a=-0.00001, b=0.0, x=+1400, y=0)#these were the KungFu Scan 2 perspective corrections, very smooth !
Crop(2, 2, -2, -2)#Perspective introduced a 2 pixel black border, we padded these up, now we crop them off
ConvertToYV12#(interlaced=true)#(RGB was needed for Perspective only)
#spinner(check=false, angle=+0.7, q=4)#these were the KungFu Scan 2 angle corrections, sometimes exceptions thrown...
# Deskew transforms a Quadrilateral part of the frame (source at least 1 pixel per side smaller than frame)
# into a Rectangle within the frame (at least 1 pixel per side smaller than frame) Result shows stairstepping ! Poor resizer (point??)
#deskew(last, blankclip, ltopx=2, ltopy=2, lbotx=12, lboty=height-2, rtopx=width-2, rtopy=2, rbotx=width-2, rboty=height-2, resize="cubic")
# (these were the KungFu Scan 2 deskewer settings)
#*/#------------------------------------------------------------End of Pre-alignment-------------------------------------------------------
#/*#-------------------------------------------------------Start of Emulgator's DeRoller 1.5----------------------------------------------
# Comment subtitles out when proper working is confirmed. 2x within deroll and 2x past deroll...
rollstart=49#first frame to be considered as rolling
rollend=100#last frame to be considered as rolling
vertstartoffset=550#Vertical offset (line number) of the lower frame border of the first frame to be derolled.
# In case of standard rolling (Lower frame border moves up from the bottom): vertstartoffset is usually a bit less than height.
# Reverse DeRolling can be accomodated ! vertstartoffset is then less than vertendoffset.
vertendoffset=6#Vertical offset (line number) of the lower frame border of the last frame to be derolled.
# In case of standard rolling (Lower frame border moves up from the bottom): vertendoffset is usually a bit greater than zero.
# Reverse DeRolling can be accomodated ! vertendoffset is then greater than vertstartoffset.
beforevertoffsetline=556#Vertical offset to be compensated globally for all frames before deroll. Wiil be applied in cliprange "before" only.
aftervertoffsetline=0#Vertical offset to be compensated globally for all frames after deroll. Will be applied in cliprange "after" only.
topbottomcrop=0#This sets the amount to crop before the splicing resizer sets in. Gets rid of half scanned lines. Was experimental Leave at 0.
#
bordercomp=0# Default = 0 ! To be kept at 0 at this moment ! Outcome of my fantasies...
# bordercomp values may be -64...0..+64. 0 = Neutral. Something experimental.
# Stretches or squeezes the upper vs the lower part over time.
# -64 makes the upper part come down vertically squeezed, the lower part descending vertically stretched.
# Upper/lower part are equally resized when splice line has arrived at half height.
# Then the upper part comes further down, now stretched more than the descending lower part,
# which is now further squeezed until it disappears.
# +64 is vice versa. The upper part starts to come down vertically stretched, while the lower part is sqeezed right from the beginning,
# Lower Part is expanding as descending, the upper part squeezing as descending,
# Upper/lower part are equally resizied when splice line has arrived at half height
# Not of real use at this moment !
rollrange=float((rollend-rollstart)+1)#If there is only 1 frame to deroll, then the framenumber difference would deliver 0, but there is still 1 frame to deroll.
before=Trim(0, rollstart-1)
rolltopsrc=Trim(rollstart, rollend+1)
# One frame was missing (frame nr <rollend>) It should be the last split frame.
# Lengthening the ends of rolltopsrc and rollbottomsrc +1 helped here.
rollbottomsrc=Trim(rollstart-1, rollend)
# The -1 offset of rollbottomsrc ensures that the lower rolling picture part which will be stacked on top
# comes from the same shooting time as the upper part, so 1 frame duration before the split scan.
after=Trim(rollend+1, 0)
picoffsetperframe=float((vertstartoffset-vertendoffset)/(rollrange+1))
deroll=ScriptClip(rolltopsrc, """
Lanczos4Resize(rolltopsrc, width, height+bordercomp)
rollframecount=current_frame+1
picoffset=2*round((height-vertstartoffset-vertendoffset)/2)+(round(rollframecount*picoffsetperframe))+(round(rollframecount*picoffsetperframe)%2)
##My version, this rounds up only...
#picoffset=2*round(rollframecount*picoffsetperframe/2.0)
##Gavinos improvement to round to nearest neighbour, but rolltopresizer chokes if this yields less than 4 pixels height
rolltop=Lanczos4Resize(rolltopsrc, width, ((height-picoffset)-(bordercomp/2)), 0, topbottomcrop, -0, (height-picoffset))
rollbottom=Lanczos4Resize(rollbottomsrc, width, (picoffset-(bordercomp/2)), 0, (height-picoffset), -0, -topbottomcrop)
#rolltop=Spline36Resize(rolltopsrc, width, ((height-picoffset)-(bordercomp/2)), 0, 0, -0, (height-picoffset))
#rollbottom=Spline36Resize(rollbottomsrc, width, (picoffset-(bordercomp/2)), 0, (height-picoffset), -0, -0)
StackVertical(rollbottom, rolltop)
Subtitle("Rollframecount = "+String(rollframecount)+"", size=12, align=1, x=(width/2)-80, y=height-40, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
Subtitle("Applied Moving Picoffset for this frame: "+String(picoffset)+" pixels vertical", size=12, align=1, x=(width/2)-80, y=height-20, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
""")
beforevertoffset=2*((height-beforevertoffsetline%(height))/2)
aftervertoffset=2*((height-aftervertoffsetline%(height))/2)
beforetopsrc=Trim(0, rollstart-1)
beforebottomsrc=Trim(0,-1)++Trim(0, rollstart-2)#Because there is no predecessor for frame 0, this has to be given for its own reconstruction
aftertopsrc=Trim(rollend+1, framecount-1)
afterbottomsrc=Trim(rollend, framecount-2)
beforetop= (beforevertoffsetline!=0) ? Lanczos4Resize(beforetopsrc, width, height-beforevertoffset, 0, topbottomcrop, -0, height-beforevertoffset) : NOP
beforebottom= (beforevertoffsetline!=0) ? Lanczos4Resize(beforebottomsrc, width, beforevertoffset, 0, height-beforevertoffset, -0, -topbottomcrop) : NOP
aftertop= (aftervertoffsetline!=0) ? Lanczos4Resize(aftertopsrc, width, height-aftervertoffset, 0, topbottomcrop, -0, height-aftervertoffset) : NOP
afterbottom= (aftervertoffsetline!=0) ? Lanczos4Resize(afterbottomsrc, width, aftervertoffset, 0, height-aftervertoffset, -0, -topbottomcrop) : NOP
beforecomp= (beforevertoffsetline==0) ? before : StackVertical(beforebottom, beforetop)
aftercomp= (aftervertoffsetline==0) ? after : StackVertical(afterbottom, aftertop)
AlignedSplice(beforecomp, deroll, aftercomp)
#Stab()
Subtitle("Rollrange = "+String(rollrange)+" Frames", size=12, align=1, x=(width/2)-80, y=height-80, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
Subtitle("Picoffset increase per frame = + "+String(picoffsetperframe)+" pixels vertical", size=12, align=1, x=(width/2)-80, y=height-60, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
Subtitle("Applied Picoffset before/after= + "+String(beforevertoffset)+" / "+String(aftervertoffset)+" pixels vertical", size=12, align=1, x=(width/2)-80, y=height-0, first_frame=0, font="Verdana", text_color=$88FF00, halo_color=$000000, interlaced=false)
#*/#-----------------------------------------------End of Emulgator's DeRoller 1.5-----------------------------------------------------