Homomorphic Filter output

别等时光非礼了梦想. 提交于 2019-12-06 12:27:41

Why is the kernel always Green?

It is simply because the function which performs the conversion of the integer-valued kernel ImageDataConverter.ToBitmap32bitColor called from HomoMorphicKernel.GetKernelBitmap explicitly only assigns to the green and alpha components of the RGBA word:

for (int i = 0; i < bitmapData.Height; i++)
{
    for (int j = 0; j < bitmapData.Width; j++)
    {
        address[0] = 0;                 //<=== No red
        address[1] = (byte)image[j, i]; //<=== This is the green component
        address[2] = 0;                 //<=== No blue
        address[3] = 255;
        //4 bytes per pixel
        address += 4;
    }//end for j
    //4 bytes per pixel
    address += (bitmapData.Stride - (bitmapData.Width * 4));
}//end for i

If you wanted to show the kernel as intensity on a grey-scale, you could either do this with a 8bit grey-scale image, or assign the same value to the red, green and blue components:

        address[0] = (byte)image[j, i];
        address[1] = (byte)image[j, i];
        address[2] = (byte)image[j, i];
        address[3] = 255;

Also, the filter was supposed to be sharpening the image. But, its not doing so. What could have possibly gone wrong?

That's the more interesting question. In short your high-pass Gaussian kernel conversion in Gaussian.GaussianKernelHPF from low-pass is incorrect. You have to correct general idea to compute a function like 1-f(x) where f(x) is the low-pass kernel, but this applies to the frequency-domain kernel response. In the spatial-domain, the constant term becomes an impulse. With some scaling considerations (to get unitary impulse in the frequency-domain and given your FFT definition, you need the magnitude of the pulse to be Width*Height in the spatial-domain) you should get something such as:

double K = 1 / D1;
double S = Width * Height / (Math.PI * Math.PI * D2 * D2);
for (int i = -halfOfWidth; i < halfOfWidth; i++)
{
    for (int j = -halfOfHeight; j < halfOfHeight; j++)
    {
        int x = halfOfWidth + i;
        int y = halfOfHeight + j;

        if (i == 0 && j == 0)
        {
            GaussianKernel[x, y] = Width * Height + (K / D1 - Kernel[x, y]) * S;
        }
        else
        {
            GaussianKernel[x, y] = -Kernel[x, y] * S;
        }
    }
}

Note that you would also need to shift the kernel such that the peak of your Gaussian kernel is at pixel location (0,0) to avoid getting a circularly shifted result image:

//Swap halves so the peak is at pixel (0,0)
double[,] shifted = new double[Width, Height];
for (int j = 0; j < halfOfHeight; j++)
{
    for (int i = 0; i < halfOfWidth; i++)
    {
        int x = i + halfOfWidth;
        int y = j + halfOfHeight;

        shifted[x, y] = GaussianKernel[i, j];
        shifted[i, j] = GaussianKernel[x, y];
        shifted[x, j] = GaussianKernel[i, y];
        shifted[i, y] = GaussianKernel[x, j];
    }
}
return shifted;

See this pull-request for an implementation of this fix, which also includes a few extra tweaks (e.g. I've modified Sigma to a less aggressive value of 4, some rescalings, displaying the kernel in log-scale, etc.) Feel free to tweak the parameters to whatever values makes sense for your requirements.

With this you should get something that looks like:

I think (I am not sure though) the color images are being filtered well.

This wasn't quite the case. For a sharpening filter I wouldn't expect the colors to be affected so much (referring to the green, yellow and red reflections of the sky on the building). The good news is that the same fix as above also handles that:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!