async void UpdateMask() { if (!IsInitialized) { return; } bool DoNew = (bool)RadioMaskNew.IsChecked; bool UseHalfmap2 = (bool)RadioHalfmap2File.IsChecked && Halfmap2 != null; float Threshold = (float)MaskThreshold; float LowpassNyquist = (float)HalfmapPixelSize * 2 / (float)MaskLowpass; ProgressMask.Visibility = Visibility.Visible; await Task.Run(() => { MaskFinal?.Dispose(); MaskFinal = null; if (!DoNew && Mask != null) { MaskFinal = Mask.GetCopyGPU(); MaskFinal.Binarize(Threshold); } else if (DoNew) { MaskFinal = Halfmap1.GetCopyGPU(); if (UseHalfmap2) { MaskFinal.Add(Halfmap2); MaskFinal.Multiply(0.5f); } MaskFinal.Bandpass(0, LowpassNyquist, true); MaskFinal.Binarize(Threshold); } Dispatcher.Invoke(() => { RendererMask.Volume = MaskFinal; }); }); ProgressMask.Visibility = Visibility.Hidden; RevalidateTab(); }
public static (Image[] Halves1, Image[] Halves2, float2[] Stats) TrainOnVolumes(NoiseNet3D network, Image[] halves1, Image[] halves2, Image[] masks, float angpix, float lowpass, float upsample, bool dontFlatten, bool performTraining, int niterations, float startFrom, int batchsize, int gpuprocess, Action <string> progressCallback) { if (batchsize != 4) { niterations = niterations * 4 / batchsize; Debug.WriteLine($"Adjusting the number of iterations to {niterations} to match different batch size.\n"); } GPU.SetDevice(gpuprocess); #region Mask Debug.Write("Preparing mask... "); progressCallback?.Invoke("Preparing mask... "); int3[] BoundingBox = Helper.ArrayOfFunction(i => new int3(-1), halves1.Length); if (masks != null) { for (int i = 0; i < masks.Length; i++) { Image Mask = masks[i]; Mask.TransformValues((x, y, z, v) => { if (v > 0.5f) { BoundingBox[i].X = Math.Max(BoundingBox[i].X, Math.Abs(x - Mask.Dims.X / 2) * 2); BoundingBox[i].Y = Math.Max(BoundingBox[i].Y, Math.Abs(y - Mask.Dims.Y / 2) * 2); BoundingBox[i].Z = Math.Max(BoundingBox[i].Z, Math.Abs(z - Mask.Dims.Z / 2) * 2); } return(v); }); if (BoundingBox[i].X < 2) { throw new Exception("Mask does not seem to contain any non-zero values."); } BoundingBox[i] += 64; BoundingBox[i].X = Math.Min(BoundingBox[i].X, Mask.Dims.X); BoundingBox[i].Y = Math.Min(BoundingBox[i].Y, Mask.Dims.Y); BoundingBox[i].Z = Math.Min(BoundingBox[i].Z, Mask.Dims.Z); } } Console.WriteLine("done.\n"); #endregion #region Load and prepare data Console.WriteLine("Preparing data:"); List <Image> Maps1 = new List <Image>(); List <Image> Maps2 = new List <Image>(); List <Image> HalvesForDenoising1 = new List <Image>(); List <Image> HalvesForDenoising2 = new List <Image>(); List <float2> StatsForDenoising = new List <float2>(); for (int imap = 0; imap < halves1.Length; imap++) { Debug.Write($"Preparing map {imap}... "); progressCallback?.Invoke($"Preparing map {imap}... "); Image Map1 = halves1[imap]; Image Map2 = halves2[imap]; float MapPixelSize = Map1.PixelSize / upsample; if (!dontFlatten) { Image Average = Map1.GetCopy(); Average.Add(Map2); if (masks != null) { Average.Multiply(masks[imap]); } float[] Spectrum = Average.AsAmplitudes1D(true, 1, (Average.Dims.X + Average.Dims.Y + Average.Dims.Z) / 6); Average.Dispose(); int i10A = Math.Min((int)(angpix * 2 / 10 * Spectrum.Length), Spectrum.Length - 1); float Amp10A = Spectrum[i10A]; for (int i = 0; i < Spectrum.Length; i++) { Spectrum[i] = i < i10A ? 1 : (Amp10A / Math.Max(1e-10f, Spectrum[i])); } Image Map1Flat = Map1.AsSpectrumMultiplied(true, Spectrum); Map1.FreeDevice(); Map1 = Map1Flat; Map1.FreeDevice(); Image Map2Flat = Map2.AsSpectrumMultiplied(true, Spectrum); Map2.FreeDevice(); Map2 = Map2Flat; Map2.FreeDevice(); } if (lowpass > 0) { Map1.Bandpass(0, angpix * 2 / lowpass, true, 0.01f); Map2.Bandpass(0, angpix * 2 / lowpass, true, 0.01f); } if (upsample != 1f) { Image Map1Scaled = Map1.AsScaled(Map1.Dims * upsample / 2 * 2); Map1.FreeDevice(); Map1 = Map1Scaled; Map1.FreeDevice(); Image Map2Scaled = Map2.AsScaled(Map2.Dims * upsample / 2 * 2); Map2.FreeDevice(); Map2 = Map2Scaled; Map2.FreeDevice(); } Image ForDenoising1 = Map1.GetCopy(); Image ForDenoising2 = Map2.GetCopy(); if (BoundingBox[imap].X > 0) { Image Map1Cropped = Map1.AsPadded(BoundingBox[imap]); Map1.FreeDevice(); Map1 = Map1Cropped; Map1.FreeDevice(); Image Map2Cropped = Map2.AsPadded(BoundingBox[imap]); Map2.FreeDevice(); Map2 = Map2Cropped; Map2.FreeDevice(); } float2 MeanStd = MathHelper.MeanAndStd(Helper.Combine(Map1.GetHostContinuousCopy(), Map2.GetHostContinuousCopy())); Map1.TransformValues(v => (v - MeanStd.X) / MeanStd.Y); Map2.TransformValues(v => (v - MeanStd.X) / MeanStd.Y); ForDenoising1.TransformValues(v => (v - MeanStd.X) / MeanStd.Y); ForDenoising2.TransformValues(v => (v - MeanStd.X) / MeanStd.Y); HalvesForDenoising1.Add(ForDenoising1); HalvesForDenoising2.Add(ForDenoising2); StatsForDenoising.Add(MeanStd); GPU.PrefilterForCubic(Map1.GetDevice(Intent.ReadWrite), Map1.Dims); Map1.FreeDevice(); Maps1.Add(Map1); GPU.PrefilterForCubic(Map2.GetDevice(Intent.ReadWrite), Map2.Dims); Map2.FreeDevice(); Maps2.Add(Map2); Debug.WriteLine(" Done."); } if (masks != null) { foreach (var mask in masks) { mask.FreeDevice(); } } #endregion int Dim = network.BoxDimensions.X; progressCallback?.Invoke($"0/{niterations}"); if (performTraining) { GPU.SetDevice(gpuprocess); #region Training Random Rand = new Random(123); int NMaps = Maps1.Count; int NMapsPerBatch = Math.Min(128, NMaps); int MapSamples = batchsize; Image[] ExtractedSource = Helper.ArrayOfFunction(i => new Image(new int3(Dim, Dim, Dim * MapSamples)), NMapsPerBatch); Image[] ExtractedTarget = Helper.ArrayOfFunction(i => new Image(new int3(Dim, Dim, Dim * MapSamples)), NMapsPerBatch); for (int iter = (int)(startFrom * niterations); iter < niterations; iter++) { int[] ShuffledMapIDs = Helper.RandomSubset(Helper.ArrayOfSequence(0, NMaps, 1), NMapsPerBatch, Rand.Next(9999)); for (int m = 0; m < NMapsPerBatch; m++) { int MapID = ShuffledMapIDs[m]; Image Map1 = Maps1[MapID]; Image Map2 = Maps2[MapID]; int3 DimsMap = Map1.Dims; int3 Margin = new int3((int)(Dim / 2 * 1.5f)); //Margin.Z = 0; float3[] Position = Helper.ArrayOfFunction(i => new float3((float)Rand.NextDouble() * (DimsMap.X - Margin.X * 2) + Margin.X, (float)Rand.NextDouble() * (DimsMap.Y - Margin.Y * 2) + Margin.Y, (float)Rand.NextDouble() * (DimsMap.Z - Margin.Z * 2) + Margin.Z), MapSamples); float3[] Angle = Helper.ArrayOfFunction(i => new float3((float)Rand.NextDouble() * 360, (float)Rand.NextDouble() * 360, (float)Rand.NextDouble() * 360) * Helper.ToRad, MapSamples); { ulong[] Texture = new ulong[1], TextureArray = new ulong[1]; GPU.CreateTexture3D(Map1.GetDevice(Intent.Read), Map1.Dims, Texture, TextureArray, true); //Map1.FreeDevice(); GPU.Rotate3DExtractAt(Texture[0], Map1.Dims, ExtractedSource[m].GetDevice(Intent.Write), new int3(Dim), Helper.ToInterleaved(Angle), Helper.ToInterleaved(Position), (uint)MapSamples); //ExtractedSource[MapID].WriteMRC("d_extractedsource.mrc", true); GPU.DestroyTexture(Texture[0], TextureArray[0]); } { ulong[] Texture = new ulong[1], TextureArray = new ulong[1]; GPU.CreateTexture3D(Map2.GetDevice(Intent.Read), Map2.Dims, Texture, TextureArray, true); //Map2.FreeDevice(); GPU.Rotate3DExtractAt(Texture[0], Map2.Dims, ExtractedTarget[m].GetDevice(Intent.Write), new int3(Dim), Helper.ToInterleaved(Angle), Helper.ToInterleaved(Position), (uint)MapSamples); //ExtractedTarget.WriteMRC("d_extractedtarget.mrc", true); GPU.DestroyTexture(Texture[0], TextureArray[0]); } //Map1.FreeDevice(); //Map2.FreeDevice(); } float[] PredictedData = null, Loss = null; { float CurrentLearningRate = 0.0001f * (float)Math.Pow(10, -iter / (float)niterations * 2); for (int m = 0; m < ShuffledMapIDs.Length; m++) { int MapID = m; bool Twist = Rand.Next(2) == 0; if (Twist) { network.Train(ExtractedSource[MapID].GetDevice(Intent.Read), ExtractedTarget[MapID].GetDevice(Intent.Read), CurrentLearningRate, 0, out PredictedData, out Loss); } else { network.Train(ExtractedTarget[MapID].GetDevice(Intent.Read), ExtractedSource[MapID].GetDevice(Intent.Read), CurrentLearningRate, 0, out PredictedData, out Loss); } } } Debug.WriteLine($"{iter + 1}/{niterations}"); progressCallback?.Invoke($"{iter + 1}/{niterations}"); } Debug.WriteLine("\nDone training!\n"); #endregion } return(HalvesForDenoising1.ToArray(), HalvesForDenoising2.ToArray(), StatsForDenoising.ToArray()); }
public void ExportParticles(Star tableIn, Star tableOut, MapHeader originalHeader, Image originalStack, int size, float particleradius, decimal scaleFactor) { if (!tableIn.HasColumn("rlnAutopickFigureOfMerit")) tableIn.AddColumn("rlnAutopickFigureOfMerit"); List<int> RowIndices = new List<int>(); string[] ColumnMicrographName = tableIn.GetColumn("rlnMicrographName"); for (int i = 0; i < ColumnMicrographName.Length; i++) if (ColumnMicrographName[i].Contains(RootName)) RowIndices.Add(i); if (RowIndices.Count == 0) return; if (!Directory.Exists(ParticlesDir)) Directory.CreateDirectory(ParticlesDir); if (!Directory.Exists(ParticleCTFDir)) Directory.CreateDirectory(ParticleCTFDir); int3 Dims = originalHeader.Dimensions; int3 DimsRegion = new int3(size, size, 1); int3 DimsPadded = new int3(size * 2, size * 2, 1); int NParticles = RowIndices.Count; float PixelSize = (float)CTF.PixelSize; float PixelDelta = (float)CTF.PixelSizeDelta; float PixelAngle = (float)CTF.PixelSizeAngle * Helper.ToRad; /*Image CTFCoords; Image CTFFreq; { float2[] CTFCoordsData = new float2[(DimsRegion.X / 2 + 1) * DimsRegion.Y]; float[] CTFFreqData = new float[(DimsRegion.X / 2 + 1) * DimsRegion.Y]; for (int y = 0; y < DimsRegion.Y; y++) for (int x = 0; x < DimsRegion.X / 2 + 1; x++) { int xx = x; int yy = y < DimsRegion.Y / 2 + 1 ? y : y - DimsRegion.Y; float xs = xx / (float)DimsRegion.X; float ys = yy / (float)DimsRegion.Y; float r = (float)Math.Sqrt(xs * xs + ys * ys); float angle = (float)(Math.Atan2(yy, xx)); float CurrentPixelSize = PixelSize + PixelDelta * (float)Math.Cos(2f * (angle - PixelAngle)); CTFCoordsData[y * (DimsRegion.X / 2 + 1) + x] = new float2(r / DimsRegion.X, angle); CTFFreqData[y * (DimsRegion.X / 2 + 1) + x] = r / CurrentPixelSize; } CTFCoords = new Image(CTFCoordsData, DimsRegion.Slice(), true); CTFFreq = new Image(CTFFreqData, DimsRegion.Slice(), true); }*/ string[] ColumnPosX = tableIn.GetColumn("rlnCoordinateX"); string[] ColumnPosY = tableIn.GetColumn("rlnCoordinateY"); string[] ColumnOriginX = tableIn.GetColumn("rlnOriginX"); string[] ColumnOriginY = tableIn.GetColumn("rlnOriginY"); int3[] Origins = new int3[NParticles]; float3[] ResidualShifts = new float3[NParticles]; for (int i = 0; i < NParticles; i++) { float2 Pos = new float2(float.Parse(ColumnPosX[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosY[RowIndices[i]], CultureInfo.InvariantCulture)) * 1.00f; float2 Shift = new float2(float.Parse(ColumnOriginX[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnOriginY[RowIndices[i]], CultureInfo.InvariantCulture)) * 1.00f; Origins[i] = new int3((int)(Pos.X - Shift.X), (int)(Pos.Y - Shift.Y), 0); ResidualShifts[i] = new float3(-MathHelper.ResidualFraction(Pos.X - Shift.X), -MathHelper.ResidualFraction(Pos.Y - Shift.Y), 0f); tableIn.SetRowValue(RowIndices[i], "rlnCoordinateX", Origins[i].X.ToString()); tableIn.SetRowValue(RowIndices[i], "rlnCoordinateY", Origins[i].Y.ToString()); tableIn.SetRowValue(RowIndices[i], "rlnOriginX", "0.0"); tableIn.SetRowValue(RowIndices[i], "rlnOriginY", "0.0"); } Image AverageFT = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true, true); Image AveragePS = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); Image Weights = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); Weights.Fill(1e-6f); Image FrameParticles = new Image(IntPtr.Zero, new int3(DimsPadded.X, DimsPadded.Y, NParticles)); float StepZ = 1f / Math.Max(Dims.Z - 1, 1); for (int z = 0; z < Dims.Z; z++) { float CoordZ = z * StepZ; if (originalStack != null) GPU.Extract(originalStack.GetDeviceSlice(z, Intent.Read), FrameParticles.GetDevice(Intent.Write), Dims.Slice(), DimsPadded, Helper.ToInterleaved(Origins.Select(v => new int3(v.X - DimsPadded.X / 2, v.Y - DimsPadded.Y / 2, 0)).ToArray()), (uint)NParticles); // Shift particles { float3[] Shifts = new float3[NParticles]; for (int i = 0; i < NParticles; i++) { float3 Coords = new float3((float)Origins[i].X / Dims.X, (float)Origins[i].Y / Dims.Y, CoordZ); Shifts[i] = ResidualShifts[i] + new float3(GetShiftFromPyramid(Coords)) * 1.00f; } FrameParticles.ShiftSlices(Shifts); } Image FrameParticlesCropped = FrameParticles.AsPadded(new int2(DimsRegion)); Image FrameParticlesFT = FrameParticlesCropped.AsFFT(); FrameParticlesCropped.Dispose(); //Image PS = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); //PS.Fill(1f); // Apply motion blur filter. #region Motion blur weighting /*{ const int Samples = 11; float StartZ = (z - 0.5f) * StepZ; float StopZ = (z + 0.5f) * StepZ; float2[] Shifts = new float2[Samples * NParticles]; for (int p = 0; p < NParticles; p++) { float NormX = (float)Origins[p].X / Dims.X; float NormY = (float)Origins[p].Y / Dims.Y; for (int zz = 0; zz < Samples; zz++) { float zp = StartZ + (StopZ - StartZ) / (Samples - 1) * zz; float3 Coords = new float3(NormX, NormY, zp); Shifts[p * Samples + zz] = GetShiftFromPyramid(Coords); } } Image MotionFilter = new Image(IntPtr.Zero, new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); GPU.CreateMotionBlur(MotionFilter.GetDevice(Intent.Write), DimsRegion, Helper.ToInterleaved(Shifts.Select(v => new float3(v.X, v.Y, 0)).ToArray()), Samples, (uint)NParticles); PS.Multiply(MotionFilter); //MotionFilter.WriteMRC("motion.mrc"); MotionFilter.Dispose(); }*/ #endregion // Apply CTF. #region CTF weighting /*if (CTF != null) { CTFStruct[] Structs = new CTFStruct[NParticles]; for (int p = 0; p < NParticles; p++) { CTF Altered = CTF.GetCopy(); Altered.Defocus = (decimal)GridCTF.GetInterpolated(new float3(Origins[p].X / Dims.X, Origins[p].Y / Dims.Y, z * StepZ)); Structs[p] = Altered.ToStruct(); } Image CTFImage = new Image(IntPtr.Zero, new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); GPU.CreateCTF(CTFImage.GetDevice(Intent.Write), CTFCoords.GetDevice(Intent.Read), (uint)CTFCoords.ElementsSliceComplex, Structs, false, (uint)NParticles); //CTFImage.Abs(); PS.Multiply(CTFImage); //CTFImage.WriteMRC("ctf.mrc"); CTFImage.Dispose(); }*/ #endregion // Apply dose. #region Dose weighting /*{ float3 NikoConst = new float3(0.245f, -1.665f, 2.81f); // Niko's formula expects e-/A2/frame, we've got e-/px/frame -- convert! float FrameDose = (float)MainWindow.Options.CorrectDosePerFrame * (z + 0.5f) / (PixelSize * PixelSize); Image DoseImage = new Image(IntPtr.Zero, DimsRegion, true); GPU.DoseWeighting(CTFFreq.GetDevice(Intent.Read), DoseImage.GetDevice(Intent.Write), (uint)DoseImage.ElementsSliceComplex, new[] { FrameDose }, NikoConst, 1); PS.MultiplySlices(DoseImage); //DoseImage.WriteMRC("dose.mrc"); DoseImage.Dispose(); }*/ #endregion //Image PSAbs = new Image(PS.GetDevice(Intent.Read), new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); //PSAbs.Abs(); //FrameParticlesFT.Multiply(PS); AverageFT.Add(FrameParticlesFT); //Weights.Add(PSAbs); //PS.Multiply(PS); //AveragePS.Add(PS); //PS.Dispose(); FrameParticlesFT.Dispose(); //PSAbs.Dispose(); } FrameParticles.Dispose(); //CTFCoords.Dispose(); //AverageFT.Divide(Weights); //AveragePS.Divide(Weights); //AverageFT.Multiply(AveragePS); Weights.Dispose(); Image AverageParticlesUncorrected = AverageFT.AsIFFT(); AverageFT.Dispose(); Image AverageParticles = AverageParticlesUncorrected.AsAnisotropyCorrected(new int2(DimsRegion), (float)(CTF.PixelSize + CTF.PixelSizeDelta / 2M), (float)(CTF.PixelSize - CTF.PixelSizeDelta / 2M), (float)CTF.PixelSizeAngle * Helper.ToRad, 8); AverageParticlesUncorrected.Dispose(); GPU.NormParticles(AverageParticles.GetDevice(Intent.Read), AverageParticles.GetDevice(Intent.Write), DimsRegion, (uint)(particleradius / (PixelSize / 1.00f)), true, (uint)NParticles); HeaderMRC ParticlesHeader = new HeaderMRC { Pixelsize = new float3(PixelSize, PixelSize, PixelSize) }; AverageParticles.WriteMRC(ParticlesPath, ParticlesHeader); AverageParticles.Dispose(); //AveragePS.WriteMRC(ParticleCTFPath, ParticlesHeader); AveragePS.Dispose(); float[] DistanceWeights = new float[NParticles]; for (int p1 = 0; p1 < NParticles - 1; p1++) { float2 Pos1 = new float2(Origins[p1].X, Origins[p1].Y); for (int p2 = p1 + 1; p2 < NParticles; p2++) { float2 Pos2 = new float2(Origins[p2].X, Origins[p2].Y); float2 Diff = Pos2 - Pos1; float Dist = Diff.X * Diff.X + Diff.Y * Diff.Y; Dist = 1f / Dist; DistanceWeights[p1] += Dist; DistanceWeights[p2] += Dist; } } for (int i = 0; i < NParticles; i++) { string ParticlePath = (i + 1).ToString("D6") + "@particles/" + RootName + "_particles.mrcs"; tableIn.SetRowValue(RowIndices[i], "rlnImageName", ParticlePath); //string ParticleCTFsPath = (i + 1).ToString("D6") + "@particlectf/" + RootName + "_particlectf.mrcs"; //tableIn.SetRowValue(RowIndices[i], "rlnCtfImage", ParticleCTFsPath); tableIn.SetRowValue(RowIndices[i], "rlnAutopickFigureOfMerit", DistanceWeights[i].ToString(CultureInfo.InvariantCulture)); } }
public void ExportParticlesMovieOld(Star table, int size) { List<int> RowIndices = new List<int>(); string[] ColumnMicrographName = table.GetColumn("rlnMicrographName"); for (int i = 0; i < ColumnMicrographName.Length; i++) if (ColumnMicrographName[i].Contains(RootName)) RowIndices.Add(i); if (RowIndices.Count == 0) return; if (!Directory.Exists(ParticlesDir)) Directory.CreateDirectory(ParticlesDir); if (!Directory.Exists(ParticleCTFDir)) Directory.CreateDirectory(ParticleCTFDir); MapHeader OriginalHeader = MapHeader.ReadFromFile(Path, new int2(MainWindow.Options.InputDatWidth, MainWindow.Options.InputDatHeight), MainWindow.Options.InputDatOffset, ImageFormatsHelper.StringToType(MainWindow.Options.InputDatType)); /*Image OriginalStack = StageDataLoad.LoadMap(Path, new int2(MainWindow.Options.InputDatWidth, MainWindow.Options.InputDatHeight), MainWindow.Options.InputDatOffset, ImageFormatsHelper.StringToType(MainWindow.Options.InputDatType));*/ //OriginalStack.Xray(20f); int3 Dims = OriginalHeader.Dimensions; int3 DimsRegion = new int3(size, size, 1); int NParticles = RowIndices.Count / Dimensions.Z; float PixelSize = (float)(MainWindow.Options.CTFPixelMin + MainWindow.Options.CTFPixelMax) * 0.5f; float PixelDelta = (float)(MainWindow.Options.CTFPixelMax - MainWindow.Options.CTFPixelMin) * 0.5f; float PixelAngle = (float)MainWindow.Options.CTFPixelAngle / (float)(180.0 / Math.PI); Image CTFCoords; { float2[] CTFCoordsData = new float2[DimsRegion.ElementsSlice()]; //Helper.ForEachElementFT(new int2(DimsRegion), (x, y, xx, yy) => for (int y = 0; y < DimsRegion.Y; y++) for (int x = 0; x < DimsRegion.X / 2 + 1; x++) { int xx = x; int yy = y < DimsRegion.Y / 2 + 1 ? y : y - DimsRegion.Y; float xs = xx / (float)DimsRegion.X; float ys = yy / (float)DimsRegion.Y; float r = (float)Math.Sqrt(xs * xs + ys * ys); float angle = (float)(Math.Atan2(yy, xx)); float CurrentPixelSize = PixelSize + PixelDelta * (float)Math.Cos(2f * (angle - PixelAngle)); CTFCoordsData[y * (DimsRegion.X / 2 + 1) + x] = new float2(r / CurrentPixelSize, angle); } //); CTFCoords = new Image(CTFCoordsData, DimsRegion.Slice(), true); //CTFCoords.RemapToFT(); } Image CTFFreq = CTFCoords.AsReal(); Image CTFStack = new Image(new int3(size, size, NParticles * Dimensions.Z), true); int CTFStackIndex = 0; string[] ColumnPosX = table.GetColumn("rlnCoordinateX"); string[] ColumnPosY = table.GetColumn("rlnCoordinateY"); int3[] Origins = new int3[NParticles]; for (int i = 0; i < NParticles; i++) Origins[i] = new int3((int)double.Parse(ColumnPosX[RowIndices[i]]) - DimsRegion.X * 2 / 2, (int)double.Parse(ColumnPosY[RowIndices[i]]) - DimsRegion.Y * 2 / 2, 0); int IndexOffset = RowIndices[0]; string[] ColumnOriginX = table.GetColumn("rlnOriginX"); string[] ColumnOriginY = table.GetColumn("rlnOriginY"); string[] ColumnPriorX = table.GetColumn("rlnOriginXPrior"); string[] ColumnPriorY = table.GetColumn("rlnOriginYPrior"); float2[] ShiftPriors = new float2[NParticles]; for (int i = 0; i < NParticles; i++) ShiftPriors[i] = new float2(float.Parse(ColumnPriorX[IndexOffset + i]), float.Parse(ColumnPriorY[IndexOffset + i])); float2[][] ParticleTracks = new float2[NParticles][]; for (int i = 0; i < NParticles; i++) { ParticleTracks[i] = new float2[Dimensions.Z]; for (int z = 0; z < Dimensions.Z; z++) ParticleTracks[i][z] = new float2(float.Parse(ColumnOriginX[IndexOffset + z * NParticles + i]) - ShiftPriors[i].X, float.Parse(ColumnOriginY[IndexOffset + z * NParticles + i]) - ShiftPriors[i].Y); } Image AverageFT = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true, true); Image AveragePS = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); Image Weights = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); Weights.Fill(1e-6f); Image FrameParticles = new Image(IntPtr.Zero, new int3(DimsRegion.X * 2, DimsRegion.Y * 2, NParticles)); float StepZ = 1f / Math.Max(Dims.Z - 1, 1); for (int z = 0; z < Dims.Z; z++) { float CoordZ = z * StepZ; /*GPU.Extract(OriginalStack.GetDeviceSlice(z, Intent.Read), FrameParticles.GetDevice(Intent.Write), Dims.Slice(), new int3(DimsRegion.X * 2, DimsRegion.Y * 2, 1), Helper.ToInterleaved(Origins), (uint)NParticles);*/ // Shift particles { float3[] Shifts = new float3[NParticles]; for (int i = 0; i < NParticles; i++) { float NormX = Math.Max(0.15f, Math.Min((float)Origins[i].X / Dims.X, 0.85f)); float NormY = Math.Max(0.15f, Math.Min((float)Origins[i].Y / Dims.Y, 0.85f)); float3 Coords = new float3(NormX, NormY, CoordZ); Shifts[i] = new float3(GridMovementX.GetInterpolated(Coords) + ParticleTracks[i][z].X, GridMovementY.GetInterpolated(Coords) + ParticleTracks[i][z].Y, 0f); } FrameParticles.ShiftSlices(Shifts); } Image FrameParticlesCropped = FrameParticles.AsPadded(new int2(DimsRegion)); Image FrameParticlesFT = FrameParticlesCropped.AsFFT(); FrameParticlesCropped.Dispose(); Image PS = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); PS.Fill(1f); // Apply motion blur filter. { const int Samples = 11; float StartZ = (z - 0.75f) * StepZ; float StopZ = (z + 0.75f) * StepZ; float2[] Shifts = new float2[Samples * NParticles]; for (int p = 0; p < NParticles; p++) { float NormX = Math.Max(0.15f, Math.Min((float)Origins[p].X / Dims.X, 0.85f)); float NormY = Math.Max(0.15f, Math.Min((float)Origins[p].Y / Dims.Y, 0.85f)); for (int zz = 0; zz < Samples; zz++) { float zp = StartZ + (StopZ - StartZ) / (Samples - 1) * zz; float3 Coords = new float3(NormX, NormY, zp); Shifts[p * Samples + zz] = new float2(GridMovementX.GetInterpolated(Coords), GridMovementY.GetInterpolated(Coords)); } } Image MotionFilter = new Image(IntPtr.Zero, new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); GPU.CreateMotionBlur(MotionFilter.GetDevice(Intent.Write), DimsRegion, Helper.ToInterleaved(Shifts.Select(v => new float3(v.X, v.Y, 0)).ToArray()), Samples, (uint)NParticles); PS.Multiply(MotionFilter); //MotionFilter.WriteMRC("motion.mrc"); MotionFilter.Dispose(); } // Apply CTF. if (CTF != null) { CTFStruct[] Structs = new CTFStruct[NParticles]; for (int p = 0; p < NParticles; p++) { CTF Altered = CTF.GetCopy(); Altered.Defocus = (decimal)GridCTF.GetInterpolated(new float3(float.Parse(ColumnPosX[RowIndices[p]]) / Dims.X, float.Parse(ColumnPosY[RowIndices[p]]) / Dims.Y, z * StepZ)); Structs[p] = Altered.ToStruct(); } Image CTFImage = new Image(IntPtr.Zero, new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); GPU.CreateCTF(CTFImage.GetDevice(Intent.Write), CTFCoords.GetDevice(Intent.Read), (uint)CTFCoords.ElementsSliceComplex, Structs, false, (uint)NParticles); //CTFImage.Abs(); PS.Multiply(CTFImage); //CTFImage.WriteMRC("ctf.mrc"); CTFImage.Dispose(); } // Apply dose weighting. /*{ float3 NikoConst = new float3(0.245f, -1.665f, 2.81f); // Niko's formula expects e-/A2/frame, we've got e-/px/frame -- convert! float FrameDose = (float)MainWindow.Options.CorrectDosePerFrame * (z + 0.5f) / (PixelSize * PixelSize); Image DoseImage = new Image(IntPtr.Zero, DimsRegion, true); GPU.DoseWeighting(CTFFreq.GetDevice(Intent.Read), DoseImage.GetDevice(Intent.Write), (uint)DoseImage.ElementsSliceComplex, new[] { FrameDose }, NikoConst, 1); PS.MultiplySlices(DoseImage); //DoseImage.WriteMRC("dose.mrc"); DoseImage.Dispose(); }*/ // Copy custom CTF into the CTF stack GPU.CopyDeviceToDevice(PS.GetDevice(Intent.Read), new IntPtr((long)CTFStack.GetDevice(Intent.Write) + CTFStack.ElementsSliceReal * NParticles * z * sizeof (float)), CTFStack.ElementsSliceReal * NParticles); Image PSAbs = new Image(PS.GetDevice(Intent.Read), new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); PSAbs.Abs(); FrameParticlesFT.Multiply(PSAbs); AverageFT.Add(FrameParticlesFT); Weights.Add(PSAbs); PS.Multiply(PSAbs); AveragePS.Add(PS); PS.Dispose(); FrameParticlesFT.Dispose(); PSAbs.Dispose(); // Write paths to custom CTFs into the .star for (int i = 0; i < NParticles; i++) { string ParticleCTFPath = (CTFStackIndex + 1).ToString("D6") + "@particlectf/" + RootName + ".mrcs"; table.SetRowValue(RowIndices[NParticles * z + i], "rlnCtfImage", ParticleCTFPath); CTFStackIndex++; } } FrameParticles.Dispose(); CTFCoords.Dispose(); CTFFreq.Dispose(); AverageFT.Divide(Weights); AveragePS.Divide(Weights); Weights.Dispose(); Image AverageParticles = AverageFT.AsIFFT(); AverageFT.Dispose(); GPU.NormParticles(AverageParticles.GetDevice(Intent.Read), AverageParticles.GetDevice(Intent.Write), DimsRegion, (uint)(90f / PixelSize), true, (uint)NParticles); HeaderMRC ParticlesHeader = new HeaderMRC { Pixelsize = new float3(PixelSize, PixelSize, PixelSize) }; AverageParticles.WriteMRC(ParticlesPath, ParticlesHeader); AverageParticles.Dispose(); //OriginalStack.Dispose(); CTFStack.WriteMRC(DirectoryName + "particlectf/" + RootName + ".mrcs"); CTFStack.Dispose(); /*for (int i = 0; i < NParticles; i++) { string ParticlePath = (i + 1).ToString("D6") + "@particles/" + RootName + "_particles.mrcs"; table.SetRowValue(RowIndices[i], "rlnImageName", ParticlePath); }*/ AveragePS.Dispose(); //table.RemoveRows(RowIndices.Skip(NParticles).ToArray()); }
public void CreateCorrected(MapHeader originalHeader, Image originalStack) { if (!Directory.Exists(AverageDir)) Directory.CreateDirectory(AverageDir); if (!Directory.Exists(CTFDir)) Directory.CreateDirectory(CTFDir); if (MainWindow.Options.PostStack && !Directory.Exists(ShiftedStackDir)) Directory.CreateDirectory(ShiftedStackDir); int3 Dims = originalStack.Dims; Image ShiftedStack = null; if (MainWindow.Options.PostStack) ShiftedStack = new Image(Dims); float PixelSize = (float)(MainWindow.Options.CTFPixelMin + MainWindow.Options.CTFPixelMax) * 0.5f; float PixelDelta = (float)(MainWindow.Options.CTFPixelMax - MainWindow.Options.CTFPixelMin) * 0.5f; float PixelAngle = (float)MainWindow.Options.CTFPixelAngle / (float)(180.0 / Math.PI); Image CTFCoords; { float2[] CTFCoordsData = new float2[Dims.ElementsSlice()]; Helper.ForEachElementFT(new int2(Dims), (x, y, xx, yy) => { float xs = xx / (float)Dims.X; float ys = yy / (float)Dims.Y; float r = (float)Math.Sqrt(xs * xs + ys * ys); float angle = (float)(Math.Atan2(yy, xx) + Math.PI / 2.0); float CurrentPixelSize = PixelSize + PixelDelta * (float)Math.Cos(2f * (angle - PixelAngle)); CTFCoordsData[y * (Dims.X / 2 + 1) + x] = new float2(r / CurrentPixelSize, angle); }); CTFCoords = new Image(CTFCoordsData, Dims.Slice(), true); CTFCoords.RemapToFT(); } Image CTFFreq = CTFCoords.AsReal(); CubicGrid CollapsedMovementX = GridMovementX.CollapseXY(); CubicGrid CollapsedMovementY = GridMovementY.CollapseXY(); CubicGrid CollapsedCTF = GridCTF.CollapseXY(); Image AverageFT = new Image(Dims.Slice(), true, true); Image AveragePS = new Image(Dims.Slice(), true, false); Image Weights = new Image(Dims.Slice(), true, false); Weights.Fill(1e-6f); float StepZ = 1f / Math.Max(Dims.Z - 1, 1); for (int nframe = 0; nframe < Dims.Z; nframe++) { Image PS = new Image(Dims.Slice(), true); PS.Fill(1f); // Apply motion blur filter. /*{ float StartZ = (nframe - 0.5f) * StepZ; float StopZ = (nframe + 0.5f) * StepZ; float2[] Shifts = new float2[21]; for (int z = 0; z < Shifts.Length; z++) { float zp = StartZ + (StopZ - StartZ) / (Shifts.Length - 1) * z; Shifts[z] = new float2(CollapsedMovementX.GetInterpolated(new float3(0.5f, 0.5f, zp)), CollapsedMovementY.GetInterpolated(new float3(0.5f, 0.5f, zp))); } // Center the shifts around 0 float2 ShiftMean = MathHelper.Mean(Shifts); Shifts = Shifts.Select(v => v - ShiftMean).ToArray(); Image MotionFilter = new Image(IntPtr.Zero, Dims.Slice(), true); GPU.CreateMotionBlur(MotionFilter.GetDevice(Intent.Write), MotionFilter.Dims, Helper.ToInterleaved(Shifts.Select(v => new float3(v.X, v.Y, 0)).ToArray()), (uint)Shifts.Length, 1); PS.Multiply(MotionFilter); //MotionFilter.WriteMRC("motion.mrc"); MotionFilter.Dispose(); }*/ // Apply CTF. /*if (CTF != null) { CTF Altered = CTF.GetCopy(); Altered.Defocus = (decimal)CollapsedCTF.GetInterpolated(new float3(0.5f, 0.5f, nframe * StepZ)); Image CTFImage = new Image(IntPtr.Zero, Dims.Slice(), true); GPU.CreateCTF(CTFImage.GetDevice(Intent.Write), CTFCoords.GetDevice(Intent.Read), (uint)CTFCoords.ElementsSliceComplex, new[] { Altered.ToStruct() }, false, 1); CTFImage.Abs(); PS.Multiply(CTFImage); //CTFImage.WriteMRC("ctf.mrc"); CTFImage.Dispose(); }*/ // Apply dose weighting. /*{ float3 NikoConst = new float3(0.245f, -1.665f, 2.81f); // Niko's formula expects e-/A2/frame, we've got e-/px/frame - convert! float FrameDose = (float)MainWindow.Options.CorrectDosePerFrame * (nframe + 0.5f) / (PixelSize * PixelSize); Image DoseImage = new Image(IntPtr.Zero, Dims.Slice(), true); GPU.DoseWeighting(CTFFreq.GetDevice(Intent.Read), DoseImage.GetDevice(Intent.Write), (uint)DoseImage.ElementsSliceComplex, new[] { FrameDose }, NikoConst, 1); PS.Multiply(DoseImage); //DoseImage.WriteMRC("dose.mrc"); DoseImage.Dispose(); }*/ Image Frame = new Image(originalStack.GetHost(Intent.Read)[nframe], Dims.Slice()); Frame.ShiftSlicesMassive(new[] { new float3(CollapsedMovementX.GetInterpolated(new float3(0.5f, 0.5f, nframe * StepZ)), CollapsedMovementY.GetInterpolated(new float3(0.5f, 0.5f, nframe * StepZ)), 0f) }); if (MainWindow.Options.PostStack) ShiftedStack.GetHost(Intent.Write)[nframe] = Frame.GetHost(Intent.Read)[0]; Image FrameFT = Frame.AsFFT(); Frame.Dispose(); //Image PSSign = new Image(PS.GetDevice(Intent.Read), Dims.Slice(), true); //Image PSSign = new Image(Dims.Slice(), true); //PSSign.Fill(1f); //PSSign.Sign(); // Do phase flipping before averaging. //FrameFT.Multiply(PSSign); //PS.Multiply(PSSign); //PSSign.Dispose(); //FrameFT.Multiply(PS); AverageFT.Add(FrameFT); Weights.Add(PS); //PS.WriteMRC("ps.mrc"); PS.Multiply(PS); AveragePS.Add(PS); PS.Dispose(); FrameFT.Dispose(); } CTFCoords.Dispose(); CTFFreq.Dispose(); //AverageFT.Divide(Weights); //AverageFT.WriteMRC("averageft.mrc"); //Weights.WriteMRC("weights.mrc"); AveragePS.Divide(Weights); Weights.Dispose(); Image Average = AverageFT.AsIFFT(); AverageFT.Dispose(); MapHeader Header = originalHeader; Header.Dimensions = Dims.Slice(); Average.WriteMRC(AveragePath); Average.Dispose(); AveragePS.WriteMRC(CTFPath); AveragePS.Dispose(); TempAverageImage = null; OnPropertyChanged("AverageImage"); using (TextWriter Writer = File.CreateText(AverageDir + RootName + "_ctffind3.log")) { decimal Mag = (MainWindow.Options.CTFDetectorPixel * 10000M / CTF.PixelSize); Writer.WriteLine("CS[mm], HT[kV], AmpCnst, XMAG, DStep[um]"); Writer.WriteLine($"{CTF.Cs} {CTF.Voltage} {CTF.Amplitude} {Mag} {MainWindow.Options.CTFDetectorPixel}"); float BestQ = 0; float2[] Q = CTFQuality; if (Q != null) foreach (var q in Q) { if (q.Y < 0.3f) break; BestQ = q.X * 2f; } Writer.WriteLine($"{(CTF.Defocus + CTF.DefocusDelta / 2M) * 1e4M} {(CTF.Defocus - CTF.DefocusDelta / 2M) * 1e4M} {CTF.DefocusAngle} {BestQ} {CTF.PhaseShift * 180M} Final Values"); } if (MainWindow.Options.PostStack) ShiftedStack.WriteMRC(ShiftedStackPath); }