/// <summary> /// Performs a fourier shift on the image. Two fourier shifts cancel each other out. /// </summary> public void FFTShift() { if (values == null) { return; } int halfWidth = FourierWidth / 2, halfHeight = FourierHeight / 2; ComplexF[] current; ComplexF temp; for (int c = 0; c < ComponentCount; c++) { current = values[c]; ParallelLoop.For(0, halfHeight, y => { int width = FourierWidth; int index1, index2; for (int x = 0; x < halfWidth; x++) { index1 = x + y * width; index2 = x + halfWidth + (y + halfHeight) * width; temp = current[index1]; current[index1] = current[index2]; current[index2] = temp; index1 = x + (y + halfHeight) * width; index2 = x + halfWidth + y * width; temp = current[index1]; current[index1] = current[index2]; current[index2] = temp; } }, ImageLib.ParallelCutoff); } }
/// <summary> /// Performs a fourier shift on the specified values. /// </summary> /// <param name="values">The values to shift.</param> /// <param name="forward">True for fftshift, false for inverse fftshift.</param> public static ComplexF[] FFTShift(ComplexF[] values, bool forward) { if (values == null) { return(null); } int length = values.Length; ComplexF[] shifted = new ComplexF[length]; int halfLength = length / 2, offset = (int)Math.Ceiling(length * 0.5); if (forward) { ParallelLoop.For(0, halfLength, i => { shifted[i + halfLength] = values[i]; shifted[i] = values[i + offset]; }, ImageLib.ParallelCutoff); if (halfLength != offset) { shifted[length - 1] = values[halfLength]; } } else { ParallelLoop.For(0, halfLength, i => { shifted[i + offset] = values[i]; shifted[i] = values[i + halfLength]; }, ImageLib.ParallelCutoff); if (halfLength != offset) { shifted[halfLength] = values[length - 1]; } } return(shifted); }
/// <summary> /// Transforms this image by dividing it element-wise with the specified kernel. /// </summary> /// <param name="kernel">The kernel to divide by. If the kernel has one channel, it will be divided from all channels of this image, else the corresponding channels will be divided.</param> public void DivideBy(FourierWorker kernel) { if (!(kernel.FourierWidth == FourierWidth && kernel.FourierHeight == FourierHeight)) { throw new ArgumentException("The passed FourierWorker must have the same FourierWidth and FourierHeight as this instance.", nameof(kernel)); } if (kernel.ShiftAxes) { FFTAfter = !FFTAfter; } if (kernel.ComponentCount == 1) { ComplexF[] mult = kernel.values[0]; ParallelLoop.For(0, FourierPixelCount, i => { int componentCount = ComponentCount; for (int c = 0; c < componentCount; c++) { values[c][i] /= mult[i]; } }, ImageLib.ParallelCutoff / ComponentCount); } else { int min = Math.Min(ComponentCount, kernel.ComponentCount); ComplexF[][] val = kernel.values; ParallelLoop.For(0, FourierPixelCount, i => { for (int c = 0; c < min; c++) { values[c][i] /= val[c][i]; } }, ImageLib.ParallelCutoff / min); } }
public SingleTask(int threadIndex, ParallelLoop owner, LoopDelegate func) { this.ThreadIndex = threadIndex; this.Owner = owner; this.func = func; FindCheckRange(); }
/// <summary> /// Generates a plot of the magnitudes of the complex values of the Fourier image. /// </summary> /// <param name="ignoreAlpha">If true, the alpha channel is ignored. If false, the image might end up transparent.</param> public PixelWorker GenerateMagnitudePlot(bool ignoreAlpha = true) { if (values == null) { return(null); } int pc = FourierPixelCount, index; int componentCount = ComponentCount; if (componentCount == 4 && ignoreAlpha) { componentCount = 3; } float[][] results = new float[componentCount][]; float[] array; float current, max = 0f, min = float.PositiveInfinity; for (int comp = 0; comp < componentCount; comp++) { array = new float[pc]; results[comp] = array; for (index = 0; index < pc; index++) { current = values[comp][index].MagnitudeDB; array[index] = current; if (current > max) { max = current; } if (current < min) { min = current; } } } if (max == min) { max = min + 1f; } else { max = 255f / (max - min); } byte[] resultant = new byte[pc * componentCount]; ParallelLoop.For(0, FourierPixelCount, i => { int offset = i * componentCount; for (int c = 0; c < componentCount; c++) { resultant[offset + c] = (byte)((results[c][i] - min) * max); } }, ImageLib.ParallelCutoff / componentCount); return(new PixelWorker(resultant, FourierWidth, FourierHeight, false)); }
/// <summary> /// Applies the specified function to all the values in the image. /// </summary> /// <param name="function">The function to apply. The first parameter is the value, the second parameter is the coordinate of the point in the image, and the return value is the new corresponding value.</param> public void ApplyFunctionToAllValues(Func <ComplexF, Point, ComplexF> function) { if (values == null) { return; } ParallelLoop.For(0, FourierPixelCount, i => { int width = FourierWidth, componentCount = ComponentCount; for (int c = 0; c < componentCount; c++) { values[c][i] = function(values[c][i], new Point(i % width, i / width)); } }, ImageLib.ParallelCutoff / ComponentCount); }
private void ParallelLoopTest() { ConcurrentBag <PLoopResult> resultBag = new ConcurrentBag <PLoopResult>(); ParallelLoop pLoop = new ParallelLoop(0, 180, ParallelPriolity.Full, LogThreadID); pLoop.RunWait(); List <PLoopResult> resultList = resultBag.ToList().OrderBy(p => p.fromInclusive).ToList(); for (int resultI = 0; resultI < resultList.Count; ++resultI) { Console.WriteLine(resultList[resultI]); } void LogThreadID(int fromInclusive, int toExclusive) { resultBag.Add(new PLoopResult(fromInclusive, toExclusive, Thread.CurrentThread.ManagedThreadId)); } }
/// <summary> /// Computes an in-place complex-to-complex 2D FFT. /// </summary> /// <param name="forward">Whether to transform forward or backward.</param> private void FFT(bool forward) { if (values == null) { return; } ParallelLoop.For(0, FourierHeight, y => { int i = y * FourierWidth; int widthLog2 = fourierWidthLog2, componentCount = ComponentCount; for (int c = 0; c < componentCount; c++) { FFT(values[c], 1, i, widthLog2, forward); } }, ImageLib.ParallelCutoff / ComponentCount); ParallelLoop.For(0, FourierWidth, i => { int heightLog2 = fourierHeightLog2, componentCount = ComponentCount, width = FourierWidth; for (int c = 0; c < componentCount; c++) { FFT(values[c], width, i, heightLog2, forward); } }, ImageLib.ParallelCutoff / ComponentCount); }
/// <summary> /// Generates a plot of the phases of the complex values of the Fourier image. /// </summary> /// <param name="ignoreAlpha">If true, the alpha channel is ignored. If false, the image might end up transparent.</param> public PixelWorker GeneratePhasePlot(bool ignoreAlpha = true) { if (values == null) { return(null); } int componentCount = ComponentCount; if (componentCount == 4 && ignoreAlpha) { componentCount = 3; } byte[] resultant = new byte[FourierPixelCount * componentCount]; const float Normalizer = 255f / Maths.TwoPIInverseF; ParallelLoop.For(0, FourierPixelCount, i => { int offset = i * componentCount; for (int c = 0; c < componentCount; c++) { resultant[offset + c] = (byte)(Normalizer * ((values[c][i].Phase + Maths.TwoPiF) % Maths.TwoPiF)); } }, ImageLib.ParallelCutoff / componentCount); return(new PixelWorker(resultant, FourierWidth, FourierHeight, false)); }
public static FuncProfileResults ProfileFunction(int repeatCount, bool useMultithread, params Action[] actions) { FuncProfileResult[] results = new FuncProfileResult[actions.Length]; LoopDelegate profileAction = (int startI, int endI) => { for (int actionI = startI; actionI < endI; ++actionI) { Stopwatch watch = new Stopwatch(); watch.Restart(); Action action = actions[actionI]; if (action != null) { for (int repeatI = 0; repeatI < repeatCount; ++repeatI) { action(); } } watch.Stop(); results[actionI] = new FuncProfileResult(action, (float)watch.GetElapsedMilliseconds()); } }; if (useMultithread) { ParallelLoop pLoop = new ParallelLoop(0, actions.Length, ParallelPriolity.Full, profileAction); pLoop.RunWait(); } else { profileAction(0, actions.Length); } return(new FuncProfileResults(results)); }
/// <summary> /// Performs Fourier inverse on the image in place. If you need to retain the Fourier image, copy it first. /// </summary> public PixelWorker ConvertToBitmapInPlace() { if (!FFTAfter && ShiftAxes) { ShiftAxes = false; FFTShift(); } FFT(false); if (FFTAfter && ShiftAxes) { ShiftAxes = false; FFTShift(); } int pc = FourierPixelCount, index; float[][] results = new float[ComponentCount][]; float[] array; float current, max = 0f; for (int comp = 0; comp < ComponentCount; comp++) { array = new float[pc]; results[comp] = array; for (index = 0; index < pc; index++) { current = values[comp][index].Magnitude; array[index] = current; if (current > max) { max = current; } } } if (max == 0f) { max = 1f; } else { max = OriginalMax / max; } bool addAlpha = !(ComponentCount == 4 || alphaReference == null || alphaReference.IsDisposed); int byteDepth = addAlpha ? 4 : ComponentCount; byte[] resultant = new byte[TargetPixelCount * byteDepth]; ParallelLoop.For(0, TargetPixelCount, i => { int componentCount = ComponentCount; int offset = i * byteDepth; int fourierIndex = (i / TargetWidth) * FourierWidth + i % TargetWidth; for (int c = 0; c < componentCount; c++) { resultant[offset + c] = (byte)(results[c][fourierIndex] * max); } if (addAlpha) { offset += 3; resultant[offset] = alphaReference[offset]; } }, ImageLib.ParallelCutoff / ComponentCount); return(new PixelWorker(resultant, TargetWidth, TargetHeight, false)); }