Please see second update
I'm trying to implement gaussian blur in frequency domain using c#.
Those are steps that I'm doing:
- Load bitmap.
- Split bitmap into separate color channels.
- Convert every channel into complex numbers.
- Create gaussian kernel:
- Create kernel using Gauss Function
- Transform kernel into complex numbers (Here's my first concern, When I create kernel that contains only values equal to 1 (that's number 1 in every cell), to do so i dont use above function. After transforming that (the kernel with values of 1 only) into complex numbers via external library, i recieve something like this: re=0.0039 im=0.0 for every cell in array, is it valid?).
- FFT on every color channel.
- FFT on kernel (Second concern - for transformed kernel of all 1, Like i mentioned ealier, i recieve array of re=0.0 im=0.0 complex numbers with 1 and only 1 entery like re=0.0039 im=0.0, is it valid?)
- Multiply all channel's complex numbers by filter complex number. (For tests kernel is size of input image).
- IFFT on every color channel.
- Merge channels into single image.
As a result, for all 1 kernel tests, I recieve totaly black image, so I made some mistakes on the way, but I dont know what's wrong.
I'm fairly new to image processing, since it's school project. Can anyone point the mistakes i made?
UPDATE #1
Uploading my code as @Olli Niemitalo asked. Several values are hardcoded so if something's unclear feel free to ask. The image i'm testing with is lena 512x512 with 3 color channels (RGB).
That's the best result i've received and i'm stuck on that. Below is the most of the code I use.
If you need something more, just ask.
Create gaussian kernel.
private ComplexImage makeGaussKernel(int side, double min, double max, double step, double std)
{
Bitmap bitmap = new Bitmap(512, 512, PixelFormat.Format8bppIndexed);
LockBitmap lbitmap = new LockBitmap(bitmap);
lbitmap.LockBits();
for (int i = 0; i < 512; ++i)
{
for (int j = 0; j < 512; ++j)
{
lbitmap.SetPixel(i, j, Color.FromArgb(255,0,0,0));
}
}
// I'm generating 16x16 white square below.
for (int i = 0; i < 16; ++i)
{
for (int j = 0; j < 16; ++j)
{
lbitmap.SetPixel(i, j, Color.FromArgb(255));
}
}
lbitmap.UnlockBits();
var result = AForge.Imaging.ComplexImage.FromBitmap(bitmap);
for (int i = 0; i < 512; ++i)
{
for (int j = 0; j < 512; ++j)
{
// Data after conversion to complex is too low, all i get without below multiplication is black image. With multiplication colors are fine.
result.Data[i, j].Re *= 1000;
}
}
return result;
}
// The gauss function
private double gauss2d(double x, double y, double std)
{
return ((1.0 / (2 * Math.PI * std * std)) * Math.Exp(-((x * x + y * y) / (2 * std * std))));
}
The multiplication:
private void applyGauss(ComplexImage complexImage, ComplexImage filter, int side)
{
int width = complexImage.Data.GetLength(1);
int height = complexImage.Data.GetLength(0);
for(int i = 0; i < height; ++i)
{
for(int j = 0; j < width; ++j)
{
complexImage.Data[i, j] = AForge.Math.Complex.Multiply(complexImage.Data[i, j], filter.Data[i, j]);
}
}
}
UPDATE #2
I've made a breakthrough. The weird shift was result of applying the filter in the middle of the image. When I moved the filter to the corner, only few artifacts remains (that's not big deal for now) - see image below.
The updated code from UPDATE #1 is the only problem now prolly (gaussian generation). I need few tips how to generate the kernel properly. As you can see in code above I generate white square in the corner. I belive it's far from real gaussian blur.
Also after conversion from normal bytes to complex numbers I receive very dark (in fact black) image. So I tried to multiply real part of complex numbers (you can see that in the code) and after that I received "good" image. I dont really know what's wrong.
Important thing that was discovered by @Olli Niemitalo is that colors are divied by 255 after conversion to complex (by AForge.NET) so If kernel's bitmap is made of 255s, after conversion I receive kernel made of re=1.0 im=0.0 etc.
I dont have to use AForge.NET to generate complex numbers, so if you've got tips how to generate those without AFN, i will take all of them.
Current result: The artifacts / "good" image
complexnumbers[x, y].re = realnumbers[x, y]; complexnumbers[x, y].im = 0;
andMaybe you should multiply your Gaussian by 255 or 256
(each modification tested separately) all I get now is well.. full redish image (R=181 G=98 B=106). $\endgroup$