Gamma Correction and Luminance Masking - image

As per Weber's law, delta(L)/L is a constant where L is luminance measured in candela/m2 )i.e. (L2 - L1)/L1. This implies that a small change in lower luminance range (darker) is perceptually much more than a small change in higher luminance range (brighter).
The sRGB images which we have stored are gamma corrected i.e. they first undergo a non-linear transfer function which also partially simulated human perception.
I would like to know what happens to luminance masking after gamma correction? Does Weber law still hold on these sRGB images or are they perceptually uniform i.e. 1 unit of difference in pixel value is same be it in darker region or in brighter region? In other words, is delta(L) constant in gamma corrected images where L is gamma corrected pixel value.

Weber's Law does not apply to sRGB coded values to the extent it does apply to luminance. In other words, sRGB value is closer to being perceptually uniform than cd/m2.
To answer your question, I would NOT expect delta(sRGB coded pseudo-L) to be (even vaguely) constant.
However, keep in mind that both Weber-Fechner and sRGB are coarse approximations to perception. CIECAM02 is a more modern alternative worth exploring.

Related

Convert RGB to sRGB?

I am trying to convert an RGB to the perceptually uniform color space, CIELAB. Wikipedia states:
"The RGB or CMYK values first must be transformed to a specific
absolute color space, such as sRGB or Adobe RGB. This adjustment will
be device-dependent, but the resulting data from the transform will be
device-independent, allowing data to be transformed to the CIE 1931
color space and then transformed into L*a * b*."
I know there are some straightforward transformations once converting to sRGB, but I have not found any material to go from RGB to sRGB. So, what methods exist to do such a conversion?
No, you should not go from (linear) RGB to sRGB. In fact, it is the other way round. Following are the steps:
Convert sRGB into linear RGB. sRGB image is a gamma encoded which means a camera applies gamma function pow(x, 1/2.2) onto the light signal. This sRGB is in gamma-space which is non-linear.
Now, converting linear RGB to LAB involves two steps: first is converting linear RGB to XYZ color space (this is a basic color-space). This conversion is a linear operation, i.e., matrix multiplication. This is the reason why you would need linear RGB values not sRGB. It needs to be in linear space. Finally, XYZ values are converted into LAB values through a non-linear operation which contains some standard formulas (which you don't need to be worried about).
Interesting links:
(i) Understanding sRGB and linear RGB space: http://filmicgames.com/archives/299; http://www.cambridgeincolour.com/tutorials/gamma-correction.htm
(ii) MATLAB tutorial: https://de.mathworks.com/help/vision/ref/colorspaceconversion.html
(iii) Python package: http://pydoc.net/Python/pwkit/0.2.1/pwkit.colormaps/
(iv) C code: http://svn.int64.org/viewvc/int64/colors/color.c?view=markup
(v) OpenCV does not do this sRGB to linear RGB conversion but it does the conversion inside color.cpp code (OpenCV_DIR\modules\imgproc\src\color.cpp). Check out method called initLabTabs(), there is a gamma encoding and decoding. OpenCV color conversion API: http://docs.opencv.org/3.1.0/de/d25/imgproc_color_conversions.html

Using CIELab color space for color reduction algorithm with dithering

I've written a program for converting images to a custom file format that uses a limited color palette of 30 specific colours.
In my application I have given the option of working in RGB or YUV color spaces and the option of: Sierra, Jarvis or Floyd-Steinberg dithering.
However I have noticed that photoshop's save to web feature with the use of color tables to limit the color palette does a much better job than my program.
So I would like to improve my application to give better results.
Right now, with the example of Floyd-Steinberg dithering I'm essentially using this pseudo code
for each y from top to bottom
for each x from left to right
oldpixel := pixel[x][y]
newpixel := find_closest_palette_color(oldpixel)
pixel[x][y] := newpixel
quant_error := oldpixel - newpixel
pixel[x+1][y ] := pixel[x+1][y ] + quant_error * 7/16
pixel[x-1][y+1] := pixel[x-1][y+1] + quant_error * 3/16
pixel[x ][y+1] := pixel[x ][y+1] + quant_error * 5/16
pixel[x+1][y+1] := pixel[x+1][y+1] + quant_error * 1/16
My pixels are stored in RGB format and to find the closest palette color I am using the Euclidean distance in RGB/YUV.
I have been reading about the CIE94 and CIEDE2000 color difference algorithms and these should work better for my "find_closest_palette_color" function.
To do these calculations I'll have to convert from RGB to the CIELab color space. Can I also use CIELab when distributing errors in my dither algorithms by:
Converting the whole image to the CIELab color space
For each pixel find the closest color in my palette using CIE94 or CIEDE2000
Calculate the error in the CIELab color space (L* , a*, b* instead of RGB).
Distribute the error in accordance with whatever dither algorithm I am using with the same weights I was using in RGB.
Yes, in fact Lab is much better suited for this purpose, because Euclidean distance between colors in Lab reflect the human perception distance between the colors, whereas the distance in RGB does not.
Converting the whole image to the CIELab color space with cache.
Clustering with pixels of source image to find the best palette using a ratio of CIE76 and CIEDE2000.
Calculate the error in the CIELab color space (YUV instead of RGB).
Mix and match the error with the aid of Blue noise distribution.
Use Generalized Hilbert ("gilbert") space-filling curve O(n) instead
of Floyd-Steinberg dithering O(n2) to diffuse errors by minimize the
MSE in RGB.
Java implementation:
https://github.com/mcychan/nQuant.j2se/

Uncertainty in L,a,b space of compressed JPEG images

My team wish to calculate the contrast between two photographs taken in a wet environment.
We will calculate contrast using the formula
Contrast = SQRT((ΔL)^2 + (Δa)^2 + (Δb)^2)
where ΔL is the difference in luminosity, Δa is the difference in (redness-greeness) and Δb is (yellowness-blueness), which are the dimensions of Lab space.
Our (so far successful) approach has been to convert each pixel from RGB to Lab space, and taking the mean values of the relevant sections of the image as our A and B variables.
However the environment limits us to using a (waterproof) GoPro camera which compresses images to JPEG format, rather than saving as TIFF, so we are not using a true-colour image.
We now need to quantify the uncertainty in the contrast - for which we need to know the uncertainty in A and B and by extension the uncertainties (or mean/typical uncertainty) in each a and b value for each RGB pixel. We can calculate this only if we know the typical/maximum uncertainty produced when converting from true-colour to JPEG.
Therefore we need to know the maximum possible difference in each of the RGB channels when saving in JPEG format.
EG. if true colour RGB pixel (5, 7, 9) became (2, 9, 13) after compression the uncertainty in each channel would be (+/- 3, +/- 2, +/- 4).
We believe that the camera compresses colour in the aspect ratio 4:2:0 - is there a way to test this?
However our main question is; is there any way of knowing the maximum possible error in each channel, or calculating the uncertainty from the compressed RGB result?
Note: We know it is impossible to convert back from JPEG to TIFF as JPEG compression is lossy. We merely need to quantify the extent of this loss on colour.
In short, it is not possible to absolutely quantify the maximum possible difference in digital counts in a JPEG image.
You highlight one of these points well already. When image data is encoded using the JPEG standard, it is first converted to the YCbCr color space.
Once in this color space, the chroma channels (Cb and Cr) are downsampled, because the human visual system is less sensitive to artifacts in chroma information than it is lightness information.
The error introduced here is content-dependent; an area of very rapidly varying chroma and hue will have considerably more content loss than an area of constant hue/chroma.
Even knowing the 4:2:0 compression, which describes the amount and geometry of downsampling (more information here), the content still dictates the error introduced at this step.
Another problem is the quantization performed in JPEG compression.
The resulting information is encoded using a Discrete Cosine Transform. In the transformed space, the results are again quantized depending on the desired quality. This quantization is set at the time of file generation, which is performed in-camera. Again, even if you knew the exact DCT quantization being performed by the camera, the actual effect on RGB digital counts is ultimately content-dependent.
Yet another difficulty is noise created by DCT block artifacts, which (again) is content dependent.
These scene dependencies make the algorithm very good for visual image compression, but very difficult to characterize absolutely.
However, there is some light at the end of the tunnel. JPEG compression will cause significantly more error in areas of rapidly changing image content. Areas of constant color and texture will have significantly less compression error and artifacts. Depending on your application you may be able to leverage this to your benefit.

gamma correction formula : .^(gamma) or .^(1/gamma)?

I'm looking for a simple gamma correction formula for grayscale images with values between 0 and 255.
Let's say that the gamma of my screen is 2.2 (it's an LCD screen so I would probably need to estimate it with a more complicated procedure, but let's assume my screen is behaving nicely).
Which one of the following formulas would be the correct one?
Corrected = 255 * (Image/255).^2.2
OR
Corrected = 255 * (Image/255).^(1/2.2)
(Those are destined to be MATLAB codes but I hope they are understandable even to non-MATLAB people)
I've been looking around on the Internet but found both formulas going around. I suspect (2) is the right one, and my confusion is due to the tendency to call "gamma value" the inverse of the actual gamma value, but I would really appreciate some feedback by people who know what they are talking about...
Both formulas are used, one to encode gamma, and one to decode gamma.
Gamma encoding is used to increase the quality of shadow values when an image is stored as integer intensity values, so to do gamma encoding you use the formula:
encoded = ((original / 255) ^ (1 / gamma)) * 255
Gamma decoding is used to restore the original values, so the formula for that is:
original = ((encoded / 255) ^ gamma) * 255
If the monitor does the gamma decoding, you would want to use the first formula to encode the image data.
Gamma correction controls the overall brightness of an image. Images which are not corrected can look either bleached out or too dark. Suppose a computer monitor has 2.2 power function as an intensity to voltage response curve. This just means that if you send a message to the monitor that a certain pixel should have intensity equal to x, it will actually display a pixel which has intensity equal to x2.2 Because the range of voltages sent to the monitor is between 0 and 1, this means that the intensity value displayed will be less than what you wanted it to be. Such a monitor is said to have a gamma of 2.2.
So in your case,
Corrected = 255 * (Image/255)^(1/2.2).

RGB Similar Color Approximation Algorithm

Given that in RGB we can represent 256^3 combinations = 16,777,216 colors, and since the human eye can only distinguish roughly 10,000,000, there is obviously a surplus of 6,777,216 RGB combinations that chromatically are indistinguishable from counterpart colors.
Compression algorithms work on this basis when approximating out spacial difference in color ranges across a frame I believe. With that in mind, how can one reliably compute whether a given color is within a range of 'similarity' to another?
Of course, 'similarity' will be some kind of arbitrary/tunable parameter that can be tweaked, but this is an approximation anyway. So any pointers, pseudocode, intuitive code samples, resources out there to help me model such a function?
Many thanks for your help
There are many ways of computing distances between colors, the simplest ones being defined on color components in any color space. These are common "distances" or metrics between RGB colors (r1,g1,b1) and (r2,g2,b2):
L1: abs(r1-r2) + abs(g1-g2) + abs(b1-b2)
L2: sqrt((r1-r2)² + (g1-g2)² + (b1-b2)²)
L∞: max(abs(r1-r2), abs(g1-g2), abs(b1-b2))
These however don't take into account the fact that human vision is less sensitive to color than to brightness. For optimal results you should convert from RGB to a color space that encodes brightness and color separately. Then use one of the above metrics in the new color space, possibly giving more weight to the brightness component and less to the color components.
Areas of color that are indistinguishable form each other are called MacAdam ellipses. The ellipses become nearly circular in the CIELUV and CIELAB color spaces, which is great for computation, but unfortunately going from RGB into these color spaces is not so simple.
JPEG converts colors into YCbCr, where Y is brightness and the two C's encode color, and then halves the resolution of the C components. You could do the same and then use a weighed version of one of the above metrics, for example:
diff = sqrt(1.4*sqr(y1-y2) + .8*sqr(cb1-cb2) + .8*sqr(cr1-cr2))
The article on color difference in wikipedia has more examples for different color spaces.
Perceptual color difference can be calculated using the The CIEDE2000 Color-Difference Formula. The CIEDE2000 formula is based on the LCH color space (Luminosity, Chroma, and Hue). LCH color space is represented as a cylinder (see image here).
A less accurate (but more manageable) model, is the CIE76 Color-Difference formula, which is based on the Lab color space ( L*a*b*). There are no simple formulas for conversion between RGB or CMYK values and L*a*b*, because the RGB and CMYK color models are device dependent. The RGB or CMYK values first need to be transformed to a specific absolute color space, such as sRGB or Adobe RGB. This adjustment will be device dependent, but the resulting data from the transform will be device independent, allowing data to be transformed to the CIE 1931 color space and then transformed into L*a*b*. This article explains the procedure and the formulas.
RGB color system is designed such that if 2 colors have values that are close to each other then the colors are also perceptually close.
Example:
color defined by RGB = (100, 100, 100) is perceptually almost the same as colors
RGB = (101, 101, 100), RGB = (98, 100, 99) etc...

Resources