Adjusting the brightness and contrast of an image by adjusting the intensity of its pixels; in addition to also adjusting the hue, saturation and lighting properties of the image.
This example focuses on two image methods:
• Brightness and Contrast Adjustment - Modify the brightness and contrast of an image by adjusting the intensity of its pixels.
• Hue, Saturation, and Lightness (HSL) Adjustment - Change the hue, saturation, and lightness to alter the color properties of the image.
Two main functions, one for adjusting the brightness and contrast (
adjustBrightnessContrast
function) and the other hue, saturation, and lightness (
adjustHSL
function).
The parameters for adjustint the colors are define by constants at the top of the shader with default values (e.g., BRIGHTNESS, CONTRAST, HUE, SATURATION, and LIGHTNESS).
Complete Code
let div = document.createElement('div'); document.body.appendChild( div ); div.style['font-size'] = '20pt'; function log( s ) { console.log( s ); let args = [...arguments].join(' '); div.innerHTML += args + '<br><br>'; }
// Output texture - output from the compute shader written to this texture // Copy this texutre to the 'canvas' - needs to be the same size as the output // canvas size const texture1 = device.createTexture({ size: [imgWidth, imgHeight, 1], format: "rgba8unorm", usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.STORAGE_BINDING });
// Default values as constants const BRIGHTNESS : f32 = 0.1; // Adjust this value for brightness const CONTRAST : f32 = 1.2; // Adjust this value for contrast const HUE : f32 = 0.3; // Adjust this value for hue const SATURATION : f32 = 1.1; // Adjust this value for saturation const LIGHTNESS : f32 = 0.1; // Adjust this value for lightness
// Function to adjust brightness and contrast fn adjustBrightnessContrast(color: vec4<f32>, brightness: f32, contrast: f32) -> vec4<f32> { let adjustedColor = (color - vec4<f32>(0.5)) * contrast + vec4<f32>(0.5) + vec4<f32>(brightness); return clamp(adjustedColor, vec4<f32>(0.0), vec4<f32>(1.0)); }
// Function to convert RGB to HSL fn rgbToHsl(color: vec3<f32>) -> vec3<f32> { let max = max(max(color.r, color.g), color.b); let min = min(min(color.r, color.g), color.b); let delta = max - min;
let l = (max + min) / 2.0;
if (delta == 0.0) { return vec3<f32>(0.0, 0.0, l); }
var s = 0.0; if (l < 0.5) { s = delta / (max + min); } else { s = delta / (2.0 - max - min); };
var h = 0.0; if (color.r == max) { var d = 0.0; if (color.g < color.b) { d=6.0; } else { d=0.0; } h = (color.g - color.b) / delta + d; } else if (color.g == max) { h = (color.b - color.r) / delta + 2.0; } else { h = (color.r - color.g) / delta + 4.0; };
return vec3<f32>(h / 6.0, s, l); }
fn mymod(x:f32, y:f32) -> f32 { return ( x - y * floor(x/y) ); }
// Function to convert HSL to RGB fn hslToRgb(hsl: vec3<f32>) -> vec3<f32> { let h = hsl.x; let s = hsl.y; let l = hsl.z;
let c = (1.0 - abs(2.0 * l - 1.0)) * s; let x = c * (1.0 - abs(mymod(h * 6.0, 2.0 ) - 1.0)); let m = l - c / 2.0;
var r = 0.0; var g = 0.0; var b = 0.0;
if (0.0 <= h && h < 1.0 / 6.0) { r=c; g=x; b=0.0; } else if (1.0 / 6.0 <= h && h < 1.0 / 3.0) { r=x; g=c; b=0.0; } else if (1.0 / 3.0 <= h && h < 1.0 / 2.0) { r=0.0; g=c; b=x; } else if (1.0 / 2.0 <= h && h < 2.0 / 3.0) { r=0.0; g=x; b=c; } else if (2.0 / 3.0 <= h && h < 5.0 / 6.0) { r=x; g=0.0; b=c; } else { r=c; g=0.0; b=x; };
var coords = vec2<f32>(f32(globalId.x), f32(globalId.y)); var uv = coords / vec2<f32>(imgWidth, imgHeight); // normalize coordinates to 0.0 - 1.0 range
// Load the color from the input texture var color = textureLoad(myTexture0, vec2<i32>(uv * vec2<f32>(imgWidth, imgHeight)), 0);
// Adjust Brightness and Contrast var adjustedColor = adjustBrightnessContrast(color, BRIGHTNESS, CONTRAST);
// Adjust Hue, Saturation, and Lightness var finalColor = adjustHSL(adjustedColor, HUE, SATURATION, LIGHTNESS);
// Store the result in the output texture textureStore(myTexture1, vec2<i32>(globalId.xy), finalColor); } `;
• Try adjusting the colors of different types of images (sky, faces, sunsets, moon, ..).
• Adjust the constant parameters to get a feel for their impact/importance.