public static float[] GetAmps1D(Image volume) { Image VolumeFT = volume.IsComplex ? volume : volume.AsFFT(true); Image VolumeAbs = VolumeFT.AsAmplitudes(); if (VolumeFT != volume) { VolumeFT.Dispose(); } int NShells = volume.Dims.X / 2; float[] PS1D = new float[NShells]; float[] Samples = new float[NShells]; float[] VolumeAbsData = VolumeAbs.GetHostContinuousCopy(); int3 DimsFT = VolumeAbs.DimsFT; Parallel.For(0, 20, p => { float[] ThreadPS1D = new float[NShells]; float[] ThreadSamples = new float[NShells]; for (int z = p; z < DimsFT.Z; z += 20) { int zz = z < DimsFT.Z / 2 + 1 ? z : z - DimsFT.Z; zz *= zz; for (int y = 0; y < DimsFT.Y; y++) { int yy = y < DimsFT.Y / 2 + 1 ? y : y - DimsFT.Y; yy *= yy; for (int x = 0; x < DimsFT.X; x++) { int xx = x; xx *= x; float R = (float)Math.Sqrt(zz + yy + xx); if (R >= NShells) { continue; } int ID = (int)R; float W1 = R - ID; float W0 = 1f - W1; int i = (z * DimsFT.Y + y) * DimsFT.X + x; float Amp = VolumeAbsData[i]; ThreadPS1D[ID] += W0 * Amp; ThreadSamples[ID] += W0; if (ID < NShells - 1) { ThreadPS1D[ID + 1] += W1 * Amp; ThreadSamples[ID + 1] += W1; } } } } lock (PS1D) for (int i = 0; i < PS1D.Length; i++) { PS1D[i] += ThreadPS1D[i]; Samples[i] += ThreadSamples[i]; } }); float[] Result = new float[NShells]; for (int i = 0; i < Result.Length; i++) { Result[i] = PS1D[i] / Math.Max(1e-6f, Samples[i]); } return(Result); }