同态滤波器输出

Homomorphic Filter output

我编写了以下代码来开发同态滤波器。

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

如果是灰度图像,

为什么内核总是绿色的?

此外,滤镜应该会锐化图像。但是,它并没有这样做。

可能出了什么问题?

.

.

源代码:

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?

仅仅是因为从HomoMorphicKernel.GetKernelBitmap调用的执行整数值内核ImageDataConverter.ToBitmap32bitColor转换的函数明确地只分配给RGBA字的绿色和alpha分量:

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

如果你想在灰度上将内核显示为强度,你可以使用 8 位灰度图像来实现,或者为红色、绿色和蓝色分量分配相同的值:

        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?

这是一个更有趣的问题。简而言之,您从低通 Gaussian.GaussianKernelHPF 中的高通高斯核转换是不正确的。你必须纠正一般的想法来计算像 1-f(x) 这样的函数,其中 f(x) 是低通内核,但这适用于频域内核响应。在空间域中,常数项变为脉冲。考虑到一些缩放因素(要在频域中获得单一脉冲并给定 FFT 定义,您需要脉冲的幅度在空间域中为 Width*Height),您应该得到如下内容:

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;
        }
    }
}

请注意,您还需要移动内核,使高斯内核的峰值位于像素位置 (0,0),以避免得到循环移动的结果图像:

//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;

请参阅 this pull-request 以了解此修复的实施,其中还包括一些额外的调整(例如,我已将 Sigma 修改为不太激进的值 4、一些重新缩放、显示内核在对数刻度等中)随意将参数调整为对您的要求有意义的任何值。

有了这个你应该得到看起来像这样的东西:

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

事实并非如此。对于锐化滤镜,我不希望颜色受到如此大的影响(指建筑物上天空的绿色、黄色和红色反射)。好消息是,与上面相同的修复也可以处理: