DIP+CV · Programming Exercise

EP06_05 — 🟠 Background Normalization by Division (Illumination Correction)

6.14.5 EP06_05 🟠 Background Normalization by Division (Illumination Correction)

A form was photographed under non-uniform illumination, causing one side of the page to appear lighter than the other. Under these conditions, global thresholding by Otsu can produce unsatisfactory results, since a single threshold does not properly separate text and background across the entire image. The solution presented in the chapter consists of normalizing the background by dividing the original image by a heavily smoothed version of itself, which represents the low-frequency illumination.

In this exercise, the original image and the smoothed background (equivalent to the result of a cv2.GaussianBlur with high \(\sigma\)) are already provided. Your task is to implement the normalization step that produces the corrected image.

6.14.5.1 📋 Implementation Guidelines

  1. Dimensions: Read the integers \(L\) (rows) and \(C\) (columns).
  2. Original image: Read the \(L \times C\) integer values of the matrix img (intensities between 0 and 255).
  3. Estimated background: Read the \(L \times C\) integer values of the matrix bg (intensities between 0 and 255, always strictly greater than zero).
  4. Normalization: For each position \((i,j)\), compute \[ \text{value}(i,j)= \frac{\text{img}(i,j)}{\text{bg}(i,j)}\times255. \]
  5. Rounding: Round the result to the nearest integer (round half away from zero, using np.floor(img + 0.5)).
  6. Saturation: Clip the obtained value to the interval \([0,255]\).
  7. Output: Print the resulting matrix img_norm.

6.14.5.2 📌 Computational Constraints

  • Division by zero: the input guarantees \(\text{bg}(i,j)>0\) at all positions.
  • Order of operations: first round, then apply saturation.
  • Independent processing: each pixel must be normalized individually, without using information from neighboring pixels.

6.14.5.3 🧠 Theoretical Foundation

Situation Effect of normalization
\(\text{img}(i,j)=\text{bg}(i,j)\) Result equal to \(255\), corresponding to the normalized background.
\(\text{img}(i,j)<\text{bg}(i,j)\) Result less than \(255\), preserving darker regions, such as text.
\(\text{img}(i,j)>\text{bg}(i,j)\) Result greater than \(255\), subsequently saturated.
Background with non-uniform illumination The division reduces slow illumination variations, making the image more homogeneous.

Dividing by the estimated background reduces the effects of non-uniform illumination and preserves the contrast between foreground and background, facilitating subsequent segmentation steps.

6.14.5.4 📦 Input and Output Specification (VPL)

Input:

  • Line 1: Integer \(L\).
  • Line 2: Integer \(C\).
  • Next \(L\) lines: elements of the matrix img.
  • Next \(L\) lines: elements of the matrix bg.

Output:

  • Matrix img_norm, with \(L\) rows and \(C\) columns, containing integer values separated by spaces.

6.14.5.5 📌 Examples

Input Output Observation
2
2
60 120
180 40
100 100
200 80
153 255
230 128
Values greater than \(255\) must be saturated; \(180/200\times255=229.5\) results in \(230\) after rounding.
1
3
30 60 90
60 60 60
128 255 255 Only the first value remains below \(255\) after normalization.
🎮 Simulator EP06_05: Background Normalization by Division (img / bg) × 255
Adjust the background gradient (left → right) and observe how division cancels the illumination variation.
img (Original)
bg (Smoothed Background)
img_norm (Output)
–
Figure 6.25: EP06_05 Simulator: Background Normalization by Division
%%writefile EP06_05.py
# Python code
Overwriting EP06_05.py
TestSuite("EP06_05.py").run()
✔️ EP06_05.cases already exists in casos/
📋 5 case(s) loaded from casos/EP06_05.cases

🔍 Testing Python: EP06_05.py
⚠️ EP06_05.py: Empty file (fewer than 3 lines). Tests skipped.