同态滤波器输出 [英] Homomorphic Filter output

查看:257
本文介绍了同态滤波器输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了下面的代码来开发一个同态滤波器。



我认为(我不确定)彩色图像是否被过滤得很好。





在灰度图像的情况下,






我认为(虽然我不确定)彩色图像被过滤得很好。


情况并非如此。对于锐化滤镜,我不会期望颜色受到太多影响(指建筑物上的天空的绿色,黄色和红色反射)。好消息是,与上面相同的解决办法也处理:


I have written the following code to develop a Homomorphic Filter.

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

In case of Grayscale images,

Why is the kernel always Green?

Also, the filter was supposed to be sharpening the image. But, its not doing so.

What could have possibly gone wrong?

.

.

Source Code:

Here is the Github repository.

public class HomomorphicFilter
{
    public HomoMorphicKernel Kernel = null;
    public bool IsPadded { get; set; }
    public int Width { get; set; }
    public int Height { get; set; }
    public double RH { get; set; }
    public double RL { get; set; }
    public double Sigma { get; set; }
    public double Slope { get; set; }
    public int PaddedWidth { get; set; }
    public int PaddedHeight { get; set; }
    public Bitmap KernelBitmap
    {
        get
        {
            if (IsPadded)
            {
                return Kernel.PaddedKernelBitmap;
            }
            else
            {
                return Kernel.KernelBitmap;
            }
        }
    }

    #region private methods
    private int[,] Apply8bit(int[,] imageData2d)
    {
        Complex[,] imageData2dShiftFftCplx = FourierShifter.ShiftFft(FourierTransform.ForwardFFT(ImageDataConverter.ToComplex(imageData2d)));

        Complex[,] fftShiftedFiltered = null;

        if (IsPadded)
        {
            fftShiftedFiltered = Tools.Multiply(Kernel.PaddedKernel, imageData2dShiftFftCplx);
        }
        else
        {
            fftShiftedFiltered = Tools.Multiply(Kernel.Kernel, imageData2dShiftFftCplx);
        }

        return ImageDataConverter.ToInteger(FourierTransform.InverseFFT(FourierShifter.RemoveFFTShift(fftShiftedFiltered)));
    }

    private int[, ,] Apply3d(int[, ,] image3d)
    {
        int[, ,] filteredImage3d = new int[image3d.GetLength(0), image3d.GetLength(1), image3d.GetLength(2)];

        int widtH = image3d.GetLength(1);
        int heighT = image3d.GetLength(2);

        int[,] imageData2d = new int[widtH, heighT];
        for (int dimension = 0; dimension < 3; dimension++)
        {
            for (int i = 0; i <= widtH - 1; i++)
            {
                for (int j = 0; j <= heighT - 1; j++)
                {
                    imageData2d[i, j] = image3d[dimension, i, j];
                }
            }

            int[,] filteredImage2d = Apply8bit(imageData2d);

            for (int i = 0; i <= widtH - 1; i++)
            {
                for (int j = 0; j <= heighT - 1; j++)
                {
                    filteredImage3d[dimension, i, j] = filteredImage2d[i, j];
                }
            }
        }

        return filteredImage3d;
    }
    #endregion

    public void Compute()
    {
        if (IsPadded)
        {
            if (Width >= PaddedWidth || Height >= PaddedHeight)
            {
                throw new Exception("PaddedWidth or PaddedHeight must be greater than Width or Height.");
            }
        }

        Kernel = new HomoMorphicKernel();
        Kernel.Width = Width;
        Kernel.Height = Height;
        Kernel.RH = RH;
        Kernel.RL = RL;
        Kernel.Sigma = Sigma;
        Kernel.Slope = Slope;
        Kernel.PaddedWidth = PaddedWidth;
        Kernel.PaddedHeight = PaddedHeight;
        Kernel.Compute();
    }

    public Bitmap Apply8bit(Bitmap image)
    {
        int[,] image2d = ImageDataConverter.ToInteger(image);

        int[,] filtered = Apply8bit(image2d);

        return ImageDataConverter.ToBitmap(filtered);
    }

    public Bitmap Apply32bitColor(Bitmap image)
    {
        int[, ,] image3d = ImageDataConverter.ToInteger3d_32bit(image);

        int[, ,] filtered = Apply3d(image3d);

        return ImageDataConverter.ToBitmap3d_32bit(filtered);
    }
}

解决方案

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:

这篇关于同态滤波器输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆