All projects

PROJECT / 002 · IMAGE PROCESSING

Grayscale Image Processing Library

A closer look at every pixel.

  • C++
  • Image Processing
  • Object-Oriented Programming

Conceptual illustration · not a screenshot or measured result

Overview

GrayLib is a dependency-free C++17 library for single-channel, 8-bit images. It implements pixel storage, ASCII and binary PGM I/O, image arithmetic, region-of-interest extraction, point transformations, convolution filters, and drawing primitives without relying on OpenCV.

Motivation

Keeping image storage and processing in the project itself makes the underlying work visible: how pixels are owned, how a file becomes an image, and how local numerical operations change that image. Grayscale data keeps the scope focused while still exposing the main ideas behind filtering and transformation.

How it works

An Image can be created in memory or loaded from a PGM file. Processors return transformed images through a shared ImageProcessor interface. Available operations include brightness and contrast adjustment, gamma correction, mean and Gaussian blur, and horizontal or vertical Sobel filtering. Drawing utilities add lines, rectangles, and circles; results can be saved as P2 or P5 PGM files.

Architecture

Public headers under include/imgproc separate Image, Geometry, Processing, and Draw. Implementations in src handle storage and file I/O, transformations, and drawing. The examples program generates synthetic images and processed outputs. A dependency-free test executable covers the library, with CMake and a GitHub Actions workflow providing the build and test structure.

Implementation decisions

Image owns its heap-allocated pixels and implements deep-copy and move semantics. Arithmetic saturates within the 0–255 range, while checked pixel access catches invalid coordinates. Odd-sized convolution kernels support either zero padding or extended borders. The polymorphic processing interface lets operations be selected through one API, while the implementation remains a straightforward single-threaded CPU approach.

Challenges

Image boundaries, pixel-range limits, and object lifetimes all need explicit behavior. The library addresses them with border modes, clamped output values, clipped drawing, and defined copy/move ownership. Tests cover those contracts alongside region extraction and both PGM encodings. Color images, broad codec support, and large-image optimization remain outside the project's intended scope.

What I learned

An image-processing algorithm is only part of a useful library. Storage, copying, bounds, and file parsing determine whether it behaves predictably. Implementing filters and drawing primitives also connects the mathematics to individual pixels, while a common processing interface shows how object-oriented design can organize operations without hiding their implementation.

Repository

GitHub repository