This project implements and benchmarks sequential and several parallel approaches to applying 2D filters to grayscale images.
- Sequential and parallel convolution
- Interactive CLI tool for applying filters to images
- Performance benchmarking and analysis
- Predefined filters
- Support for user-supplied or built-in test images
- Convolve several images at once using sequential or asynchronous pipeline
All filters are defined as 2D matrices (kernels), with optional normalization (factor) and offset (bias).
blur_3x3,blur_5x5gaussian_blur_3x3,gaussian_blur_5x5sharpenedge_detectmotion_bluridentityemboss
| Mode | Description |
|---|---|
seq |
Standard single-threaded version |
pixels |
Parallelized per-pixel |
rows |
Rows processed in parallel |
cols |
Columns processed in parallel |
tiles |
Blocks (tiles) of the image |
| Mode | Description |
|---|---|
seq |
Convolve one image at a time using any mode |
async |
Convolve several images simultaneously |
- JDK 17+
- Kotlin
- Gradle
- OpenCV via JavaCPP
Clone the repo:
git clone git@github.com:sofyak0zyreva/convolution.gitRun the following command to install the dependencies:
./gradlew buildTo apply a filter to an image via CLI:
./gradlew run --quiet --console=plainYou'll be prompted to:
- Enter an image path (or use defaults from resources/images/). You can enter path from the repository root or absolute path
- Select a mode (with optional batch/tile sizes -- they are responsible for how many pixels will be allocated per coroutine)
- Choose a filter
The result will be saved as a new .bmp file in the project directory's output folder.
You can simply run main() in the specified file (simplest for BenchmarkPipelines.kt).
To measure the performance of a specific mode (BenchmarkSizes.kt):
val result = benchmarkSingleMode(inputImage, filter, ConvolutionMode.ParallelRows(8))
println(result)Here, you can also use randomly generated images of a chosen size.
To compare all modes (BenchmarkAllModes.kt):
val results = benchmarkAllModes(image, filter)
results.forEach(::println)To benchmark scalability (e.g., for rows/cols/tiles) (EfficiencyAnalysis.kt):
val sizes = listOf(1, 4, 8, 16, 32, 64, 128)
benchmarkSizes(image, filter, { ConvolutionMode.ParallelRows(8) }, sizes) - Sequential implementation serves as the reference with key points preserved:
- Compositionality: applying filters sequentially should equal applying their composition
(e.g.,apply(filter1, apply(filter2, img)) == apply(filter1 ⊕ filter2, img)) - Identity: some filters compose to identity (e.g., shift-left then shift-right)
- Zero-padding: expanding filters with zeros shouldn't change results
- Known-output filters: test with trivial filters (zero filter, identity filter)
- Compositionality: applying filters sequentially should equal applying their composition
- All modes are tested against the sequential implementation for numerical accuracy
- Standard Error of the Mean (SEM) is reported in benchmarks. See Performance Analysis, Plots, and Results for more
Run:
./gradlew testsrc/
├── main/
│ ├── kotlin/ ← Core logic, filters, modes, pipelines and CLI
│ └── resources/
│ └── images/ ← Sample input images
└── test/
└── kotlin/
├── benchmarks/ ← Performance analysis, plots, results
└── ... ← Tests
This project uses JavaCPP Presets for OpenCV and OpenCV, both licensed under Apache License 2.0.
See LICENSE for details.