Image Processing
Uneven Illumination
Algorithm Development
Detection Techniques
Computer Vision

Robust Algorithm to detect uneven illumination in images Detection Only Needed

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Uneven illumination is a lighting problem, not necessarily a content problem. If you only need to detect it, the goal is to estimate whether low-frequency brightness variation is strong enough to distort later steps such as thresholding, segmentation, or defect detection.

Model Illumination as a Low-Frequency Signal

A practical starting point is to treat illumination as the slowly varying part of an image. Texture, edges, and small objects are mostly high-frequency details. Lighting gradients, shadows, and vignetting usually change more gradually across the frame.

That observation leads to a robust strategy:

  1. Convert the image to a luminance-like representation.
  2. Estimate the background illumination with a large blur or morphological filter.
  3. Measure how much that background varies across the image.
  4. Suppress false positives from strong texture by checking local contrast separately.

The important detail is the last step. A brick wall can have large intensity variation without suffering from uneven lighting. If you only look at raw variance, texture and illumination get mixed together.

A Detection Pipeline That Works in Practice

For many real-world images, a Gaussian blur with a large sigma is enough to approximate the illumination field. After that, you can compare each pixel's background level to the global mean or to a fitted plane. Regions with large background deviation and low local texture are strong candidates for uneven lighting.

The following example uses OpenCV and NumPy. It returns a score between 0.0 and 1.0 and a binary mask that marks suspicious regions.

python
1import cv2
2import numpy as np
3
4
5def detect_uneven_illumination(path: str) -> tuple[float, np.ndarray]:
6    image = cv2.imread(path, cv2.IMREAD_COLOR)
7    if image is None:
8        raise FileNotFoundError(path)
9
10    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY).astype(np.float32) / 255.0
11
12    # Estimate low-frequency lighting.
13    background = cv2.GaussianBlur(gray, (0, 0), sigmaX=31, sigmaY=31)
14
15    # Local texture estimate used to reject highly detailed regions.
16    local_mean = cv2.blur(gray, (21, 21))
17    local_sq_mean = cv2.blur(gray ** 2, (21, 21))
18    local_std = np.sqrt(np.maximum(local_sq_mean - local_mean ** 2, 0.0))
19
20    background_error = np.abs(background - background.mean())
21
22    mask = ((background_error > 0.08) & (local_std < 0.12)).astype(np.uint8) * 255
23    score = float(mask.mean() / 255.0)
24
25    return score, mask
26
27
28score, mask = detect_uneven_illumination("sample.jpg")
29print(f"Uneven illumination score: {score:.3f}")
30cv2.imwrite("illumination_mask.png", mask)

This detector is intentionally simple. It works because it measures two different signals: broad brightness drift and local image complexity. Large drift with low texture usually means lighting, while large drift with high texture is more likely to be scene structure.

Choosing Thresholds and Window Sizes

There is no universal blur radius or threshold. A document scan, a microscopy image, and a street scene all have different scale. The blur kernel must be large enough to ignore normal objects but small enough to preserve meaningful lighting gradients.

If your images have a consistent size, calibrate on a small validation set. For example, for 1024 x 1024 grayscale images, a blur sigma around 25 to 40 pixels is often a reasonable first pass. For very small images, that would be too aggressive and would wash out the entire frame.

You can also make the detector more global by fitting a plane to the background field and measuring residual error. That helps when the lighting pattern is mostly a smooth top-to-bottom or left-to-right gradient. The simpler blur-based version is usually enough unless you need strong invariance across different cameras.

Detection Only Versus Correction

Because the task is detection only, you do not need to divide the image by the background or reconstruct a corrected frame. That simplifies the algorithm and reduces risk. The detector only needs to answer a question such as, "Is this image likely affected enough that downstream processing should reject it or send it to a slower pipeline."

In production systems, the score is often more useful than the mask. A score lets you set policy thresholds, compare camera setups, and monitor drift over time. The mask is still valuable for debugging because it shows whether the detector is reacting to shadows, vignetting, or plain texture.

Common Pitfalls

Using a blur window that is too small makes the estimated background follow texture rather than illumination. Increase the smoothing scale until details disappear and only lighting trends remain.

Relying on variance alone causes false positives on textured surfaces such as fabric, wood, or grass. Combine background drift with a local texture measure.

Working in RGB directly often makes color changes look like lighting changes. Use grayscale or a luminance channel first.

Hard-coded thresholds can fail when camera exposure changes. Calibrate thresholds on representative samples, or normalize scores relative to image statistics.

Summary

  • Uneven illumination is best treated as a low-frequency brightness variation problem.
  • A robust detector estimates a smooth background and separates illumination from texture.
  • Combining background deviation with local standard deviation greatly reduces false positives.
  • For detection-only workflows, the output score is often more useful than a corrected image.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.