/// <summary> /// Calculate function self-convolution values /// </summary> /// <param name="f">Function values</param> /// <returns></returns> public double[] Build(double[] f) { int length = (_functionType == FunctionType.Periodic) ? f.Length : (f.Length + f.Length - 1); var input = new fftw_complexarray(length); var output = new fftw_complexarray(length); fftw_plan forward = fftw_plan.dft_1d(length, input, output, fftw_direction.Forward, fftw_flags.Estimate); fftw_plan backward = fftw_plan.dft_1d(length, input, output, fftw_direction.Backward, fftw_flags.Estimate); var complex = new Complex[length]; for (int i = 0; i < f.Length; i++) complex[i] = f[i]; input.SetData(complex); forward.Execute(); complex = output.GetData_Complex(); input.SetData(complex.Select(x => x*x/length).ToArray()); backward.Execute(); complex = output.GetData_Complex(); return complex.Select(x => x.Magnitude).ToArray(); }
/// <summary> /// Sharp bitmap with the Fastest Fourier Transform /// </summary> /// <returns>Sharped bitmap</returns> private double[, ,] Sharp(double[, ,] imageData) { int length = imageData.Length; int n0 = imageData.GetLength(0); int n1 = imageData.GetLength(1); int n2 = imageData.GetLength(2); var input = new fftw_complexarray(length); var output = new fftw_complexarray(length); fftw_plan forward = fftw_plan.dft_3d(n0, n1, n2, input, output, fftw_direction.Forward, fftw_flags.Estimate); fftw_plan backward = fftw_plan.dft_3d(n0, n1, n2, input, output, fftw_direction.Backward, fftw_flags.Estimate); var doubles = new double[length]; Buffer.BlockCopy(imageData, 0, doubles, 0, length * sizeof(double)); double average = doubles.Average(); double delta = Math.Sqrt(doubles.Average(x => x * x) - average * average); switch (_keepOption) { case KeepOption.AverageAndDelta: break; case KeepOption.Sum: average = doubles.Sum(); break; case KeepOption.Square: average = Math.Sqrt(doubles.Sum(x => x * x)); break; case KeepOption.AverageSquare: average = Math.Sqrt(doubles.Average(x => x * x)); break; default: throw new NotImplementedException(); } input.SetData(doubles.Select(x => new Complex(x, 0)).ToArray()); forward.Execute(); Complex[] complex = output.GetData_Complex(); Complex level = complex[0]; var data = new Complex[n0, n1, n2]; var buffer = new double[length * 2]; GCHandle complexHandle = GCHandle.Alloc(complex, GCHandleType.Pinned); GCHandle dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); IntPtr complexPtr = complexHandle.AddrOfPinnedObject(); IntPtr dataPtr = dataHandle.AddrOfPinnedObject(); Marshal.Copy(complexPtr, buffer, 0, buffer.Length); Marshal.Copy(buffer, 0, dataPtr, buffer.Length); switch (_mode) { case Mode.BlinderSize: Blind(data, _blinderSize); break; case Mode.FilterStep: int filterStep = _filterStep; var blinderSize = new Size(MulDiv(n1, filterStep, filterStep + 1), MulDiv(n0, filterStep, filterStep + 1)); Blind(data, blinderSize); break; default: throw new NotImplementedException(); } Marshal.Copy(dataPtr, buffer, 0, buffer.Length); Marshal.Copy(buffer, 0, complexPtr, buffer.Length); complexHandle.Free(); dataHandle.Free(); complex[0] = level; input.SetData(complex); backward.Execute(); doubles = output.GetData_Complex().Select(x => x.Magnitude).ToArray(); double average2 = doubles.Average(); double delta2 = Math.Sqrt(doubles.Average(x => x * x) - average2 * average2); switch (_keepOption) { case KeepOption.AverageAndDelta: break; case KeepOption.Sum: average2 = doubles.Sum(); break; case KeepOption.Square: average2 = Math.Sqrt(doubles.Sum(x => x * x)); break; case KeepOption.AverageSquare: average2 = Math.Sqrt(doubles.Average(x => x * x)); break; default: throw new NotImplementedException(); } // a*average2 + b == average // a*delta2 == delta double a = (_keepOption == KeepOption.AverageAndDelta) ? (delta / delta2) : (average / average2); double b = (_keepOption == KeepOption.AverageAndDelta) ? (average - a * average2) : 0; Debug.Assert(Math.Abs(a * average2 + b - average) < 0.1); doubles = doubles.Select(x => Math.Round(a * x + b)).ToArray(); Buffer.BlockCopy(doubles, 0, imageData, 0, length * sizeof(double)); return imageData; }
/// <summary> /// Catch pattern bitmap with the Fastest Fourier Transform /// </summary> /// <returns>Matrix of values</returns> private Matrix<double> Catch(Image<Gray, double> image) { const double f = 1.0; int length = image.Data.Length; int n0 = image.Data.GetLength(0); int n1 = image.Data.GetLength(1); int n2 = image.Data.GetLength(2); Debug.Assert(n2 == 1); // Allocate FFTW structures var input = new fftw_complexarray(length); var output = new fftw_complexarray(length); fftw_plan forward = fftw_plan.dft_3d(n0, n1, n2, input, output, fftw_direction.Forward, fftw_flags.Estimate); fftw_plan backward = fftw_plan.dft_3d(n0, n1, n2, input, output, fftw_direction.Backward, fftw_flags.Estimate); var matrix = new Matrix<double>(n0, n1); double[,,] patternData = _patternImage.Data; double[,,] imageData = image.Data; double[,] data = matrix.Data; var doubles = new double[length]; // Calculate Divisor Copy(patternData, data); Buffer.BlockCopy(data, 0, doubles, 0, length*sizeof (double)); input.SetData(doubles.Select(x => new Complex(x, 0)).ToArray()); forward.Execute(); Complex[] complex = output.GetData_Complex(); Buffer.BlockCopy(imageData, 0, doubles, 0, length*sizeof (double)); input.SetData(doubles.Select(x => new Complex(x, 0)).ToArray()); forward.Execute(); input.SetData(complex.Zip(output.GetData_Complex(), (x, y) => x*y).ToArray()); backward.Execute(); IEnumerable<double> doubles1 = output.GetData_Complex().Select(x => x.Magnitude); if (_fastMode) { // Fast Result Buffer.BlockCopy(doubles1.ToArray(), 0, data, 0, length*sizeof (double)); return matrix; } // Calculate Divider (aka Power) input.SetData(doubles.Select(x => new Complex(x*x, 0)).ToArray()); forward.Execute(); complex = output.GetData_Complex(); CopyAndReplace(_patternImage.Data, data); Buffer.BlockCopy(data, 0, doubles, 0, length*sizeof (double)); input.SetData(doubles.Select(x => new Complex(x, 0)).ToArray()); forward.Execute(); input.SetData(complex.Zip(output.GetData_Complex(), (x, y) => x*y).ToArray()); backward.Execute(); IEnumerable<double> doubles2 = output.GetData_Complex().Select(x => x.Magnitude); // Result Buffer.BlockCopy(doubles1.Zip(doubles2, (x, y) => (f + x*x)/(f + y)).ToArray(), 0, data, 0, length*sizeof (double)); return matrix; }