SYSTEMS / UCT · CSC3022 / 2024
Structure inside grayscale images
Turn grayscale pixels into countable regions using thresholding, breadth-first flood fill and component-size filtering in C++.

UCT / COURSE CONTEXT / 2024
CSC3022F · C++ and Machine Learning
C++ language and memory-model foundations followed by Python-based machine-learning implementation.
2026 PORTFOLIO RECREATIONS
Pixels into regionsENGINEERING PERSPECTIVE
Inside the work
Turn a grayscale raster into discrete regions that can be counted and filtered. It demonstrates classical segmentation, traversal and C++ resource ownership without claiming a trained vision model.
- C++ / std::queue
- Manage pixel buffers and run breadth-first flood fill.
- PGM / tests
- Read binary grayscale rasters, write masks and check component behaviour on bounded inputs.
Select foreground
Read a grayscale image and apply the chosen intensity threshold.
- Connectivity
- Four-neighbour adjacency groups pixels differently from diagonal/eight-neighbour connectivity.
- Threshold and size
- Intensity selects foreground; component-size bounds then remove small or oversized regions.
- Ownership
- Copy/move operations and buffer lifetime matter independently of segmentation correctness.
What the demonstration establishes
The browser recreation uses a separate visited mask. The public C++ retains the original zero-as-visited traversal and therefore rejects zero thresholds. Release-day checks include six synthetic regressions, ten malformed inputs and four safety/output cases; these are not image-accuracy benchmarks.
Evidence behind this page
Named processor source and authored synthetic input/mask execution. Public parsing, scoped ownership and iterator fixes are labelled 2026 improvements; supplied fixtures and teaching tests are withheld.
What it is
Extract connected foreground regions from PGM images, inspect component statistics and write filtered masks.
Why it was built
Identify connected foreground regions and remove components outside a chosen size range in grayscale images.
My contribution
Individual C++ coursework implementation. The public release uses authored synthetic fixtures and new verification; supplied images, Catch and original fixture-dependent tests remain privately preserved.
How it works
Apply a grayscale threshold, traverse connected neighbours using a queue-based flood fill, store component pixels and filter by minimum/maximum size.
- 01PGM image
- 02Threshold
- 03BFS traversal
- 04Size filter
- 05Output mask
Technical implementation
- Read a PGM raster, threshold grayscale pixels, then use four-neighbour queue traversal to discover connected components.
- Store component pixels, derive size statistics and filter using minimum/maximum limits before writing a mask.
- The class implements copy/move ownership behaviour. Labelled 2026 changes add bounded input parsing, reject zero thresholds, release temporary components and erase filtered elements safely without replacing the traversal algorithm.
- Private historical verification passed 19 assertions in two submitted cases. Public release-day verification separately passed six synthetic regressions, ten malformed-input cases and four additional safety/output checks.
Results & evidence
- The submitted processor compiled, passed 19 assertions in two private tests and generated a mask from a new synthetic input.
- The public release passed six synthetic regressions, ten malformed-input checks and four additional safety/output checks on 12 October 2026. Supplied fixtures and teaching tests remain excluded.
Engineering challenges
Connectivity, threshold boundaries, image parsing and object ownership need to agree; test expectations cover only a small surface.
Scope & limitations
Classical image processing, with no trained model. Only 8-bit P5 is supported; threshold zero is rejected because the original traversal uses zero as its visited marker. Safety fixes are labelled post-project improvements.
What I learned
Viewing an image as a graph and combining traversal algorithms with C++ resource management.
What I would improve now
Add sanitizer coverage, copy/move edge-case tests and an independent per-pixel reference across more synthetic connectivity cases. Improve boundary counting and clarify empty-component summary semantics.