Log in

View Full Version : Recolorization of black and white frames


VideoOnTapes
27th August 2020, 00:16
Hi there,

I'm newbie with AviSynth. I use AviSynth+ 64bit and AvsPmod 2.6.3.4.

I'm looking to restore old VHS recordings where some frames are in black and white.
Something similar to what's been done here: https://www.youtube.com/watch?v=iaUsvKDQycg

I figured out how to do it with MergeChroma() :


frame_number_with_good_colors = 128
good_frame= clip.Trim(frame_number_with_good_colors,1)

# Apply MergeChroma for frames with bad chroma (AverageChromaU() < 120)
# Apply MergeChroma for frames in black and white (vPlaneMedian() = 127 or 128)
copy=clip
chromed=MergeChroma(clip, good_frame)
clip=ConditionalSelect(clip,"v_median=vPlaneMedian()"+chr(13) \
+ "av_chromaU=AverageChromaU()"+chr(13) \
+"(v_median==128 || v_median==127)?1:(av_chromaU<120?1:0)", copy, chromed)


What I'd like to do is use the color values from the last frame that is correct.
To do this, I need to store the number of this correct frame, as it has to be reused until a new frame with correct colors is found.

However, I can't store the current_frame value in a variable. Could you help me on this point?

Also, I tried to write this value to a file:


clip = clip.WriteFile("variable.txt", "current_frame")


but it doesn't work for me :
Script error: Invalid arguments to function 'WriteFile'


NB: The video I'm working on (as a test basis) is this one:
https://www.youtube.com/watch?v=rX0r6WbiutU

manono
27th August 2020, 00:46
It looks to me the B+W frames aren't many in number consecutively and the movement is so little between frames, that it would be a whole lot easier to use frame interpolation to create good frames from bad. It would be manual, though, and you seem to be searching for an automatic solution.

StainlessS
27th August 2020, 13:28
Im kinda curious if SpotLess could do anything here [AND ALSO with your problem in other thread],
(It could be that old thing TheFluff keeps on saying, something like, "when all you have is a hammer, every problem looks like a nail", or summick like that).
But might still be worth a try.
Maybe try something like, [both of these, varying RadT downwards, maybe in steps of 5 at first]

SpotLess(RadT=30, ThSAD2=10000,BlkSz=32)

and

SpotLess(RadT=30, ThSAD2=400,BlkSz=32)


cant do any harm to try. [do report good or bad, I'm not expecting anything particularly good, but hell, its worth a shot, and it aint the end of the world if it fails].
If it does fix some, then might be required to fix single frames using eg Clipclop or ReplaceFramesSimple. [If ClipClop, then SawBones might be useful]
[will also likely be slow-ish]

EDIT:

AviSource("D:\Parade.avi")

Global frame_number_with_good_colors = 128
good_frame= Trim(frame_number_with_good_colors,-1) # -1, NOT 1

# Apply MergeChroma for frames with bad chroma (AverageChromaU() < 120)
# Apply MergeChroma for frames in black and white (vPlaneMedian() = 127 or 128)

copy=Last
chromed=MergeChroma(clip, good_frame)

# Always way easier than all the Chr(13) stuff, [also, I dont like use of Chr(13), should be Chr(10) IMHO].
SSS = """
v_median = vPlaneMedian()
Result = ((v_median==128 || v_median==127) || AverageChromaU < 120) ? 1 : 0
Global frame_number_with_good_colors = (Result == 1) ? current_frame : frame_number_with_good_colors # Will this do ?
# (Result == 1) ? RT_WriteFile(".\variable.txt","%d",current_frame) : NOP # I always find Writefile type stuff awkward, so dont/rarely use it [Not using Append=true]
Return Result
"""

ConditionalSelect(Last, SSS , copy, chromed)
Clip = Last # if you need it in clip


Above untested at all.

EDIT: RT_WriteFile from RT_Stats.
If you want write list of frames to ".\variable.txt", Add Append=true, at end of RT_WriteFile( ... , Append=true)
EDIT: I tend to use "SSS" not because it is ending of my moniker, but means triple quoted string, "S" being single quoted string.

poisondeathray
27th August 2020, 14:35
RE: internal AVS WriteFile()

Something buggy with avs+ versions . It works ok in avs 2.6 classic . Just simple script like colorbars with writefile . I think it has something to do with the "implied last" issues in recent versions. But explicitly assigning names/variables without "last" does not work either

StainlessS
27th August 2020, 14:46
works a tiny little bit to mod color [not really tweaked at all], but is problably not worth pursuing. [although some frames were fixed at least(well nearly) as well as the youtube fix, but not many]

I hacked SpotLess func adding chroma arg, allowing to switch it off in detector. [worked better than on]

# Hacked with Chroma arg
Function SpotLess(clip c,int "RadT",int "ThSAD2",int "BlkSz",Bool "chroma") {
RadT = Default(RadT,2) # Temporal radius
ThSAD2 = Default(ThSAD2,10000) # Setting lower, sets SAD thresold to limit blurring effect of more distant reference frame BAD matching blocks.
BlkSz = Default(BlkSz,8) #
chroma = Default(chroma,True)
Assert(1 <= RadT,"SpotLess: 1 <= RadT")
sup = c.MSuper(pel=2,sharp=2,hpad=16,vpad=16)
MultiVec = sup.MAnalyse(multi=true, delta=RadT,blksize=BlkSz,overlap=BlkSz/2,search=4,chroma=chroma)
c.MCompensate(sup,MultiVec,tr=RadT,ThSAD2=ThSAD2)
MedianBlurTemporal(radiusY=0,radiusU=0,radiusV=0,temporalradius=RadT) # Temporal median blur only
SelectEvery(RadT*2+1,RadT) # Return middle frame
}


AviSource(".\Colour stabilization compare -Earls Court -77-.mp4.AVI")
W=Width/2
A=Crop(0,0,W,0)
B=Crop(W,0,0,0)

RadT=10
ThSAD2=10000
BlkSz1=8
BlkSz2=8

C=A.SpotLess(radt=RadT,thsad2=ThSAD2,blksz=BLKSZ1,chroma=true)
D=A.SpotLess(radt=RadT,thsad2=ThSAD2,blksz=BLKSZ2,chroma=false)
TOP = StackHorizontal(A,B)
Bot = StackHorizontal(C,D)
StackVertical(TOP,BOT)

Return Last


Had to use about blkSz 8, did not know was such a small frame clip. [I tried the Queen clip, 2nd one I think]
Are well, at least it was a riveting experiment :0
Spotless has actually [in spotless thread] fixed full frame dropout, and also a nearly totally desaturated frame with full frame width thickish band of bad noise.

OK, well not quite as well as youtube fix[top right], src[top left], Spotless with chroma detect bot left, without chroma detect, bot right. [YT fix probably had a little hand color correction]
https://i.postimg.cc/zVkDHZp6/Col-00.jpg (https://postimg.cc/zVkDHZp6)

VideoOnTapes
29th August 2020, 15:13
Thank you very much for your help. It's very informative.

With SpotLess, it works perfectly. Unfortunately, it isn't very fast given the many treatments that are applied.
I opted for a RadT value of 5 which gives a good compromise in the case of the video I proposed.


With the other script, the frame value that is applied with Trim() is always the one defined at the beginning, despite the use of "global":


good_frame = clip.Trim(frame_number_with_good_colors,-1)


I tried a lot of things, without success.

Otherwise, I manage to save the value for each frame in a file :

RT_WriteFile(filename,"%d %d", current_frame, frame_number_with_good_colors, Append=true)



Like this :

353 353
354 354
355 355
356 355 <-- new reference for this faulty frame
357 355 <-- new reference for this faulty frame
358 355 <-- new reference for this faulty frame
359 359
360 360
361 361
362 362


But I still haven't found the syntax that would allow to read the file and apply MergeChroma only when the value of the variable is different from current_frame.
If you could help me on this point, I would be grateful. Also, may be it could be enough to only save value when needed.

Afterwards, I'm not sure this is the best approach either, since it requires two passes. One to create the file; a second to read the file and apply the changes.
Or may be, I could write the file with another langage (like Python), using data from ffprobe...

StainlessS
14th September 2020, 02:29
OK, came back to this, downloaded your 2nd clip
The video I'm working on (as a test basis) is this one

Simple script

Avisource(".\Interview Jean Jacques Goldman top 50 - 1986 -.mp4.AVI")
ORG=Last
SpotLess(RadT=5,ThSAD=5000,chroma=false,tm=false)
StackHorizontal(ORG,Last)
Prefetch(4)

Updated for SpotLess v1.04.

Makes a world of differrence [well considering the source quality].
I've only tried on about the first 2000 frames, but fixes most of the horrible double frame orange splashes, and even removes a lot of the chroma bands.
Orange flash frames pair 1560/1561 fails to be fixed, reason: is immediately following a scene change, and shortly after orange flash there is a 2nd orange flash.

Anyway, is nearly there just via above simple script.

Below a few consecutive frames showing original left, with chroma horizontal bands and orange flashes, and on right fixed.

https://i.postimg.cc/jSDLLvTx/01.jpg (https://postimages.org/)

https://i.postimg.cc/x1BqHHjK/02.jpg (https://postimages.org/)

https://i.postimg.cc/mrMkSDhK/03.jpg (https://postimages.org/)

https://i.postimg.cc/DZTZpTX0/04.jpg (https://postimages.org/)

EDIT: Above frame fixes are fairly typical, nothing special.

EDIT: Requires SpotLess v1.04.

StainlessS
15th September 2020, 22:27
Above script updated, req spotLess v1.04, all frames fixed, incl frame 1560/1561.

johnmeyer
15th September 2020, 23:59
What variables did you feed to SpotlessS? Also, it seems like the main change in v1.04 was to add the tHSAD variable. Is that why v1.04 is needed?

real.finder
16th September 2020, 00:09
for fun, I tried it with old video I recorded back in the end of 90s https://www.sendspace.com/file/pu7glm but it's almost didn't fix anything

it's very bad record using old JVC from 80s with almost dead video head
and most importantly, it was done by a kid about 10 years old :D

and since one head is a bit better than the other one SelectEven() after the source call with SpotLess make it better :)

johnmeyer
16th September 2020, 00:53
Doesn't the OP, as well as real.finder, have to adapt this script to work with interlaced video? The usual advice for a temporal filter is:

SeparateFields()
even = SelectEven(last).Spotless(...)
odd = SelectOdd(last).Spotless(...)
Interleave(even, odd)
Weave()

real.finder
16th September 2020, 01:03
Doesn't the OP, as well as real.finder, have to adapt this script to work with interlaced video? The usual advice for a temporal filter is:

SeparateFields()
even = SelectEven(last).Spotless(...)
odd = SelectOdd(last).Spotless(...)
Interleave(even, odd)
Weave()

I don't has the digital interlaced source now (but I still have the tape, but I don't think I will re-cap for this experience)

anyway, since it 50 fps it can reinterlaced, but I think it will not make a better result, but I think the code you post should work

StainlessS
16th September 2020, 09:27
tHSAD variable. Is that why v1.04 is needed?
Yes.

Main change to prev image script is

SpotLess(RadT=5,ThSAD=5000,chroma=false,tm=false)

As we now added ThSAD=5000 (defaults 10,000) and ThSAD2 defaults to ThSAD, so thresholds for ALL frames=5000, and so frame at 1560-1 is
mostly ignored (from a different scene) and so dont mess up the numbers [previously, frame 1560-1 got threshold of 10,000, and so not ignored and messed up numbers].
Likewise frame at 1560-2 ignored etc.
2nd orange frame at 1561, also ignores 1561-2 and 1561-3 etc.
Setting only ThSAD2 worked fine for double frame spots, but I really shoulda implemented ThSAD arg too as more flexible thresholds.
The above mentioned v1.04 requirement was only for the un-shown frames 1560 and 1561, the images that are shown are from somewhere else.

Dont really think good idea to handle interlaced with MC by separatefields, pixels jump in and out of one field to the other.

EDIT: As it happens, below from v1.03 would actually have worked too, I just did not try it.

SpotLess(RadT=5,ThSAD2=5000,chroma=false,tm=false) # ThSAD would be as v1.03 default 10000

EDIT:
OOps, talking total bo??ocks, only the chroma=false, tm=false fixes it for either version, ThSAD=5000 made no difference.

EDIT: I'm still tryin' to figure out how this thing works too :)

https://i.postimg.cc/DwNpKXRN/JJ-00.jpg (https://postimages.org/)

https://i.postimg.cc/QtG6Fr8k/JJ-01.jpg (https://postimages.org/)

https://i.postimg.cc/XJfsFDXM/JJ-02.jpg (https://postimages.org/)

https://i.postimg.cc/HnTBt47r/JJ-03.jpg (https://postimages.org/)

EDIT: Actually

SpotLess(RadT=2,ThSAD=5000,chroma=false,tm=false)

Gets it mostly right, but some weird behaviour @ 4081, RadT=4 seems to work all ok on quick look.