private static Complex2D DoScale(Complex2D channel, int dstWidth, int dstHeight) { var wFs = channel.Width; var hFs = channel.Height; var divX = dstWidth - wFs; var divY = dstHeight - hFs; Debug.Assert(divX != 0 || divY != 0, "No resize required."); var xOffset = divX / 2; var yOffset = divY / 2; var xEnd = xOffset + wFs; var yEnd = yOffset + hFs; if (divX < 0 || divY < 0) { throw new Exception("New size is smaller than the input size"); } var oldData = channel.Data; // TODO: correct zero padding -> FFT shifted?? return(new Complex2D( dstWidth, dstHeight, (i, j) => i >= xOffset && i < xEnd && j >= yOffset && j < yEnd ? oldData[(i - xOffset) + ((j - yOffset) * wFs)] : Zero )); }
public void Apply(Complex2D c) { var key = $"{_width}x{_height}"; double[] window; if (!_winCache.TryGetValue(key, out window)) { var hWin = CreateWindow1D(_width); var vWin = _height == _width ? hWin : CreateWindow1D(_height); window = new double[_width * _height]; for (int j = 0, k = 0; j < _height; j++) { var fy = vWin[j]; for (var i = 0; i < _width; i++, k++) { window[k] = fy * hWin[i]; } } _winCache.Add(key, window); } var d = c.Data; // elementwise multiply if (c.Width == _width) { //non zero padded? for (var i = 0; i < window.Length; i++) { d[i] *= window[i]; } return; } //zero padded var lf = c.Width - _width; for (int i = 0, j = 0; i < window.Length; j += lf) { for (var iLe = i + _width; i < iLe; i++, j++) { d[j] *= window[i]; } } }
/// <summary> /// Creates a deblur filter from three channel in frequency domain. /// </summary> /// <param name="c0Freqz">channel 0 in frequency domain</param> /// <param name="c1Freqz">channel 1 in frequency domain</param> /// <param name="c2Freqz">channel 2 in frequency domain</param> /// <param name="normalize"> /// if true, each pixel c_n with 0 < n < N-1 will be divided by 1/sum|c_n|, c_0 will be set /// to 1+j0 /// </param> /// <returns></returns> public static DeblurFilter CreateFromFrequencies(Complex2D c0Freqz, Complex2D c1Freqz, Complex2D c2Freqz, bool normalize = false) { var w = MathCV.Max(c0Freqz.Width, c1Freqz.Width, c2Freqz.Width); var h = MathCV.Max(c0Freqz.Height, c1Freqz.Height, c2Freqz.Height); var result = new DeblurFilter { C0 = c0Freqz.Width != w || c0Freqz.Height != h?DoScale(c0Freqz, w, h) : new Complex2D(c0Freqz), C1 = c1Freqz.Width != w || c1Freqz.Height != h?DoScale(c1Freqz, w, h) : new Complex2D(c1Freqz), C2 = c2Freqz.Width != w || c2Freqz.Height != h?DoScale(c2Freqz, w, h) : new Complex2D(c2Freqz) }; if (!normalize) { return(result); } var n = w * h; var d0 = result.C0.Data; var d1 = result.C1.Data; var d2 = result.C2.Data; var norm0 = (n - 1) / (d0.SumAbs() - d0[0].Magnitude); var norm1 = (n - 1) / (d1.SumAbs() - d1[0].Magnitude); var norm2 = (n - 1) / (d2.SumAbs() - d2[0].Magnitude); d0[0] = d1[0] = d2[0] = Complex.One; for (var i = 1; i < n; i++) { d0[i] *= norm0; d1[i] *= norm1; d2[i] *= norm2; } return(result); }
public Complex2D[] Complex2DRoots() { double d = Math.Pow(B, 2) - 4 * A * C; return(new Complex2D[] { (Complex2D.Sqrt(Math.Pow(B, 2) - 4 * A * C) - B) / (2 * A), (-Complex2D.Sqrt(Math.Pow(B, 2) - 4 * A * C) - B) / (2 * A) }); }