Filtro de sal y pimienta

Un filtro basado en la obtención de la media de una ventana en una imagen permite que elementos aislados con ruido sean filtrados de forma efectiva, ello ya que esta clase de filtros es capaz de ignorar por completo a todos aquellos elementos espurios que se desvíen fuertemente de la población de la ventana. Un punto a considerar en esta clase de filtros es el tamaño del mismo, ya que a mayor tamaño el filtro será mas efectivo para eliminar el ruido, sin embargo, también puede generar un efecto de homogenización que afecte a las características de la imagen.

Imagen original con ruido de sal y pimienta

Imagen filtrada

Con objeto de aplicar un filtro de media, el siguiente procedimiento debe de ser aplicado.

Como ejemplo, suponiendo se esta analizando una ventana 5x5 centrada en el pixel con el valor 104

[__0, _96, 109, 106, 255]

[255, 109, 105, __0, 103]

[089, _87, 104, 108, __0]

[131, __0, 102, 255, __0]

[102, 255, 109, 112, 255]

Considerando que la lista ordenada de valores en esta ventana es: 

0, 0, 0, 0, 0, 87, 89, 96, 103, 102, 102, 104, 105, 106, 109, 109, 109, 108, 112, 131, 255, 255, 255, 255, 255

El valor representativo de la ventana es: 105, lo cual es apropiado ya que no modifica notoriamente los valores de casillas sin ruido, pero infiere valores esperables para casillas que presenten interferencias de sal o pimienta.

Script del ejemplo empleado

import cv2 

import matplotlib.pyplot as plt

import numpy as np


# Se carga la imagen

original = cv2.imread('sydney con sal y pimienta.png', 0)


# Se extraen los tamaños de la imagen

y, x = original.shape


# Se define un tamaño de kernel

kernel_s = 7


# Se definen variables utiles

km = int((kernel_s-1)/2)

punto_medio = int((kernel_s**2)/2)


# Se genera una matriz donde depositar el resultado

filtrada = np.zeros((y-kernel_s+1, x-kernel_s+1))


# Por cada pixel com una ventana valida

for yi in range(km, y-km):

    for xi in range(km, x-km):

        # Se extrae la ventana

        ventana = original[yi-km:yi+km+1, xi-km:xi+km+1]

        # Se extrae el valor medio de la ventana

        vectorizado = ventana.flatten()

        i = np.argsort(vectorizado)[punto_medio]

        # Se almacenta el valor medio en la matriz de resultados

        filtrada[yi-km, xi-km] = ventana[i//kernel_s, i%kernel_s]


# Se guarda la imagen

cv2.imwrite('sydney filtrada.png', filtrada)