A pure-NumPy image-processing library — filtering, transforms, feature extraction, drawing, and canvas operations — built from scratch without OpenCV.
Project description
RoboVision
A pure-NumPy image-processing library — built from scratch without OpenCV.
Filtering · Transformations · Feature Extraction · Drawing · Canvas Operations
Overview
RoboVision is a lightweight, dependency-free computer vision library implemented entirely in Python and NumPy.
It covers the core image-processing pipeline from raw pixel manipulation all the way to feature extraction and drawing — without relying on OpenCV, PIL, or any compiled binary.
Built as part of CSE480: Machine Vision at Ain Shams University, Faculty of Engineering, Mechatronics Engineering Department — and structured to be a real, importable, maintainable Python package.
Why RoboVision?
| Feature | RoboVision | OpenCV |
|---|---|---|
| Dependencies | NumPy + Matplotlib only | Large compiled C++ binary |
| Channel order | RGB (natural) | BGR (legacy) |
| Output dtype | Always float32 [0,1] |
uint8 [0,255] by default |
| Error messages | Specific, typed exceptions | Silent None returns |
| Pure Python | ✅ | ❌ |
| Teachable internals | ✅ Full math in docstrings | ❌ Black box |
| Platform | Any Python 3.9+ | Platform-specific build |
Installation
pip install robovision
Or install from source:
git clone https://github.com/omarmustafa/robovision.git
cd robovision
pip install -e .
Install with optional extras:
pip install robovision[notebook] # Jupyter support
pip install robovision[dev] # Testing + linting tools
pip install robovision[all] # Everything
Quick Start
import numpy as np
from robovision.io.image_io import read_image, save_image, to_grayscale
from robovision.filters.filters import gaussian_filter, mean_filter
from robovision.filters.edge_detection import canny, sobel_gradients
from robovision.transforms.resize import resize
from robovision.features.hog import extract_hog
from robovision.utils.drawing_primitives import draw_rectangle, draw_text
# Load image
img = read_image("photo.jpg") # → float32 [0,1], RGB
gray = to_grayscale(img) # → (H, W) float32
# Filtering
blurred = gaussian_filter(img, size=5, sigma=1.0)
edges = canny(gray, low_thresh=0.05, high_thresh=0.15)
# Feature extraction
hog_feat = extract_hog(gray, cell_size=8, n_bins=9)
print(f"HOG descriptor length: {hog_feat.shape[0]}")
# Drawing
canvas = img.copy()
draw_rectangle(canvas, 50, 50, 200, 150, color=(0, 1, 0), thickness=2)
# Save
save_image(canvas, "output.png")
Package Structure
robovision/
│
├── io/
│ └── image_io.py ← read_image, save_image, to_grayscale, to_rgb
│
├── transforms/
│ ├── resize.py ← nearest-neighbour & bilinear resize
│ ├── rotate.py ← rotation with inverse mapping
│ ├── translate.py ← pixel translation
│ ├── flip.py ← horizontal / vertical / both
│ └── pyramid.py ← Gaussian & Laplacian pyramids
│
├── filters/
│ ├── filters.py ← pad_image, convolve2d, mean, gaussian, median
│ ├── thresholding.py ← global, Otsu, adaptive thresholding
│ ├── edge_detection.py ← Sobel, bit-plane slicing, Canny
│ └── histogram_ops.py ← histogram, equalization, matching, gamma
│
├── features/
│ ├── hog.py ← Histogram of Oriented Gradients
│ ├── sift.py ← SIFT keypoints + 128-D descriptors
│ ├── color_histogram.py ← per-channel & 2D joint histograms
│ ├── color_moments.py ← mean, std, skewness (RGB + HSV)
│ └── spatial_pyramid.py ← Spatial Pyramid Matching (SPM)
│
└── utils/
├── normalization.py ← min-max, z-score, scale [0-1]/[0-255]
├── pixel_clipping.py ← clip, percentile clip, sigma clip
├── padding.py ← zero, reflect, replicate, constant, circular
├── convolution.py ← convolve2d, filter2d, spatial_filter (3.5)
├── drawing_primitives.py← point, line (AA), rectangle, polygon, ellipse
└── text_placement.py ← bitmap font text rendering on NumPy arrays
API Reference
Image I/O
from robovision.io.image_io import read_image, save_image, to_grayscale, to_rgb, drop_alpha
img = read_image("photo.png") # (H,W,3) float32 [0,1]
gray = read_image("photo.png", as_gray=True) # (H,W) float32 [0,1]
gray = to_grayscale(img) # BT.601 luminance weights
rgb = to_rgb(gray) # (H,W) → (H,W,3)
img3 = drop_alpha(img) # (H,W,4) → (H,W,3)
save_image(img, "out.png")
save_image(img, "out.jpg", quality=90)
Transforms
from robovision.transforms.resize import resize
from robovision.transforms.rotate import rotate
from robovision.transforms.translate import translate
from robovision.transforms.flip import flip
from robovision.transforms.pyramid import gaussian_pyramid, laplacian_pyramid
small = resize(img, (128, 128), method='bilinear')
rotated = rotate(img, angle=45, method='bilinear', expand=True)
shifted = translate(img, tx=50, ty=30)
flipped = flip(img, mode='horizontal')
gauss = gaussian_pyramid(img, levels=4)
lap = laplacian_pyramid(img, levels=4)
Filters
from robovision.filters.filters import mean_filter, gaussian_filter, median_filter, gaussian_kernel
k = gaussian_kernel(size=5, sigma=1.0) # normalised 2-D kernel
blurred = gaussian_filter(img, size=7, sigma=1.5)
box = mean_filter(img, kernel_size=5)
clean = median_filter(img, kernel_size=3) # excellent for salt & pepper
Thresholding
from robovision.filters.thresholding import threshold_global, threshold_otsu, threshold_adaptive
binary = threshold_global(gray, thresh=0.5)
auto, t = threshold_otsu(gray, return_thresh=True)
local_mean = threshold_adaptive(gray, block_size=11, C=0.02, method='mean')
local_gauss = threshold_adaptive(gray, block_size=11, C=0.02, method='gaussian')
Edge Detection
from robovision.filters.edge_detection import sobel_gradients, canny, bit_plane_slice
grads = sobel_gradients(gray) # {'Gx', 'Gy', 'magnitude', 'angle'}
edges = canny(gray, 0.05, 0.15)
msb = bit_plane_slice(gray, plane=7) # most significant bit plane
Histogram Operations
from robovision.filters.histogram_ops import (
compute_histogram, histogram_equalization,
histogram_matching, gamma_correction
)
hist, bins = compute_histogram(gray, n_bins=256)
enhanced = histogram_equalization(gray)
matched = histogram_matching(source, reference)
bright = gamma_correction(img, gamma=0.5) # γ < 1 → brighten
dark = gamma_correction(img, gamma=2.2) # γ > 1 → darken
Feature Extraction
from robovision.features.hog import extract_hog
from robovision.features.sift import extract_sift, sift_feature_vector
from robovision.features.color_histogram import extract_color_histogram
from robovision.features.color_moments import extract_color_moments
from robovision.features.spatial_pyramid import extract_spatial_pyramid
hog = extract_hog(gray, cell_size=8, block_size=2, n_bins=9)
kps, descs = extract_sift(gray, max_keypoints=500)
chist = extract_color_histogram(img, n_bins=32) # 96-D for RGB
cmom = extract_color_moments(img) # 9-D (mean,std,skew × 3ch)
spm = extract_spatial_pyramid(img, levels=3, n_bins=16) # 1008-D
Core Utilities
from robovision.utils.normalization import normalize
from robovision.utils.pixel_clipping import clip, clip_percentile
from robovision.utils.padding import pad_image
from robovision.utils.convolution import convolve2d, spatial_filter
norm = normalize(img, mode='minmax') # also: zscore, scale_01, scale_255
safe = clip(img, 0.0, 1.0)
padded = pad_image(img, pad_width=5, mode='reflect') # also: zero, replicate, constant, circular
out = spatial_filter(img, kernel, rgb_strategy='per_channel')
Drawing & Text
from robovision.utils.drawing_primitives import (
draw_point, draw_line, draw_line_aa,
draw_rectangle, draw_polygon, draw_ellipse
)
from robovision.utils.text_placement import draw_text, get_text_size
canvas = np.zeros((400, 600, 3), dtype=np.float32)
draw_point(canvas, x=100, y=100, color=(1,0,0), radius=5)
draw_line(canvas, 0, 0, 599, 399, color=(0,1,0), thickness=2)
draw_line_aa(canvas, 10.5, 10.0, 300.5, 200.0, color=(1,1,0)) # anti-aliased
draw_rectangle(canvas, 50, 50, 250, 200, color=(0,0,1), filled=True)
draw_polygon(canvas, [(100,50),(200,20),(280,80),(240,160),(80,160)], color=(1,0.5,0), filled=True)
draw_ellipse(canvas, cx=300, cy=200, rx=80, ry=50, color=(0.8,0,0.8))
draw_text(canvas, "RoboVision 1.0", x=10, y=10, color=(1,1,1), scale=2)
Math & Algorithms
Each module contains a full docstring with the mathematical derivation.
Key algorithms implemented:
| Algorithm | Module | Notes |
|---|---|---|
| BT.601 Luminance | io/image_io.py |
Y = 0.2989R + 0.5870G + 0.1140B |
| Bilinear interpolation | transforms/resize.py |
4-neighbour weighted average |
| Inverse mapping rotation | transforms/rotate.py |
Avoids holes in output |
| Gaussian kernel | filters/filters.py |
G(x,y) = exp(-(x²+y²)/2σ²) normalised |
| Otsu's method | filters/thresholding.py |
Maximises between-class variance |
| Adaptive threshold | filters/thresholding.py |
Local mean/Gaussian − C |
| Canny 5-stage | filters/edge_detection.py |
Gaussian → Sobel → NMS → Hysteresis |
| Histogram equalisation | filters/histogram_ops.py |
CDF mapping out = CDF(in) |
| Histogram matching | filters/histogram_ops.py |
Inverse CDF lookup |
| HOG descriptor | features/hog.py |
Dalal & Triggs CVPR 2005 |
| SIFT descriptor | features/sift.py |
DoG + 128-D descriptor, Lowe 2004 |
| Spatial Pyramid | features/spatial_pyramid.py |
Lazebnik et al. CVPR 2006 |
| Bresenham line | utils/drawing_primitives.py |
Integer-only rasterisation |
| Wu anti-aliased line | utils/drawing_primitives.py |
Sub-pixel alpha blending |
| Bresenham ellipse | utils/drawing_primitives.py |
Midpoint algorithm, 4-fold symmetry |
| Scanline polygon fill | utils/drawing_primitives.py |
Even-odd rule |
Requirements
| Package | Minimum Version |
|---|---|
| Python | 3.9 |
| NumPy | 1.24.0 |
| Matplotlib | 3.7.0 |
Development
# Clone and install in editable mode
git clone https://github.com/omarmustafa/robovision.git
cd robovision
pip install -e ".[dev]"
# Run tests
pytest
# Format code
black robovision/
# Lint
ruff check robovision/
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/new-filter) - Commit your changes (
git commit -m 'Add new filter') - Push to the branch (
git push origin feature/new-filter) - Open a Pull Request
License
This project is licensed under the MIT License — see the LICENSE file for details.
Author
Omar Mustafa Mohammed
Mechatronics Engineering — Ain Shams University
CSE480: Machine Vision, Spring 2026
Acknowledgements
- Dalal & Triggs (2005) — HOG descriptor
- Lowe (2004) — SIFT descriptor
- Lazebnik, Schmid & Ponce (2006) — Spatial Pyramid Matching
- Canny (1986) — Edge detection
- Otsu (1979) — Thresholding
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file robovision_dr_gear-1.0.0.tar.gz.
File metadata
- Download URL: robovision_dr_gear-1.0.0.tar.gz
- Upload date:
- Size: 70.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
994e751c3b4ab57eabc6b6aef50fe83ee9d06856c8492ac1d9d6e4e55fbc23f5
|
|
| MD5 |
04243a85eebcffa1b28240e3640a64e3
|
|
| BLAKE2b-256 |
a39980c981b2f965f1ed4626511f74a8bf9f5846e3e6a31d03e2dd5c3d57e17e
|
File details
Details for the file robovision_dr_gear-1.0.0-py3-none-any.whl.
File metadata
- Download URL: robovision_dr_gear-1.0.0-py3-none-any.whl
- Upload date:
- Size: 79.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4daaa4fee185993d8767925721b6e4605ee130e8ebe68f31e80b0ef86d358fdf
|
|
| MD5 |
a74b50cb04ce4408c881017d9ad98e21
|
|
| BLAKE2b-256 |
ee01cc5b563e68e59f7c2b162c9e21ab293fa041c406dcaecadf767b038688c2
|