I have written some routines to sharpen a Grayscale image using a 3x3 kernel,
-1 -1 -1
-1 9 -1
-1 -1 -1
The following code is wo
The main issue appears to be with the interpretation of the kernel as an image consisting of unsigned byte values. As a result the -1
values are converted to 255
effectively computing a convolution with the kernel
255 255 255
255 9 255
255 255 255
This can be immediately observed from white area in the "Convolution Kernel" image. The resulting kernel is thus that of a low-pass filter, producing a corresponding blurring effect.
Probably the best way to handle this would be to read the kernel as a matrix of signed values instead of as an image.
If you still prefer to handle the kernel as an image, you would need to convert the image back to signed values. The simplest way I can think of achieving this result would be to create a modified version of ImageDataConverter.ToInteger(Bitmap)
where you map the bytes to signed values:
public static Complex[,] Unwrap(Bitmap bitmap)
{
int Width = bitmap.Width;
int Height = bitmap.Height;
Complex[,] array2D = new Complex[bitmap.Width, bitmap.Height];
...
else// If there is only one channel:
{
iii = (int)(*address);
if (iii >= 128)
{
iii -= 256;
}
}
Complex tempComp = new Complex((double)iii, 0.0);
array2D[x, y] = tempComp;
You would then be able to convert your image in SharpenFilter.ApplyWithPadding
with:
Complex[,] cPaddedMask = ImageDataConverter.Unwrap(maskClone);
This should then give you the following result:
While this improves on the sharpness of the image, you should immediately notice that the image is much darker than the original. This is due to the Convolution.Rescale
function which dynamically rescales the image according to it's minimum and maximum value. This can be convenient to show the image with maximum dynamic range, but could result in a different overall scaling than a standard convolution. To achieve this standard scaling (based on the scaling of your FFT implementation), you could use the following implementation:
//Rescale values between 0 and 255.
private static void Rescale(Complex[,] convolve)
{
int imageWidth = convolve.GetLength(0);
int imageHeight = convolve.GetLength(1);
double scale = imageWidth * imageHeight;
for (int j = 0; j < imageHeight; j++)
{
for (int i = 0; i < imageWidth; i++)
{
double re = Math.Max(0, Math.Min(convolve[i, j].Real * scale, 255.0));
double im = Math.Max(0, Math.Min(convolve[i, j].Imaginary * scale, 255.0));
convolve[i, j] = new Complex(re, im);
}
}
}
This should then give you an image with a more appropriate brightness level:
Finally, for a filtering operation one would typically expect the result to match the original image size (unlike a convolution which includes the tails). Cropping the result in SharpenFilter.ApplyWithPadding
with:
...
// -3 terms are due to kernel size
// +5 vertical offset term is due to vertical reflection & offset in SetPixel
Rectangle rect = new Rectangle((cPaddedLena.GetLength(0) / 2 - 3) / 2,
(cPaddedLena.GetLength(1) / 2 - 3) / 2 + 5,
cPaddedLena.GetLength(0) / 2,
cPaddedLena.GetLength(1) / 2);
return ImageDataConverter.ToBitmap(cConvolved).Clone(rect, PixelFormat.Format8bppIndexed);
should give you:
For easier visual comparison, here is the original image again: