Shady.Linearization Submodule¶
This module contains several utility functions related to linearization.
Some of these (ScreenNonlinearity
, Linearize
, ApplyLUT
)
are only useful in special circumstances where we want to recreate
“offline” what the shader is doing for us on every frame.
Others (LoadLUT
, SaveLUT
) are for general management of
lookup table arrays.
Others (BitStealingLUT
, ReportBitStealingStats
) are useful
for creating and examining a specific type of lookup table
that employs a bitstealing technique (after Tyler 1997).
Note that everything exported from this module is also available in
the toplevel Shady.*
namespace.

Shady.Linearization.
ScreenNonlinearity
(x, gamma='sRGB')¶ Maps normalized DAC values
x
(in the domain 0 to 1, which corresponds to DAC values 0 to 255 if we assume standard 8bit DACs) to ideal luminanceY
(in the range 0 to 1), given the screen nonlinearity parametergamma
.Generally,
gamma
is numeric and strictly positive, in which case the relationship isY = x ** gamma
. A special case isgamma='sRGB'
, which is also used if you pass agamma
value of 0 or less: this uses a slightly different piecewise equation, very close to thegamma=2.2
curve (even though the exponent used in it is actually 2.4).Inverse of
Linearize()

Shady.Linearization.
Linearize
(Y, gamma='sRGB')¶ Maps ideal luminance
Y
(in the domain 0 to 1) to normalized DAC valuesx
(in the range 0 to 1, which corresponds to DAC values 0 to 255 if we assume standard 8bit DACs) given the screen nonlinearity parametergamma
.Generally,
gamma
is numeric and strictly positive, in which case the relationship isx = Y ** (1/gamma)
. A special case isgamma='sRGB'
, which is also used if you pass agamma
value of 0 or less: this uses a slightly different piecewise equation, very close to thegamma=2.2
curve (even though the exponent used in it is actually 2.4).This allows us to emulate, on the CPU and in Python, the linearization operation performed automatically by the GPU in the fragment shader on every frame according to the value of of the
Stimulus.gamma
property.Inverse of
ScreenNonlinearity()

Shady.Linearization.
LoadLUT
(source, DACbits=8)¶ Load or prepare a lookup table array.
Parameters: source (str, numpy.ndarray) – Usually this is a string denoting a filename. The file may be in numpy format  either a
npy
file in which the the lookuptable has been written withnumpy.save
, or anpz
file into which the lookup table array has been saved withnumpy.savez
as either the sole variable or a variable calledlut
. If the thirdpartypillow
package is installed, the file may alternatively be apng
image file in which lookup table entries have been saved as R,G,B pixel values in column first order.The
source
may also be anumpy.ndarray
already.DACbits (int) – This is the number of bits per DAC in the graphics card for which the lookup table is intended. In this function it is used to verify that the lookuptable entries are in range and to cast the output as the appropriate numeric datatype.
Returns: Whether
source
is a filename or an array already, in either case, this function ensures that the returned result is a 3dimensionalnumpy
array, of the appropriate integer type, with extent 3 (RGB) or 4 (RGBA) in its third dimension.See also

Shady.Linearization.
SaveLUT
(filename, lut, luminance=(), DACbits=8)¶ Save a lookup table array, and optionally also the corresponding sequence of luminance values, in a file.
Parameters:  filename (str) – name of the file to save. Determines the file
format, and should end in
npy
,npz
orpng
 lut (numpy.array) – lookup table array,
n
by3 orn
by1by3 as per the output ofLoadLUT()
orBitStealingLUT()
, wheren
is the number of entries. If the format isnpz
the array will be saved under the variable namelut
.  luminance (numpy.array, list) – sequence of
n
ideal luminance values (i.e. luminance values in the range 0 to 1) corresponding to each of the lookup table entries. Only saved (under the variable nameluminance
) if the file format isnpz
 DACbits (int) – This is the number of bits per DAC in the graphics card for which the lookup table is intended. In this function it is used to verify that the lookuptable entries are in range and to cast the output as the appropriate numeric datatype.
Returns:  the filename
 the lookup table array in standardized format
 the sequence of luminance values
Return type: a tuple consisting of
See also
 filename (str) – name of the file to save. Determines the file
format, and should end in

Shady.Linearization.
ApplyLUT
(image, lut, noiseAmplitude=0, DACbits=8)¶ Translate an array of
image
pixel values via a lookup tablelut
.This allows us to emulate, on the CPU in Python, the lookup operation performed automatically by the GPU in the shader on every frame if a lookup table has been configured via the
Stimulus.lut
property.Parameters: image (numpy.array) – Source pixel values. If the array data type is floatingpoint, pixel values are assumed to refer to ideal luminances in the range 0 to 1, and are clipped to this range before scaling and rounding according to the size of the
lut
. If the array is of some integer type, the values are assumed to be direct indices into the lookup table.Note that, if the image has more than one color channel (i.e. it has a third dimension with extent > 1) then only the first channel (red) will be used.
lut (numpy.array) – Lookup table array, e.g. as output by
LoadLUT()
orBitStealingLUT()
.noiseAmplitude (float) – specifies the amplitude of an optional random signal that can be added to
image
pixel values before lookup. A negative value indicates a uniform distribution (in the range[noiseAmplitude, noiseAmplitude]
) whereas a positive value is interpreted as the standard deviation of a Gaussian noise distribution.DACbits (int) – The number of bits per digitalanalog converter in the graphics card for which the lookup table is intended. Floatingpoint image pixel values will be scaled accordingly.
Returns: An array of integer DAC values postlookup. First two dimensions match those of the input
image
. Extent in the third dimension will match that oflut
.

Shady.Linearization.
BitStealingLUT
(maxDACDeparture=2, Cmax=3.0, nbits=16, gamma='sRGB', cache_dir=None, DACbits=8)¶ Create an RGB lookup table that (a) linearizes pixel intensity values according to the specified
gamma
profile, and (b) increases dynamic range using a “bitstealing” approach (after Tyler 1997).Parameters: maxDACDeparture (int) – Red, green and blue DAC values will be considered only up to +/ this value relative to the
R==G==B
linenbits (int) – The lookup table will have
2 ** nbits
entries. It doesn’t hurt to specify a high number here, like 16—however, note that, depending on the values ofmaxDACDeparture
andCmax
you may not get that many distinct or evenlyspaced luminance levels. The actual effective precision can be investigated usingReportBitStealingStats()
Cmax (float) –
[R,G,B]
triples will not be considered if the corresponding chroma, in percent (i.e. the third column ofRGB_to_YLCHab()
output) exceeds this.gamma (float) – screen nonlinearity parameter (see
ScreenNonlinearity()
)cache_dir (str, None) – optional directory in which to look for a cached copy of the resulting LUT (or save one, after creation, if the appropriatelynamed file was not found there).
 DACbits (int):
The number of bits per digitalanalog converter in the graphics card for which the lookup table is intended. LUT values will be scaled accordingly.
Returns: numpy
array of shape[2**nbits, 1, 3]
with the appropriate integer type (usuallyuint8
), containing integer RGB triplets.

Shady.Linearization.
ReportBitStealingStats
(lut=None, image=None, gamma='sRGB', DACbits=8)¶ Prints to the console certain statistics about the lookup table
lut
, if supplied, and optionally also any givenimage
that has been through the lookup process (i.e. an output ofApplyLUT()
).Make sure that the
gamma
andDACbits
arguments match the values that were used for creatinglut
.