Take a look at this question.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Bitmap image = DataConverter2d.ReadGray(StandardImage.LenaGray);
Array2d<double> dImage = DataConverter2d.ToDouble(image);
int newWidth = Tools.ToNextPowerOfTwo(dImage.Width) * 2;
int newHeight = Tools.ToNextPowerOfTwo(dImage.Height) * 2;
double n = 6;
double f0 = 0.5;
double theta = 60;
double a = 0.4;
Array2d<Complex> kernel2d = CustomFft(newWidth, newHeight, n, f0, theta, a);
dImage.PadTo(newWidth, newHeight);
Array2d<Complex> cImage = DataConverter2d.ToComplex(dImage);
Array2d<Complex> fImage = FourierTransform.ForwardFft(cImage);
// FFT convolution .................................................
Array2d<Complex> fOutput = new Array2d<Complex>(newWidth, newHeight);
for (int x = 0; x < newWidth; x++)
{
for (int y = 0; y < newHeight; y++)
{
fOutput[x, y] = fImage[x, y] * kernel2d[x, y];
}
}
Array2d<Complex> cOutput = FourierTransform.InverseFft(fOutput);
Array2d<double> dOutput = Rescale2d.Rescale(DataConverter2d.ToDouble(cOutput));
dOutput.CropBy((newWidth - image.Width) / 2, (newHeight - image.Height) / 2);
Bitmap output = DataConverter2d.ToBitmap(dOutput, image.PixelFormat);
Array2d<Complex> cKernel = FourierTransform.InverseFft(kernel2d);
cKernel = FourierTransform.RemoveFFTShift(cKernel);
Array2d<double> dKernel = DataConverter2d.ToDouble(cKernel);
Array2d<double> dLimitedKernel = Rescale2d.Limit(dKernel);
Bitmap kernel = DataConverter2d.ToBitmap(dLimitedKernel, image.PixelFormat);
pictureBox1.Image = image;
pictureBox2.Image = kernel;
pictureBox3.Image = output;
}
private double Basic(double u, double v, double n, double f0, double rad, double a, double b)
{
double ua = u + f0 * Math.Cos(rad);
double va = v + f0 * Math.Sin(rad);
double ut = ua * Math.Cos(rad) + va * Math.Sin(rad);
double vt = (-1) * ua * Math.Sin(rad) + va * Math.Cos(rad);
double p = ut/a;
double q = vt/b;
double sqrt = Math.Sqrt(p*p + q*q);
return 1.0 / (1.0+ 0.414 * Math.Pow(sqrt, 2*n));
}
private double Custom(double u, double v, double n, double f0, double theta, double a)
{
double rad1 = (Math.PI / 180) * (90-theta);
double rad2 = rad1 + Math.PI;
double b = (a / 5.0) / (2*n);
double ka = Basic(u, v, n, f0, rad1, a, b);
double kb = Basic(u, v, n, f0, rad2, a, b);
return Math.Max(ka, kb);
}
private Array2d<Complex> CustomFft(double sizeX, double sizeY, double n, double f0, double theta, double a)
{
double halfX = sizeX / 2;
double halfY = sizeY / 2;
Array2d<Complex> kernel = new Array2d<Complex>((int)sizeX, (int)sizeY);
for (double y = 0; y < sizeY; y++)
{
double v = y / sizeY;
for (double x = 0; x < sizeX; x++)
{
double u = x / sizeX;
double kw = Custom(u, v, n, f0, theta, a);
kernel[(int)x, (int)y] = new Complex(kw, 0);
}
}
return kernel;
}
}
I created a 40-kernel filter bank where each kernel would have same size but different parameters.
This bank of filter is taking around 55000 milliseconds for the kernels to be generated.
How can I reduce this time?
Note: the following line is taking the most time:
Array2d<Complex> kernel2d = CustomFft(newWidth, newHeight, n, f0, theta, a);
.
Example source code for creating a kernel bank:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Stopwatch sw = new Stopwatch();
sw.Start();
Bitmap image = DataConverter2d.Read(StandardImage.Scratch1);
int newWidth = Tools.ToNextPowerOfTwo(image.Width);
int newHeight = Tools.ToNextPowerOfTwo(image.Height);
List<FrequencyDomainKernel> list = new List<FrequencyDomainKernel>();
for (int i = 0; i < 40; i++)
{
FrequencyDomainKernel k= new FrequencyDomainKernel();
k.Size = new System.Drawing.Size(newWidth, newHeight);
k.theta = i;
k.Compute();
list.Add(k);
}
sw.Stop();
MessageBox.Show(sw.ElapsedMilliseconds.ToString());
}
}
Note: this is not an executable code. This code is just to give an idea regarding my method of generating a kernel.
As a starting point, try this:
I am going to work on it a little more.
EDIT 1
My first observation is that you are using too many classes and in these classes too many methods. The problem with OOP is that sometimes the code is divided into too many classes with very tiny methods which in turn can make the code hard to follow (going through all the classes etc..) and unnecessarily slow for simple things. Let use some numbers:
A simple:
takes arround 65msec! It just subtitutes the real part of
cImage
with the value ofdImage
and the imaginary is set tozero
. This trully shouldn't take that much but as I said OOP and classes. Lets do a simple re-configuration and instead ofArray2d<Complex>
use a simple double array:Thats it. It stores
real-imaginary
parts linearly egLets re-write the code and test it:
Time needed ~10msec. More than 6 times faster!!!!
Lets do another one. Lets test
FFT convolution
which takes ~105msecRe-write it with simple 1 dimension double arrays:
The results, ~31msec!!! more than 3.5 times faster. Imagine how faster the whole code could be if just simple 1 dimension double arrays were used.
These are my first observations. New edits will come later.
EDIT2
In this edit we will optimize CustomFFt even more. Some observations. After some manipulation of the equations i come at this:
From the above
CustomFft
can be written as:The bottleneck of
CustomFFt
is thePow
call. Times: