我编写了以下代码来开发同态滤波器。
我认为(我不确定)彩色图像是否过滤得很好。
如果是灰度图像,
为什么内核总是绿色?
此外,过滤器应该是锐化图像。但是,它没有这样做。
可能出现什么问题?
源代码:
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);
}
}
答案 0 :(得分:1)
为什么内核总是绿色?
这只是因为执行从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,一些rescalings,在日志中显示内核-scale等)随意将参数调整为符合您要求的任何值。
我认为(我不确定)彩色图像是否过滤得很好。
事实并非如此。对于锐化滤镜,我不希望颜色受到太大影响(指的是建筑物上天空的绿色,黄色和红色反射)。好消息是,上述同样的解决方案也可以处理: