Levels

From Avisynth wiki
(Difference between revisions)
Jump to: navigation, search
m (AVS+ arguments are float as of r2580)
(add link to avs+ documentation)
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
<div style="max-width:62em" >
 
<div style="max-width:62em" >
 +
 +
<div {{BlueBox2|40|0|3px solid purple}} >
 +
{{AvsPlusFullname}}<br>
 +
Up-to-date documentation: [https://avisynthplus.readthedocs.io/en/latest/avisynthdoc/corefilters/levels.html https://avisynthplus.readthedocs.io]
 +
</div>
 +
 +
 
Adjusts brightness, contrast, and gamma. This is done using the following ''transfer function'':
 
Adjusts brightness, contrast, and gamma. This is done using the following ''transfer function'':
 
:''output'' = ( (''input'' - {{FuncArg|input_low}}) / ({{FuncArg|input_high}} - {{FuncArg|input_low}}) )<sup>(1 / {{FuncArg|gamma}})</sup> * ({{FuncArg|output_high}} - {{FuncArg|output_low}}) + {{FuncArg|output_low}}
 
:''output'' = ( (''input'' - {{FuncArg|input_low}}) / ({{FuncArg|input_high}} - {{FuncArg|input_low}}) )<sup>(1 / {{FuncArg|gamma}})</sup> * ({{FuncArg|output_high}} - {{FuncArg|output_low}}) + {{FuncArg|output_low}}
Line 12: Line 19:
 
When processing data in [[YUV]] mode, '''Levels''' only gamma-corrects the luma information, not the chroma. Gamma correction is really an RGB concept, and is only approximated here in YUV. If ''{{FuncArg|gamma}}=1.0'' (unity), the filter should have the same effect in both RGB and YUV modes. 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.
 
When processing data in [[YUV]] mode, '''Levels''' only gamma-corrects the luma information, not the chroma. Gamma correction is really an RGB concept, and is only approximated here in YUV. If ''{{FuncArg|gamma}}=1.0'' (unity), the filter should have the same effect in both RGB and YUV modes. 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.
  
{{AvsPluscon}} all parameters except {{FuncArg|gamma}} are ''non''-[[Autoscale_parameter|autoscaling]] &ndash; they must be scaled to the target bit depth.  
+
Note in {{AvsPluscon}}, the parameters {{FuncArg|input_low}}, {{FuncArg|input_high}}, {{FuncArg|output_low}} and {{FuncArg|output_high}}
 +
* are <tt>float</tt> instead of <tt>int</tt>.
 +
* are not [[Autoscale_parameter|autoscaling]] &ndash; they are relative to the current bit depth:
 +
:{| class="wikitable"
 +
|-
 +
|colspan="6" |bit depth equivalent color values
 +
|-
 +
!style="text-align:right"|8
 +
|style="text-align:right"|0
 +
|style="text-align:right"|16
 +
|style="text-align:right"|128
 +
|style="text-align:right"|235
 +
|style="text-align:right"|255
 +
|-
 +
!10
 +
|style="text-align:right"|0
 +
|style="text-align:right"|64
 +
|style="text-align:right"|512
 +
|style="text-align:right"|940
 +
|style="text-align:right"|1020
 +
|-
 +
!12
 +
|style="text-align:right"|0
 +
|style="text-align:right"|256
 +
|style="text-align:right"|2048
 +
|style="text-align:right"|3760
 +
|style="text-align:right"|4080
 +
|-
 +
!14
 +
|style="text-align:right"|0
 +
|style="text-align:right"|1024
 +
|style="text-align:right"|8192
 +
|style="text-align:right"|15040
 +
|style="text-align:right"|16320
 +
|-
 +
!16
 +
|style="text-align:right"|0
 +
|style="text-align:right"|4096
 +
|style="text-align:right"|32768
 +
|style="text-align:right"|60160
 +
|style="text-align:right"|65280
 +
|-
 +
!32
 +
|style="text-align:right"|0.0
 +
|style="text-align:right"|<sup>16</sup>/<sub>256</sub>
 +
|style="text-align:right"|<sup>128</sup>/<sub>256</sub>
 +
|style="text-align:right"|<sup>235</sup>/<sub>256</sub>
 +
|style="text-align:right"|<sup>255</sup>/<sub>256</sub>
 +
|}
  
  
 
==== Syntax and Parameters ====
 
==== Syntax and Parameters ====
 
{{FuncDef|Levels(clip ''input'', <br>
 
{{FuncDef|Levels(clip ''input'', <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ''input_low'', float ''gamma'', int ''input_high'', <br>
+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ''input_low'', float ''gamma'', int ''input_high'', int ''output_low'', int ''output_high''<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ''output_low'', int ''output_high''<br>
+
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [, bool ''coring'' , bool ''dither'' ] )}}<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [, bool ''coring'' , bool ''dither'' ] )}}
+
{{FuncDef|Levels(clip ''input'', <br>
 +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; float ''input_low'', float ''gamma'', float ''input_high'', float ''output_low'', float ''output_high''<br>
 +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [, bool ''coring'' , bool ''dither'' ] )}} {{AvsPluscon}}
  
 
:{{Par2|clip|clip|(required)}}
 
:{{Par2|clip|clip|(required)}}
 
::Source video.
 
::Source video.
  
:{{Par2|input_low|int*|(required)}}
+
:{{Par2|input_low|int/float*|(required)}}
 
::Input values at {{FuncArg|input_low}} or lower are treated as ''black'', and lighter colors are darkened proportionally.
 
::Input values at {{FuncArg|input_low}} or lower are treated as ''black'', and lighter colors are darkened proportionally.
 
::Therefore raising {{FuncArg|input_low}} darkens the output.
 
::Therefore raising {{FuncArg|input_low}} darkens the output.
:: <big>*</big> {{AvsPluscon}} only &ndash; all arguments marked ''int*'' are floating point (from version r2580)
+
:: <big>*</big> = <tt>int</tt> in AviSynth, <tt>float</tt> in AviSynth+
  
 
:{{Par2|gamma|float|(required)}}
 
:{{Par2|gamma|float|(required)}}
Line 33: Line 90:
 
::Higher {{FuncArg|gamma}} brightens the output; lower {{FuncArg|gamma}} darkens the output.  
 
::Higher {{FuncArg|gamma}} brightens the output; lower {{FuncArg|gamma}} darkens the output.  
  
:{{Par2|input_high|int*|(required)}}
+
:{{Par2|input_high|int/float|(required)}}
 
::Input values at {{FuncArg|input_high}} or higher are treated as ''white'', and darker colors are brightened proportionally.
 
::Input values at {{FuncArg|input_high}} or higher are treated as ''white'', and darker colors are brightened proportionally.
 
::Therefore lowering {{FuncArg|input_high}} brightens the output.
 
::Therefore lowering {{FuncArg|input_high}} brightens the output.
  
:{{Par2|output_low|int*|(required)}}
+
:{{Par2|output_low|int/float|(required)}}
 
::Dark values brighten to gray as {{FuncArg|output_low}} becomes larger.
 
::Dark values brighten to gray as {{FuncArg|output_low}} becomes larger.
  
:{{Par2|output_high|int*|(required)}}
+
:{{Par2|output_high|int/float|(required)}}
 
::Light values darken to gray as {{FuncArg|output_high}} becomes smaller.
 
::Light values darken to gray as {{FuncArg|output_high}} becomes smaller.
  
Line 52: Line 109:
  
 
::{{FuncArg|coring}} was created for VirtualDub compatibility, and it remains true by default for compatibility with older scripts.  
 
::{{FuncArg|coring}} was created for VirtualDub compatibility, and it remains true by default for compatibility with older scripts.  
::In the opinion of some, you should [http://forum.doom9.org/showthread.php?p=1722885#post1722885 always use ''coring=false''] if you are working directly with luma values (whether or not your input is 16{{D}}-235{{D}}).
+
::In the opinion of some, you should [https://web.archive.org/web/20160825211112/http://forum.doom9.org/showthread.php?p=1722885#post1722885 always use ''coring=false''] if you are working directly with luma values (whether or not your input is 16{{D}}-235{{D}}).
  
 
::'''Note''' TV-range video ''can'' be correctly processed with {{FuncArg|coring}}=false; for example,  
 
::'''Note''' TV-range video ''can'' be correctly processed with {{FuncArg|coring}}=false; for example,  
Line 63: Line 120:
 
:{{Par2|dither|bool|false}}
 
:{{Par2|dither|bool|false}}
 
::When ''true'', [[ordered dithering]] is applied to combat [http://en.wikipedia.org/wiki/Colour_banding banding]. Default is ''false''.
 
::When ''true'', [[ordered dithering]] is applied to combat [http://en.wikipedia.org/wiki/Colour_banding banding]. Default is ''false''.
 
  
 
==== Examples ====
 
==== Examples ====

Latest revision as of 09:35, 17 September 2022

AviSynth+
Up-to-date documentation: https://avisynthplus.readthedocs.io


Adjusts brightness, contrast, and gamma. This is done using the following transfer function:

output = ( (input - input_low) / (input_high - input_low) )(1 / gamma) * (output_high - output_low) + output_low
  • input_low and input_high determine what input pixel values are treated as pure black and pure white.
  • output_low and output_high determine what output values are treated as pure black and pure white.
  • gamma controls the degree of non-linearity in the conversion.


This is one of those filters for which it would really be nice to have a GUI. Since we can't offer a GUI (though AvsP does), we at least make this filter compatible with VirtualDub's when the clip is RGB. In that case you should be able to take the numbers from VirtualDub's Levels dialog and pass them as parameters to the Levels filter and get the same results. Unlike VirtualDub's filter however, the input and output parameters can be larger than 255d.

When processing data in YUV mode, Levels only gamma-corrects the luma information, not the chroma. Gamma correction is really an RGB concept, and is only approximated here in YUV. If gamma=1.0 (unity), the filter should have the same effect in both RGB and YUV modes. 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.

Note in AVS+, the parameters input_low, input_high, output_low and output_high

  • are float instead of int.
  • are not autoscaling – they are relative to the current bit depth:
bit depth equivalent color values
8 0 16 128 235 255
10 0 64 512 940 1020
12 0 256 2048 3760 4080
14 0 1024 8192 15040 16320
16 0 4096 32768 60160 65280
32 0.0 16/256 128/256 235/256 255/256


[edit] Syntax and Parameters

Levels(clip input,
      int input_low, float gamma, int input_high, int output_low, int output_high
      [, bool coring , bool dither ] )

Levels(clip input,
      float input_low, float gamma, float input_high, float output_low, float output_high
      [, bool coring , bool dither ] )
AVS+

clip  clip = (required)
Source video.
int/float*  input_low = (required)
Input values at input_low or lower are treated as black, and lighter colors are darkened proportionally.
Therefore raising input_low darkens the output.
* = int in AviSynth, float in AviSynth+
float  gamma = (required)
Gamma adjustment. See examples.
Higher gamma brightens the output; lower gamma darkens the output.
int/float  input_high = (required)
Input values at input_high or higher are treated as white, and darker colors are brightened proportionally.
Therefore lowering input_high brightens the output.
int/float  output_low = (required)
Dark values brighten to gray as output_low becomes larger.
int/float  output_high = (required)
Light values darken to gray as output_high becomes smaller.
bool  coring = true
When true (the default),
  1. input luma is clamped to the range 16d-235d and the chroma to 16d-240d;
  2. this clamped input is scaled from 16d-235d to 0d-255d,
  3. the conversion takes place according to the transfer function above, and then
  4. output is scaled back to 16d-235d.
When false, the conversion takes place according to the transfer function, without any scaling.
coring was created for VirtualDub compatibility, and it remains true by default for compatibility with older scripts.
In the opinion of some, you should always use coring=false if you are working directly with luma values (whether or not your input is 16d-235d).
Note TV-range video can be correctly processed with coring=false; for example,
Levels(0, 1.6, 255, 0, 255, coring=true)  
produces the same result as
Levels(16, 1.6, 235, 16, 235, coring=false)
except that the output is not clipped to TV-range. Black and white levels are preserved while adjusting gamma, unlike
Levels(0, 1.6, 255, 0, 255, coring=false)  
bool  dither = false
When true, ordered dithering is applied to combat banding. Default is false.

[edit] Examples

# does nothing (unity transfer function):
Levels(0, 1, 255, 0, 255)
# the input is scaled from [16,235] to [0,255], 
# the conversion [0,255]->[16,235] takes place (according to the formula),  
# and the output is scaled back from [0,255] to [16,235]
# (for example: the luma values in [0,16] are all converted to 30)
Levels(0, 1, 255, 16, 235)
# gamma-correct image for display in a brighter environment:
# example: luma of 16 stays 16, 59 is converted to 79, etc.
Levels(0, 1.3, 255, 0, 255)
# invert the image (make a photo-negative):
# example: luma of 16 is converted to 235
Levels(0, 1, 255, 255, 0)
# scales a [0,255] clip to [16,235]
Levels(0, 1, 255, 16, 235, coring=false)  
# note both luma and chroma components are scaled by the same amount,
# so it's not exactly the same as ColorYUV(levels="PC->TV")
# scales a [16,235] clip to [0,255]:
Levels(16, 1, 235, 0, 255, coring=false)  
# note both luma and chroma components are scaled by the same amount,
# so it's not exactly the same as ColorYUV(levels="TV->PC")
# makes a clip 100% black
Levels(0, 1.0, 255, 0, 0)
# apply fading on gamma corrected source (same holds for resizing and smoothing)
clip = ... 
gamma = 2.2
clip.Levels(0, gamma, 255, 0, 255) # undo gamma (also called gamma correction)
FadeOut(n)
Levels(0, 1.0/gamma, 255, 0, 255) # redo gamma
## use AVS+ and bit depth >= 10 to avoid banding in dark areas


[edit] Changes

AVS+ r2580 arguments are float
v2.60 added dither
v2.53 added coring (true by default, which reflects the behaviour in older versions)
Personal tools