예제 #1
0
        internal void SaveContext(string fileName)
        {
            PlateConstantsSolver oldValue = m_Context.ConstantsSolver;

            try
            {
                m_Context.ConstantsSolver = m_ConstantsSolver;
                byte[] data = m_Context.Serialize();
                System.IO.File.WriteAllBytes(fileName, data);
            }
            finally
            {
                m_Context.ConstantsSolver = oldValue;
            }
        }
예제 #2
0
        public PerformMatchResult PerformMatch(
            out LeastSquareFittedAstrometry distanceBasedSolution,
            out LeastSquareFittedAstrometry improvedSolution,
            out PlateConstantsSolver solver)
        {
            DistanceBasedContext.FieldAlignmentResult alignmentResult = null;
            improvedSolution = null;

#if UNIT_TESTS
            Flags.Reset();
#endif
            m_PerformanceWatch.Reset();
            m_PerformanceWatch.Start();
            try
            {
                if (m_StarMap.FeaturesCount < TangraConfig.Settings.Astrometry.MinimumNumberOfStars)
                {
                    distanceBasedSolution = null;
                    solver = null;
                    return(PerformMatchResult.FieldAlignmentFailed);
                }

                if (!m_IsCalibration &&
                    m_Solution != null)
                {
                    // Try using the cache from the last time
                    alignmentResult =
                        Context.DoFieldAlignment(m_StarMap, m_Solution.FitInfo, false);

                    m_Solution = GetSolution(alignmentResult);
#if UNIT_TESTS
                    Flags.CacheFromLastTimeAttempted  = true;
                    Flags.CacheFromLastTimeSuccessful = m_Solution != null;
#endif
                }

                if (m_Solution == null &&
                    !m_IsCalibration &&
                    m_ManualStarMatch != null)
                {
                    // Try using the manual star match
                    alignmentResult = Context.DoFieldAlignment(m_StarMap, m_ManualStarMatch);

                    m_Solution = GetSolution(alignmentResult);
#if UNIT_TESTS
                    Flags.ManualMatchAttempted  = true;
                    Flags.ManualMatchSuccessful = m_Solution != null;
#endif
                }

                if (m_Solution == null &&
                    !m_RatioBasedFittedFocalLengthIsDerived &&
                    !m_FitSettings.PyramidForceFixedFocalLength &&
                    !m_IsCalibration)
                {
                    m_OperationNotifier.NotifyBeginLongOperation("Performing a plate solve ...");
                    try
                    {
                        // If this is the first fit, then fit a focal length
                        alignmentResult = Context.DoFieldAlignmentFitFocalLength(m_StarMap);
                        m_Solution      = GetSolution(alignmentResult);

                        if (m_Solution != null)
                        {
                            m_RatioBasedFittedFocalLengthIsDerived = true;
                            m_RatioBasedFittedFocalLength          = m_Solution.FitInfo.FittedFocalLength;
                        }
                        else
                        {
                            if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceInfo())
                            {
                                Trace.WriteLine(string.Format("No solution after reaching combination {0} with {1} features.", Context.CurrentCombination, m_StarMap.FeaturesCount));
                            }
                        }
                    }
                    finally
                    {
                        m_OperationNotifier.NotifyEndLongOperation();
                    }
#if UNIT_TESTS
                    Flags.RatioBasedFocalLengthFitAttempted  = true;
                    Flags.RatioBasedFocalLengthFitSuccessful = m_RatioBasedFittedFocalLengthIsDerived;
#endif
                }
                else
                {
                    if (m_Solution == null)
                    {
                        if (m_RatioBasedFittedFocalLengthIsDerived &&
                            !m_IsCalibration)
                        {
                            alignmentResult = Context.DoFieldAlignment(m_StarMap, m_RatioBasedFittedFocalLength);

                            m_Solution = GetSolution(alignmentResult);
#if UNIT_TESTS
                            Flags.FitWithPreFittedFocalLengthAttempted  = true;
                            Flags.FitWithPreFittedFocalLengthSuccessful = m_Solution != null;
#endif
                        }
                        else
                        {
                            alignmentResult = Context.DoFieldAlignment(m_StarMap);

                            m_Solution = GetSolution(alignmentResult);
#if UNIT_TESTS
                            Flags.FitWithFixedFocalLengthAttempted  = true;
                            Flags.FitWithFixedFocalLengthSuccessful = m_Solution != null;
#endif
                        }
                    }
                }

                m_SearchAborted = Context.m_AbortSearch;

                if (alignmentResult != null)
                {
                    distanceBasedSolution = (LeastSquareFittedAstrometry)alignmentResult.Solution;
                    improvedSolution      = (LeastSquareFittedAstrometry)alignmentResult.ImprovedSolution;
                    m_Solution            = GetSolution(alignmentResult);
                    solver = alignmentResult.Solver;
                }
                else
                {
                    distanceBasedSolution = m_Solution;
                    solver = null;
                }

                if (m_SearchAborted)
                {
                    return(PerformMatchResult.SearchAborted);
                }

#if ASTROMETRY_DEBUG
                if (m_Solution != null)
                {
                    // No need to keep the debug log any longer when the fit is successful
                    AstrometricFitDebugger.Reset();
                }
#endif
                if (m_Solution != null)
                {
                    // Clear manually identified starting position in a case of a successful plate solve
                    m_ManualStarMatch = null;
                }

                return(m_Solution != null
                                        ? PerformMatchResult.FitSucceessfull
                                        : PerformMatchResult.FitImprovementFailed);
            }
            finally
            {
                // Reset the manually matched stars after every fit attempt
                m_ManualStarMatch = null;

                m_PerformanceWatch.Stop();

                if (m_Solution != null)
                {
                    if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceError())
                    {
                        Trace.WriteLine(string.Format(
                                            "Pyramid Match Successful: {0} ms, {1} stars total, aligned on {2} stars, {3} stars matched {4}. Combination: {5}",
                                            m_PerformanceWatch.ElapsedMilliseconds, m_CelestialStars.Count,
                                            alignmentResult != null ? (alignmentResult.Solution as LeastSquareFittedAstrometry).FitInfo.NumberOfStarsUsedInSolution() : 0,
                                            improvedSolution != null ? improvedSolution.FitInfo.NumberOfStarsUsedInSolution().ToString() : "N/A",
                                            improvedSolution != null ? string.Format(" ({0}-{1} mag)", Context.ImprovedSolutionIncludedMinMag.ToString("0.00"), Context.ImprovedSolutionIncludedMaxMag.ToString("0.00")) : null,
                                            alignmentResult != null ? alignmentResult.MatchedTriangle : null));
                    }
                }
                else
                {
                    if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceError())
                    {
                        Trace.WriteLine(string.Format("Pyramid Match Failed: {0} ms, {1} stars total, NO MATCH",
                                                      m_PerformanceWatch.ElapsedMilliseconds, m_CelestialStars.Count));
                    }

                    if (Context.DebugResolvedStars != null)
                    {
                        foreach (DistanceBasedContext.DebugTripple tripple in Context.m_DebugTripples)
                        {
                            if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose())
                            {
                                Trace.WriteLine(string.Format("DEBUG ALIGN: Missed alignment on {0}-{1}-{2}", tripple.Id1, tripple.Id2, tripple.Id3));
                            }
                        }
                    }
                }
#if ASTROMETRY_DEBUG
                Trace.Assert(!m_DetermineAutoLimitMagnitude || m_Solution == null || m_Solution.FitInfo.DetectedLimitingMagnitude != 0);
#endif
            }
        }
        public PerformMatchResult PerformMatch(
			out LeastSquareFittedAstrometry distanceBasedSolution,
			out LeastSquareFittedAstrometry improvedSolution, 
			out PlateConstantsSolver solver)
        {
            DistanceBasedContext.FieldAlignmentResult alignmentResult = null;
            improvedSolution = null;

            #if UNIT_TESTS
            Flags.Reset();
            #endif
            m_PerformanceWatch.Reset();
            m_PerformanceWatch.Start();
            try
            {
                if (m_StarMap.FeaturesCount < TangraConfig.Settings.Astrometry.MinimumNumberOfStars)
                {
                    distanceBasedSolution = null;
                    solver = null;
                    return PerformMatchResult.FieldAlignmentFailed;
                }

                if (!m_IsCalibration &&
                    m_Solution != null)
                {
                    // Try using the cache from the last time
                    alignmentResult =
                        Context.DoFieldAlignment(m_StarMap, m_Solution.FitInfo, false);

                    m_Solution = GetSolution(alignmentResult);
            #if UNIT_TESTS
                    Flags.CacheFromLastTimeAttempted = true;
                    Flags.CacheFromLastTimeSuccessful = m_Solution != null;
            #endif
                }

                if (m_Solution == null &&
                    !m_IsCalibration &&
                    m_ManualStarMatch != null)
                {
                    // Try using the manual star match
                    alignmentResult = Context.DoFieldAlignment(m_StarMap, m_ManualStarMatch);

                    m_Solution = GetSolution(alignmentResult);
            #if UNIT_TESTS
                    Flags.ManualMatchAttempted = true;
                    Flags.ManualMatchSuccessful = m_Solution != null;
            #endif
                }

                if (m_Solution == null &&
                    !m_RatioBasedFittedFocalLengthIsDerived &&
                    !m_FitSettings.PyramidForceFixedFocalLength &&
                    !m_IsCalibration)
                {
                    m_OperationNotifier.NotifyBeginLongOperation("Performing a plate solve ...");
                    try
                    {
                        // If this is the first fit, then fit a focal length
                        alignmentResult = Context.DoFieldAlignmentFitFocalLength(m_StarMap);
                        m_Solution = GetSolution(alignmentResult);

                        if (m_Solution != null)
                        {
                            m_RatioBasedFittedFocalLengthIsDerived = true;
                            m_RatioBasedFittedFocalLength = m_Solution.FitInfo.FittedFocalLength;
                        }
                        else
                        {
                            if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceInfo())
                                Trace.WriteLine("No Solution.");
                        }
                    }
                    finally
                    {
                        m_OperationNotifier.NotifyEndLongOperation();
                    }
            #if UNIT_TESTS
                    Flags.RatioBasedFocalLengthFitAttempted = true;
                    Flags.RatioBasedFocalLengthFitSuccessful = m_RatioBasedFittedFocalLengthIsDerived;
            #endif
                }
                else
                {
                    if (m_Solution == null)
                    {
                        if (m_RatioBasedFittedFocalLengthIsDerived &&
                            !m_IsCalibration)
                        {
                            alignmentResult = Context.DoFieldAlignment(m_StarMap, m_RatioBasedFittedFocalLength);

                            m_Solution = GetSolution(alignmentResult);
            #if UNIT_TESTS
                            Flags.FitWithPreFittedFocalLengthAttempted = true;
                            Flags.FitWithPreFittedFocalLengthSuccessful = m_Solution != null;
            #endif

                        }
                        else
                        {
                            alignmentResult = Context.DoFieldAlignment(m_StarMap);

                            m_Solution = GetSolution(alignmentResult);
            #if UNIT_TESTS
                            Flags.FitWithFixedFocalLengthAttempted = true;
                            Flags.FitWithFixedFocalLengthSuccessful = m_Solution != null;
            #endif
                        }
                    }
                }

                m_SearchAborted = Context.m_AbortSearch;

                if (alignmentResult != null)
                {
                    distanceBasedSolution = (LeastSquareFittedAstrometry)alignmentResult.Solution;
                    improvedSolution = (LeastSquareFittedAstrometry)alignmentResult.ImprovedSolution;
                    m_Solution = GetSolution(alignmentResult);
                    solver = alignmentResult.Solver;
                }
                else
                {
                    distanceBasedSolution = m_Solution;
                    solver = null;
                }

                if (m_SearchAborted)
                    return PerformMatchResult.SearchAborted;

            #if ASTROMETRY_DEBUG
                if (m_Solution != null)
                    // No need to keep the debug log any longer when the fit is successful
                    AstrometricFitDebugger.Reset();
            #endif
                if (m_Solution != null)
                    // Clear manually identified starting position in a case of a successful plate solve
                    m_ManualStarMatch = null;

                return m_Solution != null
                    ? PerformMatchResult.FitSucceessfull
                    : PerformMatchResult.FitImprovementFailed;

            }
            finally
            {
                // Reset the manually matched stars after every fit attempt
                m_ManualStarMatch = null;

                m_PerformanceWatch.Stop();

                if (m_Solution != null)
                {
                    if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceError())
                    {
                        Trace.WriteLine(string.Format(
                            "Pyramid Match Successful: {0} ms, {1} stars total, aligned on {2} stars, {3} stars matched {4}. Combination: {5}",
                            m_PerformanceWatch.ElapsedMilliseconds, m_CelestialStars.Count,
                            alignmentResult != null ? (alignmentResult.Solution as LeastSquareFittedAstrometry).FitInfo.NumberOfStarsUsedInSolution() : 0,
                            improvedSolution != null ? improvedSolution.FitInfo.NumberOfStarsUsedInSolution().ToString() : "N/A",
                            improvedSolution != null ? string.Format(" ({0}-{1} mag)", Context.ImprovedSolutionIncludedMinMag.ToString("0.00"), Context.ImprovedSolutionIncludedMaxMag.ToString("0.00")) : null,
                            alignmentResult != null ? alignmentResult.MatchedTriangle : null));
                    }
                }
                else
                {
                    if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceError())
                        Trace.WriteLine(string.Format("Pyramid Match Failed: {0} ms, {1} stars total, NO MATCH",
                                                      m_PerformanceWatch.ElapsedMilliseconds, m_CelestialStars.Count));

                    if (Context.DebugResolvedStars != null)
                    {
                        foreach(DistanceBasedContext.DebugTripple tripple in Context.m_DebugTripples)
                        {
                            if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose())
                                Trace.WriteLine(string.Format("DEBUG ALIGN: Missed alignment on {0}-{1}-{2}", tripple.Id1, tripple.Id2, tripple.Id3));
                        }
                    }
                }
            #if ASTROMETRY_DEBUG
                Trace.Assert(!m_DetermineAutoLimitMagnitude || m_Solution == null || m_Solution.FitInfo.DetectedLimitingMagnitude != 0);
            #endif
            }
        }
예제 #4
0
        private void ImproveSolution(LeastSquareFittedAstrometry fit, double coeff, int i, int j, int k)
		{
			m_SolutionSolver = new PlateConstantsSolver(m_PlateConfig);

			double ra0, de0;
			fit.GetRADEFromImageCoords(m_PlateConfig.CenterXImage, m_PlateConfig.CenterXImage, out ra0, out de0);
			m_SolutionSolver.InitPlateSolution(ra0, de0);

            List<IStar> consideredStars = new List<IStar>();
            List<ulong> nonStellarStars = new List<ulong>();

			foreach (IStar star in m_CelestialAllStars)
			{
				if (star.Mag < m_MinMag || star.Mag > m_MaxMag)
					continue;

				if (m_DetermineAutoLimitMagnitude && 
					!double.IsNaN(m_DetectedLimitingMagnitude) &&
					star.Mag > m_DetectedLimitingMagnitude)
				{
#if ASTROMETRY_DEBUG
					Trace.Assert(false);
#endif
					continue;
				}

				double x, y;
				fit.GetImageCoordsFromRADE(star.RADeg, star.DEDeg, out x, out y);
				if (x < 0 || x > m_PlateConfig.ImageWidth ||
					y < 0 || y > m_PlateConfig.ImageHeight)
					continue;


				ImagePixel pixel = null;
				PSFFit psfFit;
				PSFFit asymPsfFit = null; 
				//if (m_FitSettings.CenterDetectionMethod == StarCenterDetection.PSFFit)
				{
					if (m_Settings.PyramidRemoveNonStellarObject)
						m_StarMap.GetPSFFit((int)x, (int)y, PSFFittingMethod.NonLinearAsymetricFit, out asymPsfFit);

					pixel = m_StarMap.GetPSFFit((int)x, (int)y, PSFFittingMethod.NonLinearFit, out psfFit);
				}
				//else if (m_FitSettings.CenterDetectionMethod == StarCenterDetection.Centroid)
				{
					// NOTE: Centroid detection is way faster and PSF will not lead to big improvement considering the threshold for star matching
					//pixel = m_StarMap.GetCentroid((int)x, (int)y, (int)Math.Ceiling(m_Settings.SearchArea));
				}

				if (pixel != null &&
                    psfFit.Certainty >= CorePyramidConfig.Default.MinDetectionLimitForSolutionImprovement / coeff)
				{
					consideredStars.Add(star);

					double distance = fit.GetDistanceInArcSec(pixel.XDouble, pixel.YDouble, x, y);
                    if (distance < CorePyramidConfig.Default.MaxPreliminaryResidualForSolutionImprovement / coeff)
					{
#if ASTROMETRY_DEBUG
						Trace.Assert(!double.IsNaN(pixel.XDouble));
						Trace.Assert(!double.IsNaN(pixel.YDouble));
#endif

						if (
							Math.Sqrt((x - pixel.XDouble) * (x - pixel.XDouble) + (y - pixel.YDouble) * (y - pixel.YDouble)) >
                            CoreAstrometrySettings.Default.SearchArea)
							continue;

						pixel.SignalNoise = psfFit.Certainty;
						pixel.Brightness = psfFit.Brightness; 
						m_SolutionSolver.AddStar(pixel, star);

						if (m_Settings.PyramidRemoveNonStellarObject &&
							(
								asymPsfFit.FWHM < m_Settings.MinReferenceStarFWHM ||
								asymPsfFit.FWHM > m_Settings.MaxReferenceStarFWHM ||
								asymPsfFit.ElongationPercentage > m_Settings.MaximumPSFElongation)
							)
						{
							nonStellarStars.Add(star.StarNo);
						}
					}
				}
			}

			double ffl = fit.FitInfo.FittedFocalLength;
			m_ImprovedSolution = m_SolutionSolver.SolveWithLinearRegression(m_Settings, out m_FirstImprovedSolution);
            //if (m_ImprovedSolution != null && m_ImprovedSolution.FitInfo.AllStarPairs.Count < 12)
            //{
            //    // Attempt to reject errorous solutions with small number of fitted stars 
            //    int totalMatched = 0;
            //    var largeFeatures = m_StarMap.Features.Where(x => x.MaxBrightnessPixels > 1).ToList();
            //    if (largeFeatures.Count > 5)
            //    {
            //        foreach (var feature in largeFeatures)
            //        {
            //            var ftrCenter = feature.GetCenter();
            //            // TODO: PFS Fit on the feature?
            //            var matchedFittedStar = m_ImprovedSolution.FitInfo.AllStarPairs.FirstOrDefault(
            //                x =>
            //                    Math.Sqrt(Math.Pow(x.x - ftrCenter.XDouble, 2) + Math.Pow(x.x - ftrCenter.XDouble, 2)) <
            //                    2);
            //            if (matchedFittedStar != null) totalMatched++;
            //        }

            //        double percentLargeFeaturesMatched = 1.0*totalMatched/largeFeatures.Count;
            //        if (percentLargeFeaturesMatched < 0.75)
            //        {
            //            if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceInfo())
            //                Trace.WriteLine(string.Format("Only {0:0.0}% ({1} features) of the large {2} features have been matched, where 75% is required.", percentLargeFeaturesMatched*100, totalMatched, largeFeatures.Count));
            //            // At least 75% of the bright features from the video need to be matched to stars for the solution to be accepted
            //            m_ImprovedSolution = null;
            //        }
            //    }
            //}
            
            if (m_ImprovedSolution != null)
			{
				m_ImprovedSolution.FitInfo.FittedFocalLength = ffl;

                if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceWarning())
                    Trace.WriteLine(string.Format("Improved solution: {0} considered stars, UsedInSolution: {1}, ExcludedForHighResidual: {2}", 
                        m_ImprovedSolution.FitInfo.AllStarPairs.Count(), 
                        m_ImprovedSolution.FitInfo.AllStarPairs.Count(x => x.FitInfo.UsedInSolution),
                        m_ImprovedSolution.FitInfo.AllStarPairs.Count(x => x.FitInfo.ExcludedForHighResidual)));

				// Fit was successful, exclude all unused non stellar objects so they 
				// don't interfere with the included/excluded stars improved solution tests
				m_ImprovedSolution.FitInfo.AllStarPairs.RemoveAll(p =>
					(p.FitInfo.ExcludedForHighResidual || !p.FitInfo.UsedInSolution) &&
					nonStellarStars.Contains(p.StarNo));

				// NOTE: How excluding stars for FWHM/Elongation may lead to incorrectly accepted solutions that include small number of stars
				//       because the majority haven't been used for the fit. This is why we have another solution check here.
				if (m_ImprovedSolution.FitInfo.AllStarPairs.Count > 3)
				{
                    List<PlateConstStarPair> usedStarPairs = m_ImprovedSolution.FitInfo.AllStarPairs.Where(p => p.FitInfo.UsedInSolution).ToList();
                    double maxIncludedMag = usedStarPairs.Max(p => p.Mag);

                    int nonIncludedConsideredStars = consideredStars.Count(s => s.Mag <= maxIncludedMag) - usedStarPairs.Count;
                    if (nonIncludedConsideredStars > CorePyramidConfig.Default.MaxFWHMExcludedImprovemntStarsCoeff * usedStarPairs.Count)
                    {
                        LogUnsuccessfulFitImage(m_ImprovedSolution, i, j, k, 
                            string.Format("More than {0:0.0}% of the stars ({1} stars) down to mag {2:0.00} have not been matched. Attempted stars: {3}, Coeff: {4:0.00}", 
                                CorePyramidConfig.Default.MaxFWHMExcludedImprovemntStarsCoeff * 100,
                                nonIncludedConsideredStars,
                                maxIncludedMag, 
                                m_SolutionSolver.Pairs.Count, 
                                nonIncludedConsideredStars / m_SolutionSolver.Pairs.Count));
						m_ImprovedSolution = null;
						return;
					}

					List<double> intensities = usedStarPairs.Select(s => (double)s.Intensity).ToList();
					List<double> mags = usedStarPairs.Select(s => s.Mag).ToList();

                    if (usedStarPairs.Count > 3)
                    {
                        LinearRegression reg = new LinearRegression();
                        int pointsAdded = 0;
                        for (int ii = 0; ii < intensities.Count; ii++)
                        {
                            if (intensities[ii] > 0)
                            {
                                reg.AddDataPoint(intensities[ii], Math.Log10(mags[ii]));
                                pointsAdded++;
                            }
                        }

                        if (pointsAdded > 3)
                        {
                            reg.Solve();

                            if (Math.Pow(10, reg.StdDev) > CorePyramidConfig.Default.MagFitTestMaxStdDev || reg.A > CorePyramidConfig.Default.MagFitTestMaxInclination)
                            {
                                LogUnsuccessfulFitImage(m_ImprovedSolution, i, j, k, 
                                    string.Format("Failing solution for failed magnitude fit. Intensity(Log10(Magntude)) = {1} * x + {2}, StdDev = {0:0.0000}, ChiSquare = {3:0.000}", Math.Pow(10, reg.StdDev), reg.A, reg.B, reg.ChiSquare));

                                m_ImprovedSolution = null;
                                return;
                            }                            
                        }
                    }
				}
			}
		}
예제 #5
0
		private LeastSquareFittedAstrometry SolveStarPairs(
			IStarMap starMap,
			Dictionary<ImagePixel, IStar> matchedPairs,
			Dictionary<int, ulong> matchedFeatureIdToStarIdIndexes,
			ThreeStarFit.StarPair pair_i,
			ThreeStarFit.StarPair pair_j,
			ThreeStarFit.StarPair pair_k,
			double fittedFocalLength,
			PyramidEntry pyramidLog, 
            int? minMatchedStars = null)
		{
			double RA0Deg, DE0Deg;

			ThreeStarFit coarseFit = new ThreeStarFit(m_PlateConfig, pair_i, pair_j, pair_k);
			if (!coarseFit.IsSolved)
			{
				if (coarseFit.IsSingularity)
				{
                    if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose())
					    Trace.WriteLine("ThreeStarFit.Var1 - Singularity");

					Dictionary<ImagePixel, IStar> threeStarDict = new Dictionary<ImagePixel, IStar>();

				    try
				    {
                        threeStarDict.Add(ImagePixel.CreateImagePixelWithFeatureId(0, 255, pair_i.XImage, pair_i.YImage), pair_i.Star);
                        threeStarDict.Add(ImagePixel.CreateImagePixelWithFeatureId(1, 255, pair_j.XImage, pair_j.YImage), pair_j.Star);
                        threeStarDict.Add(ImagePixel.CreateImagePixelWithFeatureId(2, 255, pair_k.XImage, pair_k.YImage), pair_k.Star);
				    }
                    catch(ArgumentException)
                    {
                        if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.ThreeStarFitFailed;

                        if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose())
                            Trace.WriteLine("ThreeStarFit.Var2 - Failed with ArgumentException");

                        return null;
                    }

					DirectTransRotAstrometry threeStarSolution = 
						DirectTransRotAstrometry.SolveByThreeStars(m_PlateConfig, threeStarDict, 2);

					if (threeStarSolution == null)
					{
						if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.ThreeStarFitFailed;

                        if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose())
						    Trace.WriteLine("ThreeStarFit.Var2 - Failed");
						return null;						
					}
					else
					{
						RA0Deg = threeStarSolution.RA0Deg;
						DE0Deg = threeStarSolution.DE0Deg;
					}
				}
				else
				{
					if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.ThreeStarFitFailed;

                    if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose())
					    Trace.WriteLine("ThreeStarFit.Var1 - Failed");
					return null;					
				}
			}
			else
			{
				if (pyramidLog != null) pyramidLog.RegisterThreeStarFit(coarseFit);
				RA0Deg = coarseFit.RA0Deg;
				DE0Deg = coarseFit.DE0Deg;
			}
			

#if DEBUG || PYRAMID_DEBUG
		    if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose())
		    {
                foreach (int key in matchedFeatureIdToStarIdIndexes.Keys)
#if PYRAMID_DEBUG
                    Trace
#else
                    Debug
#endif
                    .WriteLine(string.Format("Star({0}) -> Feature({1})", matchedFeatureIdToStarIdIndexes[key], key));
		    }
#endif

            PlateConstantsSolver solver = new PlateConstantsSolver(m_PlateConfig);
			solver.InitPlateSolution(RA0Deg, DE0Deg);
		    foreach (ImagePixel feature in matchedPairs.Keys)
		    {
		        IStar star = matchedPairs[feature];
		        var kvp = matchedFeatureIdToStarIdIndexes.Single(x => x.Value == star.StarNo);
		        int featureId = kvp.Key;
                solver.AddStar(feature, star, featureId);
		    }

		    LeastSquareFittedAstrometry leastSquareFittedAstrometry = null;
			LeastSquareFittedAstrometry firstFit = null;
			try
			{
				// This is a linear regression when doing simple field alignment. We always use a Linear Fit
				leastSquareFittedAstrometry = solver.SolveWithLinearRegression(
					FitOrder.Linear,
				 	CorePyramidConfig.Default.MinPyramidAlignedStars,
					m_MaxLeastSquareResidual, 
					out firstFit);
			}
			catch (DivideByZeroException)
			{ }

			if (leastSquareFittedAstrometry != null)
			{
				if (pyramidLog != null) pyramidLog.RegisterLinearFit(leastSquareFittedAstrometry);

                if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose())
				    Trace.WriteLine("Checking possible solution. ");

				List<ulong> usedStarIds = leastSquareFittedAstrometry.FitInfo.AllStarPairs
					.Where(p => p.FitInfo.UsedInSolution)
					.Select(p => p.StarNo)
					.ToList();

				int usedStars = usedStarIds.Count;

				matchedFeatureIdToStarIdIndexes = matchedFeatureIdToStarIdIndexes
					.Where(kvp => usedStarIds.Contains(kvp.Value))
					.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

				List<double> residuals = 
					leastSquareFittedAstrometry.FitInfo.AllStarPairs
						.Where(p => !p.FitInfo.ExcludedForHighResidual)
						.Select(p => p.FitInfo.ResidualArcSec)
						.ToList();


				double secondLargeResidual = 0;

				if (residuals.Count > 0)
				{
					residuals = residuals.OrderByDescending(r => r).ToList();
					secondLargeResidual = residuals.Count > 1 ? residuals[1] : residuals[0];
				}

				double onePixDistArcSec = m_PlateConfig.GetDistanceInArcSec(0, 0, 1, 1);
				if (secondLargeResidual > onePixDistArcSec * CorePyramidConfig.Default.MaxAllowedResidualInPixelsInSuccessfulFit)
				{
					if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.SecondLargestResidualIsTooLarge;

                    if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose())
					    Trace.WriteLine(string.Format(
						    "Failing preliminary solution because the second largest residual {0}\" is larger than {1}px",
						    secondLargeResidual.ToString("0.0"), CorePyramidConfig.Default.MaxAllowedResidualInPixelsInSuccessfulFit));

					return null;
				}

                if (minMatchedStars.HasValue)
				{
                    if (usedStars < minMatchedStars.Value)
					{
						if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.InsufficientStarsForCalibration;

                        if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose())
						    Trace.WriteLine(string.Format(
						    "Failing preliminary solution because on {0} stars are used but {1} are required as a minimum for calibration.",
						    usedStars, CorePyramidConfig.Default.MinMatchedStarsForCalibration));

						return null;
					}
				}
			}
			else
			{
				if (pyramidLog != null) pyramidLog.FailureReason = PyramidEntryFailureReason.LinearFitFailed;

			    if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose())
			    {
                    Debug.WriteLine("DistanceBasedContext.LeastSquareFittedAstrometry Failed!");

                    foreach (PlateConstStarPair pair in solver.Pairs)
                    {
#if PYRAMID_DEBUG
                        Trace
#else
                        Debug
#endif
                        .WriteLine(string.Format("{0} ({1}) -> Residuals: {2}\", {3}\"", pair.StarNo,
                                                      pair.FitInfo.UsedInSolution ? "Included" : "Excluded",
                                                      pair.FitInfo.ResidualRAArcSec.ToString("0.00"),
                                                      pair.FitInfo.ResidualDEArcSec.ToString("0.00")));
                    }

			    }
			}

			if (leastSquareFittedAstrometry != null)
			{
				leastSquareFittedAstrometry.FitInfo.FittedFocalLength = fittedFocalLength;
				if (pyramidLog != null) pyramidLog.RegisterFocalLength(fittedFocalLength);
			}

			return leastSquareFittedAstrometry;
		}
예제 #6
0
        /// <summary>
        /// Used to calibrate a plate. Does the more precise astrometric fit
        /// Precondition: A coarser (m_PreliminaryFit) is required where the user has visually roughly fitted the stars to the plate
        /// </summary>
        /// <param name="limitMag">The faintest magnitude of a star to be used for the fit</param>
        /// <param name="fineFit">Used to determine the search area for the stars. When the fit is not a 'fine' fit then 2.5 times
        /// larger are is used for the fit</param>
        public bool SolvePlateConstantsPhase1(double limitMag, bool fineFit)
        {
            int             searchDistance = 10;
            IAstrometricFit previousFit;

            if (!fineFit)
            {
                searchDistance = ((int)Math.Ceiling(2.5 * CoreAstrometrySettings.Default.SearchArea) + 1);
                previousFit    = m_Context.PreliminaryFit;
            }
            else
            {
                searchDistance = (int)Math.Ceiling(CoreAstrometrySettings.Default.SearchArea) + 1;
                previousFit    = m_Context.FirstAstrometricFit;
            }

            m_ConstantsSolver = new PlateConstantsSolver(m_Context.PlateConfig);


            // NOTE: Get the coordinates of the center of the plate.
            double ra0deg, de0Deg;

            previousFit.GetRADEFromImageCoords(
                m_Context.PlateConfig.CenterXImage, m_Context.PlateConfig.CenterYImage, out ra0deg, out de0Deg);

            m_ConstantsSolver.InitPlateSolution(ra0deg, de0Deg);


            #region PASS 1 - Only using the stars down to limitMag

            int idx = -1;
            foreach (IStar star in m_Context.FieldSolveContext.CatalogueStars)
            {
                idx++;

                double x, y;
                previousFit.GetImageCoordsFromRADE(star.RADeg, star.DEDeg, out x, out y);

                if (m_Context.FitExcludeArea.Contains((int)x, (int)y))
                {
                    continue;
                }

                if (x < 0 || x > m_Context.PlateConfig.ImageWidth || y < 0 || y > m_Context.PlateConfig.ImageHeight)
                {
                    continue;
                }

                if (limitMag < star.Mag)
                {
                    continue;
                }

                StarMapFeature feature = m_Context.StarMap.GetFeatureInRadius((int)x, (int)y, searchDistance);

                Trace.WriteLine(string.Format("Searching for {0} ({1:0.0} mag) at ({2:0.0},{3:0.0}).{4}Found!", star.GetStarDesignation(0), star.Mag, x, y, feature != null ? "" : "NOT "));

                if (fineFit)
                {
                    ImagePixel centroid = m_Context.StarMap.GetCentroid((int)x, (int)y, searchDistance);
                    if (centroid != null)
                    {
                        if (centroid.SignalNoise >= m_AstrometrySettings.DetectionLimit)
                        {
                            if (!m_Context.FitExcludeArea.Contains(centroid.X, centroid.Y))
                            {
                                // NOTE: Don't add a star if outside the selected area
                                m_ConstantsSolver.AddStar(centroid, star, feature);
                            }
                        }
                    }
                    else
                    {
                        //Trace.WriteLine("m_SolvePlateConts.NoMatch:" + star.StarNo);
                    }
                }
                else if (feature != null)
                {
                    ImagePixel plateStar = feature.GetCenter();
                    if (!m_Context.FitExcludeArea.Contains(plateStar.X, plateStar.Y))
                    {
                        // NOTE: Don't add a star if outside the selected area
                        m_ConstantsSolver.AddStar(plateStar, star, feature);
                    }
                }
                else
                {
                    //Trace.WriteLine("m_SolvePlateConts.NoMatch:" + star.StarNo);
                }
            }

            // TODO: Shouldn't this be comming from the settings??
            return(m_ConstantsSolver.Pairs.Count >= 4);

            #endregion
        }