Reputation: 4912
I found a way to increase the gamma, but no way to decrease it! This article states a formula for increasing the gamma. The formula works for increasing the gamma but not for decreasing, even if I apply the reduction on a new instance of the canvas. I tried redrawing the canvas and using a negative value for gamma calculation, but I don't get my original canvas back.
//For increasing, I tried
gamma = 0.5;
gammacorrection = 1/gamma;
r = Math.pow(255 * (r / 255), gammacorrection);
g = ...
b = ...
//For decreasing
gamma = -0.5;
gammacorrection = 1/gamma;
r = Math.pow(255 * (r / 255), gammacorrection);
g = ...
b = ...
First part works. Second doesn't.
Upvotes: 0
Views: 5878
Reputation: 1171
For sake of completeness here's a working piece of code
async function adjustGamma(gamma) {
const gammaCorrection = 1 / gamma;
const canvas = document.getElementById('canvasOutput');
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(0.0, 0.0, canvas.width, canvas.height);
const data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
data[i] = 255 * Math.pow((data[i] / 255), gammaCorrection);
data[i+1] = 255 * Math.pow((data[i+1] / 255), gammaCorrection);
data[i+2] = 255 * Math.pow((data[i+2] / 255), gammaCorrection);
}
ctx.putImageData(imageData, 0, 0);
}
Here the function adjusts the gamma based on the formula in the Article linked by OP on the Canvas with id "canvasOutput"
Upvotes: 6
Reputation: 11551
There is no negative value for gamma. Ideally this value will range between 0.01
and 7.99
. So reverting back the gamma to the original value should be possible either by creating a new canvas instance with the original values of the image, then instantiating it, or either by creating a pool of pixels with the original image and reverting back to it.
I wrote a script how would i construct the algorithm for gamma reduction.
var gamma = 0.5;
var gammaCorrection = 1 / gamma;
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var imageData = ctx.getImageData(0.0, canvas.width, canvas.height);
function GetPixelColor(x, y) {
var index = parseInt(x + canvas.width * y) * 4;
var rgb = {
r : imageData.data[index + 0],
g : imageData.data[index + 1],
b : imageData.data[index + 2]
};
return rgb;
}
function SetPixelColor(x, y, color) {
var index = parseInt(x + this.width * y) * 4;
var data = imageData.data;
data[index+0] = color.r;
data[index+1] = color.g;
data[index+2] = color.b;
};
for (y = 0; y < canvas.height; y++) {
for (x = 0; x < canvas.width; x++) {
var color = GetPixelColor(x, y)
var newRed = Math.pow(255 * (color.r / 255), gammaCorrection);
var newGreen = Math.pow(255 * (color.g / 255), gammaCorrection);
var newBlue = Math.pow(255 * (color.b / 255), gammaCorrection);
var color = {
r: newRed,
g: newGreen,
b: newBlue
}
SetPixelColor(x, y, color);
}
}
I don't know how the application should adjust the gamma value, but i suppose it's done with a value adjuster. If so you should adjust the gamma value dynamically giving the min and max range. I didn't tested the code, this wasn't my scope, but the idea is hopefully clear.
EDIT: To understand the principle of gamma correction first how about to define the gamma instead.
Gamma is the monitor particularity altering the pixels input. Gamma correction is the act of inverting that process for linear RGB values so that the final output remains linear. For example, if you calculated the light intensity of an object is 0.5, you don't store the result as 0.5 in the pixel. Store it as pow(0.5, 1.0/2.2) = 0.73
. When you send 0.73 to the monitor, it will apply a gamma on the value and produce pow(0.73, 2.2) = 0.5
, which is what you want. To do this, you apply the inverse gamma function.
o=pow(i, 1.0/gamma)
Where
o
is the output value.
i
is the input value.
gamma
is the gamma value used by your monitor.
So the gamma correction is nothing else than the rise of input value to the power of inverse of gamma. So to restore the gamma to the original value you apply the formula before the gamma correction has been applied.
The blue line represents the inverse gamma curve you need to apply to your pixels before they're sent to the monitor. When your monitor applies its gamma curve (red line) to the pixels, the result is a linear line (green line) that represents your intended RGB pixel values.
Upvotes: 1
Reputation: 33163
There is no negative gamma correction. You should save the original values and use them when making gamma changes, and set gamma to 1.0
to revert back to the original.
Also note that you have the wrong order of operations (exponents come before multiplication).
var originals = { r: r, g: g, b: b };
// increase
gamma = 0.5;
gammacorrection = 1/gamma;
r = 255 * Math.pow(( originals.r / 255), gammacorrection);
g = ...
b = ...
// revert to original
gamma = 1;
gammacorrection = 1/gamma;
r = 255 * Math.pow(( originals.r / 255), gammacorrection);
g = ...
b = ...
Upvotes: 4