A full implementation of core Digital Image Processing operations in C++, supporting grayscale conversion, image flipping, brightness & contrast adjustment, blur filtering, and 90-degree rotation β with no external dependencies.
- Overview
- Features
- How It Works
- Class Overview
- Getting Started
- Usage Examples
- API Reference
- Test Cases
This project implements a custom image processing library in pure C++ with no external dependencies. Images are represented internally as 3D matrices ([height][width][channel]) and are read from and written to the PPM (P3) format β a simple, human-readable pixel format.
It is commonly used as a foundation for understanding how image operations work at the pixel level, making it ideal for educational purposes, embedded systems, or any environment where library dependencies must be minimized.
- β Grayscale Conversion β Converts RGB images using the standard luminance formula
- β Horizontal Flip β Mirrors the image left to right
- β Vertical Flip β Mirrors the image top to bottom
- β Brightness Adjustment β Adds a fixed offset to all pixel values with clamping
- β Contrast Adjustment β Scales pixel intensities around the midpoint (128)
- β Blur Filter β Smooths the image using a 3Γ3 average kernel
- β 90Β° Clockwise Rotation β Rotates the image with swapped dimensions
- β PPM File I/O β Load and save images in the P3 PPM format
- β No external libraries β Pure C++ with STL only
- β Handles edge cases: border pixels in blur, clamping in brightness/contrast
Each image is stored as a 3D vector<vector<vector<int>>> with dimensions [height][width][channels]. Operations are applied either point-wise (per pixel) or via convolution with a fixed kernel:
Original RGB Image (4Γ4) 3Γ3 Average Blur Kernel
ββββββββββββββββββββββββββββββββ βββββββββββββββββββββ
β (255,0,0) (0,255,0) β β 1/9 1/9 1/9 β
β (0,0,255) (255,255,0) β * β 1/9 1/9 1/9 β β Blurred Image
β (255,0,255) (0,255,255) β β 1/9 1/9 1/9 β
β (128,128,0) (0,0,0) β βββββββββββββββββββββ
ββββββββββββββββββββββββββββββββ
Grayscale conversion applies the ITU-R BT.601 luminance formula per pixel:
gray = 0.299Β·R + 0.587Β·G + 0.114Β·B
Blur averages each pixel's 3Γ3 neighborhood. Border pixels are left unchanged since no padding is applied.
Contrast adjustment scales each pixel around the midpoint to expand or compress the intensity range:
newVal = factor Γ (pixel β 128) + 128 β clamped to [0, 255]
| Member / Method | Type / Return | Description |
|---|---|---|
data[height][width][channel] |
vector<...> |
Internal 3D pixel storage |
Image(int w, int h, int ch = 3) |
Constructor | Creates a blank image of given dimensions |
getWidth() / getHeight() / getChannels() |
int |
Returns image dimensions and channel count |
operator()(int y, int x, int channel) |
int& |
Pixel read/write access by row, column, and channel |
loadPPM(const string& filename) |
bool |
Loads a P3 PPM file from disk |
savePPM(const string& filename) |
bool |
Saves the image to a P3 PPM file on disk |
print() |
void |
Prints pixel data to the console (for small images) |
| Function | Description |
|---|---|
convertToGrayscale(input) |
Converts a 3-channel image to a single-channel grayscale |
flipHorizontal(input) |
Mirrors the image along the vertical axis |
flipVertical(input) |
Mirrors the image along the horizontal axis |
adjustBrightness(input, value) |
Adds value to all pixel intensities, clamped to [0,255] |
adjustContrast(input, factor) |
Scales intensities around midpoint 128 by factor |
applyBlur(input) |
Applies a 3Γ3 uniform averaging filter |
rotate90(input) |
Rotates the image 90 degrees clockwise |
- C++ compiler supporting C++11 or later (e.g.
g++, MSVC, Clang) - No external libraries required β pure C++ STL only
g++ -o image_processor main.cpp -std=c++11
./image_processorAfter running, the following PPM files will be generated in the working directory:
| File | Description |
|---|---|
test_image.ppm |
The original 4Γ4 test input image |
gray_image.ppm |
Grayscale output |
flipped_horizontal.ppm |
Horizontally flipped output |
flipped_vertical.ppm |
Vertically flipped output |
bright_image.ppm |
Brightness-adjusted output (+50) |
contrast_image.ppm |
Contrast-adjusted output (Γ1.5) |
blurred_image.ppm |
Blurred output (3Γ3 average) |
rotated90_image.ppm |
90Β° clockwise rotated output |
π‘ Use an image viewer that supports PPM format, or convert to PNG/JPG using GIMP or ImageMagick:
convert output.ppm output.png
// Load an image
Image input;
input.loadPPM("test_image.ppm");
// Grayscale conversion
Image gray = convertToGrayscale(input);
gray.savePPM("gray_image.ppm");
// Flip operations
Image flippedH = flipHorizontal(input);
Image flippedV = flipVertical(input);
flippedH.savePPM("flipped_horizontal.ppm");
flippedV.savePPM("flipped_vertical.ppm");
// Brightness and contrast
Image bright = adjustBrightness(input, 50); // +50 to all channels
Image contrast = adjustContrast(input, 1.5f); // 1.5x contrast boost
bright.savePPM("bright_image.ppm");
contrast.savePPM("contrast_image.ppm");
// Blur and rotation
Image blur = applyBlur(input);
Image rotated = rotate90(input);
blur.savePPM("blurred_image.ppm");
rotated.savePPM("rotated90_image.ppm");Converts each RGB pixel to a single intensity value using the ITU-R BT.601 luminance formula:
gray = 0.299Β·R + 0.587Β·G + 0.114Β·B. Returns a new single-channel image.
Time Complexity: O(W Γ H)
Mirrors the image along the vertical axis by mapping each pixel at (y, x) to (y, widthβ1βx).
Time Complexity: O(W Γ H Γ C)
Mirrors the image along the horizontal axis by mapping each pixel at (y, x) to (heightβ1βy, x).
Time Complexity: O(W Γ H Γ C)
Adds a fixed integer value (positive to brighten, negative to darken) to every channel of every pixel, then clamps results to [0, 255].
Time Complexity: O(W Γ H Γ C)
Scales each pixel channel around midpoint 128: newVal = factor Γ (pixel β 128) + 128, clamped to [0, 255]. Values above 1.0 increase contrast; values below 1.0 reduce it.
Time Complexity: O(W Γ H Γ C)
Applies a 3Γ3 box blur by averaging each pixel's 3Γ3 neighborhood. Border pixels (first/last row and column) are left as 0 due to no border padding.
Time Complexity: O(W Γ H Γ C Γ 9) β O(W Γ H Γ C)
Rotates the image 90 degrees clockwise by mapping each pixel at (y, x) to (x, heightβ1βy) in a new image with swapped width and height dimensions.
Time Complexity: O(W Γ H Γ C)
The main() function runs a full pipeline on a programmatically generated 4Γ4 test image covering all implemented operations:
| Test | Description |
|---|---|
| 1 | Test image creation β 4Γ4 pattern with 16 named colors |
| 2 | Grayscale conversion β single-channel luminance output |
| 3 | Horizontal flip β pixel position mirror validation |
| 4 | Vertical flip β pixel position mirror validation |
| 5 | Brightness adjustment β +50 with overflow clamping |
| 6 | Contrast adjustment β Γ1.5 with underflow clamping |
| 7 | Blur filter β 3Γ3 averaging on interior pixels |
| 8 | 90Β° rotation β swapped dimensions and pixel remapping |
- Only the P3 (ASCII) PPM format is supported for file I/O
- Blur border pixels are set to
0β no border padding or pixel replication is applied - Grayscale images are saved as 3-channel PPM by repeating the intensity across R, G, B for viewer compatibility
adjustContrastusesfloatarithmetic internally before clamping to avoid integer precision loss- All operations return a new image β the original input is never modified
| Name | GitHub |
|---|---|
| Shady Mohamed | @shadimo11 |
| Kerolos Safwat | @KiroSafwat |
| Shahira Abdallah | @Shahira-Abdallah |
| Mazen Elkashlan | @toshiba-chef-89 |
| Youssef Asaad | @Usf132 |
This project is managed using Agile methodology on Jira.
Sprints are organized around function implementation phases as defined in the SRS document, with tasks distributed across team members to minimize blocking dependencies.
This project was developed as part of Winter SWE Training by Fuzetek.