/// <summary> /// Calibrates an input image using VizieR stars catalogs. /// </summary> /// <param name="VizieRStars">List of VizieR stars.</param> /// <param name="DetectedStars">List of locally detected stars.</param> /// <param name="PositionError">Maximum position error of stars. Value in arcseconds.</param> /// <returns>The Zero Point magnitude.</returns> public static double Calibrate(List <StarInfo> VizieRStars, List <Star> DetectedStars, double PositionError) { double T = double.MaxValue, B = double.MinValue, L = double.MaxValue, R = double.MinValue; List <Tuple <Star, StarInfo> > Pairs = new List <Tuple <Star, StarInfo> >(); foreach (Star s in DetectedStars) { if (s.EqCenter.Dec < T) { T = s.EqCenter.Dec; } if (s.EqCenter.Dec > B) { B = s.EqCenter.Dec; } if (s.EqCenter.RA > R) { R = s.EqCenter.RA; } if (s.EqCenter.RA < L) { L = s.EqCenter.RA; } } QuadTree <Star> Tree = new QuadTree <Star>(10, T, B, L, R); foreach (Star s in DetectedStars) { Tree.Add(s, s.EqCenter.RA, s.EqCenter.Dec); } foreach (StarInfo si in VizieRStars) { var Stars = Tree.Query(si.Coordinate.RA, si.Coordinate.Dec, Arc1Sec * PositionError); var St2 = Tree.Query(si.Coordinate.RA, si.Coordinate.Dec, Arc1Sec * PositionError * 5); if (St2.Count == 1 & Stars.Count == 1) { Pairs.Add(new Tuple <Star, StarInfo>(Stars[0], si)); } } if (Pairs.Count < 5) { throw new IndexOutOfRangeException("Could not find enough pairs for calibration."); } var Rpairs1 = Pairs.ToArray(); var ZPSet = Pairs.Select((x) => x.Item2.Magnitude + 2.5 * Math.Log10(x.Item1.Flux)).ToArray(); Array.Sort(ZPSet, Rpairs1); var Rpairs2 = Rpairs1.Skip(Rpairs1.Length / 4).Take(Rpairs1.Length / 2).ToList(); LinearRegression.LinearRegressionParameters LRP = LinearRegression.ComputeLinearRegression(Rpairs2.Select((x) => Math.Log10(x.Item1.Flux)).ToArray(), Rpairs2.Select((x) => x.Item2.Magnitude).ToArray()); if (LRP.PearsonR * LRP.PearsonR < CalibMinR * CalibMinR) { throw new ArgumentOutOfRangeException("Could not calibrate the fluxes with enough accuracy."); } return(ZPSet[ZPSet.Length / 2]); }
/// <summary>Attempts to find a tracklet given 2 image detections (from separate images).</summary> void AnalyzePair(ImageDetection a, ImageDetection b) { /* Figure out line vector */ double SepSec = (b.Time.Time - a.Time.Time).TotalSeconds; LinearRegression.LinearRegressionParameters RAT = LinearRegression.ComputeLinearRegression(new double[] { 0, SepSec }, new double[] { a.Barycenter.EP.RA, b.Barycenter.EP.RA }); LinearRegression.LinearRegressionParameters DecT = LinearRegression.ComputeLinearRegression(new double[] { 0, SepSec }, new double[] { a.Barycenter.EP.Dec, b.Barycenter.EP.Dec }); /* Search for objects */ List <ImageDetection[]> Dects = new List <ImageDetection[]>(); foreach (DateTime dt in ObsTimes) { /* Compute estimated position */ TimeSpan tsp = dt - a.Time.Time; double tspSeconds = tsp.TotalSeconds; EquatorialPoint eqp = new EquatorialPoint() { RA = RAT.Intercept + RAT.Slope * tspSeconds, Dec = DecT.Intercept + DecT.Slope * tspSeconds }; /* Limit is given by a triangle with the maximum residuals */ List <ImageDetection> ImDL = FindSourcesAround(a, b, dt, eqp, SearchExtraSmall); if (ImDL.Count == 0) { ImDL = FindSourcesAround(a, b, dt, eqp, SearchExtraBig); } Dects.Add(ImDL.ToArray()); } /* If it can be found on at least 3 images, consider it a detection */ int i, c = 0; for (i = 0; i < Dects.Count; i++) { if (Dects[i].Length != 0) { c++; } } if (c >= 3) { CandidatePairings.Add(Dects.ToArray()); foreach (ImageDetection[] mdl in Dects) { foreach (ImageDetection m in mdl) { m.FetchOrCreate <PairingProperties>().IsPaired = true; } } } }
/// <summary> /// Creates a tracklet from a set of detections. /// </summary> /// <param name="Detections">Input detections; one per image.</param> /// <returns>A new Tracklet instance.</returns> public static Tracklet CreateTracklet(ImageDetection[] Detections) { long[] Ticks = Detections.Select((x) => x.Time.Time.Ticks).ToArray(); Array.Sort(Ticks, Detections); EquatorialPoint[] ValidEP = new EquatorialPoint[Detections.Length]; double[] ValidTimes = new double[Detections.Length]; DateTime ZeroTime = Detections[0].Time.Time; WCS.IWCSProjection Projection = Detections[0].ParentImage.Transform; for (int i = 0; i < Detections.Length; i++) { ValidEP[i] = Detections[i].Barycenter.EP; ValidTimes[i] = (Detections[i].Time.Time - ZeroTime).TotalSeconds; } var XRA = ValidEP.Select((x) => x.RA).ToArray(); var XDec = ValidEP.Select((x) => x.Dec).ToArray(); var RAreg = LinearRegression.ComputeLinearRegression(ValidTimes, XRA); var Decreg = LinearRegression.ComputeLinearRegression(ValidTimes, XDec); var RADecreg = LinearRegression.ComputeLinearRegression(XRA, XDec); double ResRA = LineFit.ComputeResidualSqSum(RAreg, ValidTimes, XRA); double ResDec = LineFit.ComputeResidualSqSum(Decreg, ValidTimes, XDec); EquatorialVelocity ev = new EquatorialVelocity() { RAvel = RAreg.Slope, Decvel = Decreg.Slope }; TrackletVelocityRegression tvr = new TrackletVelocityRegression() { R_TR = RAreg.PearsonR, R_TD = Decreg.PearsonR, R_RD = RADecreg.PearsonR, S_TR = ResRA, S_TD = ResDec, ZeroTime = ZeroTime, P_TD = Decreg, P_TR = RAreg }; TrackletVelocity tvel = new TrackletVelocity() { EquatorialVelocity = ev, PixelVelocity = Projection.GetPixelVelocity(ev), SphericalVelocity = Math.Sqrt(ev.Decvel * ev.Decvel + ev.RAvel * ev.RAvel * Math.Cos(XRA[0]) * Math.Cos(XRA[0])) }; return(new Tracklet(Detections, tvel, tvr)); }
/// <summary> /// Match detections and merge those that seem to belong to the same object. /// </summary> /// <param name="RawDetections">Input set of detections.</param> /// <param name="MaxDistance">Maximum distance possible between two detections part of the same object.</param> /// <param name="MixMatch">Number of overlapping pixels before two detections are considered part of the same object.</param> /// <param name="PSFMatch">Distance between the barycenters of 2 detections before they are considered the same (for external detections mostly).</param> public static void MatchDetections(List <ImageDetection> RawDetections, double MaxDistance, int MixMatch, double PSFMatch) { int i, j; List <HashSet <PixelPoint> > LHP = RawDetections.Select((x) => x.TryFetchProperty(out ObjectPoints op) ? new HashSet <PixelPoint>(op.PixelPoints) : null).ToList(); List <PairingProperties> PairPropList = RawDetections.Select((x) => x.TryFetchProperty(out PairingProperties Prop) ? Prop : null).ToList(); for (i = 0; i < RawDetections.Count; i++) { for (j = i + 1; j < RawDetections.Count; j++) { /* Must be two detections captured at the same time */ if (RawDetections[i].Time.Time != RawDetections[j].Time.Time) { continue; } /* Check distance */ double D0 = (RawDetections[i].Barycenter.PP ^ RawDetections[j].Barycenter.PP); double D1 = (RawDetections[i].FetchProperty <ObjectSize>().PixelEllipse.SemiaxisMajor + RawDetections[j].FetchProperty <ObjectSize>().PixelEllipse.SemiaxisMajor); if (D0 - D1 > MaxDistance) { continue; } HashSet <PixelPoint> PixPi = LHP[i], PixPj = LHP[j]; bool FlagAnyCond = false; /* If there are MinPix overlapping pixels, merge detections */ if (PixPi != null & PixPj != null) { if (PixPi.Overlaps(PixPj)) { FlagAnyCond = true; } if (!FlagAnyCond) { /* Detections that are somewhat linear are checked for colinearity with others */ IEnumerable <PixelPoint> Plist = PixPi.Concat(PixPj); LinearRegression.LinearRegressionParameters pc = LinearRegression.ComputeLinearRegression(Plist); LinearRegression.LinearRegressionParameters p1 = LinearRegression.ComputeLinearRegression(PixPi); LinearRegression.LinearRegressionParameters p2 = LinearRegression.ComputeLinearRegression(PixPj); if (Math.Abs(pc.PearsonR) > Math.Abs(p1.PearsonR) && Math.Abs(pc.PearsonR) > Math.Abs(p2.PearsonR) && Math.Abs(pc.PearsonR) < Math.Abs(p1.PearsonR) + Math.Abs(p2.PearsonR)) { FlagAnyCond = true; } } } if (D0 < PSFMatch) { FlagAnyCond = true; } /* If any merging condition is satisfied, merge the detections */ if (FlagAnyCond) { if (LHP[i] != null & LHP[j] != null) { LHP[i].UnionWith(LHP[j]); } else if (LHP[i] == null) { LHP[i] = LHP[j]; } if (PairPropList[i] != null && PairPropList[j] != null) { PairPropList[i].Algorithm |= PairPropList[i].Algorithm; } LHP.RemoveAt(j); RawDetections.RemoveAt(j); PairPropList.RemoveAt(j); j--; } } } for (i = 0; i < LHP.Count; i++) { if (LHP[i] != null) { try { RawDetections[i] = StandardDetectionFactory.CreateDetection(RawDetections[i].ParentImage, LHP[i]); if (PairPropList[i] != null) { RawDetections[i].SetResetProperty(PairPropList[i]); } } catch { RawDetections.RemoveAt(i); PairPropList.RemoveAt(i); LHP.RemoveAt(i); i--; } } } }