By example:

import numpy as np
k=2
kern=np.ones(2*k+1)/(2*k+1)
arr=np.random.random((10))
out=np.convolve(arr,kern, mode='same')
Answer from Alex Alex on Stack Overflow
🌐
The Craft of Coding
craftofcoding.wordpress.com › 2017 › 11 › 23 › image-mean-filtering-i-in-python
Image mean filtering (i) – in Python – The Craft of Coding
November 23, 2017 - Image slicing is then used to extract the 5×5 block around each pixel, and the mean is calculated using the numpy mean() function. The result is then converted to an integer, and assigned to the filtered image.
🌐
GitHub
github.com › topics › mean-filter
mean-filter · GitHub Topics · GitHub
This GitHub repository contains an example demonstrating the application of fundamental image processing filters (Mean, Median, Gaussian) using Python and OpenCV, along with the addition of Salt and Pepper Noise.
🌐
GeeksforGeeks
geeksforgeeks.org › python › mahotas-mean-filter
Mahotas - Mean filter - GeeksforGeeks
June 9, 2021 - In order to do this we will use mahotas.mean_filter method Syntax : mahotas.mean_filter(img, n) Argument : It takes image object and neighbor pixel as argument Return : It returns image object
🌐
scikit-image
scikit-image.org › docs › dev › auto_examples › filters › plot_rank_mean.html
Mean filters — skimage 0.26.1rc0.dev0 documentation
import matplotlib.pyplot as plt from skimage import data from skimage.morphology import disk from skimage.filters import rank image = data.coins() footprint = disk(20) percentile_result = rank.mean_percentile(image, footprint=footprint, p0=0.1, p1=0.9) bilateral_result = rank.mean_bilateral(image, footprint=footprint, s0=500, s1=500) normal_result = rank.mean(image, footprint=footprint) fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 10), sharex=True, sharey=True) ax = axes.ravel() titles = ['Original', 'Percentile mean', 'Bilateral mean', 'Local mean'] imgs = [image, percentile_result, bilateral_result, normal_result] for n in range(0, len(imgs)): ax[n].imshow(imgs[n], cmap=plt.cm.gray) ax[n].set_title(titles[n]) ax[n].axis('off') plt.tight_layout() plt.show()
🌐
Envato Tuts+
code.tutsplus.com › home › python
Image Filtering in Python | Envato Tuts+ - Code
October 28, 2022 - This tutorial explains what we mean by image filtering, and shows how we can use Python and OpenCV to apply the median and mean filters on noisy images.
Find elsewhere
🌐
GitHub
github.com › karakanb › noise-removal
GitHub - karakanb/noise-removal: Sample Python code for Mean & Median filters and sample convolution implementation. · GitHub
Sample Python code for Mean & Median filters and sample convolution implementation. - karakanb/noise-removal
Starred by 5 users
Forked by 5 users
Languages   Python
🌐
Itk
examples.itk.org › src › filtering › smoothing › meanfilteringofanimage › documentation
Mean Filtering of an Image — v5.4.0
Apply mean filtering on an image. ... #!/usr/bin/env python import itk import argparse parser = argparse.ArgumentParser(description="Mean Filtering Of An Image.") parser.add_argument("input_image") parser.add_argument("output_image") parser.add_argument("radius", type=int) args = parser.parse_args() PixelType = itk.UC Dimension = 2 ImageType = itk.Image[PixelType, Dimension] reader = itk.ImageFileReader[ImageType].New() reader.SetFileName(args.input_image) meanFilter = itk.MeanImageFilter[ImageType, ImageType].New() meanFilter.SetInput(reader.GetOutput()) meanFilter.SetRadius(args.radius) writer = itk.ImageFileWriter[ImageType].New() writer.SetFileName(args.output_image) writer.SetInput(meanFilter.GetOutput()) writer.Update()
🌐
Python Guides
pythonguides.com › python-numpy-average
Mean Filter In Python NumPy
May 16, 2025 - I executed the above example code and added the screenshot below. This implementation manually applies the mean filter by calculating the average of each pixel’s neighborhood. While educational, it’s not the most efficient approach for larger images. Check out Create a 2D NumPy Array in Python ·
🌐
Medium
medium.com › @sarves021999 › noise-filtering-mean-median-mid-point-filter-72ab3be76da2
Noise filtering (Mean, Median &Mid-point filter) without OpenCV Library | by Sarves | Medium
February 17, 2023 - The article provides a step-by-step guide to implementing a linear filter using Python programming language, which can apply various filters such as edge detection, blurring, and sharpening to images.
🌐
scikit-image
scikit-image.org › skimage-tutorials › lectures › 1_image_filters.html
Image filtering — Image analysis in Python
The meaning of “mean kernel” should be clear now: Each pixel was replaced with the mean value within the 3x3 neighborhood of that pixel. When the kernel was over n bright pixels, the pixel in the kernel’s center was changed to n/9 (= n * 0.111). When no bright pixels were under the kernel, the result was 0. This filter is a simple smoothing filter and produces two important results:
🌐
scikit-image
scikit-image.org › docs › 0.24.x › auto_examples › filters › plot_rank_mean.html
Mean filters — skimage 0.24.0 documentation
import matplotlib.pyplot as plt from skimage import data from skimage.morphology import disk from skimage.filters import rank image = data.coins() footprint = disk(20) percentile_result = rank.mean_percentile(image, footprint=footprint, p0=0.1, p1=0.9) bilateral_result = rank.mean_bilateral(image, footprint=footprint, s0=500, s1=500) normal_result = rank.mean(image, footprint=footprint) fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 10), sharex=True, sharey=True) ax = axes.ravel() titles = ['Original', 'Percentile mean', 'Bilateral mean', 'Local mean'] imgs = [image, percentile_result, bilateral_result, normal_result] for n in range(0, len(imgs)): ax[n].imshow(imgs[n], cmap=plt.cm.gray) ax[n].set_title(titles[n]) ax[n].axis('off') plt.tight_layout() plt.show()
🌐
scikit-image
scikit-image.org › docs › stable › auto_examples › filters › plot_rank_mean.html
Mean filters — skimage 0.25.2 documentation
import matplotlib.pyplot as plt from skimage import data from skimage.morphology import disk from skimage.filters import rank image = data.coins() footprint = disk(20) percentile_result = rank.mean_percentile(image, footprint=footprint, p0=0.1, p1=0.9) bilateral_result = rank.mean_bilateral(image, footprint=footprint, s0=500, s1=500) normal_result = rank.mean(image, footprint=footprint) fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10, 10), sharex=True, sharey=True) ax = axes.ravel() titles = ['Original', 'Percentile mean', 'Bilateral mean', 'Local mean'] imgs = [image, percentile_result, bilateral_result, normal_result] for n in range(0, len(imgs)): ax[n].imshow(imgs[n], cmap=plt.cm.gray) ax[n].set_title(titles[n]) ax[n].axis('off') plt.tight_layout() plt.show()
Top answer
1 of 2
5

Code review

Peilonrays points out a mixup with the out-of-bounds testing that is valid. The statement if j ... must be within the loop for k .... One of the results is that you add a different number of elements to temp depending on which boundary you're at. But there are better ways to avoid out-of-bounds indexing, see below.

Your biggest bug, however, is that you write the result of the filter into the image you are processing. Median filtering cannot be done in-place. When you update data[i][j], you'll be reading the updated value to compute data[i][j+1]. You need to allocate a new image, and write the result there.

I would suggest not adding zeros for out-of-bounds pixels at all, because it introduces a bias to the output pixels near the boundary. The clearest example is for the pixels close to any of the corners. At the corner pixel, with a 3x3 kernel, you'll have 4 image pixels covered by the kernel. Adding 5 zeros for the out-of-bounds pixels guarantees that the output will be 0. For larger kernels this happens in more pixels of course. Instead, it is easy to simply remove the temp.append(0) statements, leading to a non-biased result. Other options are to read values from elsewhere in the image, for example mirroring the image at the boundary or extending the image by extrapolation. For median filtering this has little effect, IMO.

You set temp = [] at the very beginning of your function, then reset it when you're done using it, in preparation for the next loop. Instead, initialize it once inside the main double-loop over the pixels:

for i in range(len(data)):
   for j in range(len(data[0])):
      temp = []
      # ...

You're looping over i and j as image indices, then over z and c or k for filter kernel indices. c and k have the same function in two different loops, I would suggest using the same variable for that. z doesn't really fit in with either c or k. I would pick two names that are related in the way that i and j are, such as m and n. The choice of variable names is always very limited if it's just one letter. Using longer names would make this code clearer: for example img_column, img_row, kernel_column, kernel_row.


Out-of-bounds checking

This concludes my comments on your code. Now I'd like to offer some alternatives for out-of-bounds checking. These tests are rather expensive when performed for every pixel -- it's a test that is done \$n k\$ times (with \$n\$ pixels in the image and \$k\$ pixels in the kernel). Maybe in Python the added cost is relatively small, it's an interpreted language after all, but for a compiled language these tests can easily amount to doubling processing time. There are 3 common alternatives that I know of. I will use border = filter_size // 2, and presume filter_size is odd. It is possible to adjust all 3 methods to even-sized filters.

Separate loops for image border pixels

The idea here is that the loop over the first and last border pixels along each dimension are handled separately from the loop over the core of the image. This avoids all tests. But it does require some code duplication (all in the name of speed!).

for i in range(border):
   # here we loop over the kernel from -i to border+1
for i in range(border, len(data)-border):
   # here we loop over the full kernel
for i in range(len(data)-border, len(data)):
   # here we loop over the kernel from -border to len(data)-i

Of course, within each of those loops, a similar set of 3 loops is necessary to loop over j. The filter logic is thus repeated 9 times. In a compiled language, where this is the most efficient method, code duplication can be avoided with inlined functions or macros. I don't know how a Python function call compares to a bunch of tests for out-of-bounds access, so can't comment on the usefulness of this method in Python.

A separate code path for border pixels

The idea here is to do out-of-bounds checking only for those pixels that are close to the image boundary. For pixels within the border, you use a version of the filtering logic with out-of-bounds checking. For the pixels in the core of the image (which is the big majority of pixels), you use a second version of the logic without out-of-bounds checking.

for i in range(len(data)):
   i_border = i < border or i >= len(data)-border
   for j in range(len(data[0])):
      j_border = j < border or j >= len(data)-border
      if i_border or j_border:
         # filtering with bounds checking
      else:
         # filtering without bounds checking

Padding the image

The simplest solution, and also the most flexible one, is to create a temporary image that is larger than the input image by 2*border along each dimension, and copy the input image into it. The "new" pixels can be filled with zeros (to replicate what OP intended to do), or with values taken from the input image (for example by mirroring the image at the boundary or extrapolating in some other way).

The filter now never needs to check for out-of-bounds reads. When the filtering kernel is placed over any of the input image pixels, all samples fall within the padded image.

Since for this type of filtering it is necessary to create a new output image anyway (it is not possible to compute it in-place, as I mentioned before), this is not a huge cost: the original input image can now be re-used as output image.

This solution leads to the simplest code, allows for all sorts of boundary extension methods without complicating the filtering code, and often results in the fastest code too.

2 of 2
3

You seem to have a few bugs.

  1. if i + z - indexer < 0 or i + z - indexer > len(data) - 1:
    

    If i and z are 0, where indexer is 1, then you'll have 0 + 0 - 1 < 0. This would mean that you'd replace the data in (-1, j), (0, j) and (1, j) to 0. Since 0 and 1 probably do contain data this is just plain wrong.

  2. if j + z - indexer < 0 or j + indexer > len(data[0]) - 1:
          temp.append(0)
    

    This removes some data, meaning that the median is shifted. Say you should have (0, 0, 0, 1, 2, 3), however you removed the first three because of this you'd have (0, 1, 2, 3). Now the median is 1 rather than 0.


Your code would be simpler if you:

  1. Made a window list, that contained all the indexes that you want to move to.
  2. Have an if to check if the data in that index is out of bounds.
  3. If it's out of bounds default to 0.
  4. If it's not out of bounds use the data.

This could become:

def median_filter(data, filter_size):
    temp = []
    indexer = filter_size // 2
    window = [
        (i, j)
        for i in range(-indexer, filter_size-indexer)
        for j in range(-indexer, filter_size-indexer)
    ]
    index = len(window) // 2
    for i in range(len(data)):
        for j in range(len(data[0])):
            data[i][j] = sorted(
                0 if (
                    min(i+a, j+b) < 0
                    or len(data) <= i+a
                    or len(data[0]) <= j+b
                ) else data[i+a][j+b]
                for a, b in window
            )[index]
    return data
🌐
GitHub
github.com › MeteHanC › Python-Median-Filter
GitHub - MeteHanC/Python-Median-Filter: Simple implementation of median filter in python to remove noise from the images. · GitHub
Simple implementation of median filter in python to remove noise from the images. - MeteHanC/Python-Median-Filter
Starred by 58 users
Forked by 21 users
Languages   Python
🌐
Medium
medium.com › data-science › image-filters-in-python-26ee938e57d2
Image Filters in Python. I am currently working on a computer… | by Manvir Sekhon | TDS Archive | Medium
November 24, 2019 - The blur function from the Open-CV library can be used to apply a mean filter to an image. When dealing with color images it is first necessary to convert from RGB to HSV since the dimensions of RGB are dependent on one another where as the three dimensions in HSV are independent of one another (this allows us to apply filters to each of the three dimensions separately.) The following is a python implementation of a mean filter:
🌐
Medium
medium.com › @turgay2317 › image-processing-in-python-with-opencv-blur-3e474fda6a52
Image Processing in Python with OpenCV — Blur
December 23, 2022 - """ img2 = cv2.imread("salt-papper-img.jpeg") img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB) # Plot show original image and configuration plt.figure() plt.imshow(img2) plt.title("Image with salt-pepper noise") plt.axis("OFF") # Median mb = cv2.medianBlur(img2, ksize = 3) # Plot show median filtered image and configuration plt.figure() plt.imshow(mb) plt.title("Median Filtered image") plt.axis("OFF") Source of code: https://github.com/turgay2317/opencv-python-examples/tree/main/Example 7 - Image Blur ·