How To Make Adaptive Filters For Local Noise In C#
Adaptive local noise reduction filters are useful for processing images that have too much noise to deal with with other simpler filters.
Filter by Category
Adaptive local noise reduction filters are useful for processing images that have too much noise to deal with with other simpler filters.
Alpha trimmed mean filter is a combination of mean filters and order-statistic filters. This guide shows how to use them with C#.
Midpoint filter is a order-statistic filter and we use it to process image data in spatial domain. This guide shows how to make it with C#.
Max and min filter is one of the order-statistic filter we can use to process image data in spatial domain. This tutorial shows it with C#.
Median filter is one of the order-statistic filters for processing image data in spatial domain. This guide shows how to apply it with C#.
We can use contraharmonic mean filter to process image data in spatial domain. It's most effective against salt and pepper noise.
Harmonic mean filter is of mean filters we can use to process image data in spatial domain. This guide shows how to apply it with C#.
Geometric mean filter is one of mean filters we can use processing images in spatial domain. We use C# programming language to apply it here.
Arithmetic mean filter is one of the simplest mean filters we could use to reduce noise from an image. Learn more about spatial filtering.
Salt and pepper noise or impulse noise is one of the noise models we can use to simulate image data corruption in real life.
I’m going to talk about adaptive filters in this post. More specifically, I’m going to talk about adaptive local noise reduction filter. Basically, it’s a spatial filter and we mainly use it to filter out noise from the images.
Spatial filter or kernel is like a small window on our image which encompasses a local set of intensity values. After we get this set, we use it to calculate an output intensity value. In order to render the output image, we need to calculate for each pixel separately.
There are a few reasons why are adaptive filters better than other filters. Firstly, other filters disregard that image characteristics may vary from one point to the other across it, these do not. And secondly, their performance is superior.
However, there are also a few downsides. For one, adaptive filters are more complicated. Therefore, they need more processing power to compute each output intensity value. And for another point, they’re still good for images which have only noise degradation.
These have the simplest statistical measures for mean and variance. When we calculate new ouput values, the mean gives us the average intensity inside the filter. While variance gives us contrast information from these intensities.
Let’s take a look at the following formula and break it down.
So, first things first, g(x, y) represents the intensity value, which has a position in the center of the filter. Then, before the brackets, we have ratio between noise variance on top of the fraction and intensity variance below.
We calculate intensity variance from intensities inside the filter and we have to do it for each output pixel. And lastly, mL is the mean of intensities inside the filter region.
Despite how complex formula is, we can compute almost all values from filter set. The only unknown that remains is noise variance. We need to estimate it to be as close to variance of the noise with which our image is corrupted.
Another pointer for using this filter is to limit maximum noise variance to be less or equal to intensity variance. This way we can prevent some unwanted things happening, like negative intensity values and such.
public static Bitmap Filter(this Bitmap image, double noise_variance)
{
int w = image.Width;
int h = image.Height;
BitmapData image_data = image.LockBits(
new Rectangle(0, 0, w, h),
ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb);
int bytes = image_data.Stride * image_data.Height;
byte[] buffer = new byte[bytes];
Marshal.Copy(image_data.Scan0, buffer, 0, bytes);
image.UnlockBits(image_data);
int r = 3;
int wres = w - 2 * r;
int hres = h - 2 * r;
Bitmap result_image = new Bitmap(wres, hres);
BitmapData result_data = result_image.LockBits(
new Rectangle(0, 0, wres, hres),
ImageLockMode.WriteOnly,
PixelFormat.Format24bppRgb);
int res_bytes = result_data.Stride * result_data.Height;
byte[] result = new byte[res_bytes];
for (int x = r; x < w - r; x++)
{
for (int y = r; y < h - r; y++)
{
int pixel_location = x * 3 + y * image_data.Stride;
int res_pixel_loc = (x - r) * 3 + (y - r) * result_data.Stride;
double[] mean = new double[3];
int[][] neighborhood = new int[3][];
for (int c = 0; c < 3; c++)
{
neighborhood[c] = new int[(int)Math.Pow(2 * r + 1, 2)];
int added = 0;
for (int kx = -r; kx <= r; kx++)
{
for (int ky = -r; ky <= r; ky++)
{
int kernel_pixel = pixel_location + kx * 3 + ky * image_data.Stride;
neighborhood[c][added] = buffer[kernel_pixel + c];
added++;
}
}
}
for (int c = 0; c < 3; c++)
{
mean[c] = neighborhood[c].Sum() / Math.Pow(2 * r + 1, 2);
double variance = 0d;
for (int i = 0; i < neighborhood[c].Length; i++)
{
variance += Math.Pow(neighborhood[c][i] - mean[c], 2);
}
variance /= Math.Pow(2 * r + 1, 2);
if (noise_variance > variance)
{
noise_variance = variance;
}
result[res_pixel_loc + c] = (byte)(buffer[pixel_location + c] - (noise_variance / variance) * (buffer[pixel_location + c] - mean[c]));
}
}
}
Marshal.Copy(result, 0, result_data.Scan0, res_bytes);
result_image.UnlockBits(result_data);
return result_image;
}
We can use adaptive filters when we have significant noise corruption in our images. They give us a little more umpf than the rest of spatial filters.
I hope this guide was helpful. You can also download the project and try it out on your own images.