View Full Version : VHS post processing


Busty
12th May 2025, 20:41
Hey fellow doomers,

after working out my capture workflow, I'm on a quest to process my VHS captures for better viewing pleasure without loosing details. I learned I need to adress chroma noise and chroma shift, and would love to get rid of dots and horizontal lines. Noise reduction is something I'd like to apply at a minimum, as I don't want to lose detail.

There are lots of discussions and examples on this forum and I found really helpful posts with example scripts that I tried.

ATM, I would like to combine a

- script adressing chroma noise with CNR2 and a degrain function

- with a script including a function for chromashift

- and a script adressing white dots with Despot / depan


Now, I'm doing mostly copy and paste here without thoroughly understanding avisynth's syntax. (I did read about avisynth grammar
and can accomplish some easy scripts, but I still struggle to understand, let alone write advanced scripts)

So, I'm posting three scripts that work separately but not when I try to combine them. May I ask for assistance in combining them?
That would be awesome!

I managed to combine scripts 1 and 2, but when I try to put in script 3, I get an error: invalid argument: converttoYV12


script 1:

#JohnMeyer's Denoiser script for interlaced video using MDegrain2
#This is my recommended starting point script for VHS as of April, 2012

SetMemoryMax(768)

Loadplugin("C:\Program Files\AviSynth\plugins\mvtools2.dll")
LoadPlugin("c:\Program Files\AviSynth\plugins\Cnr2.dll")
#loadplugin("c:\Program Files\AviSynth\plugins\despot.dll")
#Loadplugin("C:\Program Files\AviSynth\plugins\removegrain.dll")
Import("C:\Program Files\AviSynth\plugins\LimitedSharpenFaster.avsi")

SetMTMode(5,4)
#Modify this line to point to your video file
source=AVISource("C:\VHS.avi").killaudio().AssumeTFF()
SetMTMode(2)

#Only use chroma restoration for analog source material
chroma=source.Cnr2("oxx",8,16,191,100,255,32,255,false) #VHS
#chroma=source.Cnr2("oxx",8,14,191,75,255,20,255,false) #Laserdisc
#Set overlap in line below to 0, 2, 4, 8. Higher number=better, but slower
#For VHS, 4,0 seems to work better than 8,2. Most of difference is in shadows
#However, 8,0 is good enough and MUCH faster. 8,2 doesn't seem to make much difference on VHS.

#output=MDegrain2i2(chroma,8,0,0)
output=MDegrain2i2(chroma,8,4,0) #Better, but slower

#output=IResize(output,720,480)

#stackvertical(source,output)
#stackhorizontal(source,output)
#return output.Levels(16, 1, 235, 0, 255, coring=false)

return output


#-------------------------------

function MDegrain2i2(clip source, int "blksize", int "overlap", int "dct")
{
Vshift=0 # 2 lines per bobbed-field per tape generation (PAL); original=2; copy=4 etc
Hshift=0 # determine experimentally
overlap=default(overlap,0) # overlap value (0 to 4 for blksize=8)
dct=default(dct,0) # use dct=1 for clip with light flicker

fields=source.SeparateFields() # separate by fields

#This line gets rid of chroma halo
fields=MergeChroma(fields,crop(fields,Hshift,Vshift,0,0).addborders(0,0,Hshift,Vshift))
#This line will shift chroma down and to the right instead of up and to the left
#fields=MergeChroma(fields,Crop(AddBorders(fields,Hshift,Vshift,0,0),0,0,-Hshift,-Vshift))

super = fields.MSuper(pel=2, sharp=1)
backward_vec2 = super.MAnalyse(isb = true, delta = 2, blksize=blksize, overlap=overlap, dct=dct)
forward_vec2 = super.MAnalyse(isb = false, delta = 2, blksize=blksize, overlap=overlap, dct=dct)
backward_vec4 = super.MAnalyse(isb = true, delta = 4, blksize=blksize, overlap=overlap, dct=dct)
forward_vec4 = super.MAnalyse(isb = false, delta = 4, blksize=blksize, overlap=overlap, dct=dct)

#Increasing thSAD doesn't seem to help
# MDegrain2(fields,super, backward_vec2,forward_vec2,backward_vec4,forward_vec4,thSAD=400)

# Eliminate next three lines and uncomment above line to use MDegrain2 instead of MDegrain3
backward_vec6 = super.MAnalyse(isb = true, delta = 6, blksize=blksize, overlap=overlap, dct=dct)
forward_vec6 = super.MAnalyse(isb = false, delta = 6, blksize=blksize, overlap=overlap, dct=dct)
MDegrain3(fields,super, backward_vec2,forward_vec2,backward_vec4,forward_vec4,backward_vec6,forward_vec6,thSCD1=400,thSAD=300)

#UnsharpMask( clip , int "strength" , int "radius" , int "threshold" )
#strength: strength. The default is 64.
#radius: the scope of the blurring process. The default is 3.
#threshold: threshold. Absolute value of the processing component is greater than the threshold blur. The default is 8.

unsharpmask(60,3,0) #not sure whether to put this before or after the weave.

#This function is unstable under SetMTMode
#limitedSharpenFaster(smode=1,strength=160,overshoot=50,radius=2, ss_X=1.5, SS_Y=1.5,dest_x=720,dest_y=480)
#LimitedSharpenFaster(strength=150) #Default strength=150

Weave()
}



script 2:

#Function FixChromaBleeding (clip input) {

# prepare to work on the V channel and reduce to speed up and filter noise
area = input.tweak(sat=4.0).VtoY.ReduceBy2

# select and normalize both extremes of the scale
red = area.Levels(255,1.0,255,255,0)
blue = area.Levels(0,1.0,0,0,255)

# merge both masks
mask = MergeLuma(red, blue, 0.5).Levels(250,1.0,250,255,0)

# expand to cover beyond the bleeding areas and shift to compensate the resizing
mask = mask.ConvertToRGB32.GeneralConvolution(0,"0 0 0 0 0 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0").ConvertToYV12

# back to full size and binarize (also a trick to expand)
mask = mask.BilinearResize(Width(input),Height(input)).Levels(10,1.0,10,0,255)

# prepare a version of the image that has its chroma shifted and less saturated
input_c = input.ChromaShift(C=-4).tweak(sat=0.8)

# combine both images using the mask
return input.overlay(input_c,mask=mask,mode="blend",opacity=1)
}



script 3:

# removal of white dots


LoadPlugin("C:\Program Files\AviSynth\plugins\depan.dll")
LoadPlugin("C:\Program Files\AviSynth\plugins\despot.dll")

AVISource("C:\VHS.avi").AssumeTFF

i = ConvertToYV12()
d = DePanEstimate(i, trust=3)
DePanInterleave(i, data=d)
DeSpot(p1=90, p2=15, pwidth=200, pheight=2, mthres=20, motpn=true, dilate=1, seg=1, sign=-1, maxpts=10)
SelectEvery(3, 1)

VideoMilk78
12th May 2025, 21:18
Maybe because you're not converting anything to yv12?

Busty
12th May 2025, 22:38
your comment gave me a hint what to take a look at, thanks.

It seems that the function MDegrain2i2 needs the word "source=" in front of the input video to operate.

The conversion to YV12 works when I delete the word "source=" in front of my video path. However, then I get an error message stating "I don't know what 'source' means".

So, if I want the output of DeSpot to be processed by MDegrain2i2, what phrase would I need to put after the processing steps of DeSpot?

VideoMilk78
12th May 2025, 23:31
You then need to define the despotted clip then you can use than clip and run it through MDegrain2i2.
I don't like to give paste in solutions to beginners as I find that doesn't really help, often it only creates more error... This is what helped me learn

Busty
13th May 2025, 23:42
I do understand that concept of learning, I appreciate your input, but I really try to find out things myself before I post questions like this. A lot of the times I find a solution. With this one however, I'm stuck.

I guess I can enter a line "return output" after DeSpot, but MDegrain212 needs a defined source, so I think I would need a name of a clip. If I enter the name of the source clip; I fear MDegrain2i2 would process the original file, not the one processed by DeSpot. I cannot find a hint how to define a source that was created within the script.

DTL
14th May 2025, 05:04
In your script you use the very old denoise functions like from the beginning of mvtools in end of 200x. Mdegrain2i2 is sort of simple example how to use mvtools for motion-compensated denoising of interlaced clips. It is now about 0.2 century old and outdated.
To the end of the active AVS+ usage at the beginning of 202x there were developed most advanced denoisers used mvtools engine like SMDegrain on mvtools-2.7.45 and also some alternative version of mvtools branched from 2.7.45 with more advanced MAnalyse and MVs processing-refining mostly described in https://forum.doom9.org/showthread.php?t=183517 . Some practical usage you can see in M_QTGMC script. General ideas on better MVs at denoising:
1. Use multi-generation MVs refining with dual-input MAnalyse where one source is always input full-noised and second input is previous generation processed clip (by MDegrain or any other denoise engine)
2. Use voting for best MV (some averaging of 3-D objects like MV of dx,dy and dissimilarity metric members) from several MVs sources - like make sevral different denoise examples (like BM3D and KNL and MDegrain) and send to next generation MAnalyse and feed MAnalyse output to MVs voting engine (MAverage()) to select most probable MV for next generation of denoise. Also possibe at block-level in MAnalyse for Area analysis of some surrounding of current position of block in blocks tesselation grid and also processing of several motion outputs with averaging engine.
3. Use multi-level MVs search with refining from larger block size (more stable with low quality source) to smaller (better tracking of small objects and complex transforms).
4. Use several different denoise engines outputs in the engine for select the most different samples values from smoothed version (anti-detail loss method). This may make denoise quality somehow worse but save more from blurring.
5. Use MDegrainN for larger tr-values with more shorter scripting (or newer features).
6. Use 'prefiltering' as some pre-processing of input source before feeding to MAnalyse engine (one of its inputs). For prefiltering any method may be used like simple more or less blur or any complex pre-denoiser engine (like BM3D or KNL). In the mvtools-only multi-generation MVs refining the previous generation denoise output used as 'prefiltered' for next generation MAnalyse (one of inputs).

This may make quality of MVs somehow better and lower blurring of output result by MDegrain because of bad blends from bad MVs. At the low quality sources and fast motion this may make some better quality denoise.

Emulgator
14th May 2025, 08:15
script 1:
return output
This forces output from here, anything down from here is never called.
Comment that out.
# return output

script 3:
AVISource("C:\VHS.avi").AssumeTFF
This envokes script 3 on untouched source.
Comment this line out:
#AVISource("C:\VHS.avi").AssumeTFF
Then this script will work on implicit last,
meaning the output from previous script 1.

script 2 (this is actually a function, but you never call it):
#Function FixChromaBleeding (clip input) {
The # comments the function out.
Remove the #
Function FixChromaBleeding (clip input) {
and now you may call the function from script 1 or the last script.
---------------
If such processing gives a good result after these corrections I can not tell, would need a sample of your source please.
And denoising: as DTL mentions, there is newer and better. You may try the following and lower tr as you see fit
SMDegrain(tr=6, thSAD=400, RefineMotion=true, contrasharp=true, interlaced=true, plane=4, prefilter=8, chroma=true, Show=false) #5: DFTTest, 6: KNLMeansCL, 7: DGDenoise, 8: BM3D
Or even better: lose interlaced, use QTGMCp and bob up to 50p/59.94p.
This denoises internally already. If this is not sufficient enough, then afterwards
SMDegrain(tr=6, thSAD=400, RefineMotion=true, contrasharp=true, interlaced=false, plane=4, prefilter=8, chroma=true, Show=false) #5: DFTTest, 6: KNLMeansCL, 7: DGDenoise, 8: BM3D

Busty
17th May 2025, 23:02
@ DTL:
thanks for the explanation. When reading different threads, it's a bit complicated to determine which denoising methods are superior, so It's nice to have it summed up.
Having installed avisynth and virtualdub via PlayOnMac, I always thought I was stuck with avisynth 2.6, but after your comment I thought I'd have a go at installing avisynth+ 3.7.5 and it installed like a breeze. So I have a whole new world of tools available. I will try some things in the coming week and report back.

Busty
17th May 2025, 23:09
@ Emulgator:

that's a great explanation of my script errors, highly appreciated, I learned something:-)

Still the same error remains: ConverttoYV12: invalid argument

or, when I remove "source" in front of my input video line; i get "I don't know what 'source' is"

This might be obsolete when I try yours and DTL's suggestions, but I'd still like to understand what is the cause of and solution to it.

Emulgator
17th May 2025, 23:23
Please post your recent script you are working from.

Busty
18th May 2025, 18:37
gladly, it's just a combination of what I posted above with your suggestions edited in:

#JohnMeyer's Denoiser script for interlaced video using MDegrain2
#This is my recommended starting point script for VHS as of April, 2012

SetMemoryMax(768)

Loadplugin("C:\Program Files\AviSynth\plugins\mvtools2.dll")
LoadPlugin("c:\Program Files\AviSynth\plugins\Cnr2.dll")
#loadplugin("c:\Program Files\AviSynth\plugins\despot.dll")
#Loadplugin("C:\Program Files\AviSynth\plugins\removegrain.dll")
Import("C:\Program Files\AviSynth\plugins\LimitedSharpenFaster.avsi")

SetMTMode(5,4)
#Modify this line to point to your video file
source=AVISource("C:\VHS.avi").killaudio().AssumeTFF()
SetMTMode(2)

#Only use chroma restoration for analog source material
chroma=source.Cnr2("oxx",8,16,191,100,255,32,255,false) #VHS
#chroma=source.Cnr2("oxx",8,14,191,75,255,20,255,false) #Laserdisc
#Set overlap in line below to 0, 2, 4, 8. Higher number=better, but slower
#For VHS, 4,0 seems to work better than 8,2. Most of difference is in shadows
#However, 8,0 is good enough and MUCH faster. 8,2 doesn't seem to make much difference on VHS.

#output=MDegrain2i2(chroma,8,0,0)
output=MDegrain2i2(chroma,8,4,0) #Better, but slower

#output=IResize(output,720,480)

#stackvertical(source,output)
#stackhorizontal(source,output)
#return output.Levels(16, 1, 235, 0, 255, coring=false)

#return output


#-------------------------------

function MDegrain2i2(clip source, int "blksize", int "overlap", int "dct")
{
Vshift=0 # 2 lines per bobbed-field per tape generation (PAL); original=2; copy=4 etc
Hshift=0 # determine experimentally
overlap=default(overlap,0) # overlap value (0 to 4 for blksize=8)
dct=default(dct,0) # use dct=1 for clip with light flicker

fields=source.SeparateFields() # separate by fields

#This line gets rid of chroma halo
fields=MergeChroma(fields,crop(fields,Hshift,Vshift,0,0).addborders(0,0,Hshift,Vshift))
#This line will shift chroma down and to the right instead of up and to the left
#fields=MergeChroma(fields,Crop(AddBorders(fields,Hshift,Vshift,0,0),0,0,-Hshift,-Vshift))

super = fields.MSuper(pel=2, sharp=1)
backward_vec2 = super.MAnalyse(isb = true, delta = 2, blksize=blksize, overlap=overlap, dct=dct)
forward_vec2 = super.MAnalyse(isb = false, delta = 2, blksize=blksize, overlap=overlap, dct=dct)
backward_vec4 = super.MAnalyse(isb = true, delta = 4, blksize=blksize, overlap=overlap, dct=dct)
forward_vec4 = super.MAnalyse(isb = false, delta = 4, blksize=blksize, overlap=overlap, dct=dct)

#Increasing thSAD doesn't seem to help
# MDegrain2(fields,super, backward_vec2,forward_vec2,backward_vec4,forward_vec4,thSAD=400)

# Eliminate next three lines and uncomment above line to use MDegrain2 instead of MDegrain3
backward_vec6 = super.MAnalyse(isb = true, delta = 6, blksize=blksize, overlap=overlap, dct=dct)
forward_vec6 = super.MAnalyse(isb = false, delta = 6, blksize=blksize, overlap=overlap, dct=dct)
MDegrain3(fields,super, backward_vec2,forward_vec2,backward_vec4,forward_vec4,backward_vec6,forward_vec6,thSCD1=400,thSAD=300)

#UnsharpMask( clip , int "strength" , int "radius" , int "threshold" )
#strength: strength. The default is 64.
#radius: the scope of the blurring process. The default is 3.
#threshold: threshold. Absolute value of the processing component is greater than the threshold blur. The default is 8.

unsharpmask(60,3,0) #not sure whether to put this before or after the weave.

#This function is unstable under SetMTMode
#limitedSharpenFaster(smode=1,strength=160,overshoot=50,radius=2, ss_X=1.5, SS_Y=1.5,dest_x=720,dest_y=480)
#LimitedSharpenFaster(strength=150) #Default strength=150

Weave()
}



Function FixChromaBleeding (clip input) {

# prepare to work on the V channel and reduce to speed up and filter noise
area = input.tweak(sat=4.0).VtoY.ReduceBy2

# select and normalize both extremes of the scale
red = area.Levels(255,1.0,255,255,0)
blue = area.Levels(0,1.0,0,0,255)

# merge both masks
mask = MergeLuma(red, blue, 0.5).Levels(250,1.0,250,255,0)

# expand to cover beyond the bleeding areas and shift to compensate the resizing
mask = mask.ConvertToRGB32.GeneralConvolution(0,"0 0 0 0 0 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0").ConvertToYV12

# back to full size and binarize (also a trick to expand)
mask = mask.BilinearResize(Width(input),Height(input)).Levels(10,1.0,10,0,255)

# prepare a version of the image that has its chroma shifted and less saturated
input_c = input.ChromaShift(C=-4).tweak(sat=0.8)

# combine both images using the mask
return input.overlay(input_c,mask=mask,mode="blend",opacity=1)
}



# removal of white dots


LoadPlugin("C:\Program Files\AviSynth\plugins\depan.dll")
LoadPlugin("C:\Program Files\AviSynth\plugins\despot.dll")

i = ConvertToYV12()
d = DePanEstimate(i, trust=3)
DePanInterleave(i, data=d)
DeSpot(p1=90, p2=15, pwidth=200, pheight=2, mthres=20, motpn=true, dilate=1, seg=1, sign=-1, maxpts=10)
SelectEvery(3, 1)

johnmeyer
18th May 2025, 19:54
I didn't remember posting my original denoising script with all of my alternative ideas still intact. It makes if pretty confusing.

If you just want to denoise, don't forget to uncomment "# return output". You did that in post #1, but you have to remove the # in order to get the script to do anything.

As someone already suggested, you may need to do a colorspace conversion in the initial line:

source=AVISource("C:\VHS.avi").killaudio().AssumeTFF().ConvertToYV12()

Make sure to change the "AssumeTFF()" to "AssumeBFF()" if your interlaced video is bottom field first.

My ancient script uses an old version of multi-threading ("SetMTMode"). This probably won't work if you are using a reasonably modern version of AVISynth. Until you get the script working I would suggest you simply delete those two SetMTMode lines.

The white dot removal section should be moved up to the end of my script (right after the "#return output" line). If you want it to do anything, keep the comment symbol (#) in front of "return output" and then feed "output" to the first line in the despotting section, e.g., i = output.ConvertToYV12()Since, if you do what I suggest above, you have already done that color conversion, you can simply write:

i = output

Busty
18th May 2025, 23:34
Thank you John, that did it. The script opens. Now I can play with it and tweak it.

Just to understand it: Should something be different when I add "return output" at the very end of the script? I had the impression that the removal of white dots didn't work when I added that line.

I'd love to try SMDeGrain or KNLMeansCL or BM3D, but I still can't get any of those to work. Avisynth+ didn't help there.

KNLMeansCL gives me an "unrecognized system exception".

BM3DCUDA claims "module not found", which I think refers to CUDA CUDA seems to be unsupported by my Graphics Card (Nvidia Geforce 8800 GT).

SMDegrain won't open because of an exe error, which might be a 32bit / 64bit mismatch between app and plugin. Is the latest version of SMDeGrain 64bit, and if so, is there a 32bit version available?

DTL
19th May 2025, 06:21
SMDegrain is only a script but used lots of plugins (as pre-filters or masking and more) and you need to get all used plugins in 32bit versions (or set lowest settings to use a few plugins). Better to use 64bit processing software. Try to get all required plugins as 64bit builds.

Busty
19th May 2025, 14:07
it seems to be SMDegrain itself that does not work for me. I removed all plugins from the plugin folder but SMDegrain and still got this error.

I tried the current version 4.7.0d and version 1.8d, which were the only ones I could find, they both return this error.

My installation of Avisynth can load MVTools2, Dither and MaskTools, other dependencies are listed as optional.

johnmeyer
19th May 2025, 15:53
The script holds intermediate steps in variables, like "source," "chroma," and "output." At the end of the script you have to "return" one of those variables. This is usually the result of the last variable assignment which, in my original script that ends with "return output," is the variable "output." Whatever is contained in that variable is the video that your script produces.

Busty
19th May 2025, 17:21
The script holds intermediate steps in variables, like "source," "chroma," and "output." At the end of the script you have to "return" one of those variables. This is usually the result of the last variable assignment which, in my original script that ends with "return output," is the variable "output." Whatever is contained in that variable is the video that your script produces.

I see, so when I add "return output" at the end of that script, it gives me the result of MDegrain2i2, because that's where the term output is defined.

Thanks for explaining, I appreciate it.

johnmeyer
19th May 2025, 18:07
I see, so when I add "return output" at the end of that script, it gives me the result of MDegrain2i2, because that's where the term output is defined. Yes, and that's true even if there are other operations further down in the script. Those will get ignored.

Busty
28th May 2025, 14:07
I mainly used your (johnmeyer's) script as a base because I wanted to adress chroma noise and chroma shift, the denoising part is mostly a bonus. (Maybe I'll replace that part at some point as suggested)

However, I still notice some double edges, which I guess is either chroma bleeding or halo or something like that.

I upload a 20 sec sample as an example what I'm dealing with. Have a look at the face in frame 456 for example, on the forehead there is a red doubling to the right. I tried to shift it with chromashift which resulted in the same thing, only on the left side.
Or on frame 578 the red is still right of the drummers arm, and when I shift that , like 6 pixel to the left, I see it appearing left from the singer's head.

There's also a similar effect visible on the TV logo, is that the same issue? What exactly am I looking at, e.g. what would you call this issue?

Can this script be tweaked to adress this (on the halo line) or would I need to insert something else?

Edit: Sample upload needs to wait,I get an error from the site (security token missing) and guess I need to wait for an admin to answer...

Busty
2nd June 2025, 17:15
ok, here are two files, one is an unalterered 20 sec video and one is the output of the script. Any tips how to get rid of the chroma bleed - or shift?

https://limewire.com/?referrer=pq7i8xx7p2

johnmeyer
2nd June 2025, 19:39
Your link didn't take me to a file and instead just took me to the file sharing site.

Therefore, I don't know what your chroma problem looks like. The CNR function is for chroma shimmering, not chroma shift. If you have a colored halo which follows the outline of an object at the transition between light and dark, you need to set a non-zero value for HShift and/or VShift (found in the MDegrain2 function). In the last code you posted, you had enabled the feature but still had Hshift set to 0. Try 1, 2, or 3 and see what you get. If you set it too high, you'll create halos on the other side. I don't think negative values are needed for VHS, but I haven't used it for a long time, so I can't say for sure.

As my comment in the code you posted said, you need to "determine experimentally" (i.e., trial and error) to see what value works for your clip.

Hshift=0 # determine experimentally

Busty
2nd June 2025, 22:03
ok, great, I'll try that.

my bad concerning the links. For me, it points to the site showing both links, but here are the actual links to the files:

https://limewire.com/d/ijXMk#B1VXd3KPAJ
https://limewire.com/d/eGm8J#xgqeAYGxAZ

Busty
3rd June 2025, 14:20
I tested changing the shift values and have the impression that a vertical and horizontal shift of 2 yields the most appropriate result for this video.

I *think* it looks better. There were some greenish lines at the top before shifting, afterwards they are at the bottom and on the right side. (I guess I can make them disappear if I crop the fuzzy edges after shifting, I'll try that with a future capture)

However, there is still some halo or something similar around the edges, just not as vibrant as before. Can these be adressed somehow?

https://limewire.com/d/gnkVw#2kCAj6IaY2

Edit: let me know if I should use a different upload service.

Emulgator
4th June 2025, 00:07
mediainfo says about the source 770x574x25.
Since this had been a PAL broadcast any "untouched" capture should return PAL 720x576x25i.
Before the search for those missing lines ends in vain: How did you obtain that capture ?
Any uneven cropping before your desired processing destroys the hints your next algos have to rely on.
Cropping should be applied later.

Busty
4th June 2025, 22:15
Right. Thanks for looking at my files.

With that capture, I made a mistake while cropping and padding the edges. My capture card (MiroMotion DC30+) creates 768 x 576 square pixel and I wanted to get rid of the fuzzy edges, I just messed up the padding part. With "unaltered" I meant that it's not compressed or converted.

I see your point and I will move the crop/pad part to the end of my processing chain. Thanks for pointing that out.

In fact I captured that video again:

https://limewire.com/d/8b7Y8#A4tTwZhxaW (unchanged)
https://limewire.com/d/4fouD#Olhfo0Ok7S (run through script)

I noticed a part of the video where the chroma shift is way worse than before, look at the drum sticks and the red near it:

https://limewire.com/d/5Dj4S#INxuVeq1UA (unchanged)
https://limewire.com/d/tgI65#VAp0kZ6N93 (run through script)

Is this chroma processing using temporal information? If so, this video might have an issue. I don't know why, but there is something going on with the field order. After processing, when I play deinterlaced with yadif2, playback is stuttering. I can repair that, but if chroma processing uses temporal information, the fields issue might disturb the outcome. I described it here:

https://forum.doom9.org/showthread.php?p=2019258#post2019258

Emulgator
6th June 2025, 23:23
MiroMotion DC30+ (1998) should deliver MJPEG ? Well then...
Sample 3: There had been recoding damage already, Histogram has holes/peaks.
Capturing device: I was recommended a Hauppauge USB Live 2 here, and it can indeed deliver 4:2:2 8bit uncompressed,
and is less picky about TBC issues than my other Video ADC (Blackmagic Intensity Shuttle USB3, 4:2:2 10bit uncompressed)

A quick and dirty approach, not tailored in any way.
No caring about Dehaloing /Chroma here, this is up to you.
v=LWLibavVideoSource"<yourpathhere>"
a=LWLibavAudioSource"<yourpathhere>""
AudioDub(v,a)
propSet("_FieldBased",1)
#QTGMC(EdiMode="BWDIF+NNEDI3", tr2=3, sharpness=1.0, Lossless=2, SourceMatch=3, Sbb=1, ShowSettings=false, Denoiser="KNLMeansCL", NoiseTR=2)
QTGMCp(InputType=0,EdiMode="BWDIF", tr2=3, Rep1=2, RepChroma=true, ChromaMotion=false, DenoiseMC=true, sharpness=2.0, lossless=0, NoiseProcess=1, GrainRestore=0.0, NoiseRestore=0.5, ChromaNoise=true, show=false)
ChromaShiftSP(X=2.0, Y=2.0)
SMDegrain(tr=6, thSAD=400, RefineMotion=true, contrasharp=false, interlaced=false, plane=4, prefilter=8, chroma=true, Show=false) #5: DFTTest, 6: KNLMeansCL, 7: DGDenoise, 8: BM3D
MedSharp(str=3)

Busty
9th June 2025, 11:51
Thanks again, Emulator.

The DC30+ runs with a driver from squared5 which supports multicodec input, I can use every codec quicktime can read. I guess you are talking about the pinnacle windows driver, which is less flexible iirc.
The Happauge USB Live 2 only has windows drivers, so I can't go for that one on a mac, but I'm quite content with my DC30+. But I'd sure like to hear anyone's opinion on that card or / and my capture quality.

here's a link to the driver and description
http://www.squared5.com/svideo/dc30-xact-mac.html

I tested some different devices (Aurora Fuse and Fuse X, Miglia Alchemy DVR, Canopus ADVC-300 Blackmagic Intensity Shuttle TB) and liked the DC30+ most.

Good observation on the histogram of the processed file, I took a look at it after your comment and see the luma levels being too widespread. I'll have to examine which part of the script is responsible for that (I'm open to suggestions about that though:-))

On the unprocessed capture the highs seem to be fine around 225, maybe the lows are a bit tight with a value of 10?

ATM I'm trying to test your suggested script. As I'm at a 32bit setup, I can only use BWDIF 1.2.1 latest, which does lack some settings QTGMCp wants to set, namely thr and pass. I also had to change SMDegrain's prefilter to 5 because I cant' use CUDA (yet) and delete the show=false argument. Processing runs at 0.7 fps...
The rsulting file has luma low value nailed to 0, is that how it is supposed to be? Doesn't this need to be at 16, lowest?

While the result looks pretty good regarding noise, I would rather not deinterlace the file itself but only when playing back, so QTGMC might not be the path to go for me.

And I still see these red areas around the drum sticks on sample 3, sometimes preceeding, sometimes following the drum stick, of which I don't know why there are there.

So, your comment made me aware of color space issues once more.

In the end, I want to digitize about 200 VHS tapes, 95% recorded with the same recorder from tv concert broadcasts. The capture part is solved, and i'm looking for a mostly automated process after capture. I'm getting myself a CUDA-compatible GPU for BM3D denoising, but am still searching for a way to adress chroma noise / bleed / halo and of course I want to stay within valid color spaces after all the conversion.

Because I don't want to adress every video with dedicated settings, I'd go for more sensitive settings that don't overdo anything.

Is there a way to examine a whole video for color values and shift them automatically to a desired value while staying in YUV? Would that make some sense?

Busty
10th June 2025, 15:23
regarding the levels: I can't see which part of the initial JohnMeyer's script produces these extremes. Is there distortion already or is it still within the representable range of values?

I can tame them with autolevels, but I don't know if that is sufficient: When I add autolevels at the end of the script, does it just shift values that are already distorted before?

Emulgator
11th June 2025, 10:37
Well, your side has to run on a mac, and I can not tell how, but I get the suspicion that there might be something wrong in your decoding chain, Quicktime, that is...
I get moving drumsticks without any temporal artifacts, and no crushed blacks, Y sits nicely 16..230.

Selur
11th June 2025, 15:03
I was playing around with BasicVSR++ to see when the debluring model (7,8) were useful, I did a few test-encodes (using this Vapoursynth script (https://pastebin.com/45HrNMa8) and only switching the models).
The conclusion was, that drum sticks are too fast for the deblurring models of BasicVSR++, but in case anyone is interested I uploaded the clips (https://www.mediafire.com/folder/lrda8gcfhktws/basic_vsr_models).

Cu Selur

Busty
11th June 2025, 17:41
Emulgator,

yes, the "red stick ghost" seems to be gone when using your untailored script. But the reported levels are still on 0 / 255 for that frame. It doesn't look blown though and the luma curve looks fine, as far as I can tell. I cannot wrap my head around why this is that way.

What I also don't understand is: When I apply autolevels, the values look fine, but the image has visible distortion.

As you are using the same file as me and get satisfactory results, any problems need to be in my usage of avisynth or virtualdub. The problem is already seen in virtualdub.

Maybe I changed your script in a way that results to this (or I might need to check plugin versions):

loadplugin("C:\Program Files\AviSynth\plugins\masktools2.dll")
loadplugin("C:\Program Files\AviSynth\plugins\mvtools2.dll")
loadplugin("C:\Program Files\AviSynth\plugins\nnedi3.dll")
loadplugin("C:\Program Files\AviSynth\plugins\RgTools.dll")
#loadplugin("C:\Program Files\AviSynth\plugins\SMDegrain.avsi")
loadplugin("C:\Program Files\AviSynth\plugins\AutoLevels_x86.dll")


AVISource("Z:\Volumes\Video\sample3_unaltered.avi").ConverttoYUV422
propSet("_FieldBased",1)
QTGMCp(InputType=0,EdiMode="BWDIF", tr2=3, Rep1=2, RepChroma=true, ChromaMotion=false, DenoiseMC=true, sharpness=2.0, lossless=0, NoiseProcess=1, GrainRestore=0.0, NoiseRestore=0.5, ChromaNoise=true)
ChromaShiftSP(X=2.0, Y=2.0)
SMDegrain(tr=6, thSAD=400, RefineMotion=true, contrasharp=false, interlaced=false, plane=4, prefilter=5, chroma=true, Show=false) #5: DFTTest, 6: KNLMeansCL, 7: DGDenoise, 8: BM3D
MedSharp(str=3)
#Autolevels(border=8)
Crop(2,0,0,-8)
#ConvertToYV12(interlaced=true)
ColorYUV(Analyze=true)
#turnright.Histogram.turnleft
Histogram("Levels")
#Histogram("color2")
return last

untailoredScript Sample: https://postimg.cc/hJFpVhfq
untailoredScriptWithAutolevels Sample: https://postimg.cc/xXN6kLjR

2nd untailoredScript Sample: https://postimg.cc/JtK6S1db
2nd untailoredScriptWithAutolevels Sample: https://postimg.cc/xkKg5YzN

Emulgator
11th June 2025, 18:12
LWLibavVideoSource please, and no ConvertToYUV422.

Sharc
11th June 2025, 19:34
.... And I still see these red areas around the drum sticks on sample 3, sometimes preceeding, sometimes following the drum stick, of which I don't know why there are there.

Sample3: Your script (which script did you use?) messes up something (chroma). See the red ghosts around the drum sticks (picture on the right).

https://mega.nz/file/Sd1ChKxJ#XrtRLlD9-coxfoXOBfwWRbxFWaTfnbszS-cbvXQnuIE

Edit: While I posted ..... Seems that got clarified and sorted out. Never mind.

Busty
12th June 2025, 12:49
LWLibavVideoSource works as input, but without conversion I get an error "YUY2 format not allowed", appearantly from ExTools and SharpenersPack.

Changing the input filter does not help the min and max levels.

Emulgator, does my file open for you without conversion, or which conversion did you do?

And it seems I spoke too soon regarding the ghosts around the drum sticks, they are still there at some frames, for example at frames 160-167.

I used the script Emulgator thankfully provided, as well as the one based on JohnMeyer's script on page 1 of this thread https://forum.doom9.org/showthread.php?p=2018663#post2018663

The red ghost sticks are present with both scripts.

Emulgator
12th June 2025, 13:10
mediainfo sees "sample3_unaltered.avi" as ULY2 4:2:2 8bit.
LWLibavVideoSource decodes "sample3_unaltered.avi" as YV16 here, not YUY2.
BSVideoSource decodes "sample3_unaltered.avi" as YV16 here, not YUY2.
FFVideoSource decodes "sample3_unaltered.avi" as YV16 here, not YUY2.
I apply no conversion, and get all frames without chroma ghosts.

If there are ghosts, then there is wrong choma placement involved. Why only applicable for a few frames, I can not tell.
UT has changed over the times, there are incompatibilities across versions !
On this emergency replacement system of mine I have no standalone UTVideo installed,
so the AviSynth decoders use their internal UT implementation here.

Try uncompressed.

Sharc
12th June 2025, 14:02
Sample3_tweaked.avi is a flawed interlaced 4:2:2 to 4:2:0 (YV12) conversion IMO, therefore the chroma ghosting. See the attached slowmotion video. On the right you can see that the chroma (U,V) advances not correctly in sync with the bobbed (deinterlaced) source fields. It advances at framerate (baserate) only, producing the ghosts.
https://mega.nz/file/XJtiHKAB#RBoXm-ZnsTvFMxTFPUfdc_uJ8EVGRv4LUJuvzHgnTMI

Added: And for comparison the Samle3_unaltered which is interlaced 4:2:2. One can see that the chroma (U,V on the right side) advances correctly and synchronously with the bobbed fields.
https://mega.nz/file/aZdDlbYS#YrSCVm6bGSXcceecQZVNUvjsAE7IPkyyLLIXXLpGEhQ

So the conversion from interlaced 4:2:2 to interlaced 4:2:0 was not done properly IMO (Script, encoder ... whatever).

Busty
12th June 2025, 19:07
@ Emulgator

mediainfo reports the same for me.

I tried the original captured file, before I converted to UTVideo. That one is reported as 2vuy 4:2:2 lossless by mediainfo. I also captured a part again, just to make sure.

It does open too, but still needs conversion; this time, I did converttoYV16. The min / max values are still 0 / 255 (or nearby for any other frame), so UTVideo seems to not be responsible.

But I found that when I delete the MedSharp part of the script, the values do not sit at 0 / 255 but within a very much better range. Still more expanded than the original file, but not always scratching on 0 / 255.

It's still a mystery to me why it opens without color space conversion for you but not for me. Thanks for all the input and time!

@ sharc:

thanks for taking the time to produce the examples and upload them.
Just so I understand correctly: Could a conversion from interlaced 4:2:2 to 4:2:0 produce this behaviour? Is this drum stick situation maybe a good example of the benefits of 4:2:2, because it moves so fast that 4:2:0 is just too slow at half the speed of 4:2:2? Or could this be produced by wrong field order? I'm asking because at one point this video had field order issues that did not show upon normal playback, but only when deinterlaced with yadif2. Fields/frames moved back and forth which reminded me of the red ghost sticks sometimes preceeding, sometimes following the luma drum stick.

Sharc
12th June 2025, 20:54
But I found that when I delete the MedSharp part of the script, the values do not sit at 0 / 255 but within a very much better range. Still more expanded than the original file, but not always scratching on 0 / 255.
Sharpening often causes sharpening artifacts like overshoots (halos) around edges, extending the luma shortly to >235 and <16 locally. Use a waveform monitor rather than coloryuv(analyze=true) which catches any instantaneous local min/max extremes which can be misleading.

Just so I understand correctly: Could a conversion from interlaced 4:2:2 to 4:2:0 produce this behaviour?
Yes, if the conversion is done incorrectly.
Is this drum stick situation maybe a good example of the benefits of 4:2:2, because it moves so fast that 4:2:0 is just too slow at half the speed of 4:2:2?
No. Imagine that all DVD's, Blu-rays, Broadcast video are 4:2:0. It has nothing to do with motion speed but rather with spatial color resolution (as you can see on the size of the U,V panels of my uploaded chroma motion examples). The ghosting is basically everywhere present in your tweaked video, one just doesn't notice the "ghosts" in static scenes. It becomes visible in motion scenes only.
Or could this be produced by wrong field order?
No. This would just produce jerkiness.


- How did you convert the unaltered 4:2:2 source to 4:2:0 for your tweaked variant? Dis you use ConvertToYV12() instead of ConvertToYV12(interlaced=true) while the video was still interlaced?

- Maybe your script accepts planar 4:2:2 YUV only, so you could try ConvertToYV16(interlaced=true) which converts stacked to planar format.

Revisit your script. (I didn't follow the entire history of this thread, so I may have missed something).

Emulgator
12th June 2025, 23:13
Med Sharp will indeed exaggerate values, as this is to be expected with any sharpening kernel.
As Sharc mentioned.
Just uncomment it, it was just cosmetic to show possibilities.

Just so I understand correctly: Could a conversion from interlaced 4:2:2 to 4:2:0 produce this behaviour?

Yes.

PAL, (NTSC, SECAM) had been broadcast linewise, so, taking into account that any broadcast chroma has to be restricted in bandwidth from the start anyway,
the 4:2:2 professional storage subsampling was the appropriate sampling format for all systems BEFORE broadcasting,

After broadcasting on PAL consumer side 4:2:0 had been chosen as the storage format (as the halfway effficient way out),
because every other 64µs chroma line had to be transmitted phase alternated, on receiver side stored away in an 64µs analog delay line
and processed with the previous line, canceling out out phase error, but effectively halving chroma line resolution.

Then digitally storing this as a 4:2:0 576i25 "field-frame" and not as 2 288p50 fields had (quote:) "(and 'i' means it is) irreversively destroyed"
any sane way of linewise chroma representation for decades to come. Well, these days one can reconstruct from that mess.

BUT: As long as you have an analog linewise recording (which VHS is), staying at 4:2:2 is of advantage as long as the processing chain deals with interlaced.
Once an elevated deinterlacing-with-bobbing-algo has successfully restored temporally and spatially clean full frames, knowing about these PAL implications,
you may resort to 4.2:0 for storage, because the restored chroma from that limited transmission bandwidth now is just worth these 4:2:0. (From VHS much less, and luma-guided chroma restoration out of the equation, of course)

SECAM (Séquentiel couleur à mémoire) would as well use a 64µs line worth of chroma storage, IIRC.
(As I was born into SECAM land ;-) I still remember these potted-in-blue delay lines like HxWxD 50x30x8mm³ from my color TV excursions.)

NTSC would need a different approach.
Since there is no chroma line storage buffer involved, chroma is indeed transmitted unique for every line (although even less bandwidth given).
Hence the appropriate subsampling representation on consumer side had been chosen as 4:1:1 (NTSC-DV, that is),
in the end sharing the same storage requirements between both systems.

Sharc
13th June 2025, 07:25
Just to add that PAL may suffer from Hanover bars caused by non perfect cancellation. These usually manifest as horizontal color stripes. I doubt however that Hanover bars are the main problem with the OP's tweaked 4:2:0 file with the red ghosts, as these would also be present in his original unaltered 4:2:2 capture. So I still think the OP should revisit his 4:2:2 -> 4:2:0 conversion, or stay in 4:2:2 throughout his workflow.

Busty
13th June 2025, 12:22
Yes, I indeed converted with ConvertToYV12(). It was AssumeTFF().ConverttoYV12(). Does the AssumeTFF() argument change anything? If not, then you found the reason for ghosts playing drums:-) Thank you for finding and for explaining that to me. I learn things here that I never would have thought I'd need to deal with... Really appreciated!

I converted to ConverttoYV12 because I had Despot in my script. I just read on Despot's description that it also supports "special planar YUY2" format (is that YV16 then?), so maybe I can change that to stay in 4:2:2. Which I'd prefer either way. Also, that script is not final yet, so requirements from plugins may change. I'll keep an eye out for proper conversions.

Thank you again Emulgator & Sharc for this excursion.

Back to my task to find a good way for chroma shift, but maybe I'll wait for my CUDA-compatible GPU first...

Sharc
13th June 2025, 13:11
Your Sample3_unaltered.avi is interlaced, Bottom Field First, hence AssumeBFF() would be correct, regardless what MediaInfo may tell you.
If you want or need to convert to 4:2:0, use ConvertToYV12(interlaced=true)
If you want/need 4:2:2 planar use ConvertToYV16(interlaced=true) instead.

(In any case you should always know whether your video is interlaced or progressive before applying a certain filter, and use the filters accordingly. Take note that many filters work on progressive video only and are not interlace aware. Filtering of interlaced video is a topic of its own).

lollo2
13th June 2025, 17:14
If you want/need 4:2:2 planar use ConvertToYV16(interlaced=true) instead.

from 4:2:2 interleaved (YUY2) to 4:2:2 planar (YV16) the parameter interlaced=true is not needed ;)

from http://www.avisynth.nl/index.php/Convert:
Note, interlaced=true has an effect only on YV12↔YUY2 or YV12↔RGB conversions. More about that can be found here.

Sharc
13th June 2025, 17:30
from 4:2:2 interleaved (YUY2) to 4:2:2 planar (YV16) the parameter interlaced=true is not needed ;)

from http://www.avisynth.nl/index.php/Convert:
Note, interlaced=true has an effect only on YV12↔YUY2 or YV12↔RGB conversions. More about that can be found here.
Yep, thanks. I left it routinely in as it does no harm either ;)

Lucky38
16th February 2026, 09:25
hello,

i'm looking any help with removing horizontal lines on this picture:

https://i.postimg.cc/sXWp38dy/sample.png

mainly those on top of the pictures.

i have used Busty's script to clean up some problems, but i can't remove those lines...

rgr
16th February 2026, 14:53
Every frame or every other? A video clip would be helpful.

Lucky38
16th February 2026, 15:24
Every frame or every other? A video clip would be helpful.

https://mega.nz/file/JdBRzDJQ#nmJg67FetxfPyjFJMKc9pdxqalIps17HvYPwKXwQa3M

rgr
16th February 2026, 15:25
https://mega.nz/file/JdBRzDJQ#nmJg67FetxfPyjFJMKc9pdxqalIps17HvYPwKXwQa3M

"Nie można uzyskać dostępu do pliku"

Edit: Już OK, musiałem się wylogować ze swojego konta.

Edit2: Straszna kiszka, 25p zamiast 50p lub 50i. Trzeba zgrać jeszcze raz i niekoniecznie do MPEG2.

Lucky38
16th February 2026, 15:31
"Nie można uzyskać dostępu do pliku"

Edit: Już OK, musiałem się wylogować ze swojego konta.

Edit2: Straszna kiszka, 25p zamiast 50p lub 50i. Trzeba zgrać jeszcze raz i niekoniecznie do MPEG2.

uzywam easy CAP +VHS to DVD 3.0

nie mam jak lepiej tego zgrac.

edit1: no chyba że polecasz jakis sprzęt lepszy do tego zadania.

edit2: moze inny soft?

rgr
16th February 2026, 15:47
uzywam easy CAP +VHS to DVD 3.0

nie mam jak lepiej tego zgrac.
edit1: no chyba że polecasz jakis sprzęt lepszy do tego zadania.
edit2: moze inny soft?

Zgraj VirtualDubem bezstratnie (Huffyuv, FFV1, ewentualnie ProRes). W innych wątkach znajdziesz mnóstwo informacji jak to zrobić. Takie pasy występują też przy kiepskim VCR.

Lucky38
16th February 2026, 15:52
Zgraj VirtualDubem bezstratnie (Huffyuv, FFV1, ewentualnie ProRes). W innych wątkach znajdziesz mnóstwo informacji jak to zrobić. Takie pasy występują też przy kiepskim VCR.

dzieki za podpowiedzi.

edit1: czy wedlug tego powinienem robic?

https://www.doom9.org/index.html?/capture/capturing_vdub.html

pytam, bo nigdy tego nie robiłem

Columbo
16th February 2026, 17:01
Forum rule 13: only English is allowed. Thank you.

Lucky38
16th February 2026, 20:24
sorry. I will remember.

Sharc
17th February 2026, 10:29
https://mega.nz/folder/DYUEBAbD#NFXbMl2irutkz91ayZPn9A

Lucky38
18th February 2026, 14:37
https://mega.nz/folder/DYUEBAbD#NFXbMl2irutkz91ayZPn9A

@Sharc,

looks good.

Could you please share script you have used to clean this out?

Lucky38
18th February 2026, 14:41
i have got even worse vhs

https://mega.nz/file/xQglUQSB#cSf_zxfJpZJHw3-mYPT8q6a9VOKpEmTRHyP1-Wu-SQo

Sharc
18th February 2026, 17:08
@Sharc,

looks good.

Could you please share script you have used to clean this out?
Oh, I deleted the script. So from memory the steps were:
- downscale vertically and re-upscale, which blurs the horizontal stripes
- Then apply some denoiser to clean it up a bit
- Also, I think I reduced the color saturation as the clip was oversaturated.

But principally you should think about recapturing the tape properly into lossless interlaced 4:2:2 format to begin with..... and only then postprocess it.

AVIL
19th February 2026, 21:25
Hi:

A quick denoise for your video:


p1=avisource("W:\sample_vhs.avi").converttoyv12()
p2=p1.mergechroma(p1.frfun7(tuv=128.0))
p2.vhsclean()


You can grab vhsclean from https://forum.doom9.org/showthread.php?t=185261

Busty
12th March 2026, 00:18
I'd like to add those diagnostics to my inventar, that shows all those clip info, including the field order which is shown in Emulgators screenshot on page 2 of this thread. I'm talking about the info in the green line at the top of the screenshot. And while i'm at it, the histograms on top and on the side of the frame would be nice to have, too.

can I add them to a script somehow?

https://forum.doom9.org/showthread.php?p=2019566#post2019566

StainlessS
12th March 2026, 02:23
I'd like to add those diagnostics to my inventar,

PortalScope:- https://forum.doom9.org/showthread.php?t=186015

EDIT: Similar-ish,
VideoTek (Avisynth and MPV Waveform Monitor) :- https://forum.doom9.org/showthread.php?t=175249

Tempter57
12th March 2026, 08:59
https://mega.nz/file/JdBRzDJQ#nmJg67FetxfPyjFJMKc9pdxqalIps17HvYPwKXwQa3M

https://mega.nz/fm/YaYG0LTD
The script is based on idea by Dogway

prefix="C:\Program Files (x86)\AviSynth+"
AddAutoloadDir(prefix+"plugins64")

setmemorymax(8000)

FFvideoSource("C:\Users\Asus\Downloads\sample_vhs.mkv", rffmode=0, threads=1).AssumeFPS(25.000)

ConvertToYV16()

SmoothTweak(contrast=1.0, saturation=0.65, hue1=-1, hue2=1, HQ=true,TVrange=false, Limiter=False)

LevelsLumaOnly(input_low=0, gamma=1.0, input_high=244, output_low=16, output_high=235, coring=false, dither=true)

spline36resize(720, 288)

bifrost(interlaced=false).ASTDR(strength=5, tempsoftrad=3, tempsoftth=7, tempsoftsc=6, tht=255, dcn=15, edgem=false, exmc=false)#.MergeLuma(video_org_sep_even, 0.66).MergeChroma(video_org_sep_even, 0.33)

SceneStats("Range+Stats")

Stage=06

PREl1 = ex_autolevels( true ,true, true,Deflicker=true,tv_out=false)
PREl2 = ex_autolevels(PREl1,false,true,false,Deflicker=true,tv_out=false)
PREmo = ex_Median(PREl2,mode="IQMST", UV=3,thres=min(100,(Stage*10)))
PREm = ex_blend(PREl2,PREmo,"blend",opacity=0.3).ex_sbr(1,UV=3)

PREs = SMDegrain(mode="TemporalSoften", tr=6, thSAD=(Stage*70), thSADc=(Stage*60), thSCD1=max(400,(Stage*80)), Str=2.0, contrasharp=false, LFR=false, DCTFlicker=false, refinemotion=false, truemotion=true, blksize=16, search=5, pel=2, subpixel=3, prefilter=PREmo, chroma=true, plane=4, gpuid=-1, interlaced=false)

SMDegrain(mode="MDegrain", tr=6, thSAD=(Stage*60), thSADc=(Stage*50), thSCD1=max(400,(Stage*70)), Str=2.0, contrasharp=true, LFR=true, DCTFlicker=true, refinemotion=true, truemotion=true, blksize=16, search=5, pel=2, subpixel=3, mfilter=PREm, prefilter=PREs, chroma=true, plane=4, gpuid=-1, interlaced=false)

ex_unsharp(Stage/40.).ex_unsharp((Stage/20.),Fc=width()/1.5)

nnedi3_rpow2(rfactor=2,cshift="lanczosresize",fwidth=720,fheight=576)

# ==== Sharpening ====

F3KDB_3(range=20, Y=32, Cb=24, Cr=24, grainY=24, grainC=16, dither_algo=2)

ConverttoYV12()

Prefetch(8, 16)

Script for sample_2.mkv
prefix="C:\Program Files (x86)\AviSynth+\"
AddAutoloadDir(prefix+"plugins64")

setmemorymax(8000)

FFvideoSource("C:\Users\Asus\Downloads\sample_2.mkv", rffmode=0, threads=1).ChangeFPS(25.000)

Jinc144Resize(640, 480, 0,0,-80,-96)

ConvertToYV16()

SmoothTweak(contrast=1.0, saturation=0.89, hue1=-0, hue2=0, HQ=true,TVrange=false, Limiter=False)

LevelsLumaOnly(input_low=14, gamma=1.0, input_high=237, output_low=16, output_high=235, coring=false, dither=true)

SpotLess(BlkSz=12, OLap=4, pel=2, Tm=false, Bblur=0.0, ThSAD=1000, RadT=1)
MCTD (settings="high")

mergechroma(aWarpSharp2(depth=8, blur=3, type=1)).EEDI3()
turnright()
mergechroma(aWarpSharp2(depth=8, blur=3, type=1)).EEDI3()
turnleft()

F3KDB_3(range=20, Y=32, Cb=24, Cr=24, grainY=24, grainC=16, dither_algo=2)

ConverttoYV12()

Prefetch(8, 16)

Busty
12th March 2026, 10:47
yes, thank you Stainless, great! Thanks to Emulgator and hanfrunz, too!

Now I see that my captures all are BFF. This either happens during capture or during conversion to utvideo with ffmpeg.

I do the conversion like this:

(ffmpeg -i video.mov -c:v utvideo -vf format=yuv422p -an video.avi)

When I play them in VLC with deinterlace on and set to yadif (2x), the video playback is jerky (kinda back and forth stuttering)

I can get rid of that with a small script that goes like this:

SeparateFields()
Trim(1,0)
Weave()

They play fine then with yadif (2x), but PortalScope still reports them as BFF.

Wouldn't it be better to convert them to TFF and if so, how can I achieve that?

StainlessS
12th March 2026, 12:21
I think (but am not sure) that BFF is the Avisynth default unless you use eg "AssumeTFF",
Perhaps Portalscope is just reporting the default field order as it has not been changed by you (or script).


SeparateFields()
Trim(1,0)
Weave()
AssumeTFF()


Above is maybe not the best fix (maybe an odd field [EDIT: or more likely duplicate field] left at end of clip).

@Emulgator, care to comment. :)

Emulgator
13th March 2026, 14:36
Yes, Portalscope just reports what AviSynth thinks what it is using GetParity()

So Tempter57's source might not be first generation, and Busty's Source:
AviSynth (and Portalscope) do not know what field order any capture card delivered in reality,

AviSynth just assumes BFF for anything that could have been DV-AVI and passes that down the river,
right or wrong, until someone comes along and checks for real, and corrects if necessary.

As always: Separate Fields() to find out what the real field order is, then AssumeTFF() or BFF().
From then on the flagging can be assumed correct.

johnmeyer
13th March 2026, 17:28
... As always: Separate Fields() to find out what the real field order is, then AssumeTFF() or BFF().
From then on the flagging can be assumed correct.Exactly. While people are doing less with interlaced video these days, that advice should be given to everyone who ever encounters interlaced video for the first time. I have seen WAY too much video that was edited using the wrong field order and you then end up with all those strange artifacts when the camera pans horizontally.

Busty
14th March 2026, 22:10
Thanks Emulgator and johnmeyer. I tried that and PortalScope still reports BFF after SeperateFields(). However, for VLC playing it smoothly with yadif2, I need to add AssumeTFF after the file input. I can add AssumeTFF or AssumeBFF at the end without noticing any change, it plays fine either way.

I mean, I am fine with adding AssumeTFF after file input, I was just wondering if this introduces any problems I don't think/know of right now.

Busty
21st April 2026, 14:51
ok, onto the next issue while on my quest to search for my post processing workflow:

I'd like to use QTGMC for some videos, but run into a problem: The lower half of the frame has annoyimg artefacts, as seen in the screenshot. The upper half is fine. When I convert to YV12 or when I use SourceMatch=0 it looks fine. With YV24 it's even worse, then the upper right quarter is affected too.

Obviously, I would like to use YV16 or YUY2 and SourceMatch=3

This happens with AviSource and LWLibavVideoSource as input.

Does someone know what I can do about it?

https://limewire.com/d/sXh1r#iQSfoltn6P

Sharc
21st April 2026, 17:05
ok, onto the next issue while on my quest to search for my post processing workflow:

I'd like to use QTGMC for some videos, but run into a problem: The lower half of the frame has annoyimg artefacts, as seen in the screenshot. The upper half is fine. When I convert to YV12 or when I use SourceMatch=0 it looks fine. With YV24 it's even worse, then the upper right quarter is affected too.

Obviously, I would like to use YV16 or YUY2 and SourceMatch=3

This happens with AviSource and LWLibavVideoSource as input.

Does someone know what I can do about it?

https://limewire.com/d/sXh1r#iQSfoltn6P
Upload a snippet (few seconds) of the source video to a filehoster so users can check. Pictures don't reveal much.

Emulgator
21st April 2026, 18:08
This was a plane rendering fault, mvtools2 IIRC ?
Update all concerning plugins. Later versions should be free of that.

Busty
22nd April 2026, 21:32
Hey Sharc, I was just about to upload a snippet of the video when I read Emulgator's comment and tried that first. Good call, there were lots of plugins to be updated! Still, the issue remained after updating every dependency for QTGMC. But recently, I had the occasion where it wasn't enough to update a plugin, I additionally had to remove other versions, I think it was masktools or mt_masktools which got in the way of masktools2. Might have been a different plugin.
Long story short, I updated all required plugins, tossed everything else out of the plugins folder and now it seems to work properly.

So, thanks again, Emulgator, your input is appreciated as always!

Busty
27th April 2026, 13:26
QMGMC is working, but now I experience changing colors in every other frame.

Maybe this is even present in the original file already. When I play the unchanged file in VLC with yadif(x2), I see the same color problem. So this might be happening during capture, though I wouldn't know why and how to avoid it.

Does anyone know what causes this and how to get rid of it?

This time with 10 sec snippets :-)

befroeQTMGC: https://limewire.com/d/hCWGH#2eL1viXFBK
afterQTGMC: https://limewire.com/d/7vzfl#JiJncMfU9R

Sharc
27th April 2026, 19:44
The problem is in the source. One field has a tint shift compared to the other field. You can try to tweak the color of one of the fields for a better match.

Does this look any better to you?
https://mega.nz/file/vQEyHSwK#UktTn3HNxGAHcFjNY3Rta8VWvxchUuaLCzbB8tofVSI

Busty
27th April 2026, 21:20
Thanks for looking at and playing with my files, Sharc. And yes, your file does look way better, I wouldn't notice that problem with this one. Could you share what you did exactly? I guess that would help me a lot.

Most likely I have this problem with all my captures then, but only notice it when processing them as 50fps.

I can rule out the VCR and TBC since I used different VCRs and also see this on captures without TBC. I'm suspecting my capture card or conversion from apple quicktime to utvideo.

Sharc
28th April 2026, 08:04
Something like this:
AVISource("beforeQTGMC.avi")
assumeBFF()
separatefields()
e=selecteven()
o=selectodd()
e=mergechroma(e,o,1.0) #copy the chroma of the odd field to the even field
interleave(e,o).weave() #re-interlace

qtgmc()
#optionally add derainbow/denoise filter(s) here ....

Busty
28th April 2026, 09:27
Thank you, Sharc.

While this is definitely an upgrade, it means that I loose some chroma information and I might need to check what happens at scene changes with this merged chroma.

So finding what causes this would still be preferable. I will check if this happens with a different codec during capture too and with a different capture card and report back.

Busty
6th May 2026, 20:32
I narrowed it done to the capture card. I checked three units of the card, they all have the same outcome, while a different card (Aurora Fuse) with a different driver looks fine. I also let the DC30 capture with a different driver and the issue is also present with that other driver. Unfortunately, I would have to run the other (Aurora) card on an older system and can't get it to work without getting substantial dropped frames. Also, while colors seem fine, my impression is that with the Aurora card, everything does look a bit worse overall. So it wouldn't be an ideal switch to begin with.

So I guess I live with this flaw. Still, I'd like to adress it, to make the impact as small as I can get it. For this goal, I'd like to tweak the colors of only the, let's say, odd field. I imagine that the tint is always the same on all captures, although I need to check that.

Now my scripting abilities are very limited, I tried to make a script that manipulates the color of odd fields only, but failed. Anything I try affects the even fields, too.

Can someone help me with the right syntax to achieve that?

Edit: after closely reviewing my test captures, I have to correct myself. It's not the capture card(s), it's also present with the Aurora card.

I noticed too, that every other frame is sharper than the other. Would that maybe point to video heads?

Sharc
7th May 2026, 19:12
.... I tried to make a script that manipulates the color of odd fields only, but failed. Anything I try affects the even fields, too.

Can someone help me with the right syntax to achieve that?

Try this:
<your source filter here>
assumeBFF() #set the field order acc. your source
separatefields()
e=selecteven() #even fields (0,2,4,6 .....)
o=selectodd() #odd fields (1,3,5,7 .....)
o=o.<your tweaking filter for the odd fields here>, for example tweak(hue=4)
interleave(e,o) #restore the fields sequence (0,1,2,3,4,5......)
weave() #reinterlace


Edit: after closely reviewing my test captures, I have to correct myself. It's not the capture card(s), it's also present with the Aurora card.
Capture cards capture the video field by field by field ...(0,1,2,3,4,5 .....). They don't distinguish between even and odd fields or process these differently
Maybe heads/track misalignment of the camera or of the VCR. I don't know.

Busty
9th May 2026, 23:41
Thank you Sharc, your input is helpful to me. Got the script working, thanks for that, too:-) I'll play around a bit with settings and see if I can get somewhere with that.

Sharc
10th May 2026, 05:47
Another approach would be to replace the bad fields with a motion interpolated version of adjacent good fields.
I may return to it if you don't succeed in a few days.

Busty
14th May 2026, 13:18
That would be a definitive upgrade to just replacing the field.

In the meantime, I didn't make a lot of progress. When I lower red in one field, it becomes too green before the red level is right. Lowering the saturation affects both planes and is instantly visible. I tried ColorYUV and Tweak.

I think I just need to lower reds a little, maybe increase yellow, too, but without affecting green or blue.

It might work out better in RBG colorspace and my impression is that there are lots of possibilies, but which approach would be the most suitable one? A suggestion which plugin to use would be very welcome. I wouldn't want t o convert the whole clip to RGB, just process chroma on one field and then convert that back, leaving everything else in YUV, if possible.


I noticed another thing, too. I did a different processing of that same clip before and it didn't show that annoying color flickering. The fields had the same problem, e. g. one is more red than the other, but viewing it in 50fps did not result in flickering, at least none that I saw. I didn't use QTGMC but EZDenoise on that one. So it might be enough to get the fields match better (not necessarily perfect) and tweak my denoising settings to avoid this distracting flickering.

Emulgator
14th May 2026, 13:45
Only taking manual care of the field chroma mismatch, not caring about chroma placement restoration (unsmearing, shifting) so far, and just throwing any untuned QTGMC on it:
P.S. Well, couldn't resist:
AssumeBFF()
SeparateFields()
Even=Tweak(SelectEven(),hue=-2.0,sat=1.05)
Odd=Tweak(SelectOdd(),hue=2.0,sat=1.0)
# Plus the Sharc approach of chroma merging maybe ? Up to you. I am interleaving straight here.
Interleave(Even,Odd)
Weave()
ChromaShiftSP(X=3.0, Y=3.0)
smoothdebug=0 #0 no Diagram, 1 = Curve only, 2: Tweak only, 3: Both, 4: portalscope
ShowSmoothCurveDiagram=smoothdebug==1 ? true : smoothdebug==3 ? true : false
ShowSmoothTweakDiagram=smoothdebug==2 ? true : smoothdebug==3 ? true : false
smoothdebugwidth=1920
smoothdebugheight=1080
SmoothCurve16(ConvertTo16bit().ConvertToStacked(), \
Ycurve="0-0;16383-15000;24575-24575;42000-45000;65535-65535", \
Ucurve="0-0;8191-8191;16383-16383;22575-24575;32000-32767;37000-40959;49151-52000;57343-57343;65535-65535", \
Vcurve="0-0;8191-8191;16383-14383;24575-21575;32000-32767;40959-40959;49151-49151;57343-57343;65535-65535", \
limiter=false, HQ=true, interp=100, debug=ShowSmoothCurveDiagram, screenW=smoothdebugwidth, screenH=smoothdebugheight)
ConvertFromStacked()
Smoothdebug==4 ? portalscope() : NOP()
propSet("_FieldBased",1)
QTGMCp()

Sharc
15th May 2026, 10:46
Here a version with chroma interpolation, means substituting the chroma of the "bad" field with motion interpolated chroma of the "good" field. (No other color tweaking applied):
https://mega.nz/file/DdcjFTTa#IFVAPbR3hn7bvtudnjIlyNwWVU6QD4f9n7GP7mcGNFc

ConverttoYV16(interlaced=true)
assumeBFF()
SeparateFields()
ipol = Interpol_RIFE(SelectOdd().AssumeFrameBased()).SelectOdd().Loop(2,0,0)
even = MergeChroma(SelectEven(), ipol)
Interleave(even,SelectOdd())
Weave()
QTGMC(preset="slow")

###########
function Interpol_RIFE(clip source)
{
source.z_ConvertFormat(pixel_type="RGBPS", colorspace_op="601:auto:auto:limited=>rgb:same:same:full")
RIFE(model=5, sc=false)
z_ConvertFormat(pixel_type=source.pixeltype, colorspace_op="rgb:auto:auto:full=>601:same:same:limited")
}
##########

Busty
16th May 2026, 13:14
That's what I love this forum for! You guys take problem somenone else has as a challenge. Quite the professional curiosity.

Thank you Emulgator & Sharc for playing with my files.

@ Emulgator, I couldn't test the whole script because I get an error, that there is no function named "ex_bs"
The tweaking part at the beginning looks like a great improvement for this sample. I tested it on a different capture and it didn't translate, unfortunately.

Is there an easy way to adjust saturation for one plane only?

And you write I could combine it with Sharc's merging, but as far as I understand it, it's one way or the other, right? I mean, I either change colors of a field OR discard the whole field and use a new one, no sense to tweak colors on a newly generated field, or am i missing something here?

@ Sharc, I installed the initial version of rife, as it's the only only for x86. Your script gives me the error "there is no function naned z_ConvertFormat"

Anything I can do about that?

Sharc
16th May 2026, 13:56
@ Sharc, I installed the initial version of rife, as it's the only only for x86. Your script gives me the error "there is no function naned z_ConvertFormat"

Anything I can do about that?
Download the Avisynth plugin Avsresize
http://avisynth.nl/index.php/Avsresize

Actually you can use any other framerate doubler (motion interpolator, like FrameRateConverter etc.) instead of RIFE.

Busty
16th May 2026, 15:55
Thanks, yeah, I did that, and now I'm stuck at how to change the script so it works with FrameRateConverter instead of RIFE.
I did get it to load, but now the colors are all over the place. I guess the syntax has to be changed to match FramerateConverter, but I don't know how to do that (yes i looked at the syntax and yes, I'm obviously that bad in scripting still...)

I tried it just like this:

ConverttoYV16(interlaced=true)
assumeBFF()
SeparateFields()
ipol = FrameRateConverter(SelectOdd().AssumeFrameBased()).SelectOdd().Loop(2,0,0)
even = MergeChroma(SelectEven(), ipol)
Interleave(even,SelectOdd())
Weave()
QTGMC(preset="slow")

###########
function FrameRateConverter(clip source)
{
source.z_ConvertFormat(pixel_type="RGBPS", colorspace_op="601:auto:auto:limited=>rgb:same:same:full")

z_ConvertFormat(pixel_type=source.pixeltype, colorspace_op="rgb:auto:auto:full=>601:same:same:limited")
}
##########

Sharc
16th May 2026, 16:41
Thanks, yeah, I did that, and now I'm stuck at how to change the script so it works with FrameRateConverter instead of RIFE.
I did get it to load, but now the colors are all over the place. I guess the syntax has to be changed to match FramerateConverter, but I don't know how to do that (yes i looked at the syntax and yes, I'm obviously that bad in scripting still...)

I tried it just like this: .............

Sorry, your script doesn't make sense at all.
FrameRateConverter is found here:
http://avisynth.nl/index.php/FrameRateConverter
Study its documentation to use it properly.

If RIFE works just stay with it. No reason to change to anything else.

Busty
17th May 2026, 08:12
No, RIFE does not work. I get a system exemption error on the lines calling RIFE. That's why I wanted to use FrameRateDoubler instead. But I really am sorry (and a bit embarrassed), I am lost when trying to make it work. I just don't know how to phrase the interpolation for FrameRateDoubler, even after looking at the info pages of FrameRateDoubler and RIFE. Can I ask for help on how to replace RIFE with FrameRateDoubler?

rgr
17th May 2026, 09:01
https://github.com/Asd-g/AviSynthPlus-RIFE/tree/main

Busty
17th May 2026, 09:52
Thanks rgr, I've seen that site before, but RIFE still does not work on my system. It's a bit special. I got this all running on a Mac and installed it via PlayOnMac, so some things I just can't get to work under the circumstances.

Sharc
17th May 2026, 10:58
Try this using FrameRateConverter:
AssumeBFF()
SeparateFields()
ipol = FrameRateConverter(SelectOdd()).SelectOdd().Loop(2,0,0)
even = MergeChroma(SelectEven(), ipol)
Interleave(even,SelectOdd())
Weave()
QTGMC()
ChromaShiftSP(x=4,y=4) #align the chroma with the luma

Emulgator
17th May 2026, 15:20
Busty, I just threw all my .avsi on notepad++ and searched for ex_bs:
475 hits, most are in Dogway's scripts.
If you follow your assertion it will tell which script path and line it was called from and then go searching from there.

Busty
17th May 2026, 20:31
@ Sharc: This works perfect for me! Thank you so much!

@ Emulgator: While this did the trick and I found it in ExTools, VDub wasn't done complaining about other functions missing. Found them all, but in the end I got a "system Excemption " again. QTGMC+ (or QTGMCp) doesn't work for me, I'm afraid.