Search code examples
image-processingedge-detection

What's the right way to normalize a convolution filter?


I'm following these instructions. But my results aren't coming out right. I'm using this kernel:

-1 -1 -1
-1  8 -1
-1 -1 -1

So that means the sum for a given convolution will be between -8 and 8, assuming I have already normalized my input (0-255 -> 0-1). Then I do the convolution. Then I find the percent my value is between the minimum and maximum values. For example, with this kernel my min is -8 and max is 8. So if the value is 0 that's 50% which works out to 255 * .5 = 127.5. But that's clearly not right and what it gives is a mostly gray image. The parts that aren't gray are still monochrome even though I'm running the kernel on each channel individually.

enter image description here

    static int EvaluateKernelAtPoint(Bitmap bitmap, Matrix<double> kernel, int x, int y, Func<int, int, int> onGetIntensity)
    {
        double sum = 0;
        for (int a = 0; a < kernel.ColumnCount; a++)
        {
            for (int b = 0; b < kernel.RowCount; b++)
            {
                var xn = x + a - 1;
                var yn = y + b - 1;

                var intensity = (double)onGetIntensity(xn, yn); // returns R,G, or B color channel at that pixel
                intensity /= 255; // intensity is 0-1
                sum += intensity * kernel.At(a, b);
            }
        }

        var result = (sum - (-8d)) / (8d - (-8d)); // find the % between the min and max of -8 and 8
        result *= 255; // bring it back to 0-255
    }

Solution

  • There is no right way to normalize, because the range is content-dependent.

    In good RGB images, the range of values is usually [0, 255], provided the dynamic range is well adjusted.

    But the output of this Laplacian filter, which can be seen as the difference between the original image and a smoothed version of it, usually has much smaller amplitude. But this depends on the local variations: an already smooth image will give no response, while noise (especially salt & pepper) can yield huge values.

    You also need to decide what to do with negative values: shift so that zero appears as mid-gray, clamp to zero or take the absolute value.

    Taking the min-max range and mapping it to 0-255 is an option, but leads to a "floating" zero and uncontrolled gain. I would prefer to set a constant gain for a set of images of the same origin.

    Last but not least, histogram equalization is another option.