Code : Human Made
ReadMe : Ai generated under my guidance
This project provides a comprehensive implementation, analysis, and optimization of an Adaptive Median Filter designed to remove high-density salt-and-pepper noise from grayscale images. It compares the adaptive filter against a classic median filter, demonstrates a massive >30x performance optimization using Python, NumPy, and Numba, and introduces a novel mathematical analysis to determine the filter's "breaking point."
The project culminates in an interactive Streamlit dashboard for real-time visualization and exploration of the filter's behavior.
- Implementations: Includes clear, from-scratch implementations of both the Classic and Adaptive Median Filters.
- Performance Optimization: Showcases a step-by-step optimization process, moving from slow pure Python to a highly efficient, JIT-compiled version using Numba.
-
In-Depth Analysis: Introduces a method to analyze a filter's effectiveness by examining the proportional growth rate of error (
$d'/d$ ), identifying a "breaking point" where performance catastrophically degrades. -
Interactive Dashboard: An
app.pybuilt with Streamlit allows users to apply filters, adjust parameters, and explore the step-by-step filtering process on individual pixels. -
Benchmarking Suite: A full test harness (
speed_comparison.py) measures execution time, memory usage, and CPU hotspots for all filter implementations.
Salt-and-pepper noise introduces random black (0) and white (255) pixels into an image, severely corrupting its details. While a classic median filter can handle low levels of this noise, it struggles with high densities and often blurs important image features.
From left to right: The original image, the image with 40% noise, the output of a classic 3x3 median filter, and the superior output of the adaptive median filter.
The classic median filter's main flaw is its fixed window size. It treats all pixels equally, which leads to blurring of edges and loss of fine detail. The adaptive median filter intelligently varies its window size to distinguish noise from actual image features.
The algorithm operates in two stages at each pixel
-
Stage A: Is the median value
$Z_{med}$ itself noise?- It computes the minimum (
$Z_{min}$ ), maximum ($Z_{max}$ ), and median ($Z_{med}$ ) intensity values within the current window$S_{xy}$ . - If the condition
$Z_{min} < Z_{med} < Z_{max}$ is true, it means$Z_{med}$ is a representative intensity value and not an outlier. The algorithm proceeds to Stage B. - If this condition is false,
$Z_{med}$ is likely salt or pepper noise. The filter increases its window size and repeats Stage A.
- It computes the minimum (
-
Stage B: Is the center pixel
$Z_{xy}$ noise?- If the condition
$Z_{min} < Z_{xy} < Z_{max}$ is true, the center pixel$Z_{xy}$ is not noise. The algorithm preserves this original value, preventing image blurring. - If this condition is false,
$Z_{xy}$ is identified as noise, and it is replaced by the non-noise median$Z_{med}$ .
- If the condition
This adaptive process allows the filter to apply strong filtering only where needed, preserving details in other areas.
A naive Python implementation of this algorithm is extremely slow due to nested loops. This project demonstrates a powerful optimization pipeline.
(Note the logarithmic scale, highlighting orders-of-magnitude improvement)
-
Pure Python Baseline: The initial implementations use Python loops to iterate over each pixel. While easy to understand, they are computationally expensive. The pure Python adaptive filter is the slowest of all, taking over 12 seconds for a single large image.
-
JIT Compilation with Numba: By adding a simple
@njitdecorator from the Numba library, the Python loops are Just-in-Time (JIT) compiled into highly efficient machine code. This single step eliminates the Python interpreter overhead and provides a ~20x speedup, bringing the execution time down from 12.14s to 0.58s. -
Vectorization + Numba (Fastest): The pinnacle of performance is achieved by first rewriting the algorithm's logic to use NumPy's vectorized operations (operating on arrays instead of individual elements) and then compiling this new version with Numba. Numba can optimize and fuse these high-level NumPy calls, resulting in an additional ~2x speedup. The final version runs in just 0.35s, a total 34x improvement over the original.
Beyond just implementing the filter, this project analyzes when a filter is effective. The error, or normalized difference
By plotting the proportional growth rate of error (
-
Top Plot (Observation): The normalized error (
$d$ ) increases at an accelerating rate as noise is added. -
Bottom Plot (Insight): The proportional growth of error (
$\frac{d'}{d}$ ) reveals a distinct peak. This peak is the breaking point, where the filter's performance degrades most violently. This allows us to define three operational zones:-
Safe Zone (
$p < 0.23$ ): The filter is highly effective. -
Critical Zone (
$p \approx 0.23$ ): The filter begins to fail catastrophically. -
Failure Zone (
$p > 0.23$ ): The filter is overwhelmed and may do more harm than good.
-
Safe Zone (
This analysis provides a data-driven threshold for deciding whether applying the filter is advisable.
The superiority of the adaptive filter, especially at high noise densities, is evident across a wide range of images.
To explore these concepts interactively, run the Streamlit application:
streamlit run app.pyThe dashboard allows you to:
- Upload your own images.
- Adjust noise levels in real-time.
- Change filter parameters for both classic and adaptive filters.
- Select a pixel and see a step-by-step visualization of the algorithm's decision-making process.
-
Clone the repository:
git clone <your-repo-url> cd <your-repo-name>/code
-
Create a virtual environment and activate it:
python -m venv .venv source .venv/bin/activate -
Install the required dependencies: (You should create a
requirements.txtfile withnumpy,matplotlib,numba,memory-profiler,streamlit, andPillow)pip install -r requirements.txt
-
Run the analysis and benchmarking scripts (optional):
# To run the performance comparison python speed_comparison.py # To generate all the documentation images python docs_material.py python docs_material_extended.py
- Grayscale Only: The current implementation is optimized for 2D grayscale images.
-
Static Breaking Point: The
$\frac{d'}{d}$ analysis was performed for a fixed 3x3 classic filter. This breaking point would shift for different filter sizes or types. - Noise Type: The filters are specifically designed for salt-and-pepper noise and are not effective against other types like Gaussian noise.
Future enhancements could include:
- Support for 3-channel (RGB) color images.
- Implementation of other advanced noise reduction filters for comparison.
- GPU acceleration using CuPy or Numba's CUDA capabilities for even faster processing.
.
├── code
│ ├── adaptive_median_filter.py # Pure Python adaptive filter
│ ├── adaptive_median_filter_p.py # Numba JIT compiled version
│ ├── adaptive_median_filter_p_compiled.py # Vectorized + Numba version (fastest)
│ ├── app.py # Streamlit interactive dashboard
│ ├── docs/ # Generated images for documentation
│ ├── docs_material.py # Script to generate primary plots
│ ├── docs_material_extended.py # Script to generate image galleries
│ ├── image_io.py # Image loading/saving utilities
│ ├── images/ # Sample images for testing
│ ├── median_filter.py # Pure Python classic filter
│ ├── noise_generator.py # Salt-and-pepper noise utility
│ └── speed_comparison.py # Performance benchmarking script
└── README.md
- Sources :
[https://en.wikipedia.org/wiki/Noise_reduction]
[https://en.wikipedia.org/wiki/Median_filter]
[https://www.irjet.net/archives/V6/i10/IRJET-V6I10148.pdf]
Human Code LLM generated README




