NivaarExam PrepOfficial exam papers ↗

20-Bio-B4 Robotics · December 2014

Question 6 of 6: Application — Counting Objects With and Without Holes

Nivaar worked solution (AI-drafted; not reviewed by a licensed engineer)

Notes on this paper

Paper format: National Exams, December 2014 — 04-Bio-B4 Digital Image Processing. Three hours, open book (any paper notes or textbooks permitted, but no calculator or computer). Six questions of equal value (20 marks each); five constitute a complete paper and only the first five appearing in the answer book are marked. All six are solved here, because this set is a study resource rather than an examination script. Every question is essay/descriptive (definitions, algorithm design, system design) except the operation-count comparison in Question 2(d), which is a short analytical calculation.

Reference texts (the books a candidate should have reviewed for this subject):

Question 6: Application — Counting Objects With and Without Holes (20 marks)

Question text not reproduced: the examination questions are © Engineers and Geoscientists BC. Open the official past paper (linked at the top of this page) to read the question, then follow the worked solution below.

Given. A binary image $I$ (1 = object, 0 = background/hole) corrupted by salt-and-pepper noise, containing an unknown number of non-touching, arbitrarily-shaped objects.

Find. An algorithm that correctly reports how many objects have at least one internal hole and how many do not, ignoring noise.

Approach. Denoise first, label foreground objects, then determine which background components are truly enclosed (holes) rather than reachable from the image border.

Binary image I(1=object, 0=bg/hole)with salt and pepper noiseMedian filter(3x3) + area-open(remove impulse noise)Connected-componentlabel FOREGROUND(8-conn) -> objects OkConnected-componentlabel BACKGROUNDfrom a border flood-fillAny 0-component NOTreached from border =a hole; assign to itsenclosing object OkCount objects with>=1 hole vs 0 holes
Proposed hole-counting pipeline: denoise, label foreground objects, separately label background components via a border flood-fill, then classify.
  1. Denoise. Apply a 3×3 median filter to $I$ (impulsive salt-and-pepper noise is exactly the case the median filter is designed for: an isolated flipped pixel is always outvoted by its 8 unaffected neighbours, and, unlike a mean/linear filter, the median does not blur true object boundaries). Follow with a small morphological area-opening (remove any surviving foreground blob below a minimum-area threshold $A_{\min}$, set well below the smallest expected true object) as a safety net against any noise the median filter did not fully remove.
  2. Label foreground objects. Run 8-connected connected-component labelling on the "1" pixels of the cleaned image, producing labels $O_1, O_2, \dots, O_K$ (one per true object, since objects are stated not to touch).
  3. Label background components with a border flood-fill. Run 4-connected connected-component labelling on the "0" pixels. (4-connectivity is deliberately used for the background against 8-connectivity for the foreground — using the same connectivity for both would let a diagonal chain of foreground pixels and a diagonal chain of background pixels cross without ever meeting, the classic connectivity paradox.) Any background component that touches the image border is the outer background; every other background component is fully enclosed.
  4. Classify. For every enclosed background component (a candidate hole) that survives the same area threshold $A_{\min}$ (filtering out any residual pepper-noise speck too small to be a genuine hole), find the foreground label(s) immediately adjacent to its boundary pixels. Since objects do not touch, exactly one object label borders each true hole; mark that object as "has a hole".
  5. Count. Report the number of objects with $\ge 1$ associated hole, and the number with zero.
function countHoles(I):
    I_clean = medianFilter3x3(I)
    I_clean = areaOpen(I_clean, A_min)          // drop tiny leftover foreground specks

    [fgLabels, K]  = connectedComponents(I_clean, value=1, connectivity=8)
    [bgLabels, M]  = connectedComponents(I_clean, value=0, connectivity=4)

    borderLabels = { bgLabels(y,x) : (y,x) on the image border, bgLabels(y,x) != 0 }

    hasHole = array of K false values
    for each background label L in 1..M:
        if L in borderLabels: continue           // reachable from outside -> not a hole
        pixels = pixels with bgLabels == L
        if size(pixels) < A_min: continue         // residual pepper noise, not a real hole
        neighbourObjects = { fgLabels(y2,x2) : (y2,x2) is 4-adjacent to some pixel in pixels,
                              fgLabels(y2,x2) != 0 }
        for k in neighbourObjects: hasHole[k] = true

    nWithHoles    = count(hasHole == true)
    nWithoutHoles = K - nWithHoles
    return nWithHoles, nWithoutHoles
StepPurposeKey design choice
Median filter + area-openRemove salt-and-pepper noise before it can be mistaken for objects or holesMedian (not mean) filter: preserves edges, rejects impulsive noise
Foreground labellingIdentify each true object8-connectivity
Background labelling + border flood-fillDistinguish outer background from true enclosed holes4-connectivity (paired with 8-connectivity foreground to avoid the connectivity paradox)
Area-threshold on holesReject any leftover 1-pixel pepper defect that survived filteringSame $A_{\min}$ philosophy as the foreground clean-up
Check: assumes a minimum true object/hole area $A_{\min}$ can be chosen that is larger than any residual noise blob but smaller than the smallest genuine object or hole in the image; this holds for typical salt-and-pepper (single-pixel) corruption but would need re-tuning if the noise came in larger clusters.

The pipeline above (median filter, 8-connected foreground labelling, 4-connected background labelling with a border flood-fill, area-thresholded hole classification) is robust to isolated salt-and-pepper noise, whereas running the same classification on the raw, un-denoised image gives the wrong count, so the denoising stage is not optional.

Back to the paper →