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).
Related
I want to write an image enhancement algorithm which is similar to photoshop's highlight and shadows alteration feature. Can you help me regarding what does this feature of photoshop do internally to an image?
Simple approach
To begin with, you can already find already some clue in their documentation: https://helpx.adobe.com/photoshop/using/adjust-shadow-highlight-detail.html
It's quite hard to guess from those documents which algorithm they use exactly. Below I will only try to explain some approaches I would use if I was facing this problem. Don't expect there a clear algorithm, but use my answer as pointers to drive you at least to a path.
As I understood, this algorithm improve the contrast in a local scale, meaning for each pixel it will adjust the value based on the neighborhood.
To do so you have several input parameters:
Neighborhood size (or Kernel)
Highlight Threshold: Everything above is considered as belonging to highlight
Shadow Threshold: Everything below is considered as belonging to shadow
Other ones are mentioned in the documentation, but they are not useful to understand the algorithmic concept.
1. Determine to which category the pixel belong: Highlight / Shadow / none.
For this part you might consider using either the grayscale image or the Value channel from HSV transformation.
I would take a look to the pixel and its neighborhood.
Compute statistics of the local distribution (mean and variance).
I will compare the mean to the thresholds value define previously, then use the variance to distinguish if the pixel is noisy or belonging to a contour, which on those case I'll expect a huge variance.
2. Apply the processing
In case the pixel is belonging to the shadow or highlight class you want to improve its contrast, not the "gray" but the "color" contrast.
Dumb approach:
Will be to weight your color channel according to their intra-variances.
Here is an example: Consider your pixel being: (32, 35, 50)(R,G,B) and belonging to shadow class. I will determine 3 coefficients Rc, Gc, Bc which are defined between 0.5 - 1.5 (arbitrary) which apply to the respective channel.
Since the Blue is dominant I would have a high coefficient for the blue like 1.3 and lower the importance of R and G channel with a coefficient about 0.8.
To compute these coefficients you can think to look at color variance, meaning differences between the color channels themselves and differences between each channels and the pixel mean.
Other (high-level) approaches
Laplacian Pyramids
Using the pyramids to distinguish the details in different scales and the laplacian to improve the contrast.
http://mcclanahoochie.com/blog/portfolio/opencl-image-pyramid-detail-enhancement/
https://www.darktable.org/2017/11/local-laplacian-pyramids/
Those links could be really helpful for you, especially because the sources are available and the concept are well explained.
I would advise you to continue your quest to look deeper in darktable. It's a powerful free/open-source alternative to Lightroom.
I already find some interesting stuff just by looking at their blog.
Sorry for this incomplete answer, I'll probably come back there to improve it.
All comments and suggestions are more than welcome
You can follow the following technique. It is not accurate but imitates well.
lumR = 0.299;
lumG = 0.587;
lumB = 0.114;
// we have to find luminance of the pixel
// here 0.0 <= source.r/source.g/source.b <= 1.0
// and 0.0 <= luminance <= 1.0
luminance = sqrt( lumR*pow(source.r,2.0) + lumG*pow(source.g,2.0) + lumB*pow(source.b,2.0));
// here highlights and and shadows are our desired filter amounts
// highlights/shadows should be >= -1.0 and <= +1.0
// highlights = shadows = 0.0 by default
// you can change 0.05 and 8.0 according to your needs but okay for me
h = highlights * 0.05 * ( pow(8.0, luminance) - 1.0 );
s = shadows * 0.05 * ( pow(8.0, 1.0 - luminance) - 1.0 );
output.r = source.r + h + s;
output.g = source.g + h + s;
output.b = source.b + h + s;
I am using Laplacian of Gaussian for edge detection using a combination of what is described in http://homepages.inf.ed.ac.uk/rbf/HIPR2/log.htm and http://wwwmath.tau.ac.il/~turkel/notes/Maini.pdf
Simply put, I'm using this equation :
for(int i = -(kernelSize/2); i<=(kernelSize/2); i++)
{
for(int j = -(kernelSize/2); j<=(kernelSize/2); j++)
{
double L_xy = -1/(Math.PI * Math.pow(sigma,4))*(1 - ((Math.pow(i,2) + Math.pow(j,2))/(2*Math.pow(sigma,2))))*Math.exp(-((Math.pow(i,2) + Math.pow(j,2))/(2*Math.pow(sigma,2))));
L_xy*=426.3;
}
}
and using up the L_xy variable to build the LoG kernel.
The problem is, when the image size is larger, application of the same kernel is making the filter more sensitive to noise. The edge sharpness is also not the same.
Let me put an example here...
Suppose we've got this image:
Using a value of sigma = 0.9 and a kernel size of 5 x 5 matrix on a 480 × 264 pixel version of this image, we get the following output:
However, if we use the same values on a 1920 × 1080 pixels version of this image (same sigma value and kernel size), we get something like this:
[Both the images are scaled down version of an even larger image. The scaling down was done using a photo editor, which means the data contained in the images are not exactly similar. But, at least, they should be very near.]
Given that the larger image is roughly 4 times the smaller one... I also tried scaling the sigma by factor of 4 (sigma*=4) and the output was... you guessed it right, a black canvas.
Could you please help me realize how to implement a LoG edge detector that finds the same features from an input signal, even if the incoming signal is scaled up or down (scaling factor will be given).
Looking at your images, I suppose you are working in 24-bit RGB. When you increase your sigma, the response of your filter weakens accordingly, thus what you get in the larger image with a larger kernel are values close to zero, which are either truncated or so close to zero that your display cannot distinguish.
To make differentials across different scales comparable, you should use the scale-space differential operator (Lindeberg et al.):
Essentially, differential operators are applied to the Gaussian kernel function (G_{\sigma}) and the result (or alternatively the convolution kernel; it is just a scalar multiplier anyways) is scaled by \sigma^{\gamma}. Here L is the input image and LoG is Laplacian of Gaussian -image.
When the order of differential is 2, \gammais typically set to 2.
Then you should get quite similar magnitude in both images.
Sources:
[1] Lindeberg: "Scale-space theory in computer vision" 1993
[2] Frangi et al. "Multiscale vessel enhancement filtering" 1998
I have a pptx file with a single shape. Setting it to 70% transaprent I can compare the pptx and see the only difference is in /ppt/slides/slide1.xml
<a:solidFill>
<a:schemeClr val="accent1">
<a:alpha val="40000"/>
</a:schemeClr>
</a:solidFill>
Anyone have any idea how on earth "70%" translates to "40000"?
It seems different for me. My alpha values seem to use this function:
y = -1000x + 100000
Where x is the percentage and y is the alpha value. I recommend you do the same (figure out a function based on your computer and verify them) and not worry about it.
It seems each single percentage unit corresponds to 1000 of these alpha units.
I want to take a picture of something.
The colors in the picture are not the same as I see in my eyes.
So in order to fix this problem, I decided to place a red paper (with RGB: [255 0 0]) and then take a picture including this paper.
If I see that the RGB of the paper is changed (such as [243 15 7]),
I will change all the RGB in the picture by the next way:
R (red), it will be added by value 12.
G (green), it will be subtracted by value 15.
B (blue), it will be subtracted by value 7.
By this way, my paper will be changed to his correct RGB [255 0 0] and then I can be sure that all the rest picture's RGB was changed to its original color.
What do you think about this way?
What you are trying to do is called Color Management/Color Correction.
I have some remarks:
First, you must make sure that your monitor is calibrated. If it isn't calibrated, it makes no sense to do a visual check. If you have a standard consumer monitor, chances are that you cannot calibrate it at all.
Why do you assume that the RGB of the paper is [255,0,0]? It could be slightly greener or bluer. You should use a known target, like Macbeth ColorChecker
The offset transformation that you are using, will not work if amount of light is changed. Instead, it should be multiplicative to be invariant to illumination intensity. Check out the standard method of color correction, Color Correction Matrix.
You will need more than one known color. Three is the absolute minimum to calibrate the matrix.
You can try to use white paper instead of red. By doing this, you will have information about three colors, not only red. In the perfect case, RGB values for white paper will be equal, for example, you get (197,197,197). But if they are not equal, for example (190, 204, 203), you can change them for each pixel by multiplying on some number:
mean = (190 + 204 + 203) / 3
red_new = red * mean / 190
green_new = green * mean / 204
blue_new = blue * mean / 203
i read about an iterative process of colour correction that could perhaps be applied in your case:
Correction with Photoshop in 7 Easy Steps by Helen
Bradley,
nevertheless, confirm that it works as expected
good luck
I'm trying to implement blend modes from the PDF specification, for my own pleasure, in SASS.
PDF Specification:
http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf
Page 322 is the alpha compositing section.
The input values are in RGBA format, but now I'm trying to implement blending of the alpha component. How do I excatly go about doing it? From what I gather my values should be between 0.0 and 1.0, that's done. However from the specs it seems that you should blend for each color channel? Do I just average it out to get back to RGBA form for my alpha component?
Any help is appriciated, I don't mind reading blog, books etc. to get my answer, as this is purely an intellectual exercise.
Thanks in advance,
Emil
The SVG spec has a lot of good equations for various blending modes. And yes, you do have to calculate both the new alpha and the new colour -- for each channel. For standard blending modes, the alpha is calculated this way:
alpha_final = alpha_bg + alpha_fg - alpha_bg * alpha_fg
Note: I see you're considering alpha to be between 0 and 1, which is good. Alpha values in CSS are always defined as float values from 0 to 1; it's good to stick with this convention, because it makes the calculations immensely easier.
It helps to 'premultiply' each colour channel by its alpha; these are more helpful for interpreting and using the usual formulae:
colour_bg_a = colour_bg * alpha_bg
In other words:
red_bg_a = red_bg * alpha_bg
green_bg_a = green_bg * alpha_bg
blue_bg_a = blue_bg * alpha_bg
Then, for plain-jane alpha compositing (like overlaying sheets of tracing paper, also known as src-over in Porter and Duff's original paper and the SVG alpha compositing spec), you take each channel and calculate it thus:
colour_final_a = colour_fg_a + colour_bg_a * (1 - alpha_fg)
The last step is to 'un-multiply' each final colour channel value by the final alpha:
colour_final = colour_final_a / alpha_final
and put it into your mixin somehow:
rgba(red_final, green_final, blue_final, alpha_final)
The other blending modes (multiply, difference, screen, etc) are slightly more complicated formulas, but the concept for every single mode is the same:
Separate the R, G, B, and A values of both the foreground and background colours
Calculate the alpha of the new, final colour with the above formula
Pre-multiply all the R, G, and B values by their alpha value
Calculate the new, final R, G, and B values (insert blending mode formula here)
Un-multiply the final R, G, and B values by the final alpha
Clip the final R, G, and B values so that they are between 0 and 255 (necessary for some modes, but not all)
Put the colour back together again!
If you're still interested in this, I've been doing the very thing in Stylus. You can see my progress here: https://github.com/pdaoust/stylus-helpers/blob/master/blend.styl You might be able to use it as a starting point for your own Sass mixin.
The first thing I do is convert all the R, G, and B values from 0 - 255 values to 0 - 1 float values for the purposes of the calculations. I don't know if that's necessary, and it does require converting them back to 0 - 255 values. It felt right to me, and Porter and Duff worked in 0 - 1 float values in their original paper.
(I'm encountering trouble with some of the compositing modes, which produce wildly different results from the expected results that the SVG spec pictures. I suspect that the spec gives the wrong equations. If anyone knows about Porter/Duff blending modes, I'd be very grateful for their help!)