Hi everyone!
We had a brief talk about it, but we never talked about the cause why. Using aviSynth Level() will effect the Black/White levels based on the parameters you use, but also raise the chroma values. I used Level() often, and when the results has blown out colors, I merged back the original chroma. But that makes me wonder. Why does Level(), which expect white/black levels, also effect the chroma? Is that actually a good practice to modify the Chroma values when you change the Luma? When I use level() and the colors are not blown out, I wonder if It's better to merge the original Chroma, or stick with the new Chroma values Level() modified.
Thanks!
+ Reply to Thread
Results 1 to 30 of 44
-
-
Does it really change the chroma? Any change in levels will tend to change the saturation and intensity of the colors, which can also make them appear to shift.
-
Levels() increases saturation when you increase the contrast. It reduces the saturation when you reduce the contrast. Ie, it changes the levels of the U and V channels as well as the Y channel.
http://avisynth.nl/index.php/Levels
For adjusting brightness or contrast in YUV mode, it may be better (depending on the effect you are looking for) to use Tweak or ColorYUV, because Levels changes the chroma of the clip.Last edited by jagabo; 3rd Nov 2020 at 13:38.
-
It depends on what you are doing
There is YLevels if you want Y affected only
http://avisynth.nl/index.php/Ylevels -
So that's what I wonder about. Is there a reason why Levels() adjust the saturation? should Saturation be normally increased when increasing the contrast? How can one know when to use Levels() (with Saturation change) vs when to use YLevels/Tweak? is there any rule of a thumb?
-
There is no "rule of thumb",
It depends on your source, and what you want to do, and how you want to do it
And often there is more than one way to get a similar end result
People have different approaches to performing color manipulations. eg. Some prefer to work in RGB, hue/saturation curves, RGB levels and curves.
Even "saturation" has slightly different definitions and ways of calculating and adjusting it.
Classically, in RGB , increasing contrast increases the saturation. (e.g If you were to check a waveform monitor and vectorscope) -
Levels() was meant to emulate VirtualDub's Levels filter working in RGB mode. The transform that calculated from the values given to Levels() is applied equally to each RGB channel. The result is that the U and V channels change along with the Y channel. Here's an AviSynth script that shows this:
Code:function ChangeLevels(clip v, float mult) { Levels(v, 0,1.0,255, 0,int(255.0*mult)) } BlankClip(color=$808020, pixel_type="RGB32, frames=100") Animate(0,100,"ChangeLevels", last,1.0, last,2.0) ConvertToYV24().Histogram(mode="color")
-
Classically, in RGB , increasing contrast increases the saturation. (e.g If you were to check a waveform monitor and vectorscope)Levels() was meant to emulate VirtualDub's Levels filter working in RGB mode.
So when I see the RGB is blown out after Levels(), I use MergeChroma to apply the original Chroma. If it's not - I leave with the RGB values Levels(). But I wonder - how does one properly calibrate colors? Is it even possible to do it without calibrated screen? -
You don't necessarily need a perfectly calibrated screen. But being close helps a lot. Checking colors visually is somewhat subjective. Even with a perfectly calibrated monitor the brightness and color temperature of the room lights can make colors look different. Or staring at say, a blue screen for a while, then switching to a greyscale image will make those greys look non-grey. You can read RGB values off the screen with a program like CSamp:
https://forum.videohelp.com/threads/361379-VCR-Hi8-capture-tests-help-evaluate/page7#post2303973
Unless your video is a color chart it's hard to know exactly what the colors are supposed to be. Full black and white are a place to start. If you have something you know is medium grey that gets you some of the middle shades.
You can use a tool to look for illegal YUV combinations:
http://forum.doom9.org/showthread.php?t=154731
That function is very slow to start up -- it used to take about a minute on my old i5 2500K. So I wrote a faster and simpler function that's a little less accurate though usually adequate, HighlightBadRGB():
https://forum.videohelp.com/threads/360935-Capturing-Correct-Chroma-and-Hue-Levels-Fro...gb#post2289672
Reading through the rest of that thread may help. -
I am no expert, so just some thoughts:
One can calibrate a monitor with the help of a colorimeter AFAIK. It may not be required though.
Basic monitor adjustments are normally done with tools like
http://www.lagom.nl/lcd-test/
A monitor or TV will display the colors according to its settings, and these settings are normally adjusted for a subjectively pleasant or 'natural' view.
Test pictures (like colorbars or more advanced test patterns) can help with the basic adjustments.
Even with a calibrated monitor it is however not possible to reversely tune a video source reliably and absolutely IMO. Where in the natural picture is the 'standard red' for example? Does it exist at all in the filmed object or in the video?
The Avisynth color tools (levels(), colorYUV(), Tweak()) help to set the color data 'technically correct' i.e. for complying with a specification (range, gamut ...), for example. They are however not very intuitive, and to obtain a desired correction can be tiresome. For advanced color management one would have to resort to specialized tools/GUIs - and your (calibrated) monitor + your eyes at the end.
In addition to the avisynth wiki documentation you may find these links useful:
http://poynton.ca/notes/colour_and_gamma/
http://www.poynton.com/notes/brightness_and_contrast/index.html
https://worqx.com/color/index.htm
http://handprint.com/HP/WCL/color18a.html -
Thank you both. I will be reading all the links you shared later on, but reading between the lines It sounds like it's pretty hard to adjust colors - and most people without profession gear or a lot of experience will adjust them subjectively by "that's looks better to me"?
As you remember, my source is VHS tapes. A workflow that sounds reasonable to me is use `Level()`to set contract/brights and check the color histogram afterwards. If no color are getting blown, keep the saturation Level() has picked (what was called "technically correct"). If any of the colors are blown out out, use MergeChroma to restore the original Chroma before Level() were applied. That's sound like a valid mid-way?
Thanks! -
You may still need to follow up with other color adjustments. And it may not be necessary to merge the original chroma back, depending on what other adjustments you are making. And even keeping the original chroma may lead to illegal colors.
Look again at the image of the RGB cube within the YUV cube:
[Attachment 55735 - Click to enlarge]
Remember the inner cube is all the legal RGB values, the outer cube is all possible YUV combinations. Only the YUV values inside the RGB cube result in valid RGB values. Say you have a pixel that's very near the cyan corner of the RGB cube. If you raise the Y value, even without change the U and V values, it will move outside the RGB cube, producing an illegal color. -
FWIW I have been using this script based on avisynth's 'Limiter()' for testing legal values.
The grey small images on the right get colored when U,V are out of range. Color codes according to the Limiter() documentation.
Code:AVISource("sample.avi") tweak(hue=0,sat=1.5,bright=50,cont=1,coring=false) histomode="levels" #classic, levels, color, color2 converttoYV12() width=width() height=height() checkLevels=colorYUV(analyze=true).Histogram(histomode).subtitle("source") #Note: The histogram includes the text of the 'analyze' checkLuma=Limiter(16,235,16,240,show="luma_grey").bilinearresize(width/2,height/2).subtitle("limit check luma") checkChroma=Limiter(16,235,16,240,show="chroma_grey").bilinearresize(width/2,height/2).subtitle("limit check chroma") stackhorizontal(checkLevels,stackvertical(checkLuma,checkChroma)) return last
Last edited by Sharc; 4th Nov 2020 at 10:06.
-
-
Right. I remember that one. Even have that picture saved
So yes, even if the original chroma might lead to illegal colors. So it sounds the choices boils down to that:
- Apply Levels(), check chroma values are legal.
- If legal, leave it at that (even if those are not 'precise'. But at least technically right. Until I can get the proper eye to tune it manually).
- If after Level() chroma values are still illegal, Merge the original chroma values.
- Check the values again. If they are not legal with the original chroma values, It mean more advanced tuning is needed.
So the two open questions are:
1. How can I check if Chroma values are legal. Checking the Color Histogram?
2. If the original Chroma values are wrong - what's better - Using Level to tune Contrast/Brightness and accept chroma is illegal, or skip using Level() all together (hoping that original capture chroma values are legal). -
Use jagabo's script. See his last link in post #11:
https://forum.videohelp.com/threads/360935-Capturing-Correct-Chroma-and-Hue-Levels-Fro...gb#post2289672
2. If the original Chroma values are wrong - what's better - Using Level to tune Contrast/Brightness and accept chroma is illegal, or skip using Level() all together (hoping that original capture chroma values are legal).
But sometimes less is moreLast edited by Sharc; 4th Nov 2020 at 13:52.
-
Use jagabo's script.
I would perhaps make sure that Y, Cb(U) and Cr(V) fit in the outer cube (TV range) without clipping -
You can use the script which I posted in post #15.
You could also combine the 2 scripts and have everything under one umbrella.
Normally you will find the Cb(U), Cr(V) values to be well within the limits (0.... 240) leaving quite some headroom for tweaking, so you shouldn't have to worry much - unless something went wrong with the VHS capturing process.Last edited by Sharc; 4th Nov 2020 at 16:10.
-
Sounds good. I will start adding that to my workflow. Adjust Level() based on the histogram and checking illegal values with your script afterwards. If three are, I will modify the Level() values in small steps - under most/all of the colors are legal.
Great! Thank again everyone! -
So I felt free to add jagabo's RGB check to the script. It shows the (tweaked) source and the outer (Y,Cb,Cr) and inner RGB limits side by side.
I hope the script is valid and has no basic flaws....
You may want to try it with your VHS sources, and apply tweaks (section 2) until everything fits within the limits. Good luck!
Code:#------------------------------------ # COLOR ANALYSIS #------------------------------------ # SOURCE AVISource("your.avi") # 1) PRE-PROCESSING, as required converttoYV16(interlaced=true,matrix="Rec601") assumeTFF().separatefields().selectodd() crop(16,8,-16,-16) #remove any borders and crud # 2) COLOR TWEAK AND FILTER OPTIONS #Levels(32,1.3,200,36,200,coring=false) #Levels w/o chroma copyback #mergechroma(Levels(0,1.0,255,0,240,coring=false),last) #Levels with Chroma copyback Tweak(hue=15,sat=0.8,bright=6,cont=0.86,coring=false) #colorYUV(gain_y=0,off_y=0,cont_y=0,gain_u=0,off_u=0,cont_u=0,gain_v=0,off_v=-0,cont_v=0,f2c=false) # more filters ..... # 3) ANALYZE histomode="levels" #levels, classic, color, color2 converttoYV12() width=width() height=height() checkLevels=colorYUV(analyze=true).Histogram(histomode).subtitle("source (filtered)") #Note: The histogram includes the analyze text checkLuma=Limiter(16,235,16,240,show="luma").bilinearresize(width/2,height/2).subtitle("highlight illegal luma Y") checkChroma=Limiter(16,235,16,240,show="chroma").bilinearresize(width/2,height/2).subtitle("highlight illegal chroma Cb,Cr") IllegalRGB=HighlightBadRGB(color_red) # 4) LAYOUT limit=stackhorizontal(checkLevels,stackvertical(checkLuma,checkChroma),IllegalRGB.horizontalreduceby2().subtitle("highlight illegal RGB")) return limit #---------------- FUNCTION © jagabo@videohelp ------------------------------------------------------------------------------- # https://forum.videohelp.com/threads/360935-Capturing-Correct-Chroma-and-Hue-Levels-From-VHS/page2?highlight=highlightbadrgb#post2289672 function HighlightBadRGB(clip vid, int "color") { color = default(color, $ff0000) badcolor = BlankClip(vid, color=color) Subtract(ConvertToYV24(vid), ConvertToYV24(vid).ConvertToRGB().ConvertToYV24()) absY = Overlay(ColorYUV(off_y=-126), Invert().ColorYUV(off_y=-130), mode="add") absU = Overlay(UtoY().ColorYUV(off_y=-128), UtoY().Invert().ColorYUV(off_y=-128), mode="add") absV = Overlay(VtoY().ColorYUV(off_y=-128), VtoY().Invert().ColorYUV(off_y=-128), mode="add") Overlay(absU,absV, mode="add") Overlay(last,absY, mode="add") ColorYUV(gain_y=65000) Overlay(vid,badcolor,0,0,last) }
-
Whoo, awesome! Thanks!
One thing though, why Tweak? and colorYuv? only to show other ways to modify brightness/contract? (I know tweak won't touch the chroma). -
-
Great! I create a function out of your code, so now I have one for Inner verification and one for outer
I wonder though, what does the "Limit Check Luma" does? and what's the middle histogram is good for? -
What are you referring to? The Y (luma) has to be checked for being in the legal range for the outer cube as well, not only the Chroma (Cb,Cr)
and what's the middle histogram is good for? -
The Y (luma) has to be checked for being in the legal range for the outer cube as well
Thank you! -
looks its settled in this thread, so I post Vapoursynth port of script from post #22,
that shows filtered video, illegal Y in green, illegal chroma in yellow and bad RGB in red
Code:import vapoursynth as vs from vapoursynth import core import adjust #if using Tweak filter, google "github vapoursynth adjust.py" by dubhater import functools #standard python library, comes with python #for histogram: download dll from github, search "github vapoursynth histogram" by dubhater clip = core.avisource.AVISource("some.avi") #YUV420P8 def print_stats(clip): def stats(n, clip): f=clip.get_frame(n) return clip.text.Text( f"Frame {n}\nPlanes Y: U: V:\n" "Average {:.2f}{:8.2f}{:8.2f}\n" "Minimum {: <8}{: <8}{: <8}\n" "Maximum {: <8}{: <8}{: <8}".format(f.props["STATS_Y_Average"]*255 ,f.props["STATS_U_Average"]*255, f.props["STATS_V_Average"]*255, f.props["STATS_Y_Min"], f.props["STATS_U_Min"], f.props["STATS_V_Min"], f.props["STATS_Y_Max"], f.props["STATS_U_Max"], f.props["STATS_V_Max"]) ) return core.std.FrameEval(clip, functools.partial(stats, clip=clip)) def HighlightBadRGB(vid, color=(81,90,240)): badcolor = core.std.BlankClip(vid, color=color) YUV444P8 = vid.resize.Point(format=vs.YUV444P8) subtract = core.std.MakeDiff(YUV444P8, YUV444P8.resize.Point(format=vs.RGB24, matrix_in_s='170m').resize.Point(format=vs.YUV444P8, matrix_s='170m')) #value for mask in python syntax: value = 0 if (x==128 and y==128 and z==128) else 255 mask = core.std.Expr([subtract.std.ShufflePlanes(plane, vs.GRAY) for plane in [0,1,2]], ['x 128 = y 128 = and z 128 = and 0 255 ?']) return core.std.MaskedMerge(vid, badcolor, mask) # 1) PRE-PROCESSING clip = core.std.SetFrameProp(clip, prop="_Matrix", intval=6) #6 or 5 (170m or 470bg, in case of Matrix, it is the same, bt601) #2) FILTER OPTIONS in floating point YUV444PS = core.resize.Bicubic(clip, format=vs.YUV444PS) #YUV444PS = adjust.Tweak(YUV444PS, hue=15,sat=0.8,bright=6/255,cont=0.86,coring=False) # 3) ANALYZE histomode = "Levels" #Classic, Levels, Color, Color2 YUV420P8 = YUV444PS.resize.Bicubic(format=vs.YUV420P8) YUV420P8 = YUV420P8.std.PlaneStats(plane=0, prop="STATS_Y_").std.PlaneStats(plane=1, prop="STATS_U_").std.PlaneStats(plane=2, prop="STATS_V_") #histogram_clip = core.hist.Levels(YUV420P8) histogram_clip = getattr(core.hist, histomode)(YUV420P8).text.Text("source (filtered)", alignment=1) checkLevels = print_stats(histogram_clip) illegal_luma_mask = core.std.Expr(YUV420P8.std.ShufflePlanes(0, vs.GRAY), 'x 16 < x 235 > or 255 0 ?') illegal_luma_color = core.std.BlankClip(YUV420P8, color=(145,54,34)) #YUV green checkLuma = core.std.MaskedMerge(YUV420P8, illegal_luma_color, illegal_luma_mask).resize.Bilinear(width=YUV420P8.width/2, height=YUV420P8.height/2).text.Text("highlight illegal luma Y (green)") illegal_chroma_mask = core.std.Expr([YUV420P8.std.ShufflePlanes(plane, vs.GRAY) for plane in [1,2]], 'x 16 < x 240 > or y 16 < or y 240 > or 255 0 ?') illegal_chroma_color = core.std.BlankClip(YUV420P8, width=YUV420P8.width/2, height=YUV420P8.height/2, color=(210,16,146)) #YUV yellow checkChroma = core.std.MaskedMerge(YUV420P8.resize.Bilinear(width=YUV420P8.width/2, height=YUV420P8.height/2), illegal_chroma_color, illegal_chroma_mask).text.Text("highlight illegal chroma Cb,Cr (yellow)") IllegalRGB=HighlightBadRGB(YUV420P8, color=(81,90,240)) #YUV red (81,90,240) # 4) LAYOUT limit = core.std.StackHorizontal([checkLevels, core.std.StackVertical([checkLuma,checkChroma]),IllegalRGB.text.Text("highlight illegal RGB (red)")]) limit.set_output()
Avisynths, colorYUV(...., analyze=true) was done with created print function in vapoursynth.
Expressions seemed to make it easier to figure out illegal RGB color together with MakeDiff() which might be Avisynths Subtract() equivalent.
Also Avisynths Limiter(...., show="luma" or show="chroma") was done by extracting planes and using expressions getting masks and then merging them into video using particular color.Last edited by _Al_; 8th Nov 2020 at 00:56.
-
Screen comparisons avisynth and vapoursynth:
avisynth seams to load video with wrong colors, not sure why, but not using avs so not important, maybe something in the menu of AvsPMod. -
No, AviSynth loads the video with whatever YUV values are in the video. Your problem here is that when those YUV values are displayed they are using the wrong matrix to convert to RGB, rec.601 vs. rec.709. If you want to see the correct RGB values from AviSynth use ConvertToRGB(matrix="rec601"), or ConvertToRGB(matrix="rec709") whichever is appropriate.
The HighlightBadRGB() I posted assumes limited range rec.601 colors.
Similar Threads
-
How do I modify scaled size of an H.264 encoded video?
By kfitfk in forum Video ConversionReplies: 2Last Post: 21st Oct 2019, 21:59 -
Metadata Editing (Protect or modify information)
By zerowalk in forum Video ConversionReplies: 41Last Post: 25th Sep 2019, 22:33 -
how to reduce chroma level with avisynth?
By marcorocchini in forum Newbie / General discussionsReplies: 3Last Post: 24th Nov 2018, 13:15 -
Modify Color Space Flag
By chris319 in forum Newbie / General discussionsReplies: 74Last Post: 1st Aug 2017, 22:30 -
What Is Video Level and How To Change Video Level
By Aashik Alam in forum Video ConversionReplies: 3Last Post: 12th Jan 2016, 07:26