Пример #1
0
        public void NextFrame(int frameNo, IAstroImage astroImage, IStarMap starMap, LeastSquareFittedAstrometry astrometricFit)
        {
            IsTrackedSuccessfully = false;

            ImagePixel centroid = AstrometryContext.Current.StarMap.GetCentroid(
                (int)TrackedObject.LastKnownX,
                (int)TrackedObject.LastKnownY,
                CoreAstrometrySettings.Default.PreMeasureSearchCentroidRadius);

            if (centroid != null)
            {
                PSFFit psfFit;
                AstrometryContext.Current.StarMap.GetPSFFit(
                    centroid.X, centroid.Y, PSFFittingMethod.NonLinearFit, out psfFit);

                if (psfFit != null)
                {
                    double ra, de;
                    astrometricFit.GetRADEFromImageCoords(psfFit.XCenter, psfFit.YCenter, out ra, out de);

                    double maxPosDiffArcSec =
                        astrometricFit.GetDistanceInArcSec(astrometricFit.Image.CenterXImage, astrometricFit.Image.CenterYImage,
                                                           astrometricFit.Image.CenterXImage + CoreAstrometrySettings.Default.PreMeasureSearchCentroidRadius, astrometricFit.Image.CenterYImage);

                    if (!double.IsNaN(TrackedObject.RAHours))
                    {
                        double posDif = 3600 * AngleUtility.Elongation(15 * TrackedObject.RAHours, TrackedObject.DEDeg, ra, de);
                        if (posDif > maxPosDiffArcSec)
                        {
                            // NOTE: Not a valid measurement
                            Trace.WriteLine(string.Format("The target position is too far from the last measured position", posDif));
                            return;
                        }
                    }

                    TrackedObject.RAHours    = ra / 15.0;
                    TrackedObject.DEDeg      = de;
                    TrackedObject.LastKnownX = psfFit.XCenter;
                    TrackedObject.LastKnownY = psfFit.YCenter;
                    TrackedObject.PSFFit     = psfFit;

                    IsTrackedSuccessfully = true;
                }
            }
        }
Пример #2
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;
                            }                            
                        }
                    }
				}
			}
		}
Пример #3
0
        public void NextFrame(int frameNo, IAstroImage astroImage, IStarMap starMap, LeastSquareFittedAstrometry astrometricFit)
        {
            IsTrackedSuccessfully = false;
            int searchRadius = (int)Math.Ceiling(Math.Max(m_LastMovementPixels, CoreAstrometrySettings.Default.PreMeasureSearchCentroidRadius));

            PSFFit psfFit = null;

            int startingX = (int)TrackedObject.LastKnownX;
            int startingY = (int)TrackedObject.LastKnownY;

            if (m_RepeatedIntergationPositions * 4 < m_PastFrameNos.Count)
            {
                var expectedPos = GetExpectedPosition(frameNo);
                if (expectedPos != null)
                {
                    startingX = expectedPos.X;
                    startingY = expectedPos.Y;
                }
            }

            var nearbyFeatures = starMap.GetFeaturesInRadius(startingX, startingY, searchRadius).ToArray();

            var nonStarNearbyFeature = new List <StarMapFeature>();

            foreach (var feature in nearbyFeatures)
            {
                var center = feature.GetCenter();
                var referenceStarFeatures = astrometricFit.FitInfo.AllStarPairs.Where(x => x.FitInfo.UsedInSolution).ToList();
                var refStar = referenceStarFeatures.FirstOrDefault(s => Math.Sqrt((s.x - center.X) * (s.x - center.X) + (s.y - center.Y) * (s.y - center.Y)) < 2);

                double raf, def;
                astrometricFit.GetRADEFromImageCoords(center.XDouble, center.YDouble, out raf, out def);
                var pastKnownStar = m_LastFrameStars.FirstOrDefault(s => AngleUtility.Elongation(s.RADeg, s.DEDeg, raf, def) * 3600.0 < 2);

                if (refStar == null && pastKnownStar == null)
                {
                    nonStarNearbyFeature.Add(feature);
                }
            }

            if (nonStarNearbyFeature.Count > 0)
            {
                StarMapFeature closestFeature   = nonStarNearbyFeature[0];
                var            lastKnownCenter  = new ImagePixel(TrackedObject.LastKnownX, TrackedObject.LastKnownY);
                var            smallestDistance = lastKnownCenter.DistanceTo(closestFeature.GetCenter());

                for (int i = 1; i < nonStarNearbyFeature.Count; i++)
                {
                    var distance = lastKnownCenter.DistanceTo(nonStarNearbyFeature[i].GetCenter());
                    if (distance < smallestDistance)
                    {
                        smallestDistance = distance;
                        closestFeature   = nonStarNearbyFeature[i];
                    }
                }

                if (closestFeature != null)
                {
                    var center = closestFeature.GetCenter();
                    AstrometryContext.Current.StarMap.GetPSFFit(center.X, center.Y, PSFFittingMethod.NonLinearFit, out psfFit);
                }
            }

            if (psfFit == null)
            {
                // The expected location cannot be matched with any brighter feature so it is likely a faint object
                // with no brighter objects around. Lets find the brightest (faint) object in the are and use it
                ImagePixel centroid = AstrometryContext.Current.StarMap.GetCentroid(startingX, startingY, searchRadius);

                if (centroid != null)
                {
                    AstrometryContext.Current.StarMap.GetPSFFit(centroid.X, centroid.Y, PSFFittingMethod.NonLinearFit, out psfFit);
                }
            }

            if (psfFit != null)
            {
                double ra, de;
                astrometricFit.GetRADEFromImageCoords(psfFit.XCenter, psfFit.YCenter, out ra, out de);

                double maxPosDiffArcSec =
                    astrometricFit.GetDistanceInArcSec(astrometricFit.Image.CenterXImage, astrometricFit.Image.CenterYImage,
                                                       astrometricFit.Image.CenterXImage + Math.Max(m_LastMovementPixels, CoreAstrometrySettings.Default.MaxAllowedDefaultMotionInPixels), astrometricFit.Image.CenterYImage);

                if (!double.IsNaN(TrackedObject.RAHours))
                {
                    double posDif = 3600 * AngleUtility.Elongation(15 * TrackedObject.RAHours, TrackedObject.DEDeg, ra, de);
                    if (posDif > maxPosDiffArcSec)
                    {
                        // NOTE: Not a valid measurement
                        Trace.WriteLine(string.Format("The target position is too far from the last measured position", posDif));
                        return;
                    }
                }

                TrackedObject.RAHours = ra / 15.0;
                TrackedObject.DEDeg   = de;

                if (TrackedObject.PSFFit != null)
                {
                    m_LastMovementPixels = 1.2 * ImagePixel.ComputeDistance(TrackedObject.LastKnownX, psfFit.XCenter, TrackedObject.LastKnownY, psfFit.YCenter);
                }
                TrackedObject.LastKnownX = psfFit.XCenter;
                TrackedObject.LastKnownY = psfFit.YCenter;
                TrackedObject.PSFFit     = psfFit;

                var lastKnownCenter = new ImagePixel(TrackedObject.LastKnownX, TrackedObject.LastKnownY);
                var thisFrameStars  = astrometricFit.FitInfo.AllStarPairs.Where(x => lastKnownCenter.DistanceTo(x.x, x.y) > 2 * psfFit.FWHM).ToList();
                if (thisFrameStars.Count > 0)
                {
                    m_LastFrameStars = thisFrameStars.Select(x => new Star(x.StarNo, x.RADeg, x.DEDeg, x.Mag) as IStar).ToList();
                }

                IsTrackedSuccessfully = true;
            }

            if (psfFit != null && psfFit.XCenter > 0 && psfFit.YCenter > 0)
            {
                m_PastFramePosX.Add(psfFit.XCenter);
                m_PastFramePosY.Add(psfFit.YCenter);
                m_PastFrameNos.Add(frameNo);
            }
        }
Пример #4
0
        public LeastSquareFittedAstrometry SolvePlateConstantsPhase4(double pyramidLimitMag)
        {
            double ra0deg, de0Deg;

            m_SolvedPlate.GetRADEFromImageCoords(m_SolvedPlate.Image.CenterXImage, m_SolvedPlate.Image.CenterYImage, out ra0deg, out de0Deg);

            FocalLengthFit distFit = m_ConstantsSolver.ComputeFocalLengthFit();

            m_Context.PlateConfig.EffectiveFocalLength = m_Context.FieldSolveContext.FocalLength;
            distFit.GetFocalParameters(m_Context.PlateConfig.EffectiveFocalLength, out m_Context.PlateConfig.EffectivePixelWidth, out m_Context.PlateConfig.EffectivePixelHeight);

            DistanceBasedAstrometrySolver distMatch = new DistanceBasedAstrometrySolver(
                m_AstrometryController,
                m_Context.PlateConfig,
                m_AstrometrySettings,
                m_Context.FieldSolveContext.CatalogueStars,
                m_Context.FieldSolveContext.RADeg,
                m_Context.FieldSolveContext.DEDeg,
                m_Context.FieldSolveContext.DetermineAutoLimitMagnitude);

            distMatch.SetMinMaxMagOfStarsForAstrometry(CorePyramidConfig.Default.DefaultMinAstrometryMagnitude, 18);

            distMatch.SetMinMaxMagOfStarsForPyramidAlignment(CorePyramidConfig.Default.DefaultMinPyramidMagnitude, pyramidLimitMag);
            Trace.WriteLine(string.Format("Stars for alignment in range: {0:0.0} - {1:0.0} mag", CorePyramidConfig.Default.DefaultMinPyramidMagnitude, pyramidLimitMag));

            Dictionary <PSFFit, IStar> manualStars = null;
            var threeStarFit = m_Context.PreliminaryFit as ThreeStarAstrometry;

            if (threeStarFit != null)
            {
                manualStars = new Dictionary <PSFFit, IStar>();
                foreach (var kvp in threeStarFit.UserStars)
                {
                    PSFFit psfFit;
                    m_Context.StarMap.GetPSFFit(kvp.Key.X, kvp.Key.Y, PSFFittingMethod.NonLinearFit, out psfFit);
                    if (psfFit != null && psfFit.IsSolved)
                    {
                        manualStars.Add(psfFit, kvp.Value);
                    }
                }
            }

            distMatch.InitNewMatch(m_Context.StarMap, PyramidMatchType.PlateSolve, manualStars);

#if ASTROMETRY_DEBUG
            Dictionary <int, ulong> debugInfo = new Dictionary <int, ulong>();

            var starList = m_Context.SecondAstrometricFit.FitInfo.AllStarPairs
                           .Where(p => !p.FitInfo.ExcludedForHighResidual);

            foreach (var x in starList)
            {
                if (!debugInfo.ContainsKey(x.FeatureId))
                {
                    debugInfo.Add(x.FeatureId, x.StarNo);
                }
            }

            foreach (var f in m_Context.StarMap.Features)
            {
                Trace.WriteLine(string.Format("{0} - {1}", f.FeatureId, debugInfo.ContainsKey(f.FeatureId) ? "INCLUDED" : "MISSING"));
            }

            distMatch.SetDebugData(new DistanceBasedAstrometrySolver.PyramidDebugContext()
            {
                ResolvedStars       = debugInfo,
                ResolvedFocalLength = m_Context.SecondAstrometricFit.FitInfo.FittedFocalLength
            });
#endif

            LeastSquareFittedAstrometry fit         = null;
            LeastSquareFittedAstrometry improvedFit = null;
            PlateConstantsSolver        solver;
            distMatch.PerformMatch(out fit, out improvedFit, out solver);

            m_Context.DistanceBasedFit         = fit;
            m_Context.ImprovedDistanceBasedFit = improvedFit;

            if (fit != null)
            {
                m_Context.PlateConstants = new TangraConfig.PersistedPlateConstants
                {
                    EffectiveFocalLength = m_Context.PlateConfig.EffectiveFocalLength,
                    EffectivePixelWidth  = m_Context.PlateConfig.EffectivePixelWidth,
                    EffectivePixelHeight = m_Context.PlateConfig.EffectivePixelHeight
                };

                m_Context.ConstantsSolver = solver;

                if (improvedFit != null)
                {
                    foreach (var pair in improvedFit.FitInfo.AllStarPairs)
                    {
                        if (pair.FitInfo.ExcludedForHighResidual)
                        {
                            continue;
                        }

                        Trace.WriteLine(string.Format("{6}; {0}; {1}; {2}; {3}; ({4}\", {5}\")",
                                                      pair.RADeg, pair.DEDeg, pair.x.ToString("0.00"), pair.y.ToString("0.00"),
                                                      pair.FitInfo.ResidualRAArcSec.ToString("0.00"), pair.FitInfo.ResidualDEArcSec.ToString("0.00"),
                                                      pair.StarNo));

                        double x, y;
                        improvedFit.GetImageCoordsFromRADE(pair.RADeg, pair.DEDeg, out x, out y);
                        double dist = improvedFit.GetDistanceInArcSec(x, y, pair.x, pair.y);
                    }
                }
            }
            else
            {
                m_Context.PlateConstants = null;
            }

            return(fit);
        }