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

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

c# - 同态滤波器输出-LMLPHP

如果是灰度图像,

c# - 同态滤波器输出-LMLPHP

为什么内核总是绿色?

同样,滤镜被认为可以锐化图像。但是,它没有这样做。

可能出了什么问题?





源代码:

c# - 同态滤波器输出-LMLPHP

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

最佳答案

为什么内核总是绿色?


仅仅是因为执行从ImageDataConverter.ToBitmap32bitColor调用的整数值内核HomoMorphicKernel.GetKernelBitmap的转换函数显式地仅分配给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;



  同样,滤镜被认为可以锐化图像。但是,它没有这样做。可能出了什么问题?


那是更有趣的问题。简而言之,您在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,进行了一些重新缩放,以对数比例显示内核等)。可随意将参数调整为适合您要求的任何值。

有了这个,您应该得到如下所示的内容:
c# - 同态滤波器输出-LMLPHP


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


情况并非如此。对于锐化滤镜,我认为颜色不会受到太大影响(指建筑物上天空的绿色,黄色和红色反射)。好消息是,与上述相同的修复程序也可以解决以下问题:

c# - 同态滤波器输出-LMLPHP

10-04 20:42