Search code examples
c#image-processingpgm

Minimum Filter function doesn't represent the right result


I made a minimum filter function that should work for PGM P2 images. The problem is that the output is wrong. Everything is described below.

Algorithm: http://www.roborealm.com/help/Min.php and https://www.youtube.com/watch?v=Y_QF0Xq8zGM

Debugging sample:

The beginning part of my image:

PGM P2 Image

matrixSize = 3

offset = 1

First loop iteration:

j = 1, i = 1 neighboursNumbers = Count = 9

neighboursNumbers values: (note that this is before sorting)

first iteration

Second loop iteration:

j = 1, i = 2 neighboursNumbers = Count = 9

neighboursNumbers values: (again before sorting)

second iteration

Code:

// Properties
public string Format { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public int MaxGrayLevel { get; set; }
public int[] Pixels { get; set; }

// Minimum Filter Code
int matrixSize = 3;

int offset = (matrixSize - 1) / 2;

for (int j = offset; j < image.Height - offset; j++)
{
    for (int i = offset; i < image.Width - offset; i++)
    {
        List<int> neighboursNumbers = (from x in Enumerable.Range(i - offset, matrixSize)
                                       from y in Enumerable.Range(j - offset, matrixSize)
                                       where (x >= 0) && (x < image.Width) && (y >= 0) && (y < image.Height)
                                       select image.Pixels[y * Width + x]).ToList();

        neighboursNumbers.Sort();

        int minIndex = neighboursNumbers[0];
        image.Pixels[j * image.Width + i] = minIndex;
    }
}

Result:

Output

Expected (this result is using radius 7.0 in ImageJ):

Expected result


Solution

  • You are replacing the data of the source image Pixels in the loop with the output of the filter. You should not do that, because the filter must be applied to the entire source image.

    To see the problem, imagine you are applying the filter to the pixel (X,Y) and get an output of M. The next step in your algorithm is to apply the filter to (X+1,Y). The neighborhood of that pixel includes (X,Y), but you replaced its value with M in the earlier step. So a local minimum value will persist, until a new minimum is found. That creates the structure of your resulting image.

    In order to fix it, simply create a new image in which you put the filter output, and don't modify the filter input.