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.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Usage

Reply
 
Thread Tools Search this Thread Display Modes
Old 6th April 2013, 08:05   #1  |  Link
johnmeyer
Registered User
 
Join Date: Feb 2002
Location: California
Posts: 2,691
Bad 1950s Kinescope - Hopeless?

This is one of the few Kinescopes of an actual American NFL football TV broadcast from the 1950s.

1955 NFL TV Kinescope

The clip posted here is a simple MPEG-2 cut from the DVD I received from the owner.

Unfortunately, this particular video to film transfer was not done with a true Kinescope setup: it was probably done by someone with a lot of money (film was expensive!!) simply filming their TV set. As a result, the shutter on the film camera was not synced to the TV screen, and the result is noise bars. These happen when the shutter on the film camera is closed during the period when the film is advanced. This is a typical frame:



If you download the short (6MB) video clip, you'll see that it looks much worse than the still frame.

I don't think this can be fixed, because nothing repeats exactly. However, because of the unique and valuable nature of this film, I thought I'd ask the experts here if they can suggest any approach that might reduce the noise bars.

Thanks!

======================
[edit]Here is a link to the post, later in the thread, where I show an approach worked, and did solve the problem:

Mask Code For Correcting Noise Bars

Last edited by johnmeyer; 30th October 2019 at 23:59. Reason: Provide link to post that shows my "solution"; later, replace Photobucket image
johnmeyer is offline   Reply With Quote
Old 7th April 2013, 00:27   #2  |  Link
creaothceann
Registered User
 
Join Date: Jul 2010
Location: Germany
Posts: 357
The picture is interlaced, so assuming the source was progressive means that it can be deinterlaced with AnimeIVTC. Then... try adding a temporal denoiser?
creaothceann is offline   Reply With Quote
Old 7th April 2013, 01:17   #3  |  Link
johnmeyer
Registered User
 
Join Date: Feb 2002
Location: California
Posts: 2,691
Deinterlacing Kinescopes can be a little tricky, but I have done that successfully. I think I can do that here as well. However, I don't know whether those wide horizontal noise bars will be diminished much by a temporal denoiser, but I guess I should try, and then see what happens.
johnmeyer is offline   Reply With Quote
Old 7th April 2013, 09:36   #4  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
Okay, we have old true 60i filmed at 24fps unsynced, then presented here as hard 3:2 telecine into 29.97i

First analyse the stream.
Code:
Mpeg2Source("Bad Kinescope.d2v")
Bob()
Recognised as 3:2 telecine material.

Analyse for correct phase.
Code:
Mpeg2Source("Bad Kinescope.d2v")
BicubicResize(640, 480) # Fit on 1920 display
DoubleWeave()
a = Pulldown(0,2).Subtitle("0,2")
b = Pulldown(1,3).Subtitle("1,3")
c = Pulldown(2,4).Subtitle("2,4")
d = Pulldown(0,3).Subtitle("0,3")
e = Pulldown(1,4).Subtitle("1,4")
ShowFiveVersions(a,b,c,d,e)
Recognise 1,4 and 2,4 as the two correct phase results.

Check for soft or hard telecine.
Code:
Mpeg2Source("Bad Kinescope.d2v")
BicubicResize(640, 480)
ShowFrameNumber(True)
DoubleWeave()
c = Pulldown(2,4).Subtitle("2,4")
e = Pulldown(1,4).Subtitle("1,4")
StackHorizontal(e, Subtract(e, c).Levels(120, 1, 136, 0, 255), c)
Yes the 2 correct phase results are slightly different, indicating hard telecine (okay DGIndex already told me this).

Thus we can get back the original 24fps progressive film frames :-
Code:
Mpeg2Source("Bad Kinescope.d2v")
DoubleWeave()
c = Pulldown(2,4)
e = Pulldown(1,4)
Merge(e, c)
Here we can see from the bright bars cycling on an approximate 5 frame pattern that this was a movie camera stuck in front of a TV. Also the motion non-fluidity is typical of 60i sampled at 24p.

The bright lines are where the TV raster was actually scanning when the shutter was open, the rest of the less bright image is the CRT persistence.

With enough dedication this can be repaired.
IanB is offline   Reply With Quote
Old 7th April 2013, 12:49   #5  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
Well the bright pattern appears to be actually a 7 frame cycle :-
Code:
Mpeg2Source("Bad Kinescope.d2v")
DoubleWeave()
c = Pulldown(2,4)
e = Pulldown(1,4)
Merge(e, c)

BicubicResize(480, 480)

A=SelectEvery(7, 0)
B=SelectEvery(7, 1)
C=SelectEvery(7, 2)
D=SelectEvery(7, 3)
E=SelectEvery(7, 4)
F=SelectEvery(7, 5)
G=SelectEvery(7, 6)
H=BlankClip(G)

X=StackHorizontal(A,B,C,D)
Y=StackHorizontal(E,F,G,H)

StackVertical(X,Y)
For each seventh frame we can see the bright region is in roughly the same place. Well it actually creeps upwards slightly each cycle, but that is to be expected because the original camera was not synced to the original TV.

With this knowledge you can build a suitable mask clip with the same rolling pattern and correct the bright strips. From the sample there appears to be some jitter in the bright strip position so the mask clip may need some manual tweaking to keep it in sync with the film.

Other may have some ideas how to better analyse the bright strip pattern timing.

Points to remember are that original TV display would have been 60 interlaced fields of 243 picture lines with 19.5 blanking lines each second, or 15750 lines per second. A 24 fps frame period would be 656.25 line periods.
IanB is offline   Reply With Quote
Old 8th April 2013, 16:50   #6  |  Link
johnmeyer
Registered User
 
Join Date: Feb 2002
Location: California
Posts: 2,691
Interesting examples in how to deconstruct the video back to 24fps. Quite different than how I was doing it, and very instructive.

How to make a moving mask that will follow the rising noise bar in the recovered film frames is still the challenge that stumps me. I'll work on this later today and see if I can come up with some detection ideas.
johnmeyer is offline   Reply With Quote
Old 8th April 2013, 18:17   #7  |  Link
johnmeyer
Registered User
 
Join Date: Feb 2002
Location: California
Posts: 2,691
Here is my current thinking:

1. Do IVTC. TFM/Tdecimate() seems to work fine.

2. Using the resulting 24 fps frames, create an estimated frame using the previous and next frame. Here's code for that:

Code:
super = MSuper(source)
backward_vectors = MAnalyse(super, isb = true, delta=2)
forward_vectors = MAnalyse(super, isb = false, delta=2)
inter = MFlowInter(source,super, backward_vectors, forward_vectors, time=50, ml=70)
3. Create a mask using some blurred difference between the actual current frame and the estimated ("inter") frame. Do this difference in such a way that only the luma differences are used, and such a way that the average across the entire horizontal raster line is used.

It is step #3 that has me completely stumped. I think the general idea is correct (although I need to come up with better code for the estimation in #2 above). The general idea is that if the current frame contains the bright horizontal bar, then in almost all cases the immediately preceding frame does not have that bar, nor does the next frame. Thus, if I estimate the current frame using these two adjacent frames, there should be no bright horizontal bar in the estimated frame. Therefore if I can somehow use some sort of blurred difference between the actual frame and this estimated frame, and do this in such a way as to ignore all the high frequency small details, and only keep the difference across the horizontal bar, then I can use that mask to decrease the gamma for that horizontal stripe.

Last edited by johnmeyer; 8th April 2013 at 18:57. Reason: Changed code ten minutes after original post
johnmeyer is offline   Reply With Quote
Old 9th April 2013, 05:52   #8  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
@johnmeyer,

Nice idea but the bright patches screw the frame motion interpolation. Of the 3 frame involved 1, 2 or 3 always have a bright patch. Great if the ones before and after a bright bar free, but that seems to only occur once every 7 frames.

If you imagine a canvas 525 lines high, 480 lines of picture plus 45 extra lines of fly-back blanking then somewhere during the canvas scan time will be the camera shutter open time, which corresponds to the bright bar. Whenever the shutter is open during the fly-back blanking then you see no bright bar.

I have been analysing your clip line by line looking for the brightest pixel on each line and there is moderate to good correlation to the bright bars, but the problem I have is that the overall image brightness varies with screen location. The left side has a dark region, the top is darker than the middle and the bottom is slightly darker than the middle and brighter than the top. This script adds a 48 pixel stripe to the end of each line corresponding to the brightest pixel in that line. The number written at the top of the strip is the maximum of all the brightest. The script is god awfully slow.
Code:
Mpeg2Source("Bad Kinescope.d2v")
ConvertToY8()
DoubleWeave()
c = Pulldown(2,4)
e = Pulldown(1,4)
Merge(e, c)
Orig=Spline16Resize(428, 480)

SeparateRows(480)
ScriptClip("BlankClip(Last, Color_YUV=$8080+$10000*YplaneMax())")
Crop(0, 0, 48, 0)
WeaveRows(480)
ScriptClip("SubTitle(String(YplaneMax()))")
StackHorizontal(Orig, Last)

A=SelectEvery(7, 0)
B=SelectEvery(7, 1)
C=SelectEvery(7, 2)
D=SelectEvery(7, 3)
E=SelectEvery(7, 4)
F=SelectEvery(7, 5)
G=SelectEvery(7, 6)
H=BlankClip(G)
X=StackHorizontal(A,B,C,D)
Y=StackHorizontal(E,F,G,H)
StackVertical(X,Y)
The bright bar region is at least 15 units brighter than in the adjacent frames, but the positional brightness variation is least 20 units.
IanB is offline   Reply With Quote
Old 9th April 2013, 06:06   #9  |  Link
johnmeyer
Registered User
 
Join Date: Feb 2002
Location: California
Posts: 2,691
It's late at night here, and I'll be gone all day tomorrow, but on Wednesday I'll try your script and see where that takes me. Thanks!!
johnmeyer is offline   Reply With Quote
Old 9th April 2013, 07:01   #10  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
Okay using the average of the peak brightness's from the next and previous frames as a base brightness seems to work very well, I suspect using the min of the 2 might work even better, but we don't have a tool to hand. :-
Code:
Mpeg2Source("Bad Kinescope.d2v")
ConvertToY8()
DoubleWeave()
c = Pulldown(2,4)
e = Pulldown(1,4)
Merge(e, c)
Orig=Last

SeparateRows(480)
ScriptClip("BlankClip(Last, Color_YUV=$8080+$10000*YplaneMax())")
Crop(0, 0, 48, 0)
WeaveRows(480)
Blur(0, 1)
Next=DeleteFrame(0)
Prev=DuplicateFrame(0).FreezeFrame(0,0,3)
Subtract(Merge(Prev, Next)) # Min(Prev, Next) might work better if we had such...
ScriptClip("SubTitle(String(YplaneMax()))")
Levels(137, 2, 150, 32, 235, False)
StackHorizontal(Orig, Last)
This really needs a plugin to do the SeparateRows/ScriptClip/WeaveRows max luma per line work.

Next trick is to turn the bright line mask into a noise resistant bright bar correction.

Rules need to be something like, when we have a 35 to 45 line mask area correct the matching lines centred on the mask.
IanB is offline   Reply With Quote
Old 10th April 2013, 10:32   #11  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
I've knocked up a plugin to create the YPlaneMax band:- (filters for both Avisynth v2.58 & v2.6)

Link Removed, See this thread:
http://forum.doom9.org/showthread.php?t=167663

script mod
Code:
MPEG2Source("D:\AVS\Bad Kinescope.d2v")
ConvertToY8()

DoubleWeave()
c = Pulldown(2,4)
e = Pulldown(1,4)
Merge(e, c)
Orig=Spline16Resize(428, 480)

#SeparateRows(480)
#ScriptClip("BlankClip(Last, Color_YUV=$8080+$10000*YplaneMax())")
#Crop(0, 0, 48, 0)
#WeaveRows(480)

# threshold as for YPlanemin/max/minmaxdiff, Matrix=PC601: Zebra creates 4 bands, Left=YPlaneMin,YPlaneMax,YPlaneMinMaxDifference,YPlaneMedian
Zebra(threshold=0.0,matrix=2).Crop(48,0,48,0)	# Crop Selects 2nd band, YPlaneMax (Bands are 48 pixels wide)


ScriptClip("SubTitle(String(YplaneMax()))")
StackHorizontal(Orig, Last)

A=SelectEvery(7, 0)
B=SelectEvery(7, 1)
C=SelectEvery(7, 2)
D=SelectEvery(7, 3)
E=SelectEvery(7, 4)
F=SelectEvery(7, 5)
G=SelectEvery(7, 6)
H=BlankClip(G)
X=StackHorizontal(A,B,C,D)
Y=StackHorizontal(E,F,G,H)
StackVertical(X,Y)

convertToRGB32()

and
Code:
Mpeg2Source("Bad Kinescope.d2v")
ConvertToY8()
DoubleWeave()
c = Pulldown(2,4)
e = Pulldown(1,4)
Merge(e, c)
Orig=Last

#SeparateRows(480)
#ScriptClip("BlankClip(Last, Color_YUV=$8080+$10000*YplaneMax())")
#Crop(0, 0, 48, 0)
#WeaveRows(480)

# threshold as for YPlanemin/max/minmaxdiff, Matrix=PC601: Zebra creates 4 bands, Left=YPlaneMin,YPlaneMax,YPlaneMinMaxDifference,YPlaneMedian
Zebra(threshold=0.0,matrix=2).Crop(48,0,48,0)	# Crop Selects 2nd band, YPlaneMax (Bands are 48 pixels wide)

Blur(0, 1)
Next=DeleteFrame(0)
Prev=DuplicateFrame(0).FreezeFrame(0,0,3)
Subtract(Merge(Prev, Next)) # Min(Prev, Next) might work better if we had such...
ScriptClip("SubTitle(String(YplaneMax()))")
Levels(137, 2, 150, 32, 235, False)
StackHorizontal(Orig, Last)

ConvertToRGB32()
and description

Code:
Zebra(clip c, Float "threshold"=0.0,int "matrix"=2,bool "Row"=true)     # Avisynth v2.5/v2.6 Plugin by StainlessS

Creates a 4 bar clip in two modes,
    Row=True, creates a set of 4 bars 48 pixels wide per bar and same height as source clip.
        Each horizontal pixel row in the bars represents the contents of the horizontal rows of the source clip.

    Row=False, creates a set of 4 bars 48 pixels tall per bar and same width as source clip.
        Each vertical pixel column in the bars represents the contents of the vertical columns of the source clip.

The 4 bands it creates are (from left to right if Row==true and top to bottom if Row==false)

1 ) YPlanemin
2 ) YPlanemax
3 ) YPlaneminmaxDifference
4 ) YPlaneMedian

Threshold used for bands 1, 2, and 3 as for eg YPlaneMin (to avoid extreme pixels, ie noise).

Matrix,(For RGB -> Luma-Y conversion, not used in YUV modes)

0) = rec601
1) = rec709
2) = PC601
3) = PC709


Zebra.dll is for Avisynth v2.58 and Zebra26.dll is for Avisynth v2.6.
The v2.58 version supports Y8 in avisynth v2.6.
Running version v2.6 on Avisynth v2.58, will not find a plugin named Zebra.
LINK DELETED

EDIT:- AvsMeter shows about 9 FPS for 1st script, and 63 FPS for 2nd script.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 12th April 2013 at 22:50.
StainlessS is offline   Reply With Quote
Old 11th April 2013, 02:38   #12  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
New Version Zebra v1.01, Previous Post updated.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???
StainlessS is offline   Reply With Quote
Old 11th April 2013, 03:31   #13  |  Link
johnmeyer
Registered User
 
Join Date: Feb 2002
Location: California
Posts: 2,691
Stainless & IanB,

Wow, I can't wait to try this out tomorrow. Sorry for the delay in responding, but I was out for a day and then spent all day today catching up. Your code looks very cool.

John
johnmeyer is offline   Reply With Quote
Old 11th April 2013, 04:54   #14  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
It looks to me as if the bands are slanted from top left to bottom right.
Might like to chop clip in half and have zebra bars showing on both left and right
to gauge the angle. Perhaps David Horman's plugs will come in handy.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???
StainlessS is offline   Reply With Quote
Old 11th April 2013, 07:18   #15  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
Once the bright bar was located, I was sort of thinking aligning and applying a hand draw mask to the area in question, assuming the bright bar is a fixed geometry.
IanB is offline   Reply With Quote
Old 11th April 2013, 18:42   #16  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
I was thinking about modifying the RT_YInRangeLocate func for this, if baffle (number of scanlines that must break thresh)
exceeds the number of scanlines (width or height of area to examine) then the Baffle for that axis is limited to the number
of scanlines on that axis, could do this without changing args. Should allow use here to find the bands.
Think I'll do that presently.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???
StainlessS is offline   Reply With Quote
Old 11th April 2013, 19:42   #17  |  Link
StainlessS
HeartlessS Usurer
 
StainlessS's Avatar
 
Join Date: Dec 2009
Location: Over the rainbow
Posts: 10,980
Here RT_Stats with RT_YInRangeLocate() mod, not tested at all, but trivial mod. YInRangeLocate.avs
also modded. Have to go out now, thought you may like to test out.

LINK REMOVED See sig for download.

You could set eg width to examine to 1 pixel wide, and height to full height and baffle to eg
minimum acceptable band height. think it should work.
__________________
I sometimes post sober.
StainlessS@MediaFire ::: AND/OR ::: StainlessS@SendSpace

"Some infinities are bigger than other infinities", but how many of them are infinitely bigger ???

Last edited by StainlessS; 12th April 2013 at 18:40.
StainlessS is offline   Reply With Quote
Old 11th April 2013, 22:30   #18  |  Link
johnmeyer
Registered User
 
Join Date: Feb 2002
Location: California
Posts: 2,691
Quote:
It looks to me as if the bands are slanted from top left to bottom right.
I can fix that outside of AVISynth. My editing program (Vegas Pro) can easily rotate the clip, and I can interactively use the display in that program to ensure that the picture (and noise bars) are exactly horizontal.

No need to spend time on this.

I easily got the Zebra function to work:



and I'm now working on understanding the RT_Stats DLL. I need to go look at the original AVS scripts on which the DLL is based.

This is definitely beginning to look possible. Thanks so much for spending the time on this.

Last edited by johnmeyer; 31st October 2019 at 00:01. Reason: removed comment about mask in Vegas; later, replace Photobucket image
johnmeyer is offline   Reply With Quote
Old 12th April 2013, 00:51   #19  |  Link
johnmeyer
Registered User
 
Join Date: Feb 2002
Location: California
Posts: 2,691
Getting close, but may need a little more help.

I apply this test script fragment to the IVTC'd 23.97 version of the video:

Code:
source=AVISource("e:\fs.avi")
p=selectevery(source,1, -1) #Previous frame

Z1=Zebra(source,threshold=100,row=true)
Z2=Zebra(p,threshold=100,row=true)

output=Subtract(Z1,Z2).crop(144,0,0,0)

stackhorizontal(source,output)
I then get this:



I think I am two steps away from making this work. Here's what I think I need to do:

1. When the luma values in the comparison column are >128 for more than eight consecutive rows, construct a mask, the width of the original frame, and the height of that block. The beginning of the block [row(n)] will be the first row where the following averageluma condition is met:

row(n) >128
row(n+1) >128
...
row(n+7) >128

The last row is determined in similar fashion.

2. Apply this mask with a gain factor derived from the averageluma of the bright block in the comparison column divided by the averageluma of the eight rows (or whatever number of rows seems to work) immediately above or below (depending on whether the bright block is in the upper or lower half of the screen).

I'm pretty sure I could eventually figure out both of these tasks, but I would appreciate a few hints. This is especially needed for #2 because I think the mask needs to be "feathered" on the top and bottom edges.

An alternative to doing everything in AVISynth would be to simply get the Y coordinates for the top and bottom of the block in #1, and export to a text file those two coordinates (assuming one horizontal band per frame), along with the current frame number. I can then create a series of PNG masks which I can import to Vegas and do the masking there.

It would be a lot easier to do it all in AVISynth, however, if I can figure out the solution to at least these two issues.

[edit]I'll also have to add some noise averaging code so that flicker that is not related to the noise bar doesn't harm the process.

Last edited by johnmeyer; 31st October 2019 at 00:02. Reason: Removed next frame from code because it wasn't being used; added comment about noise averaging; later, replace Photobucket im
johnmeyer is offline   Reply With Quote
Old 12th April 2013, 03:55   #20  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
We have a prototype for bright bar detection, that is surprisingly resilient. On the short sample I have it only has slight trouble with the few frames that are free of a bright bar (false positive). Analysing the occurrence pattern and using it for guidance would eliminate this, i.e. from the cycle and jitter we expect the next bright bar to be between lines 200 and 260, if we get a 225 it's okay, if we get a 142 its a false hit or a break in the cycle or a scene/reel change. Whatever it is it needs to be analysed. Also remember the cycle space is 525 lines not 480 because of the vertical blanking period. Dumping the positions to a file and loading it into Excel could be very illuminating.


Correcting the brightness variation versus screen position will probably help the detection algorithm a great deal. You probably want to do this as part of your restoration effort anyway. Do you have any scenes that are uniformly highly bright eg ball in the sky, or an advert graphic. We just need 1 frame were the content is an expected uniform brightness, you can hand paint out the ball or any small splotches.

Having the screen brightness unified should also make the white bar correction much easier. Assuming such the mask becomes position independent and we just position it between -45 and +525. As we are at present we effectively need 570 different correction masks.

Unfortunately because the image is slightly rotated counter clockwise, applying simple line brightness correction based on the detection values is not really possible. That said I will investigate rotating the sample to see what can be achieved. ....
IanB is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 19:06.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.