Sunday, April 19, 2026

Histogram in a grayscale image processing class had bugs that Claude.ai pointed out(8 Year old project)

I was researching histograms and have an app that draws one using qt.. here is the code for histogram.cpp.. I want you to explain at a high level and check if it is correct? 

The GITHUB repo link first: https://github.com/JCamiloo/ImageProcessing

Here's a high-level explanation and code review:

What the Code Does

This implements a grayscale image processing class with three main capabilities:

  1. Histogram calculation — counts how many pixels exist at each intensity value (0–255)
  2. Histogram equalization — redistributes pixel intensities to improve contrast
  3. Thresholding — converts a grayscale image to binary (black/white) using either ISODATA or Otsu's method

Bugs & Issues

1. calculateHistogram — Wrong pixel format assumption

originalPixels = image.bits(); // assumes 1 byte per pixel

image.bits() returns raw bytes, but most Qt images use more than 1 byte per pixel (e.g. RGB = 3 bytes, ARGB = 4 bytes). You should either enforce Format_Grayscale8 before calling this, or stride by bytesPerPixel. Without this, you're reading garbage values for non-grayscale images.

2. calculateHistogram — Array never reset

histogramArray[value]++;

histogramArray is never zeroed before accumulating. If calculateHistogram is called more than once (which it is — both equalizeHistogram and calculateThreshold call it), values from previous calls accumulate, producing a corrupt histogram.

Fix: Add memset(histogramArray, 0, sizeof(histogramArray)); at the start.

3. calculateThreshold (Otsu) — Division by zero risk

float m2 = (sum - meanF) / q2;

When i = 255, q2 becomes 0, causing a divide-by-zero crash.

Fix:

if (q1 == 0 || q2 == 0) continue;

4. calculateThreshold — Missing return for OTSU path edge case

The function has no return threshold at the bottom — if somehow neither branch is entered (malformed enum), behavior is undefined. Minor, but worth a default return 0 at the end.

5. equalizeHistogramequalizedHistogram never reset

Same issue as histogramArrayequalizedHistogram accumulates across calls.

6. thresholding — Image format mismatch risk

qThresholdedImage = QImage(image.width(), image.height(), image.format());

If the source image isn't Format_Grayscale8, writing single bytes per pixel into thresholdedPixels will misalign with the actual bytes-per-pixel of the format, corrupting the output.


Summary Table

Issue Severity
Histogram array not reset between calls 🔴 High
Pixel format not enforced (bytesPerPixel) 🔴 High
Otsu divide-by-zero at q2=0 🔴 High
equalizedHistogram not reset 🟡 Medium
Thresholding format mismatch 🟡 Medium
Missing default return in calculateThreshold 🟢 Low

The core logic of equalization and both thresholding algorithms is correct — the math checks out. The bugs are mostly around memory/format assumptions that are easy to fix.

No comments:

Post a Comment