private void BuildPiramidMatchingUsingOldKVector() { #region The old way of doing it // The distance base "Pyramid" matching only uses limited number of stars m_CelestialPyramidStars = m_CelestialAllStars.FindAll((star) => star.Mag >= m_PyramidMinMag && star.Mag <= m_PyramidMaxMag); if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine(string.Format("Building Pyramid Alignment Dataset of {0}/{1} stars in range {2}m - {3}m", m_CelestialPyramidStars.Count, m_CelestialAllStars.Count, m_PyramidMinMag.ToString("0.0"), m_PyramidMaxMag.ToString("0.0"))); m_Distances.Clear(); m_Entries.Clear(); m_StarsDistanceCache.Clear(); m_IndexLower.Clear(); m_IndexUpper.Clear(); // Build a list of distances double maxFovInDeg = m_PlateConfig.GetMaxFOVInArcSec() / 3600.0; for (int i = 0; i < m_CelestialPyramidStars.Count; i++) { IStar star1 = m_CelestialPyramidStars[i]; for (int j = i + 1; j < m_CelestialPyramidStars.Count; j++) { IStar star2 = m_CelestialPyramidStars[j]; double dist = AngleUtility.Elongation(star1.RADeg, star1.DEDeg, star2.RADeg, star2.DEDeg); if (dist > maxFovInDeg) continue; dist *= 3600.0; m_Distances.Add(dist); DistanceEntry entry = new DistanceEntry(star1, star2, dist); m_Entries.Add(entry); #region PerStar distance cache ulonglong id1 = new ulonglong(star1.StarNo, star2.StarNo); ulonglong id2 = new ulonglong(star2.StarNo, star1.StarNo); Dictionary<ulonglong, DistanceEntry> map; if (!m_StarsDistanceCache.TryGetValue(star1.StarNo, out map)) { map = new Dictionary<ulonglong, DistanceEntry>(); m_StarsDistanceCache.Add(star1.StarNo, map); } map.Add(id1, entry); if (!m_StarsDistanceCache.TryGetValue(star2.StarNo, out map)) { map = new Dictionary<ulonglong, DistanceEntry>(); m_StarsDistanceCache.Add(star2.StarNo, map); } map.Add(id2, entry); #endregion } } // Build a K-Vector double[] distArr = m_Distances.ToArray(); DistanceEntry[] entryArr = m_Entries.ToArray(); Array.Sort(distArr, entryArr); m_Distances = new List<double>(distArr); m_Entries = new List<DistanceEntry>(entryArr); //Console.WriteLine(m_Distances.Count.ToString() + " match distances."); double errorInArcSec = m_PlateConfig.GetDistanceInArcSec(m_Settings.PyramidDistanceToleranceInPixels); errorInArcSec = 0; /* the error will be factored in later on */ int maxIdx = (int)Math.Round(m_PlateConfig.GetMaxFOVInArcSec() + 2 * errorInArcSec) + 1; for (int i = 0; i < maxIdx; i++) { m_IndexLower.Add(i, -1); m_IndexUpper.Add(i, -1); } int lower = -1; int upper = -1; for (int i = 0; i < m_Distances.Count; i++) { int dstL = Math.Max((int)(m_Distances[i] - errorInArcSec), (int)errorInArcSec); if (dstL > lower) { lower = dstL; for (int j = lower; j >= 0 && m_IndexLower[j] == -1; j--) m_IndexLower[j] = Math.Max(i - 1, 0); } int dstU = Math.Max((int)Math.Round(m_Distances[i] + errorInArcSec), (int)errorInArcSec); if (dstU > upper) { upper = dstU; for (int j = upper; j >= 0 && m_IndexUpper[j] == -1; j--) m_IndexUpper[j] = Math.Min(i, m_Distances.Count - 1); } } for (int j = m_IndexLower.Count - 1; j >= 0 && m_IndexLower[j] == -1; j--) m_IndexLower[j] = m_Distances.Count - 1; for (int j = m_IndexUpper.Count - 1; j >= 0 && m_IndexUpper[j] == -1; j--) m_IndexUpper[j] = m_Distances.Count - 1; #endregion }
internal IAstrometricFit IsSuccessfulMatch( IStarMap starMap, int i, int j, int k, DistanceEntry ijEntry, DistanceEntry ikEntry, DistanceEntry jkEntry, ulong iStarNo, ulong starNo2, ulong starNo3, double fittedFocalLength, bool isRatioFittedFocalLength, double toleranceInArcSec) { i--; j--; k--; ImagePixel feature_i = GetCenterOfFeature(starMap.GetFeatureById(i), starMap); ImagePixel feature_j = GetCenterOfFeature(starMap.GetFeatureById(j), starMap); ImagePixel feature_k = GetCenterOfFeature(starMap.GetFeatureById(k), starMap); #region find the numbers of the three stars: i, j, k #if ASTROMETRY_DEBUG Trace.Assert(ijEntry.Star1.StarNo == iStarNo || ijEntry.Star2.StarNo == iStarNo); #endif ulong jStarNo, kStarNo; if (ijEntry.Star1.StarNo == iStarNo) { jStarNo = ijEntry.Star2.StarNo; if (ijEntry.Star2.StarNo == starNo2) kStarNo = starNo3; else kStarNo = starNo2; } else { jStarNo = ijEntry.Star1.StarNo; if (ijEntry.Star1.StarNo == starNo2) kStarNo = starNo3; else kStarNo = starNo2; } #if ASTROMETRY_DEBUG Trace.Assert(ikEntry.Star1.StarNo == kStarNo || ikEntry.Star2.StarNo == kStarNo); Trace.Assert(jkEntry.Star1.StarNo == kStarNo || jkEntry.Star2.StarNo == kStarNo); #endif #endregion //if (DebugResolvedStars != null) //{ // uint ii = 0, jj = 0, kk = 0; // if (DebugResolvedStars.TryGetValue(i + 1, out ii) && // DebugResolvedStars.TryGetValue(j + 1, out jj) && // DebugResolvedStars.TryGetValue(k + 1, out kk)) // { // if (ii == iStarNo && jj == starNo2 && kk == starNo3) // { // Debugger.Break(); // } // else // Trace.WriteLine(string.Format("PYRAMID: {0} = {1}, {2} = {3}, {4} = {5}", // i, i == ii ? "YES" : "NO" // , j, j == jj ? "YES" : "NO" // , k, k == kk ? "YES" : "NO")); // } // else // Trace.WriteLine(string.Format("PYRAMID: {0} = {1}, {2} = {3}, {4} = {5}", // i, i == ii ? "YES" : "MISSING" // , j, j == jj ? "YES" : "MISSING" // , k, k == kk ? "YES" : "MISSING")); //} #if ASTROMETRY_DEBUG PyramidEntry pyramidLog = new PyramidEntry(i, j, k, feature_i, feature_j, feature_k, iStarNo, jStarNo, kStarNo); #endif //// Note this is actually cheap way to confirm whether the 3 stars are good or not. //List<IStar> threeStars = m_CelestialAllStars.FindAll(s => s.StarNo == iStarNo || s.StarNo == jStarNo || s.StarNo == kStarNo); //if (threeStars.Count == 3) //{ // Dictionary<AstroPixel, IStar> threeStarDict = new Dictionary<AstroPixel, IStar>(); // IStar stari = threeStars.Find(s => s.StarNo == iStarNo); // threeStarDict.Add(feature_i, stari); // IStar starj = threeStars.Find(s => s.StarNo == jStarNo); // threeStarDict.Add(feature_j, starj); // IStar stark = threeStars.Find(s => s.StarNo == kStarNo); // threeStarDict.Add(feature_k, stark); // DirectTransRotAstrometry solution = DirectTransRotAstrometry.SolveByThreeStars(m_PlateConfig, threeStarDict); // if (solution != null) // { // pyramidLog.RegisterPreliminaryThreeStarFit(solution); // } //} int locatedStars = 3; m_MatchedPairs.Clear(); m_AmbiguousMatches.Clear(); m_MatchedFeatureIdToStarIdIndexes.Clear(); List<ulong> usedPyramidAngles = new List<ulong>(); foreach (StarMapFeature feature in starMap.Features) { if (feature.FeatureId == i) continue; if (feature.FeatureId == j) continue; if (feature.FeatureId == k) continue; long idx_ix = ((long)i << 32) + (long)feature.FeatureId; double dist_ix; ImagePixel feature_x = GetCenterOfFeature(feature, starMap); if (m_MatchedPairs.ContainsKey(feature_x)) continue; if (isRatioFittedFocalLength || !m_FeaturesDistanceCache.TryGetValue(idx_ix, out dist_ix)) { dist_ix = m_PlateConfig.GetDistanceInArcSec(feature_i.X, feature_i.Y, feature_x.X, feature_x.Y, fittedFocalLength); long idx_xi = ((long)feature.FeatureId << 32) + (long)i; if (!isRatioFittedFocalLength) { m_FeaturesDistanceCache.Add(idx_ix, dist_ix); m_FeaturesDistanceCache.Add(idx_xi, dist_ix); } } Dictionary<ulonglong, DistanceEntry> iStarDists = m_StarsDistanceCache[iStarNo]; foreach (ulonglong key in iStarDists.Keys) { // We have found a distance that matches the current feature ulong xStarNo = key.Lo; if (usedPyramidAngles.IndexOf(xStarNo) != -1) continue; DistanceEntry entry_ix = iStarDists[key]; if (entry_ix.DistanceArcSec + toleranceInArcSec < dist_ix) continue; if (entry_ix.DistanceArcSec - toleranceInArcSec > dist_ix) continue; Dictionary<ulonglong, DistanceEntry> xStarDists = m_StarsDistanceCache[xStarNo]; #region Test the J-X pair ulonglong jxKey = new ulonglong(xStarNo , jStarNo); DistanceEntry entry_jx; if (!xStarDists.TryGetValue(jxKey, out entry_jx)) continue; long idx_jx = ((long)j << 32) + (long)feature.FeatureId; double dist_jx; if (isRatioFittedFocalLength || !m_FeaturesDistanceCache.TryGetValue(idx_jx, out dist_jx)) { dist_jx = m_PlateConfig.GetDistanceInArcSec(feature_j.X, feature_j.Y, feature_x.X, feature_x.Y, fittedFocalLength); long idx_xj = ((long)feature.FeatureId << 32) + (long)j; if (!isRatioFittedFocalLength) { m_FeaturesDistanceCache.Add(idx_jx, dist_jx); m_FeaturesDistanceCache.Add(idx_xj, dist_jx); } } if (entry_jx.DistanceArcSec + toleranceInArcSec < dist_jx) continue; if (entry_jx.DistanceArcSec - toleranceInArcSec > dist_jx) continue; #endregion #region Test the K-X pair ulonglong kxKey = new ulonglong(xStarNo, kStarNo); DistanceEntry entry_kx; if (!xStarDists.TryGetValue(kxKey, out entry_kx)) continue; long idx_kx = ((long)k << 32) + (long)feature.FeatureId; double dist_kx; if (isRatioFittedFocalLength || !m_FeaturesDistanceCache.TryGetValue(idx_kx, out dist_kx)) { dist_kx = m_PlateConfig.GetDistanceInArcSec(feature_k.X, feature_k.Y, feature_x.X, feature_x.Y, fittedFocalLength); long idx_xk = ((long)feature.FeatureId << 32) + (long)k; if (!isRatioFittedFocalLength) { m_FeaturesDistanceCache.Add(idx_kx, dist_kx); m_FeaturesDistanceCache.Add(idx_xk, dist_kx); } } if (entry_kx.DistanceArcSec + toleranceInArcSec < dist_kx) continue; if (entry_kx.DistanceArcSec - toleranceInArcSec > dist_kx) continue; #endregion // If we are here, then we have found another star locatedStars++; IStar xStar = entry_kx.Star1.StarNo == xStarNo ? entry_kx.Star1 : entry_kx.Star2; #if ASTROMETRY_DEBUG Trace.Assert(xStar.StarNo != iStarNo); Trace.Assert(xStar.StarNo != jStarNo); Trace.Assert(xStar.StarNo != kStarNo); #endif if (RegisterRecognizedPair(feature_x, xStar, feature.FeatureId)) { usedPyramidAngles.Add(xStar.StarNo); } //Console.WriteLine(string.Format(" {0} ({1}) {2}\" {3}\" {4}\"", xStarNo, feature.FeatureId, dist_ix.ToString("0.0"), dist_jx.ToString("0.0"), dist_kx.ToString("0.0"))); } } if (locatedStars >= CorePyramidConfig.Default.MinPyramidAlignedStars) { ThreeStarFit.StarPair pair_i = new ThreeStarFit.StarPair(feature_i.X, feature_i.Y); ThreeStarFit.StarPair pair_j = new ThreeStarFit.StarPair(feature_j.X, feature_j.Y); ThreeStarFit.StarPair pair_k = new ThreeStarFit.StarPair(feature_k.X, feature_k.Y); if (ijEntry.Star1.StarNo == iStarNo) { pair_i.RADeg = ijEntry.Star1.RADeg; pair_i.DEDeg = ijEntry.Star1.DEDeg; pair_i.Star = ijEntry.Star1; pair_j.RADeg = ijEntry.Star2.RADeg; pair_j.DEDeg = ijEntry.Star2.DEDeg; pair_j.Star = ijEntry.Star2; #if ASTROMETRY_DEBUG Trace.Assert(ijEntry.Star1.StarNo == iStarNo); Trace.Assert(ijEntry.Star2.StarNo == jStarNo); #endif RegisterRecognizedPair(feature_i, ijEntry.Star1, i); RegisterRecognizedPair(feature_j, ijEntry.Star2, j); } else { pair_i.RADeg = ijEntry.Star2.RADeg; pair_i.DEDeg = ijEntry.Star2.DEDeg; pair_i.Star = ijEntry.Star2; pair_j.RADeg = ijEntry.Star1.RADeg; pair_j.DEDeg = ijEntry.Star1.DEDeg; pair_j.Star = ijEntry.Star1; #if ASTROMETRY_DEBUG Trace.Assert(ijEntry.Star2.StarNo == iStarNo); Trace.Assert(ijEntry.Star1.StarNo == jStarNo); #endif RegisterRecognizedPair(feature_i, ijEntry.Star2, i); RegisterRecognizedPair(feature_j, ijEntry.Star1, j); } if (ikEntry.Star1.StarNo == kStarNo) { pair_k.RADeg = ikEntry.Star1.RADeg; pair_k.DEDeg = ikEntry.Star1.DEDeg; pair_k.Star = ikEntry.Star1; #if ASTROMETRY_DEBUG Trace.Assert(ikEntry.Star1.StarNo == kStarNo); #endif RegisterRecognizedPair(feature_k, ikEntry.Star1, k); } else { pair_k.RADeg = ikEntry.Star2.RADeg; pair_k.DEDeg = ikEntry.Star2.DEDeg; pair_k.Star = ikEntry.Star2; #if ASTROMETRY_DEBUG Trace.Assert(ikEntry.Star2.StarNo == kStarNo); #endif RegisterRecognizedPair(feature_k, ikEntry.Star2, k); } if (m_AmbiguousMatches.Count > 0 && locatedStars - m_AmbiguousMatches.Count >= CorePyramidConfig.Default.MinPyramidAlignedStars) { // If we have sufficient number of stars and ambiguous stars (close doubles that satisfy more than one solution) // then remove all ambiguous stars before proceeding foreach (ImagePixel matchedPixel in m_AmbiguousMatches) { IStar matchedStar = m_MatchedPairs[matchedPixel]; int featureToRemove = -1; foreach (int featureId in m_MatchedFeatureIdToStarIdIndexes.Keys) { if (m_MatchedFeatureIdToStarIdIndexes[featureId] == matchedStar.StarNo) { featureToRemove = featureId; break; } } m_MatchedFeatureIdToStarIdIndexes.Remove(featureToRemove); m_MatchedPairs.Remove(matchedPixel); } } if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Debug.WriteLine(string.Format("Attempting DistanceBasedContext.LeastSquareFittedAstrometry ({0}={1}; {2}={3}; {4}={5})", i, iStarNo, j, jStarNo, k, kStarNo)); return SolveStarPairs( starMap, m_MatchedPairs, m_MatchedFeatureIdToStarIdIndexes, pair_i, pair_j, pair_k, fittedFocalLength, #if ASTROMETRY_DEBUG pyramidLog #else null #endif ); } else { #if PYRAMID_DEBUG || DEBUG foreach(ImagePixel pixel in m_MatchedPairs.Keys) { IStar star = m_MatchedPairs[pixel]; foreach(int featureId in m_MatchedFeatureIdToStarIdIndexes.Keys) { if (m_MatchedFeatureIdToStarIdIndexes[featureId] == star.StarNo) { if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { #if DEBUG Debug #endif #if PYRAMID_DEBUG Trace #endif .WriteLine(string.Format("({0}, {1}) - StarNo: {2}; FeatureId: {3}", pixel.X, pixel.Y, star.StarNo, featureId)); } break; } } } #endif #if ASTROMETRY_DEBUG pyramidLog.FailBecauseOfTooFiewLocatedStars(locatedStars); AstrometricFitDebugger.RegisterFailedPyramid(pyramidLog); #endif } return null; }
public static PyramidStarsDensityDistributor BuildPyramidMatchingByMagnitude( List<IStar> pyramidStars, AstroPlate image, IAstrometrySettings settings, Dictionary<int, ulong> debugResolvedStarsWithAppliedExclusions, List<ulong> alwaysIncludeStars, out List<DistanceEntry> distancesByMagnitude, out Dictionary<ulong, Dictionary<ulonglong, DistanceEntry>> starsDistanceCache) { // 1) This should be the first N brightest (or all stars) // 2) The memory structure should be a dictionary of Pairs with values all other pairs that include one of the pair // 3) The dictionary should be sorted by brightness i.e. brightest pairs should be on the top/ NOTE: Exclude the brightest // stars until the mag difference between the next 2 bright stars becomes less than 1 mag // 4) Matching should be done by searching the distance match checking the brightest pairs first. distancesByMagnitude = new List<DistanceEntry>(); starsDistanceCache = new Dictionary<ulong, Dictionary<ulonglong, DistanceEntry>>(); if (pyramidStars.Count == 0) return null; PyramidStarsDensityDistributor distributor; pyramidStars.Sort((s1, s2) => s1.Mag.CompareTo(s2.Mag)); int n = pyramidStars.Count; double maxFovInDeg = image.GetMaxFOVInArcSec() / 3600.0; distributor = new PyramidStarsDensityDistributor(pyramidStars, image, settings); distributor.DebugResolvedStarsWithAppliedExclusions = debugResolvedStarsWithAppliedExclusions; distributor.Initialize(alwaysIncludeStars); distancesByMagnitude.Clear(); starsDistanceCache.Clear(); List<ulong> resolvedDebugStarsNos = null; if (debugResolvedStarsWithAppliedExclusions != null) { // This is disabled at the moment resolvedDebugStarsNos = debugResolvedStarsWithAppliedExclusions.Values.ToList(); int pyramidStarsLocated = 0; for (int i = resolvedDebugStarsNos.Count - 1; i >= 0 ; i--) { ulong starNo = resolvedDebugStarsNos[i]; IStar star = pyramidStars.FirstOrDefault(s => s.StarNo == starNo); if (star != null) pyramidStarsLocated++; else resolvedDebugStarsNos.Remove(starNo); Trace.Assert(star != null, string.Format("Debug Star {0} not found in the pyramid stars!", starNo)); } if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine( string.Format("DEBUG ALIGN: {0} out of {1} Debug Stars found among the pyramid stars ({2})", pyramidStarsLocated, resolvedDebugStarsNos.Count, resolvedDebugStarsNos.Count > 1 ? resolvedDebugStarsNos.Select(s => s.ToString()).Aggregate((a, b) => string.Concat(a, " ", b)) : "")); } // Start building the pairs for (int j = 0; j < n; j++) { IStar jStar = pyramidStars[j]; if (!distributor.CheckStar(jStar)) { if (resolvedDebugStarsNos != null) { if (resolvedDebugStarsNos.Contains(jStar.StarNo)) { //Trace.Assert(false, "DebugResolved star pair not added to the pyramid areas because the distributor rejected it."); } } continue; } for (int i = j + 1; i < n; i++) { IStar iStar = pyramidStars[i]; double distDeg = AngleUtility.Elongation(iStar.RADeg, iStar.DEDeg, jStar.RADeg, jStar.DEDeg); if (distDeg > maxFovInDeg) { if (resolvedDebugStarsNos != null) { if (resolvedDebugStarsNos.Contains(iStar.StarNo) && resolvedDebugStarsNos.Contains(jStar.StarNo)) { //Trace.Assert(false, "DebugResolved star pair not added to the pyramid areas because the distance is too large."); } } continue; } if (!distributor.CheckStar(iStar)) { if (resolvedDebugStarsNos != null) { if (resolvedDebugStarsNos.Contains(iStar.StarNo)) { //Trace.Assert(false, string.Format("DebugResolved star {0} not added to the pyramid areas because the distributor rejected it.", iStar.StarNo)); } } continue; } distributor.MarkStar(iStar); distributor.MarkStar(jStar); DistanceEntry entry = new DistanceEntry(iStar, jStar, distDeg * 3600); distancesByMagnitude.Add(entry); #region PerStar distance cache ulonglong id1 = new ulonglong(iStar.StarNo, jStar.StarNo); ulonglong id2 = new ulonglong(jStar.StarNo, iStar.StarNo); Dictionary<ulonglong, DistanceEntry> map; if (!starsDistanceCache.TryGetValue(iStar.StarNo, out map)) { map = new Dictionary<ulonglong, DistanceEntry>(); starsDistanceCache.Add(iStar.StarNo, map); } map.Add(id1, entry); if (!starsDistanceCache.TryGetValue(jStar.StarNo, out map)) { map = new Dictionary<ulonglong, DistanceEntry>(); starsDistanceCache.Add(jStar.StarNo, map); } map.Add(id2, entry); #endregion } } //if (resolvedDebugStarsNos != null) //{ // foreach(uint starNo in resolvedDebugStarsNos) // { // DensityArea area = distributor.m_Areas.FirstOrDefault(a => a.m_IncludedStarNos.Contains(starNo)); // if (area != null) // Trace.WriteLine(string.Format("DEBUG ALIGN: Star {0} located to area [{1:0.00}, {2:0.0}]", starNo, area.XMiddle, area.YMiddle)); // Trace.Assert(area != null); // } //} return distributor; }
internal IAstrometricFit IsSuccessfulMatch( IStarMap starMap, int i, int j, int k, DistanceEntry ijEntry, DistanceEntry ikEntry, DistanceEntry jkEntry, ulong iStarNo, ulong starNo2, ulong starNo3, double toleranceInArcSec) { return IsSuccessfulMatch( starMap, i, j, k, ijEntry, ikEntry, jkEntry, iStarNo, starNo2, starNo3, m_PlateConfig.EffectiveFocalLength, false, toleranceInArcSec); }