public void RemoveCentroid()
        {
            if (ClusterCount == 0)
            {
                return;
            }
            GameObject removeRoidObj = Centroids[Centroids.Count - 1].GetGameObject();

            Centroids.RemoveAt(Centroids.Count - 1);
            UnityEngine.Object.Destroy(removeRoidObj);
            ClusterCount--;
        }
Exemple #2
0
        public float4[] Match(Image volume, float diameterAngstrom, float threshold, Func <int3, int, string, bool> progressCallback)
        {
            float PixelSizeBN       = PixelSize;
            int3  DimsRegionBN      = CubeNet.BoxDimensionsPredict;
            int3  DimsRegionValidBN = CubeNet.BoxDimensionsValidPredict;
            int   BorderBN          = (DimsRegionBN.X - DimsRegionValidBN.X) / 2;

            int3 DimsBN = volume.Dims;

            GPU.Normalize(volume.GetDevice(Intent.Read),
                          volume.GetDevice(Intent.Write),
                          (uint)volume.ElementsReal,
                          1);

            volume.FreeDevice();

            float[] Predictions = new float[DimsBN.Elements()];
            float[] Mask        = new float[DimsBN.Elements()];


            {
                int3   DimsPositions = (DimsBN + DimsRegionValidBN - 1) / DimsRegionValidBN;
                float3 PositionStep  = new float3(DimsBN - DimsRegionBN) / new float3(Math.Max(DimsPositions.X - 1, 1),
                                                                                      Math.Max(DimsPositions.Y - 1, 1),
                                                                                      Math.Max(DimsPositions.Z - 1, 1));

                int NPositions = (int)DimsPositions.Elements();

                int3[] Positions = new int3[NPositions];
                for (int p = 0; p < NPositions; p++)
                {
                    int Z = p / (DimsPositions.X * DimsPositions.Y);
                    int Y = (p - Z * DimsPositions.X * DimsPositions.Y) / DimsPositions.X;
                    int X = p % DimsPositions.X;
                    Positions[p] = new int3((int)(X * PositionStep.X + DimsRegionBN.X / 2),
                                            (int)(Y * PositionStep.Y + DimsRegionBN.Y / 2),
                                            (int)(Z * PositionStep.Z + DimsRegionBN.Z / 2));
                }

                float[][] PredictionTiles = Helper.ArrayOfFunction(i => new float[DimsRegionBN.Elements()], NPositions);

                int NGPUThreads = MaxThreads;

                Image[] Extracted = new Image[NGPUThreads];
                int     DeviceID  = GPU.GetDevice();

                int BatchesDone = 0;

                Helper.ForCPU(0, NPositions, NGPUThreads,

                              threadID =>
                {
                    GPU.SetDevice(DeviceID);
                    Extracted[threadID] = new Image(IntPtr.Zero, DimsRegionBN);
                },

                              (b, threadID) =>
                {
                    int GPUID       = threadID / NGPUThreads;
                    int GPUThreadID = threadID % NGPUThreads;

                    #region Extract and normalize windows

                    GPU.Extract(volume.GetDevice(Intent.Read),
                                Extracted[threadID].GetDevice(Intent.Write),
                                volume.Dims,
                                DimsRegionBN,
                                new int[] { Positions[b].X - DimsRegionBN.X / 2, Positions[b].Y - DimsRegionBN.Y / 2, Positions[b].Z - DimsRegionBN.Z / 2 },
                                1);

                    //GPU.Normalize(Extracted[threadID].GetDevice(Intent.Read),
                    //              Extracted[threadID].GetDevice(Intent.Write),
                    //              (uint)Extracted[threadID].ElementsReal,
                    //              1);

                    #endregion

                    //Extracted[threadID].WriteMRC("d_extracted.mrc", true);

                    #region Predict

                    long[] BatchArgMax;
                    float[] BatchProbability;
                    Predict(Extracted[threadID].GetDevice(Intent.Read),
                            GPUThreadID,
                            out BatchArgMax,
                            out BatchProbability);

                    //new Image(BatchArgMax.Select(v => (float)v).ToArray(), new int3(DimsRegionBN)).WriteMRC("d_labels.mrc", true);

                    for (int i = 0; i < BatchArgMax.Length; i++)
                    {
                        int Label         = (int)BatchArgMax[i];
                        float Probability = BatchProbability[i * NClasses + Label];

                        PredictionTiles[b][i] = (Label >= 1 && Probability >= threshold ? Probability : 0);
                    }

                    #endregion

                    lock (volume)
                        progressCallback?.Invoke(new int3(NPositions, 1, 1), ++BatchesDone, "");
                },

                              threadID =>
                {
                    int GPUID       = threadID / NGPUThreads;
                    int GPUThreadID = threadID % NGPUThreads;

                    Extracted[threadID].Dispose();
                });

                for (int z = 0; z < DimsBN.Z; z++)
                {
                    for (int y = 0; y < DimsBN.Y; y++)
                    {
                        for (int x = 0; x < DimsBN.X; x++)
                        {
                            int ClosestX  = (int)Math.Max(0, Math.Min(DimsPositions.X - 1, (int)(((float)x - DimsRegionBN.X / 2) / PositionStep.X + 0.5f)));
                            int ClosestY  = (int)Math.Max(0, Math.Min(DimsPositions.Y - 1, (int)(((float)y - DimsRegionBN.Y / 2) / PositionStep.Y + 0.5f)));
                            int ClosestZ  = (int)Math.Max(0, Math.Min(DimsPositions.Z - 1, (int)(((float)z - DimsRegionBN.Z / 2) / PositionStep.Z + 0.5f)));
                            int ClosestID = (ClosestZ * DimsPositions.Y + ClosestY) * DimsPositions.X + ClosestX;

                            int3 Position = Positions[ClosestID];
                            int  LocalX   = Math.Max(0, Math.Min(DimsRegionBN.X - 1, x - Position.X + DimsRegionBN.X / 2));
                            int  LocalY   = Math.Max(0, Math.Min(DimsRegionBN.Y - 1, y - Position.Y + DimsRegionBN.Y / 2));
                            int  LocalZ   = Math.Max(0, Math.Min(DimsRegionBN.Z - 1, z - Position.Z + DimsRegionBN.Z / 2));

                            Predictions[(z * DimsBN.Y + y) * DimsBN.X + x] = PredictionTiles[ClosestID][(LocalZ * DimsRegionBN.Y + LocalY) * DimsRegionBN.X + LocalX];
                        }
                    }
                }

                volume.FreeDevice();
            }

            #region Apply Gaussian and find peaks

            Image PredictionsImage = new Image(Predictions, new int3(DimsBN));
            PredictionsImage.WriteMRC("d_predictions.mrc", true);

            //Image PredictionsConvolved = PredictionsImage.AsConvolvedGaussian((float)options.ExpectedDiameter / PixelSizeBN / 6);
            //PredictionsConvolved.Multiply(PredictionsImage);
            //PredictionsImage.Dispose();

            //PredictionsImage.WriteMRC(MatchingDir + RootName + "_boxnet.mrc", PixelSizeBN, true);

            int3[] Peaks = PredictionsImage.GetLocalPeaks((int)(diameterAngstrom / PixelSizeBN / 4 + 0.5f), 1e-6f);
            PredictionsImage.Dispose();

            int BorderDist = (int)(diameterAngstrom / PixelSizeBN * 0.8f + 0.5f);
            Peaks = Peaks.Where(p => p.X > BorderDist &&
                                p.Y > BorderDist &&
                                p.Z > BorderDist &&
                                p.X < DimsBN.X - BorderDist &&
                                p.Y < DimsBN.Y - BorderDist &&
                                p.Z < DimsBN.Z - BorderDist).ToArray();

            #endregion

            #region Label connected components and get centroids

            List <float3> Centroids;
            List <int>    Extents;
            {
                List <List <int3> > Components = new List <List <int3> >();
                int[] PixelLabels = Helper.ArrayOfConstant(-1, Predictions.Length);

                foreach (var peak in Peaks)
                {
                    if (PixelLabels[DimsBN.ElementFromPosition(peak)] >= 0)
                    {
                        continue;
                    }

                    List <int3> Component = new List <int3>()
                    {
                        peak
                    };
                    int CN = Components.Count;

                    PixelLabels[DimsBN.ElementFromPosition(peak)] = CN;
                    Queue <int3> Expansion = new Queue <int3>(100);
                    Expansion.Enqueue(peak);

                    while (Expansion.Count > 0)
                    {
                        int3 pos        = Expansion.Dequeue();
                        int  PosElement = (int)DimsBN.ElementFromPosition(pos);

                        if (pos.X > 0 && Predictions[PosElement - 1] > 0 && PixelLabels[PosElement - 1] < 0)
                        {
                            PixelLabels[PosElement - 1] = CN;
                            Component.Add(pos + new int3(-1, 0, 0));
                            Expansion.Enqueue(pos + new int3(-1, 0, 0));
                        }
                        if (pos.X < DimsBN.X - 1 && Predictions[PosElement + 1] > 0 && PixelLabels[PosElement + 1] < 0)
                        {
                            PixelLabels[PosElement + 1] = CN;
                            Component.Add(pos + new int3(1, 0, 0));
                            Expansion.Enqueue(pos + new int3(1, 0, 0));
                        }

                        if (pos.Y > 0 && Predictions[PosElement - DimsBN.X] > 0 && PixelLabels[PosElement - DimsBN.X] < 0)
                        {
                            PixelLabels[PosElement - DimsBN.X] = CN;
                            Component.Add(pos + new int3(0, -1, 0));
                            Expansion.Enqueue(pos + new int3(0, -1, 0));
                        }
                        if (pos.Y < DimsBN.Y - 1 && Predictions[PosElement + DimsBN.X] > 0 && PixelLabels[PosElement + DimsBN.X] < 0)
                        {
                            PixelLabels[PosElement + DimsBN.X] = CN;
                            Component.Add(pos + new int3(0, 1, 0));
                            Expansion.Enqueue(pos + new int3(0, 1, 0));
                        }

                        if (pos.Z > 0 && Predictions[PosElement - DimsBN.X * DimsBN.Y] > 0 && PixelLabels[PosElement - DimsBN.X * DimsBN.Y] < 0)
                        {
                            PixelLabels[PosElement - DimsBN.X * DimsBN.Y] = CN;
                            Component.Add(pos + new int3(0, 0, -1));
                            Expansion.Enqueue(pos + new int3(0, 0, -1));
                        }
                        if (pos.Z < DimsBN.Z - 1 && Predictions[PosElement + DimsBN.X * DimsBN.Y] > 0 && PixelLabels[PosElement + DimsBN.X * DimsBN.Y] < 0)
                        {
                            PixelLabels[PosElement + DimsBN.X * DimsBN.Y] = CN;
                            Component.Add(pos + new int3(0, 0, 1));
                            Expansion.Enqueue(pos + new int3(0, 0, 1));
                        }
                    }

                    Components.Add(Component);
                }

                Centroids = Components.Select(c => MathHelper.Mean(c.Select(v => new float3(v)))).ToList();
                Extents   = Components.Select(c => c.Count).ToList();
            }

            List <int> ToDelete = new List <int>();

            // Hit test with crap mask
            //for (int c1 = 0; c1 < Centroids.Count; c1++)
            //{
            //    float2 P1 = Centroids[c1];
            //    if (MaskHitTest[(int)P1.Y * DimsBN.X + (int)P1.X] == 0)
            //    {
            //        ToDelete.Add(c1);
            //        continue;
            //    }
            //}

            for (int c1 = 0; c1 < Centroids.Count - 1; c1++)
            {
                float3 P1 = Centroids[c1];

                for (int c2 = c1 + 1; c2 < Centroids.Count; c2++)
                {
                    if ((P1 - Centroids[c2]).Length() < diameterAngstrom / PixelSizeBN / 1.5f)
                    {
                        int D = Extents[c1] < Extents[c2] ? c1 : c2;

                        if (!ToDelete.Contains(D))
                        {
                            ToDelete.Add(D);
                        }
                    }
                }
            }

            ToDelete.Sort();
            for (int i = ToDelete.Count - 1; i >= 0; i--)
            {
                Centroids.RemoveAt(ToDelete[i]);
                Extents.RemoveAt(ToDelete[i]);
            }

            #endregion

            //new Image(Predictions, DimsBN).WriteMRC("d_predictions.mrc", true);

            #region Write peak positions and angles into table

            return(Centroids.Select((c, i) => new float4(c.X, c.Y, c.Z, Extents[i])).ToArray());

            #endregion
        }