Gamma Correction
Implement a point operator to apply gamma correction to an image. This process transforms the image's intensity values to adjust its brightness and contrast.
Gamma correction is a non-linear operation that modifies the image's pixel values based on a power-law relationship, which can brighten or darken regions. The gamma value determines the amount of correction, where values less than 1 increase the brightness of dark areas and values greater than 1 decrease the brightness.
Here are the steps to perform gamma correction:
- Normalize the input image intensity values to the range [0,1].
- Raise each normalized value to the power of gamma.
- Scale the result back to the original range [0,255].
This technique is widely used in image and video processing applications to adjust the display's brightness and contrast.
Example:
gamma_correct([[64, 128]], 0.5)
[[128, 181]]
- First, apply the formula Ioutβ=255β (255Iinββ)0.5 to each pixel value in [[64,128]].
- For 64: 25564ββ0.251, then 0.2510.5β0.501, and 255β 0.501β128.
- For 128: 255128ββ0.502, then 0.5020.5β0.708, and 255β 0.708β181.
- Rounding these results gives the output [[128,181]].
Constraints:
- gamma > 0
- Output rounded to nearest integer
- Background Knowledge
Gamma correction is a point operation on images: each pixel is transformed independently according to a nonlinear function, without considering its neighbors. For an 8-bit grayscale (or per-channel color) image, pixel intensities lie in [0,255]. The given formula
Ioutβ=255β (255Iinββ)Ξ³maps each input intensity Iinβ to a new intensity Ioutβ using an exponent Ξ³.
Because the function is nonlinear, it redistributes brightness: Ξ³<1 stretches dark values and brightens shadows, while Ξ³>1 compresses bright values and darkens the image. Conceptually, this is related to how human vision and displays respond nonlinearly to light: applying gamma correction lets us adjust perceived contrast and brightness more naturally than with a simple linear scaling.
- Algorithm / Approach
General pattern for this type of point-operator problem:
- Normalize pixel values to a standard range (usually [0,1]).
- Apply a mathematical function independently to each pixel (here, power with exponent Ξ³).
- Rescale back to the original value range (e.g., [0,255]) and data type (e.g., 8-bit).
For color images, the same formula is usually applied per channel (R, G, B) unless the problem specifies working in a different color space (e.g., only on luminance).
-
Step-by-Step Strategy
-
Read the image
- Get pixel values as a numeric array.
- Ensure you know the data type (e.g., uint8) and shape (grayscale vs color).
- Convert to float
- Cast to a floating-point type to avoid integer overflow/truncation during computation.
- Normalize
- Compute X=Iinβ/255.0.
- Now Xβ[0,1].
- Apply gamma
- Compute Y=XΞ³ (element-wise power).
- Rescale
- Compute Iout_floatβ=255β Y.
- Clamp and cast
- Clamp values to [0,255] to avoid rounding artifacts.
- Cast back to the original integer type (e.g., uint8).
- Return or display
- Ensure the output has the same shape and type as the input.
Example (Python-like pseudocode):
def gamma_correction(img, gamma):
img_float = img.astype(np.float32)
normalized = img_float / 255.0
corrected = np.power(normalized, gamma)
out = corrected * 255.0
out = np.clip(out, 0, 255)
return out.astype(np.uint8)
- Common Pitfalls
- Integer math: Applying powers on integer arrays without converting to float will give wrong results (due to truncation and overflow).
- Wrong normalization: Forgetting to divide by 255 (or dividing twice) changes the meaning of Ξ³.
- Type and range issues: Not clamping to [0,255] before casting back to uint8 can cause wrap-around in some environments.
- Color images: Treating a color image as grayscale accidentally (e.g., by averaging channels) if the problem expects per-channel gamma.
- Gamma sign / value: Using negative or zero gamma will break the formula; typically Ξ³>0 is assumed.
- Time & Space Complexity
Let N be the number of pixels (for color, think of N as βnumber of scalar values,β i.e., width Γ height Γ channels):
-
Time complexity: O(N) You perform a constant number of arithmetic operations per pixel.
-
Space complexity:
-
If you create a separate output image: O(N) extra space.
-
If you do it in-place (carefully, with correct types): auxiliary space can be O(1) beyond the image itself.