Skip to content

Commit d79af07

Browse files
youssefelzedyKeavon
authored andcommitted
Optimize median filter algorithm by reusing buffers and improving pixel neighborhood collection
1 parent 0d29373 commit d79af07

File tree

1 file changed

+19
-11
lines changed

1 file changed

+19
-11
lines changed

node-graph/nodes/raster/src/filter.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ async fn blur(
3636
Raster::new_cpu(box_blur_algorithm(image.into_data(), radius, gamma))
3737
} else if median {
3838
Raster::new_cpu(median_filter_algorithm(image.into_data(), radius as u32, gamma))
39-
}
40-
else {
39+
} else {
4140
Raster::new_cpu(gaussian_blur_algorithm(image.into_data(), radius, gamma))
4241
};
4342

@@ -195,16 +194,26 @@ fn median_filter_algorithm(mut original_buffer: Image<Color>, radius: u32, gamma
195194
let (width, height) = original_buffer.dimensions();
196195
let mut output = Image::new(width, height, Color::TRANSPARENT);
197196

197+
// Pre-allocate and reuse buffers outside the loops to avoid repeated allocations.
198+
let window_capacity = ((2 * radius + 1).pow(2)) as usize;
199+
let mut r_vals: Vec<f32> = Vec::with_capacity(window_capacity);
200+
let mut g_vals: Vec<f32> = Vec::with_capacity(window_capacity);
201+
let mut b_vals: Vec<f32> = Vec::with_capacity(window_capacity);
202+
let mut a_vals: Vec<f32> = Vec::with_capacity(window_capacity);
203+
198204
for y in 0..height {
199205
for x in 0..width {
200-
// Collect pixel neighborhood
201-
let mut r_vals = Vec::with_capacity(((2 * radius + 1).pow(2)) as usize);
202-
let mut g_vals = Vec::with_capacity(r_vals.capacity());
203-
let mut b_vals = Vec::with_capacity(r_vals.capacity());
204-
let mut a_vals = Vec::with_capacity(r_vals.capacity());
205-
206-
for ny in y.saturating_sub(radius)..=(y + radius).min(height - 1) {
207-
for nx in x.saturating_sub(radius)..=(x + radius).min(width - 1) {
206+
r_vals.clear();
207+
g_vals.clear();
208+
b_vals.clear();
209+
a_vals.clear();
210+
211+
// Use saturating_add to avoid potential overflow in extreme cases
212+
let y_max = y.saturating_add(radius).min(height - 1);
213+
let x_max = x.saturating_add(radius).min(width - 1);
214+
215+
for ny in y.saturating_sub(radius)..=y_max {
216+
for nx in x.saturating_sub(radius)..=x_max {
208217
if let Some(px) = original_buffer.get_pixel(nx, ny) {
209218
r_vals.push(px.r());
210219
g_vals.push(px.g());
@@ -214,7 +223,6 @@ fn median_filter_algorithm(mut original_buffer: Image<Color>, radius: u32, gamma
214223
}
215224
}
216225

217-
// Use quickselect instead of sorting for efficiency
218226
let r = median_quickselect(&mut r_vals);
219227
let g = median_quickselect(&mut g_vals);
220228
let b = median_quickselect(&mut b_vals);

0 commit comments

Comments
 (0)