public void Test2_NearSouthPole() { var matrix = new CCDMatrix(8.6, 8.3, 752, 582); var astroPlate = new AstroPlate(matrix, 720, 576, 16); var userStars = new Dictionary<ImagePixel, IStar>(); var star1 = new TestStar(670000669, 14.040622402203727, -76.691539882008868, 13.389); var pixel1 = new ImagePixel(111.28789147012657, 170.18336583345945); userStars.Add(pixel1, star1); var star2 = new TestStar(680000642, 13.3447869927272, -76.594950217617452, 9.932); var pixel2 = new ImagePixel(575.00594900921817, 446.45890095859744); userStars.Add(pixel2, star2); var star3 = new TestStar(670000641, 13.550035599758042, -76.722167259223085, 13.842); var pixel3 = new ImagePixel(425.86138030460097, 63.057739094752051); userStars.Add(pixel3, star3); var newAstro = new ThreeStarAstrometry(astroPlate, userStars, 2); Assert.IsTrue(newAstro.Success); Assert.AreEqual(-76.6498, newAstro.DE0Deg, 0.0001); Assert.AreEqual(13.6644, newAstro.RA0Deg, 0.0001); double ra, de; newAstro.GetRADEFromImageCoords(111.28789147012657, 170.18336583345945, out ra, out de); Assert.AreEqual(14.0406224, ra, 0.0000001); Assert.AreEqual(-76.6915398, de, 0.0000001); double x, y; newAstro.GetImageCoordsFromRADE(14.040622402203727, -76.691539882008868, out x, out y); Assert.AreEqual(111.2879, x, 0.0001); Assert.AreEqual(170.1833, y, 0.0001); }
public static ImagePixel CreateImagePixelWithFeatureId(int featureId, int brightness, double x, double y) { var rv = new ImagePixel(brightness, x, y); rv.FeautureId = featureId; return(rv); }
public ObjectClickEventArgs(ImagePixel pixel, PSFFit gausian, Point location, bool shiftHeld, bool ctrlHeld, MouseEventArgs mouseEventArgs) { ClickLocation = location; Pixel = pixel; Gausian = gausian; Shift = shiftHeld; Control = ctrlHeld; MouseEventArgs = mouseEventArgs; }
public void SetTrackedObjectMatch(PSFFit psfFitMatched) { PSFFit = psfFitMatched; Center = new ImagePixel((int)psfFitMatched.IMax, psfFitMatched.XCenter, psfFitMatched.YCenter); IsLocated = true; NotMeasuredReasons = NotMeasuredReasons.TrackedSuccessfully; if (PSFFit != null && PSFFit.IsSolved) { LastKnownGoodPosition = new ImagePixel(Center.Brightness, Center.XDouble, Center.YDouble); LastKnownGoodPsfCertainty = PSFFit.Certainty; } }
public PyramidEntry(int i, int j, int k, ImagePixel iPixel, ImagePixel jPixel, ImagePixel kPixel, ulong iStarNo, ulong jStarNo, ulong kStarNo) { Xi = iPixel.XDouble; Yi = iPixel.YDouble; Xj = jPixel.XDouble; Yj = jPixel.YDouble; Xk = kPixel.XDouble; Yk = kPixel.YDouble; SNi = iStarNo; SNj = jStarNo; SNk = kStarNo; this.i = i; this.j = j; this.k = k; }
public void Test1() { var matrix = new CCDMatrix(8.6, 8.3, 752, 582); var astroPlate = new AstroPlate(matrix, 720, 576, 8); var userStars = new Dictionary<ImagePixel, IStar>(); var star1 = new TestStar(2890001240, 18.528885242458674, -32.262447583319769, 11.033); var pixel1 = new ImagePixel(72.0519465443632, 240.48754416283302); userStars.Add(pixel1, star1); var star2 = new TestStar(2890001234, 18.353495385568369, -32.296976944037546, 12.294); var pixel2 = new ImagePixel(421.79863331879409, 329.57539665223919); userStars.Add(pixel2, star2); var star3 = new TestStar(2890001229, 18.284537781225755, -32.213242615932892, 10.882); var pixel3 = new ImagePixel(559.51676838260289, 114.86160161500557); userStars.Add(pixel3, star3); var plateSolve = DirectTransRotAstrometry.SolveByThreeStars(astroPlate, userStars, 2); Assert.IsNotNull(plateSolve); Assert.AreEqual(1.2836, plateSolve.Aspect, 0.0001); Assert.AreEqual(-32.2808, plateSolve.DE0Deg, 0.0001); Assert.AreEqual(18.3845, plateSolve.RA0Deg, 0.0001); Assert.AreEqual(179.9401, plateSolve.EtaDeg, 0.0001); Assert.AreEqual(0.00, plateSolve.Residual, 0.01); var newAstro = new ThreeStarAstrometry(astroPlate, userStars, 2); Assert.IsTrue(newAstro.Success); Assert.AreEqual(-32.2808, newAstro.DE0Deg, 0.0001); Assert.AreEqual(18.3845, newAstro.RA0Deg, 0.0001); double ra, de; newAstro.GetRADEFromImageCoords(72.0519465443632, 240.48754416283302, out ra, out de); Assert.AreEqual(18.5288852, ra, 0.0000001); Assert.AreEqual(-32.2624475, de, 0.0000001); double x, y; newAstro.GetImageCoordsFromRADE(18.528885242458674, -32.262447583319769, out x, out y); Assert.AreEqual(72.0519, x, 0.0001); Assert.AreEqual(240.4875, y, 0.0001); }
internal NotMeasuredReasons DoNonLinearProfileFittingPhotometry( PSFFit fit, uint[,] matrix, int x0Int, int y0Int, float x0, float y0, float aperture, int matrixSize, bool useNumericalQadrature, bool isFullyDisappearingOccultedStar, uint[,] backgroundArea, bool mayBeOcculted /* Some magic based on a pure guess */, double refinedFWHM, float bgAnnulusFactor) { double distance = ImagePixel.ComputeDistance(fit.XCenter, x0, fit.YCenter, y0); double tolerance = isFullyDisappearingOccultedStar ? m_TimesHigherPositionToleranceForFullyOccultedStars * m_PositionTolerance : m_PositionTolerance; if (fit.IsSolved) { SetPsfFitReading(fit, aperture, useNumericalQadrature, backgroundArea, bgAnnulusFactor); } else { m_Aperture = aperture; m_XCenter = (float)fit.X0_Matrix; m_YCenter = (float)fit.Y0_Matrix; m_TotalReading = 0; m_TotalBackground = 0; } if (!fit.IsSolved || // The PSF solution failed, mark the reading invalid (distance > tolerance && !mayBeOcculted) || // If this doesn't look like a full disappearance, then make the reading invalid (fit.FWHM < 0.5 * refinedFWHM || fit.FWHM > 1.5 * refinedFWHM) // The FWHM is too small or too large, make the reading invalid ) { return(!fit.IsSolved ? NotMeasuredReasons.MeasurementPSFFittingFailed : (distance > tolerance && !mayBeOcculted) ? NotMeasuredReasons.DistanceToleranceTooHighForNonFullDisappearingOccultedStar : NotMeasuredReasons.FWHMOutOfRange); } else { return(NotMeasuredReasons.MeasuredSuccessfully); } }
internal NotMeasuredReasons DoLinearProfileFittingOfAveragedMoodelPhotometry( PSFFit fit, uint[,] matrix, int x0Int, int y0Int, float x0, float y0, float modelFWHM, float aperture, int matrixSize, bool useNumericalQadrature, bool isFullyDisappearingOccultedStar, uint[,] backgroundArea, bool mayBeOcculted /* Some magic based on a pure guess */, float bgAnnulusFactor, IBackgroundModelProvider backgroundModel) { double distance = ImagePixel.ComputeDistance(fit.XCenter, x0, fit.YCenter, y0); double tolerance = isFullyDisappearingOccultedStar ? m_TimesHigherPositionToleranceForFullyOccultedStars * m_PositionTolerance : m_PositionTolerance; // We first go and do the measurement anyway if (fit.IsSolved) { SetPsfFitReading(fit, aperture, useNumericalQadrature, backgroundArea, bgAnnulusFactor, backgroundModel); } else { m_Aperture = aperture; m_XCenter = (float)fit.X0_Matrix; m_YCenter = (float)fit.Y0_Matrix; m_TotalReading = 0; m_TotalBackground = 0; } if (!fit.IsSolved || // The PSF solution failed, mark the reading invalid (distance > tolerance && !mayBeOcculted) // If this doesn't look like a full disappearance, then make the reading invalid ) { return(!fit.IsSolved ? NotMeasuredReasons.MeasurementPSFFittingFailed : NotMeasuredReasons.DistanceToleranceTooHighForNonFullDisappearingOccultedStar); } else { return(NotMeasuredReasons.MeasuredSuccessfully); } }
private void TrackSingleStar(int frameNo, IAstroImage astroImage) { TrackedStar.NewFrame(); float expectedX; float expectedY; GetExpectedXY(out expectedX, out expectedY); uint[,] pixels = astroImage.GetPixelsArea((int)expectedX, (int)expectedY, FIT_AREA); // There is only one object in the area, just do a wide fit followed by a fit with the selected matrix size PSFFit gaussian = new PSFFit((int)expectedX, (int)expectedY); gaussian.Fit(pixels, FIT_AREA); IImagePixel firstCenter = new ImagePixel((int)gaussian.XCenter, (int)gaussian.YCenter); pixels = astroImage.GetPixelsArea(firstCenter.X, firstCenter.Y, FIT_AREA); gaussian = new PSFFit(firstCenter.X, firstCenter.Y); gaussian.Fit(pixels, TrackedStar.PsfFitMatrixSize); if (gaussian.IsSolved) { TrackedStar.PSFFit = gaussian; TrackedStar.ThisFrameX = (float)gaussian.XCenter; TrackedStar.ThisFrameY = (float)gaussian.YCenter; TrackedStar.ThisSignalLevel = (float)(gaussian.IMax - gaussian.I0); TrackedStar.ThisFrameCertainty = (float)gaussian.Certainty; TrackedStar.SetIsLocated(true, NotMeasuredReasons.TrackedSuccessfully); } else { TrackedStar.ThisFrameX = expectedX; TrackedStar.ThisFrameY = expectedY; TrackedStar.ThisFrameCertainty = (float)gaussian.Certainty; Trace.WriteLine(string.Format("Frame {0}: Cannot confirm target {1} [SingleStar]. Cannot solve second PSF", m_FrameNo, TrackedStar.TargetNo)); TrackedStar.SetIsLocated(false, NotMeasuredReasons.PSFFittingFailed); } }
public static void PreProcessingAddRemoveHotPixels(uint[,] model, ImagePixel[] pixels, uint imageMedian, uint maxPixelValue) { uint[] xPos = pixels.Select(x => (uint)x.X).ToArray(); uint[] yPos = pixels.Select(x => (uint)x.Y).ToArray(); uint[] flatModel = Pixelmap.ConvertFromXYToFlatArray(model, 7, 7); PreProcessingAddRemoveHotPixels(flatModel, (uint)xPos.Length, xPos, yPos, imageMedian, maxPixelValue); }
public void MergePixels(StarMapFeature mergeWith) { bool pixelsMerged = false; foreach (ulong idx in mergeWith.m_Pixels.Keys) { if (!this.m_Pixels.ContainsKey(idx)) { this.m_Pixels.Add(idx, mergeWith.m_Pixels[idx]); pixelsMerged = true; } } if (pixelsMerged) m_Merges++; m_Center = null; }
public override void DoManualFrameCorrection(int targetId, int deltaX, int deltaY) { int firstFrameId = m_PreviousPositionFrameIds[0]; float expectedX = (float)m_LinearFitX.ComputeY(m_FrameNo - firstFrameId); float expectedY = (float)m_LinearFitY.ComputeY(m_FrameNo - firstFrameId); m_PreviousPositions.Clear(); m_PreviousPositionFrameIds.Clear(); ImagePixel newCenter = new ImagePixel(expectedX + deltaX, expectedY + deltaY); m_PreviousPositions.Add(newCenter); m_PreviousPositionFrameIds.Add(m_FrameNo); m_PreviousPositions.Add(newCenter); m_PreviousPositionFrameIds.Add(m_FrameNo - 1); m_PreviousPositions.Add(newCenter); m_PreviousPositionFrameIds.Add(m_FrameNo - 2); DoLinearFit(); }
public static StarMagnitudeFit PerformFit( IAstrometryController astrometryController, IVideoController videoController, int bitPix, uint maxSignalValue, FitInfo astrometricFit, TangraConfig.PhotometryReductionMethod photometryReductionMethod, TangraConfig.PsfQuadrature psfQuadrature, TangraConfig.PsfFittingMethod psfFittingMethod, TangraConfig.BackgroundMethod photometryBackgroundMethod, TangraConfig.PreProcessingFilter filter, List<IStar> catalogueStars, Guid magnitudeBandId, float encodingGamma, TangraConfig.KnownCameraResponse reverseCameraResponse, float? aperture, float? annulusInnerRadius, int? annulusMinPixels, ref float empericalPSFR0) { uint saturatedValue = TangraConfig.Settings.Photometry.Saturation.GetSaturationForBpp(bitPix, maxSignalValue); MeasurementsHelper measurer = new MeasurementsHelper( bitPix, photometryBackgroundMethod, TangraConfig.Settings.Photometry.SubPixelSquareSize, saturatedValue); measurer.SetCoreProperties( annulusInnerRadius ?? TangraConfig.Settings.Photometry.AnnulusInnerRadius, annulusMinPixels ?? TangraConfig.Settings.Photometry.AnnulusMinPixels, CorePhotometrySettings.Default.RejectionBackgroundPixelsStdDev, 2 /* TODO: This must be configurable */); var bgProvider = new BackgroundProvider(videoController); measurer.GetImagePixelsCallback += new MeasurementsHelper.GetImagePixelsDelegate(bgProvider.measurer_GetImagePixelsCallback); List<double> intencities = new List<double>(); List<double> magnitudes = new List<double>(); List<double> colours = new List<double>(); List<double> residuals = new List<double>(); List<bool> saturatedFlags = new List<bool>(); List<IStar> stars = new List<IStar>(); List<PSFFit> gaussians = new List<PSFFit>(); List<MagFitRecord> fitRecords = new List<MagFitRecord>(); AstroImage currentAstroImage = videoController.GetCurrentAstroImage(false); Rectangle osdRectToExclude = astrometryController.OSDRectToExclude; Rectangle rectToInclude = astrometryController.RectToInclude; bool limitByInclusion = astrometryController.LimitByInclusion; int matSize = CorePhotometrySettings.Default.MatrixSizeForCalibratedPhotometry; double a = double.NaN; double b = double.NaN; double c = double.NaN; int excludedStars = 0; double empericalFWHM = double.NaN; try { foreach (PlateConstStarPair pair in astrometricFit.AllStarPairs) { if (limitByInclusion && !rectToInclude.Contains((int)pair.x, (int)pair.y)) continue; if (!limitByInclusion && osdRectToExclude.Contains((int)pair.x, (int)pair.y)) continue; IStar star = catalogueStars.Find(s => s.StarNo == pair.StarNo); if (star == null || double.IsNaN(star.Mag) || star.Mag == 0) continue; uint[,] data = currentAstroImage.GetMeasurableAreaPixels((int)pair.x, (int)pair.y, matSize); PSFFit fit = new PSFFit((int)pair.x, (int)pair.y); fit.Fit(data, PSF_FIT_AREA_SIZE); if (!fit.IsSolved) continue; MagFitRecord record = new MagFitRecord(); record.Star = star; record.Pair = pair; record.PsfFit = fit; record.Saturation = IsSaturated(data, matSize, saturatedValue); if (!EXCLUDE_SATURATED_STARS || !record.Saturation) fitRecords.Add(record); } // We need the average R0 if it hasn't been determined yet if (float.IsNaN(empericalPSFR0)) { empericalPSFR0 = 0; foreach (MagFitRecord rec in fitRecords) { empericalPSFR0 += (float)rec.PsfFit.R0; } empericalPSFR0 /= fitRecords.Count; } empericalFWHM = 2 * Math.Sqrt(Math.Log(2)) * empericalPSFR0; foreach (MagFitRecord record in fitRecords) { ImagePixel center = new ImagePixel(255, record.Pair.x, record.Pair.y); int areaSize = filter == TangraConfig.PreProcessingFilter.NoFilter ? 17 : 19; int centerX = (int)Math.Round(center.XDouble); int centerY = (int)Math.Round(center.YDouble); uint[,] data = currentAstroImage.GetMeasurableAreaPixels(centerX, centerY, areaSize); uint[,] backgroundPixels = currentAstroImage.GetMeasurableAreaPixels(centerX, centerY, 35); measurer.MeasureObject( center, data, backgroundPixels, currentAstroImage.Pixelmap.BitPixCamera, filter, photometryReductionMethod, psfQuadrature, psfFittingMethod, aperture != null ? aperture.Value : (float)Aperture(record.PsfFit.FWHM), record.PsfFit.FWHM, (float)empericalFWHM, new FakeIMeasuredObject(record.PsfFit), null, null, false); double intensity = measurer.TotalReading - measurer.TotalBackground; if (intensity > 0) { var mag = record.Star.GetMagnitudeForBand(magnitudeBandId); var clr = record.Star.MagJ - record.Star.MagK; if (!double.IsNaN(mag) && !double.IsNaN(clr) && !double.IsInfinity(mag) && !double.IsInfinity(clr)) { intencities.Add(intensity); magnitudes.Add(record.Star.GetMagnitudeForBand(magnitudeBandId)); colours.Add(record.Star.MagJ - record.Star.MagK); gaussians.Add(record.PsfFit); stars.Add(record.Star); saturatedFlags.Add(measurer.HasSaturatedPixels || record.PsfFit.IMax >= measurer.SaturationValue); } } } // Remove stars with unusual PSF fit radii (once only) double sum = 0; for (int i = 0; i < gaussians.Count; i++) { sum += gaussians[i].R0; } double averageR = sum / gaussians.Count; residuals.Clear(); sum = 0; for (int i = 0; i < gaussians.Count; i++) { residuals.Add(averageR - gaussians[i].R0); sum += (averageR - gaussians[i].R0) * (averageR - gaussians[i].R0); } double stdDev = Math.Sqrt(sum) / gaussians.Count; if (EXCLUDE_BAD_RESIDUALS) { for (int i = residuals.Count - 1; i >= 0; i--) { if (Math.Abs(residuals[i]) > 6 * stdDev) { intencities.RemoveAt(i); magnitudes.RemoveAt(i); colours.RemoveAt(i); stars.RemoveAt(i); gaussians.RemoveAt(i); saturatedFlags.RemoveAt(i); } } } double maxResidual = Math.Max(0.1, TangraConfig.Settings.Photometry.MaxResidualStellarMags); for (int itter = 1; itter <= MAX_ITERR; itter++) { residuals.Clear(); SafeMatrix A = new SafeMatrix(intencities.Count, 3); SafeMatrix X = new SafeMatrix(intencities.Count, 1); int idx = 0; for (int i = 0; i < intencities.Count; i++) { A[idx, 0] = magnitudes[i]; A[idx, 1] = colours[i]; A[idx, 2] = 1; X[idx, 0] = -2.5 * Math.Log10(intencities[i]); idx++; } SafeMatrix a_T = A.Transpose(); SafeMatrix aa = a_T * A; SafeMatrix aa_inv = aa.Inverse(); SafeMatrix bx = (aa_inv * a_T) * X; double Ka = bx[0, 0]; double Kb = bx[1, 0]; double Kc = bx[2, 0]; // -2.5 * a * Log(Median-Intensity) = A * Mv + B * Mjk + C - b // -2.5 * Log(Median-Intensity) = Ka * Mv + Kb * Mjk + Kc // Mv = -2.5 * a * Log(Median-Intensity) - b * Mjk - c a = 1 / Ka; b = -Kb / Ka; c = -Kc / Ka; int starsExcludedThisTime = 0; if (EXCLUDE_BAD_RESIDUALS) { List<int> indexesToRemove = new List<int>(); for (int i = 0; i < intencities.Count; i++) { double computed = a * -2.5 * Math.Log10(intencities[i]) + b * colours[i] + c; double diff = Math.Abs(computed - magnitudes[i]); if (itter < MAX_ITERR) { if (Math.Abs(diff) > maxResidual) { indexesToRemove.Add(i); } } else residuals.Add(diff); } for (int i = indexesToRemove.Count - 1; i >= 0; i--) { int idxToRemove = indexesToRemove[i]; intencities.RemoveAt(idxToRemove); magnitudes.RemoveAt(idxToRemove); colours.RemoveAt(idxToRemove); stars.RemoveAt(idxToRemove); gaussians.RemoveAt(idxToRemove); saturatedFlags.RemoveAt(idxToRemove); excludedStars++; starsExcludedThisTime++; } } if (starsExcludedThisTime == 0) break; } } catch (Exception ex) { Trace.WriteLine(ex.ToString()); } return new StarMagnitudeFit( currentAstroImage, bitPix, intencities, magnitudes, colours, stars, gaussians, new List<double>(), saturatedFlags, a, b, c, encodingGamma, reverseCameraResponse, excludedStars, filter, empericalFWHM, photometryReductionMethod, photometryBackgroundMethod, psfQuadrature, psfFittingMethod, measurer, aperture); }
public byte[,] GetMeasurableAreaDisplayBitmapPixels(ImagePixel center) { return GetMeasurableAreaDisplayBitmapPixels(center.X, center.Y); }
private ImagePixel GetExpectedPosition(int frameNo) { ImagePixel rv = null; var intervalValues = new Dictionary<int, List<ImagePixel>>(); var intervalMedians = new Dictionary<int, ImagePixel>(); int earliestFrame = m_PastFrameNos[0]; for (int i = 0; i < m_PastFrameNos.Count; i++) { int integrationInterval = (m_PastFrameNos[i] - earliestFrame) / m_MeasurementContext.IntegratedFramesCount; List<ImagePixel> intPoints; if (!intervalValues.TryGetValue(integrationInterval, out intPoints)) { intPoints = new List<ImagePixel>(); intervalValues.Add(integrationInterval, intPoints); } intPoints.Add(new ImagePixel(m_PastFramePosX[i], m_PastFramePosY[i])); } var calcBucketX = new List<double>(); var calcBucketY = new List<double>(); foreach (int key in intervalValues.Keys) { calcBucketX.Clear(); calcBucketY.Clear(); intervalValues[key].ForEach(v => { calcBucketX.Add(v.XDouble); calcBucketY.Add(v.YDouble); }); double xMed = calcBucketX.Median(); double yMed = calcBucketY.Median(); intervalMedians.Add(key, new ImagePixel(xMed, yMed)); } var xMotion = new LinearRegression(); var yMotion = new LinearRegression(); foreach (int intInt in intervalMedians.Keys) { long t = intInt; double x = intervalMedians[intInt].XDouble; double y = intervalMedians[intInt].YDouble; if (x > 0 && y > 0) { xMotion.AddDataPoint(t, x); yMotion.AddDataPoint(t, y); } } try { xMotion.Solve(); yMotion.Solve(); int currIntInterval = (frameNo - earliestFrame) / m_MeasurementContext.IntegratedFramesCount; rv = new ImagePixel(xMotion.ComputeY(currIntInterval), yMotion.ComputeY(currIntInterval)); } catch (Exception ex) { Trace.WriteLine(ex.GetFullStackTrace()); } return rv; }
private bool GetFitInMatrix(ITrackedObjectPsfFit gaussian, ref int matirxSize, float preselectedAperture) { rbGuidingStar.Text = "Guiding Star"; m_IsBrightEnoughForAutoGuidingStar = false; if (m_Aperture == null) { if (gaussian != null && !double.IsNaN(gaussian.FWHM) && TangraConfig.Settings.Photometry.SignalApertureUnitDefault == TangraConfig.SignalApertureUnit.FWHM) m_Aperture = (float)(gaussian.FWHM * TangraConfig.Settings.Photometry.DefaultSignalAperture); else m_Aperture = (float)(TangraConfig.Settings.Photometry.DefaultSignalAperture); } else if ( gaussian != null && !double.IsNaN(gaussian.FWHM) && TangraConfig.Settings.Photometry.SignalApertureUnitDefault == TangraConfig.SignalApertureUnit.FWHM && m_Aperture < (float)(gaussian.FWHM * TangraConfig.Settings.Photometry.DefaultSignalAperture)) { m_Aperture = (float) (gaussian.FWHM*TangraConfig.Settings.Photometry.DefaultSignalAperture); } nudFitMatrixSize.ValueChanged -= nudFitMatrixSize_ValueChanged; try { uint[,] autoStarsPixels = m_AstroImage.GetMeasurableAreaPixels(m_Center.X, m_Center.Y, 35); m_AutoStarsInLargerArea = StarFinder.GetStarsInArea( ref autoStarsPixels, m_AstroImage.Pixelmap.BitPixCamera, m_AstroImage.Pixelmap.MaxSignalValue, m_AstroImage.MedianNoise, LightCurveReductionContext.Instance.DigitalFilter); m_ProcessingPixels = ImageFilters.CutArrayEdges(autoStarsPixels, 9); m_DisplayPixels = m_AstroImage.GetMeasurableAreaDisplayBitmapPixels(m_Center.X, m_Center.Y, 17); m_AutoStarsInArea = new List<PSFFit>(); foreach (PSFFit autoStar in m_AutoStarsInLargerArea) { if (autoStar.XCenter > 9 && autoStar.XCenter < 9 + 17 && autoStar.YCenter > 9 && autoStar.YCenter < 9 + 17) { // Don't change original star so use a clone PSFFit clone = autoStar.Clone(); clone.SetNewFieldCenterFrom35PixMatrix(8, 8); m_AutoStarsInArea.Add(clone); } } int oldMatirxSize = matirxSize; if (m_AutoStarsInArea.Count == 0) { rbGuidingStar.Text = "Guiding Star"; // There are no stars that are bright enough. Simply let the user do what they want, but still try to default to a sensible aperture size MeasurementsHelper measurement = ReduceLightCurveOperation.DoConfiguredMeasurement(m_ProcessingPixels, m_Aperture.Value, m_AstroImage.Pixelmap.BitPixCamera, m_AstroImage.Pixelmap.MaxSignalValue, 3.0, ref matirxSize); if (measurement.FoundBestPSFFit != null && measurement.FoundBestPSFFit.IsSolved && measurement.FoundBestPSFFit.Certainty > 0.1) { m_X0 = measurement.XCenter; m_Y0 = measurement.YCenter; m_FWHM = (float) measurement.FoundBestPSFFit.FWHM; } else { m_X0 = 8; m_Y0 = 8; m_FWHM = 6; } m_Gaussian = null; nudFitMatrixSize.SetNUDValue(11); } else if (m_AutoStarsInArea.Count == 1) { // There is exactly one good star found. Go and do a fit in a wider area double bestFindTolerance = 3.0; for (int i = 0; i < 2; i++) { MeasurementsHelper measurement = ReduceLightCurveOperation.DoConfiguredMeasurement(m_ProcessingPixels, m_Aperture.Value, m_AstroImage.Pixelmap.BitPixCamera, m_AstroImage.Pixelmap.MaxSignalValue, bestFindTolerance, ref matirxSize); if (measurement != null && matirxSize != -1) { if (matirxSize < 5) { // Do a centroid in the full area, and get another matix centered at the centroid ImagePixel centroid = new ImagePixel(m_Center.X, m_Center.Y); m_ProcessingPixels = m_AstroImage.GetMeasurableAreaPixels(centroid); m_DisplayPixels = m_AstroImage.GetMeasurableAreaDisplayBitmapPixels(centroid); m_X0 = centroid.X; m_Y0 = centroid.Y; m_FWHM = 6; m_Gaussian = null; nudFitMatrixSize.SetNUDValue(11); } else { m_X0 = measurement.XCenter; m_Y0 = measurement.YCenter; if (measurement.FoundBestPSFFit != null) { m_FWHM = (float)measurement.FoundBestPSFFit.FWHM; m_Gaussian = measurement.FoundBestPSFFit; } else { m_FWHM = 6; m_Gaussian = null; } m_ProcessingPixels = measurement.PixelData; nudFitMatrixSize.SetNUDValue(matirxSize); } } else { matirxSize = oldMatirxSize; return false; } if (m_Gaussian != null) { if (IsBrightEnoughtForGuidingStar()) { rbGuidingStar.Text = "Guiding/Comparison Star"; m_IsBrightEnoughForAutoGuidingStar = true; } break; } } } else if (m_AutoStarsInArea.Count > 1) { rbGuidingStar.Text = "Guiding Star"; // There are more stars found. double xBest = m_Gaussian != null ? m_Gaussian.XCenter : m_IsEdit ? ObjectToAdd.ApertureMatrixX0 : 8.5; double yBest = m_Gaussian != null ? m_Gaussian.YCenter : m_IsEdit ? ObjectToAdd.ApertureMatrixY0 : 8.5; // by default use the one closest to the original location PSFFit closestFit = m_AutoStarsInArea[0]; double closestDist = double.MaxValue; foreach (PSFFit star in m_AutoStarsInArea) { double dist = Math.Sqrt((star.XCenter - xBest) * (star.XCenter - xBest) + (star.YCenter - yBest) * (star.YCenter - yBest)); if (closestDist > dist) { closestDist = dist; closestFit = star; } } m_X0 = (float)closestFit.XCenter; m_Y0 = (float)closestFit.YCenter; m_FWHM = (float)closestFit.FWHM; m_Gaussian = closestFit; nudFitMatrixSize.SetNUDValue(m_IsEdit ? ObjectToAdd.PsfFitMatrixSize : closestFit.MatrixSize); } //if (m_Gaussian == null && gaussian.Certainty > 0.1 && ImagePixel.ComputeDistance(gaussian.X0_Matrix, 8, gaussian.Y0_Matrix, 8) < 3) //{ // // Id we failed to locate a bright enough autostar, but the default Gaussian is still certain enough and close enought to the center, we present it as a starting point // m_X0 = (float)gaussian.X0_Matrix; // m_Y0 = (float)gaussian.Y0_Matrix; // m_FWHM = (float)gaussian.FWHM; // m_Gaussian = gaussian; //} decimal appVal; if (float.IsNaN(preselectedAperture)) { if (float.IsNaN(m_Aperture.Value)) { appVal = Convert.ToDecimal(TangraConfig.Settings.Photometry.DefaultSignalAperture); } else { appVal = Convert.ToDecimal(m_Aperture.Value); if (nudAperture1.Maximum < appVal) nudAperture1.Maximum = appVal + 1; } } else appVal = (decimal)preselectedAperture; if ((float)appVal > m_Aperture) m_Aperture = (float)appVal; nudAperture1.SetNUDValue(Math.Round(appVal, 2)); PlotSingleTargetPixels(); PlotGaussian(); return true; } finally { nudFitMatrixSize.ValueChanged += nudFitMatrixSize_ValueChanged; } }
public NotMeasuredReasons MeasureObject( IImagePixel center, uint[,] data, uint[,] backgroundPixels, int bpp, TangraConfig.PreProcessingFilter filter, TangraConfig.PhotometryReductionMethod reductionMethod, TangraConfig.PsfQuadrature psfQuadrature, TangraConfig.PsfFittingMethod psfFittingMethod, float aperture, double refinedFWHM, float refinedAverageFWHM, IMeasurableObject measurableObject, IImagePixel[] objectsInGroup, float[] aperturesInGroup, bool fullDisappearance) { // NOTE: This is how the center of the pixel area passed in data and background arrays is determined // TODO: Pass the center as an argument int centerX = (int)Math.Round(center.XDouble); int centerY = (int)Math.Round(center.YDouble); float msrX0 = (float)center.XDouble; float msrY0 = (float)center.YDouble; float bgAnnulusFactor = 1; switch (filter) { case TangraConfig.PreProcessingFilter.LowPassFilter: data = ImageFilters.LowPassFilter(data, bpp, true); backgroundPixels = ImageFilters.LowPassFilter(backgroundPixels, bpp, true); break; case TangraConfig.PreProcessingFilter.LowPassDifferenceFilter: data = ImageFilters.LowPassDifferenceFilter(data, bpp, true); backgroundPixels = ImageFilters.LowPassDifferenceFilter(backgroundPixels, bpp, true); break; default: break; } float modelFWHM = float.NaN; if (psfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel) { if (TangraConfig.Settings.Photometry.UseUserSpecifiedFWHM) { modelFWHM = TangraConfig.Settings.Photometry.UserSpecifiedFWHM; } else { modelFWHM = refinedAverageFWHM; } } DoublePSFFit doublefit = null; PSFFit fit = null; IBackgroundModelProvider backgroundModel = null; // 1 - Fit a PSF to the current obejct if (objectsInGroup != null && objectsInGroup.Length == 2) { // 1A - When this is a star group int x1 = (int)Math.Round((data.GetLength(0) / 2) + objectsInGroup[0].XDouble - center.XDouble); int y1 = (int)Math.Round((data.GetLength(0) / 2) + objectsInGroup[0].YDouble - center.YDouble); int x2 = (int)Math.Round((data.GetLength(0) / 2) + objectsInGroup[1].XDouble - center.XDouble); int y2 = (int)Math.Round((data.GetLength(0) / 2) + objectsInGroup[1].YDouble - center.YDouble); doublefit = new DoublePSFFit(centerX, centerY); if (psfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel && !float.IsNaN(modelFWHM)) { doublefit.FittingMethod = PSFFittingMethod.LinearFitOfAveragedModel; doublefit.SetAveragedModelFWHM(modelFWHM); } doublefit.Fit(data, x1, y1, x2, y2); PSFFit star1 = doublefit.GetGaussian1(); PSFFit star2 = doublefit.GetGaussian2(); if (m_BackgroundMethod == TangraConfig.BackgroundMethod.Background3DPolynomial) { var bg3dFit = new Background3DPolynomialFit(); bg3dFit.Fit(data, star1, star2); doublefit.Fit(data, bg3dFit, x1, y1, x2, y2); star1 = doublefit.GetGaussian1(); star2 = doublefit.GetGaussian2(); backgroundModel = bg3dFit; } double d1 = ImagePixel.ComputeDistance(measurableObject.Center.XDouble, doublefit.X1Center, measurableObject.Center.YDouble, doublefit.Y1Center); double d2 = ImagePixel.ComputeDistance(measurableObject.Center.XDouble, doublefit.X2Center, measurableObject.Center.YDouble, doublefit.Y2Center); fit = (d1 < d2) ? star1 : star2; if (reductionMethod == TangraConfig.PhotometryReductionMethod.AperturePhotometry) { // NOTE: If aperture photometry is used, we measure the double object in a single larger aperture centered at the middle double alpha = Math.Atan((star2.YCenter - star1.YCenter) / (star2.XCenter - star1.XCenter)); float dx = (float)((star1.FWHM - star2.FWHM) * Math.Cos(alpha)); float dy = (float)((star1.FWHM - star2.FWHM) * Math.Sin(alpha)); msrX0 = (float)(star1.XCenter - star1.FWHM + star2.XCenter + star2.FWHM) / 2.0f - dx; msrY0 = (float)(star1.YCenter - star1.FWHM + star2.YCenter + star2.FWHM) / 2.0f - dy; aperture = aperturesInGroup.Sum(); bgAnnulusFactor = 0.67f; } } else if (reductionMethod != TangraConfig.PhotometryReductionMethod.AperturePhotometry) { // 1B - When this is a single star fit = new PSFFit(centerX, centerY); if (psfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel && !float.IsNaN(modelFWHM)) { fit.FittingMethod = PSFFittingMethod.LinearFitOfAveragedModel; fit.SetAveragedModelFWHM(modelFWHM); } fit.Fit(data, measurableObject.PsfFittingMatrixSize); if (m_BackgroundMethod == TangraConfig.BackgroundMethod.Background3DPolynomial) { // If 3D Poly Background is used then fit the background, and supply it to the PSF Fitting var bg3dFit = new Background3DPolynomialFit(); bg3dFit.Fit(backgroundPixels, fit, null); backgroundModel = bg3dFit; if (psfFittingMethod != TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel) { /* 3D Poly modelling works in a direct fit only with non-linear fitting */ fit.Fit(backgroundPixels, bg3dFit, measurableObject.PsfFittingMatrixSize); } } } else if ( reductionMethod == TangraConfig.PhotometryReductionMethod.AperturePhotometry && m_BackgroundMethod == TangraConfig.BackgroundMethod.Background3DPolynomial) { // 1C - Single star with aperture photometry and 3D Poly Background var bg3dFit = new Background3DPolynomialFit(); bg3dFit.Fit(backgroundPixels, (float)(centerX - msrX0 + 17), (float)(centerY - msrY0 + 17), 2 * aperture); backgroundModel = bg3dFit; } // 2 - Do the actual photometric measurements (signal and background) based on the selected methods if (reductionMethod == TangraConfig.PhotometryReductionMethod.PsfPhotometry) { // 2A - PSF Photometry if (TangraConfig.Settings.Photometry.PsfFittingMethod == TangraConfig.PsfFittingMethod.DirectNonLinearFit) { return(DoNonLinearProfileFittingPhotometry( fit, data, centerX, centerY, msrX0, msrY0, aperture, measurableObject.PsfFittingMatrixSize, psfQuadrature == TangraConfig.PsfQuadrature.NumericalInAperture, measurableObject.IsOccultedStar && fullDisappearance, backgroundPixels, measurableObject.MayHaveDisappeared, refinedFWHM, bgAnnulusFactor)); } else if (psfFittingMethod == TangraConfig.PsfFittingMethod.LinearFitOfAveragedModel) { return(DoLinearProfileFittingOfAveragedMoodelPhotometry( fit, data, centerX, centerY, msrX0, msrY0, modelFWHM, aperture, measurableObject.PsfFittingMatrixSize, psfQuadrature == TangraConfig.PsfQuadrature.NumericalInAperture, measurableObject.IsOccultedStar && fullDisappearance, backgroundPixels, measurableObject.MayHaveDisappeared, bgAnnulusFactor, backgroundModel)); } else { throw new NotImplementedException(); } } else if (reductionMethod == TangraConfig.PhotometryReductionMethod.AperturePhotometry) { return(DoAperturePhotometry( data, centerX, centerY, msrX0, msrY0, aperture, measurableObject.PsfFittingMatrixSize, backgroundPixels, bgAnnulusFactor, backgroundModel, measurableObject.Center.X, measurableObject.Center.Y)); } else if (reductionMethod == TangraConfig.PhotometryReductionMethod.OptimalExtraction) { return(DoOptimalExtractionPhotometry( fit, data, centerX, centerY, msrX0, msrY0, aperture, measurableObject.PsfFittingMatrixSize, measurableObject.IsOccultedStar && fullDisappearance, backgroundPixels, measurableObject.MayHaveDisappeared, refinedFWHM, bgAnnulusFactor)); } else { throw new ArgumentOutOfRangeException("reductionMethod"); } }
internal NotMeasuredReasons DoOptimalExtractionPhotometry( PSFFit fit, uint[,] matrix, int x0Int, int y0Int, float x0, float y0, float aperture, int matrixSize, bool isFullyDisappearingOccultedStar, uint[,] backgroundArea, bool mayBeOcculted /* Some magic based on a pure guess */, double refinedFWHM, float bgAnnulusFactor) { // Proceed as with PSF Non linear, Then find the variance of the PSF fit and use a weight based on the residuals of the PSF fit // Signal[x, y] = PSF(x, y) + weight * Residual(x, y) double distance = ImagePixel.ComputeDistance(fit.XCenter, x0, fit.YCenter, y0); double tolerance = isFullyDisappearingOccultedStar ? m_TimesHigherPositionToleranceForFullyOccultedStars * m_PositionTolerance : m_PositionTolerance; float psfBackground = (float)fit.I0; // almost like aperture if (matrix.GetLength(0) != 17 && matrix.GetLength(0) != 35) { throw new ApplicationException("Measurement error. Correlation: AFP-101B"); } int side = matrix.GetLength(0); float halfSide = side * 1f / 2f; m_HasSaturatedPixels = false; m_PSFBackground = double.NaN; m_FoundBestPSFFit = null; m_XCenter = x0 - x0Int + halfSide; m_YCenter = y0 - y0Int + halfSide; m_Aperture = aperture; m_PixelData = matrix; m_TotalPixels = 0; double varR0Sq = fit.GetVariance(); varR0Sq = varR0Sq * varR0Sq * 2; double deltaX = fit.X0_Matrix - m_XCenter; double deltaY = fit.Y0_Matrix - m_YCenter; m_TotalReading = GetReading( m_Aperture, m_PixelData, side, side, m_XCenter, m_YCenter, delegate(int x, int y) { double videoPixel = m_PixelData[x, y]; double psfValue = fit.GetValue(x + deltaX, y + deltaY); if (fit.UsesBackgroundModel) { psfValue += fit.GetFittedBackgroundModelValue(x + deltaX, y + deltaY); } double residual = videoPixel - psfValue; double weight = Math.Exp(-residual * residual / varR0Sq); return(psfValue + residual * weight); }, ref m_TotalPixels); if (m_TotalPixels > 0) { if (m_BackgroundMethod == TangraConfig.BackgroundMethod.PSFBackground) { if (float.IsNaN(psfBackground)) { m_TotalBackground = 0; } else { m_TotalBackground = (uint)Math.Round(m_TotalPixels * psfBackground); } } else if (m_BackgroundMethod == TangraConfig.BackgroundMethod.Background3DPolynomial) { if (!fit.UsesBackgroundModel) { throw new InvalidOperationException("3D-Polynomial was not applied correctly."); } m_TotalBackground = Integration.IntegrationOverCircularArea( (x, y) => fit.GetFittedBackgroundModelValue(x, y), m_Aperture); } else if (m_BackgroundMethod != TangraConfig.BackgroundMethod.PSFBackground) { int offset = (35 - fit.MatrixSize) / 2; double bgFromAnnulus = GetBackground(backgroundArea, m_Aperture, m_XCenter + offset, m_YCenter + offset, bgAnnulusFactor); m_TotalBackground = (uint)Math.Round(m_TotalPixels * (float)bgFromAnnulus); } else { throw new ApplicationException("Measurement error. Correlation: AFP-102B"); } if (!fit.IsSolved || // The PSF solution failed, mark the reading invalid (distance > tolerance && !mayBeOcculted) || // If this doesn't look like a full disappearance, then make the reading invalid (fit.FWHM < 0.75 * refinedFWHM || fit.FWHM > 1.25 * refinedFWHM) // The FWHM is too small or too large, make the reading invalid ) { return(!fit.IsSolved ? NotMeasuredReasons.MeasurementPSFFittingFailed : (distance > tolerance && !mayBeOcculted) ? NotMeasuredReasons.DistanceToleranceTooHighForNonFullDisappearingOccultedStar : NotMeasuredReasons.FWHMOutOfRange); } } else { // We can't do much here, but this should never happen (??) m_TotalBackground = 0; m_TotalReading = 0; return(NotMeasuredReasons.NoPixelsToMeasure); } return(NotMeasuredReasons.MeasuredSuccessfully); }
private bool CheckTriangleWithRatios(int i, int j, int k, ImagePixel iCenter, ImagePixel jCenter, ImagePixel kCenter, double toleranceInArcSec) { double dijMax = m_PlateConfig.GetDistanceInArcSec(iCenter.XDouble, iCenter.YDouble, jCenter.XDouble, jCenter.YDouble, (1 - m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); double dijMin = m_PlateConfig.GetDistanceInArcSec(iCenter.XDouble, iCenter.YDouble, jCenter.XDouble, jCenter.YDouble, (1 + m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); double dikMax = m_PlateConfig.GetDistanceInArcSec(iCenter.XDouble, iCenter.YDouble, kCenter.XDouble, kCenter.YDouble, (1 - m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); double dikMin = m_PlateConfig.GetDistanceInArcSec(iCenter.XDouble, iCenter.YDouble, kCenter.XDouble, kCenter.YDouble, (1 + m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); double djkMax = m_PlateConfig.GetDistanceInArcSec(jCenter.XDouble, jCenter.YDouble, kCenter.XDouble, kCenter.YDouble, (1 - m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); double djkMin = m_PlateConfig.GetDistanceInArcSec(jCenter.XDouble, jCenter.YDouble, kCenter.XDouble, kCenter.YDouble, (1 + m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); // Candidates for the matches int idxIJLower = m_IndexLower[Math.Min(Math.Max((int)Math.Round(dijMin - toleranceInArcSec) - 1, 0), m_IndexUpper.Keys.Count - 1)]; int idxIJUpper = m_IndexUpper[Math.Min(Math.Max((int)Math.Round(dijMax + toleranceInArcSec) + 1, 0), m_IndexUpper.Keys.Count - 1)]; int idxIKLower = m_IndexLower[Math.Min(Math.Max((int)Math.Round(dikMin - toleranceInArcSec) - 1, 0), m_IndexUpper.Keys.Count - 1)]; int idxIKUpper = m_IndexUpper[Math.Min(Math.Max((int)Math.Round(dikMax + toleranceInArcSec) + 1, 0), m_IndexUpper.Keys.Count - 1)]; int idxJKLower = m_IndexLower[Math.Min(Math.Max((int)Math.Round(djkMin - toleranceInArcSec) - 1, 0), m_IndexUpper.Keys.Count - 1)]; int idxJKUpper = m_IndexUpper[Math.Min(Math.Max((int)Math.Round(djkMax + toleranceInArcSec) + 1, 0), m_IndexUpper.Keys.Count - 1)]; ulong iDebugStarNo = 0, jDebugStarNo = 0, kDebugStarNo = 0; bool debugStarMatch = false; if (DebugResolvedStars != null) { if (DebugResolvedStars.TryGetValue(i, out iDebugStarNo) && DebugResolvedStars.TryGetValue(j, out jDebugStarNo) && DebugResolvedStars.TryGetValue(k, out kDebugStarNo)) { IStar iStarAllDbg = m_CelestialAllStars.FirstOrDefault(s => s.StarNo == iDebugStarNo); IStar jStarAllDbg = m_CelestialAllStars.FirstOrDefault(s => s.StarNo == jDebugStarNo); IStar kStarAllDbg = m_CelestialAllStars.FirstOrDefault(s => s.StarNo == kDebugStarNo); #if ASTROMETRY_DEBUG Trace.Assert(iStarAllDbg != null); Trace.Assert(jStarAllDbg != null); Trace.Assert(kStarAllDbg != null); #endif IStar iStarDbg = m_CelestialPyramidStars.FirstOrDefault(s => s.StarNo == iDebugStarNo); IStar jStarDbg = m_CelestialPyramidStars.FirstOrDefault(s => s.StarNo == jDebugStarNo); IStar kStarDbg = m_CelestialPyramidStars.FirstOrDefault(s => s.StarNo == kDebugStarNo); if (iStarDbg != null && jStarDbg != null && kStarDbg != null) { debugStarMatch = true; DistanceEntry deIJDbg = m_Entries.FirstOrDefault(e => (e.Star1.StarNo == iDebugStarNo && e.Star2.StarNo == jDebugStarNo) || (e.Star1.StarNo == jDebugStarNo && e.Star2.StarNo == iDebugStarNo)); DistanceEntry deIKDbg = m_Entries.FirstOrDefault(e => (e.Star1.StarNo == iDebugStarNo && e.Star2.StarNo == kDebugStarNo) || (e.Star1.StarNo == kDebugStarNo && e.Star2.StarNo == iDebugStarNo)); DistanceEntry deJKDbg = m_Entries.FirstOrDefault(e => (e.Star1.StarNo == kDebugStarNo && e.Star2.StarNo == jDebugStarNo) || (e.Star1.StarNo == jDebugStarNo && e.Star2.StarNo == kDebugStarNo)); #if ASTROMETRY_DEBUG Trace.Assert(deIJDbg != null); Trace.Assert(deIKDbg != null); Trace.Assert(deJKDbg != null); #endif double dijDbg = AngleUtility.Elongation(iStarDbg.RADeg, iStarDbg.DEDeg, jStarDbg.RADeg, jStarDbg.DEDeg) * 3600; double dikDbg = AngleUtility.Elongation(iStarDbg.RADeg, iStarDbg.DEDeg, kStarDbg.RADeg, kStarDbg.DEDeg) * 3600; double djkDbg = AngleUtility.Elongation(kStarDbg.RADeg, kStarDbg.DEDeg, jStarDbg.RADeg, jStarDbg.DEDeg) * 3600; #if ASTROMETRY_DEBUG Trace.Assert(Math.Abs(dijDbg - deIJDbg.DistanceArcSec) < 1); Trace.Assert(Math.Abs(dikDbg - deIKDbg.DistanceArcSec) < 1); Trace.Assert(Math.Abs(djkDbg - deJKDbg.DistanceArcSec) < 1); #endif //TODO: Find the real focal length, then find the difference in percentages //NOTE: Stars are not included because initial focal length is not correct !!! #if ASTROMETRY_DEBUG Trace.Assert(dijMax > dijDbg); Trace.Assert(dijMin < dijDbg); Trace.Assert(dikMax > dikDbg); Trace.Assert(dikMin < dikDbg); Trace.Assert(djkMax > djkDbg); Trace.Assert(djkMin < djkDbg); #endif } else { #if ASTROMETRY_DEBUG if (iStarDbg == null) Trace.Assert((iStarAllDbg.Mag > m_PyramidMaxMag) || (iStarAllDbg.Mag < m_PyramidMinMag)); if (jStarDbg == null) Trace.Assert((jStarAllDbg.Mag > m_PyramidMaxMag) || (jStarAllDbg.Mag < m_PyramidMinMag)); if (kStarDbg == null) Trace.Assert((kStarAllDbg.Mag > m_PyramidMaxMag) || (kStarAllDbg.Mag < m_PyramidMinMag)); #endif } } } DistanceEntry ijEntry = null; DistanceEntry ikEntry = null; DistanceEntry jkEntry = null; for (int ij = idxIJLower; ij <= idxIJUpper; ij++) { ijEntry = m_Entries[ij]; if (debugStarMatch) { if ((ijEntry.Star1.StarNo == iDebugStarNo && ijEntry.Star2.StarNo == jDebugStarNo) || (ijEntry.Star1.StarNo == jDebugStarNo && ijEntry.Star2.StarNo == iDebugStarNo)) { #if ASTROMETRY_DEBUG Trace.Assert(ijEntry.DistanceArcSec + toleranceInArcSec >= dijMin); Trace.Assert(ijEntry.DistanceArcSec - toleranceInArcSec <= dijMax); #endif } } if (ijEntry.DistanceArcSec + toleranceInArcSec < dijMin) continue; if (ijEntry.DistanceArcSec - toleranceInArcSec > dijMax) continue; for (int ik = idxIKLower; ik <= idxIKUpper; ik++) { ikEntry = m_Entries[ik]; bool debugIKPairFound = false; if (debugStarMatch) { if ((ikEntry.Star1.StarNo == iDebugStarNo && ikEntry.Star2.StarNo == kDebugStarNo) || (ikEntry.Star1.StarNo == kDebugStarNo && ikEntry.Star2.StarNo == iDebugStarNo)) { #if ASTROMETRY_DEBUG Trace.Assert(ikEntry.DistanceArcSec + toleranceInArcSec >= dikMin); Trace.Assert(ikEntry.DistanceArcSec - toleranceInArcSec <= dikMax); Trace.Assert(Math.Abs(ijEntry.DistanceArcSec - (dijMin / dikMin) * ikEntry.DistanceArcSec) < toleranceInArcSec); #endif debugIKPairFound = true; } } if (ikEntry.DistanceArcSec + toleranceInArcSec < dikMin) continue; if (ikEntry.DistanceArcSec - toleranceInArcSec > dikMax) continue; if (ikEntry.Star1.StarNo != ijEntry.Star1.StarNo && ikEntry.Star1.StarNo != ijEntry.Star2.StarNo && ikEntry.Star2.StarNo != ijEntry.Star1.StarNo && ikEntry.Star2.StarNo != ijEntry.Star2.StarNo) { // There is no possible (i, j, k) configuration that involves the same 3 stars continue; } double ratioDifference = Math.Abs(ijEntry.DistanceArcSec - (dijMin/dikMin) * ikEntry.DistanceArcSec); if (ratioDifference > toleranceInArcSec) continue; // Ratios are preserved when changing the focal length (with linear fit) so check the ratios here double fittedFocalLength = m_PlateConfig.GetFocalLengthFromMatch( ijEntry.DistanceArcSec, ikEntry.DistanceArcSec, iCenter, jCenter, kCenter, toleranceInArcSec, m_Settings.PyramidFocalLengthAllowance); if (debugIKPairFound) { #if ASTROMETRY_DEBUG Trace.Assert(!double.IsNaN(fittedFocalLength)); #endif } if (double.IsNaN(fittedFocalLength)) continue; double djk = m_PlateConfig.GetDistanceInArcSec(jCenter.XDouble, jCenter.YDouble, kCenter.XDouble, kCenter.YDouble, fittedFocalLength); ulong iStarNo = uint.MaxValue; ulong needIdx1 = uint.MaxValue; ulong needIdx2 = uint.MaxValue; if (ikEntry.Star1.StarNo == ijEntry.Star1.StarNo) { // ik_1 = ij_1 = (i) iStarNo = ikEntry.Star1.StarNo; needIdx1 = ikEntry.Star2.StarNo; needIdx2 = ijEntry.Star2.StarNo; } else if (ikEntry.Star1.StarNo == ijEntry.Star2.StarNo) { // ik_1 = ij_2 = (i) iStarNo = ikEntry.Star1.StarNo; needIdx1 = ikEntry.Star2.StarNo; // (k) needIdx2 = ijEntry.Star1.StarNo; // (j) } else if (ikEntry.Star2.StarNo == ijEntry.Star1.StarNo) { // ik_2 = ij_1 = (i) iStarNo = ikEntry.Star2.StarNo; needIdx1 = ikEntry.Star1.StarNo; // (k) needIdx2 = ijEntry.Star2.StarNo; // (j) } else if (ikEntry.Star2.StarNo == ijEntry.Star2.StarNo) { // ik_2 = ij_2 = (i) iStarNo = ikEntry.Star2.StarNo; needIdx1 = ikEntry.Star1.StarNo; // (k) needIdx2 = ijEntry.Star1.StarNo; // (j) } else continue; if (needIdx1 == needIdx2) continue; jkEntry = m_Entries.Where(e => (e.Star1.StarNo == needIdx1 && e.Star2.StarNo == needIdx2) || (e.Star1.StarNo == needIdx2 && e.Star2.StarNo == needIdx1)).FirstOrDefault(); if (debugIKPairFound) { #if ASTROMETRY_DEBUG Trace.Assert(jkEntry != null); #endif if (jkEntry != null) { #if ASTROMETRY_DEBUG Trace.Assert(jkEntry.DistanceArcSec + toleranceInArcSec >= djk); Trace.Assert(jkEntry.DistanceArcSec - toleranceInArcSec <= djk); Trace.Assert(jkEntry.DistanceArcSec + toleranceInArcSec >= djkMin); Trace.Assert(jkEntry.DistanceArcSec - toleranceInArcSec <= djkMax); #endif } } if (jkEntry != null) { ulong jStarNo = ulong.MinValue; ulong kStarNo = ulong.MinValue; if (jkEntry.DistanceArcSec + toleranceInArcSec < djkMin) continue; if (jkEntry.DistanceArcSec - toleranceInArcSec > djkMax) continue; if (jkEntry.DistanceArcSec + toleranceInArcSec < djk) continue; if (jkEntry.DistanceArcSec - toleranceInArcSec > djk) continue; if (jkEntry.Star1.StarNo == needIdx1 && jkEntry.Star2.StarNo == needIdx2) { m_Solution = IsSuccessfulMatch(m_StarMap, i, j, k, ijEntry, ikEntry, jkEntry, iStarNo, needIdx1, needIdx2, fittedFocalLength, true, toleranceInArcSec); if (m_Solution == null) continue; jStarNo = needIdx1; kStarNo = needIdx2; } if (jkEntry.Star1.StarNo == needIdx2 && jkEntry.Star2.StarNo == needIdx1) { m_Solution = IsSuccessfulMatch(m_StarMap, i, j, k, ijEntry, ikEntry, jkEntry, iStarNo, needIdx1, needIdx2, fittedFocalLength, true, toleranceInArcSec); if (m_Solution == null) continue; jStarNo = needIdx2; kStarNo = needIdx1; } if (m_Solution != null) { if (TangraConfig.Settings.Astrometry.PyramidNumberOfPivots == 3) // Exist the initial alignment with only 3 candidate pivots return true; for (int l = 0; l < m_StarMap.Features.Count; l++) { var piramid = m_StarMap.Features[l]; if (piramid.FeatureId == i || piramid.FeatureId == j || piramid.FeatureId == k) continue; var lCenter = piramid.GetCenter(); // NOTE: Continue until a set of distances is found in the cache for the 4-th pivot double dli = m_PlateConfig.GetDistanceInArcSec(lCenter.XDouble, lCenter.YDouble, iCenter.XDouble, iCenter.YDouble, fittedFocalLength); double dlj = m_PlateConfig.GetDistanceInArcSec(lCenter.XDouble, lCenter.YDouble, jCenter.XDouble, jCenter.YDouble, fittedFocalLength); double dlk = m_PlateConfig.GetDistanceInArcSec(lCenter.XDouble, lCenter.YDouble, kCenter.XDouble, kCenter.YDouble, fittedFocalLength); List<DistanceEntry> ilCandidates = m_DistancesByMagnitude .Where(e => (e.Star1.StarNo == iStarNo || e.Star2.StarNo == iStarNo) && e.DistanceArcSec < dli + toleranceInArcSec && e.DistanceArcSec > dli - toleranceInArcSec) .ToList(); foreach (var cand_il in ilCandidates) { var lStar = cand_il.Star1.StarNo == iStarNo ? cand_il.Star2 : cand_il.Star1; List<DistanceEntry> jlCandidates = m_DistancesByMagnitude .Where(e => ((e.Star1.StarNo == jStarNo && e.Star2.StarNo == lStar.StarNo) || (e.Star1.StarNo == lStar.StarNo && e.Star2.StarNo == jStarNo)) && e.DistanceArcSec < dlj + toleranceInArcSec && e.DistanceArcSec > dlj - toleranceInArcSec) .ToList(); List<DistanceEntry> klCandidates = m_DistancesByMagnitude .Where(e => ((e.Star1.StarNo == kStarNo && e.Star2.StarNo == lStar.StarNo) || (e.Star1.StarNo == lStar.StarNo && e.Star2.StarNo == kStarNo)) && e.DistanceArcSec < dlk + toleranceInArcSec && e.DistanceArcSec > dlk - toleranceInArcSec) .ToList(); if (jlCandidates.Count > 0 && klCandidates.Count > 0) { if (klCandidates.Count > 0) return true; } } } } } //#if DEBUG // int bestKId = -1; // double bestDiff = double.MaxValue; //#endif // for (int jk = idxJKLower; jk <= idxJKUpper; jk++) // { // jkEntry = m_Entries[jk]; //#if DEBUG // double diff = Math.Abs(jkEntry.DistanceArcSec - djk); // if (diff < bestDiff) // { // bestDiff = diff; // bestKId = jk; // } //#endif // } //#if DEBUG // jkEntry = m_Entries[bestKId]; // Debug.WriteLine( // string.Format("3-rd star match failed by {0}\" ({1}, {2}, {3}) -> ({4}: {5}, {6}); [{7},{8}]", // bestDiff, i, j, k, // foundIdx0, needIdx1, needIdx2, // jkEntry.Star1.StarNo, jkEntry.Star2.StarNo)); //#endif } } return false; }
public override void MouseClick(ObjectClickEventArgs e) { if (m_OperationState == SpectroscopyState.ChoosingStar && e.Gausian != null && e.Gausian.IsSolved && e.Gausian.Certainty > 0.2) { float bestAngle = m_SpectroscopyController.LocateSpectraAngle(e.Gausian); if (float.IsNaN(bestAngle)) { SelectedStar = new ImagePixel(e.Gausian.XCenter, e.Gausian.YCenter); SelectedStarFWHM = e.Gausian.FWHM; m_SelectedStarGaussian = e.Gausian; MeasurementAreaWing = (int)(2 * Math.Ceiling(SelectedStarFWHM)); BackgroundAreaWing = MeasurementAreaWing; BackgroundAreaGap = 5; SelectedAnglePoint = Point.Empty; m_ControlPanel.ClearSpectra(); m_OperationState = SpectroscopyState.ChoosingAngleManually; } else { SelectedStar = new ImagePixel(e.Gausian.XCenter, e.Gausian.YCenter); SelectedStarFWHM = e.Gausian.FWHM; m_SelectedStarGaussian = e.Gausian; MeasurementAreaWing = (int)(2 * Math.Ceiling(SelectedStarFWHM)); BackgroundAreaWing = MeasurementAreaWing; BackgroundAreaGap = 5; SetBestAngle(bestAngle); } m_VideoController.RedrawCurrentFrame(false, true); } else if (m_OperationState == SpectroscopyState.ChoosingAngleManually && SelectedStar != null) { double atanAgnle = 180 * Math.Atan((SelectedStar.YDouble - e.Pixel.YDouble)/(e.Pixel.XDouble - SelectedStar.XDouble)) / Math.PI; if (atanAgnle < 0) atanAgnle = 360 + atanAgnle; int roughAngle = (int) atanAgnle; float bestAngle = m_SpectroscopyController.LocateSpectraAngle(e.Gausian, roughAngle); if (!float.IsNaN(bestAngle)) { SetBestAngle(bestAngle); m_VideoController.RedrawCurrentFrame(false, true); } } }
internal frmAddOrEditSingleTarget(int objectId, ImagePixel center, PSFFit gaussian, LCStateMachine state, VideoController videoController) { InitializeComponent(); m_VideoController = videoController; m_AutocenteredApertureAvailable = true; Text = "Add Object"; btnAdd.Text = "Add"; btnDontAdd.Text = "Don't Add"; btnDelete.Visible = false; m_IsEdit = false; nudFitMatrixSize.Value = 11; nudFitMatrixSize.Maximum = 15; m_ObjectId = objectId; m_State = state; m_AstroImage = m_State.VideoOperation.m_StackedAstroImage; ObjectToAdd = new TrackedObjectConfig(); m_Center = new ImagePixel(center); Initialize(); if (rbOccultedStar.Enabled) SelectedObjectType = TrackingType.OccultedStar; else SelectedObjectType = TrackingType.GuidingStar; // Apply filtering to the processing pixels according to the configured default filter value int matirxSize = (int)nudFitMatrixSize.Value; GetFitInMatrix(gaussian, ref matirxSize); nudFitMatrixSize.Maximum = matirxSize; if (SelectedObjectType != TrackingType.OccultedStar) SetHeightAndType(); }
public TrackedObjectLight(byte targetNo, TrackedObjectConfig originalObject) : base(targetNo, originalObject) { Center = new ImagePixel(originalObject.OriginalFieldCenterX, originalObject.OriginalFieldCenterY); }
internal frmAddOrEditSingleTarget(int objectId, TrackedObjectConfig selectedObject, LCStateMachine state, VideoController videoController) { InitializeComponent(); m_VideoController = videoController; m_AutocenteredApertureAvailable = true; Text = "Edit Object"; btnAdd.Text = "Save"; btnDontAdd.Text = "Cancel"; btnDelete.Visible = true; m_IsEdit = true; m_ObjectId = objectId; m_State = state; m_AstroImage = m_State.VideoOperation.m_StackedAstroImage; ObjectToAdd = selectedObject; if (selectedObject.TrackingType != TrackingType.ComparisonStar) nudFitMatrixSize.SetNUDValue(selectedObject.PsfFitMatrixSize); m_Center = new ImagePixel( selectedObject.OriginalFieldCenterX, selectedObject.OriginalFieldCenterY); if (ObjectToAdd.PositionTolerance > 0) nudPositionTolerance.SetNUDValue((decimal)ObjectToAdd.PositionTolerance); Initialize(); if (!selectedObject.IsWeakSignalObject && !selectedObject.IsFixedAperture) { int matrixSize = selectedObject.PsfFitMatrixSize; GetFitInMatrix(selectedObject.Gaussian, ref matrixSize, selectedObject.ApertureInPixels); selectedObject.PsfFitMatrixSize = matrixSize; } else { m_ProcessingPixels = m_AstroImage.GetMeasurableAreaPixels(m_Center); m_DisplayPixels = m_AstroImage.GetMeasurableAreaDisplayBitmapPixels(m_Center); m_FWHM = 6; m_Gaussian = null; m_X0 = selectedObject.ApertureMatrixX0; m_Y0 = selectedObject.ApertureMatrixY0; dx = selectedObject.ApertureDX; dy = selectedObject.ApertureDY; PlotSingleTargetPixels(); nudAperture1.SetNUDValue((decimal) Math.Round(ObjectToAdd.ApertureInPixels, 2)); } SetHeightAndType(); if (selectedObject.TrackingType == TrackingType.GuidingStar) SelectedObjectType = TrackingType.GuidingStar; else if (selectedObject.TrackingType == TrackingType.OccultedStar) SelectedObjectType = TrackingType.OccultedStar; }
internal void LoadFromNativeData(NativeTrackedObjectInfo trackingInfo, NativePsfFitInfo psfInfo, double[] residuals) { Center = new ImagePixel(trackingInfo.CenterX, trackingInfo.CenterY); LastKnownGoodPosition = new ImagePixel(trackingInfo.LastGoodPositionX, trackingInfo.LastGoodPositionY); LastKnownGoodPsfCertainty = trackingInfo.LastGoodPsfCertainty; IsLocated = trackingInfo.IsLocated == 1; IsOffScreen = trackingInfo.IsOffScreen == 1; m_TrackingFlags = TranslateTrackingFlags((NativeTrackerNotMeasuredReasons)trackingInfo.TrackingFlags); m_NativePsfFit.LoadFromNativePsfFitInfo(psfInfo, residuals); }
public ImagePixel GetCentroid(int x, int y, int radius, bool doPeakPixelFirst, uint noiseLevel) { uint minimum = m_Pixelmap.MaxPixelValue; uint maximum = 0; int xMax = x, yMax = y; PixelAreaOperation(x, y, radius, delegate(int x1, int y1, uint z) { if (minimum > z) minimum = z; if (maximum < z) { maximum = z; if (doPeakPixelFirst) { xMax = x1; yMax = y1; } } }); if (maximum < noiseLevel) return null; double xx = xMax; double yy = yMax; double deltax = 0; double deltay = 0; for (int itter = 0; itter < 10; itter++) { xx += deltax; yy += deltay; double sumMomentumX = 0; double sumMomentumY = 0; double sumIntensity = 0; PixelAreaOperation(xMax, yMax, radius, delegate(int x1, int y1, uint z) { uint diff = Math.Max(z - minimum, 0); sumMomentumX += diff * (x1 - xx); sumMomentumY += diff * (y1 - yy); sumIntensity += diff; }); deltax = sumMomentumX / sumIntensity; deltay = sumMomentumY / sumIntensity; } if (double.IsNaN(xx) || double.IsNaN(yy)) return null; ImagePixel retVal = new ImagePixel(xx, yy); retVal.SignalNoise = retVal.Brightness * 1.0 / noiseLevel; return retVal; }
public void AddStar(ImagePixel plateStar, IStar celestialPyramidStarEntry) { AddStar(plateStar, celestialPyramidStarEntry, null); }
public uint[,] GetMeasurableAreaPixels(ImagePixel center) { return GetMeasurableAreaPixels(center.X, center.Y); }
public void AddStar(ImagePixel plateStar, IStar celestialPyramidStarEntry, int featureId) { var starPair = AddStar(plateStar, celestialPyramidStarEntry, null); starPair.FeatureId = featureId; }
public double GetIntencity(ImagePixel center, out bool isSaturated) { isSaturated = false; uint[,] data = m_CurrentAstroImage.GetMeasurableAreaPixels(center.X, center.Y, 17); PSFFit fit = new PSFFit(center.X, center.Y); fit.Fit(data, PSF_FIT_AREA_SIZE); if (!fit.IsSolved) return double.NaN; int areaSize = m_Filter == TangraConfig.PreProcessingFilter.NoFilter ? 17 : 19; int centerX = (int)Math.Round(center.XDouble); int centerY = (int)Math.Round(center.YDouble); data = m_CurrentAstroImage.GetMeasurableAreaPixels(centerX, centerY, areaSize); uint[,] backgroundPixels = m_CurrentAstroImage.GetMeasurableAreaPixels(centerX, centerY, 35); m_Measurer.MeasureObject( center, data, backgroundPixels, m_CurrentAstroImage.Pixelmap.BitPixCamera, m_Filter, m_PhotometryReductionMethod, m_PsfQuadrature, m_PsfFittingMethod, m_MeasurementAperture ?? (float)Aperture(fit.FWHM), fit.FWHM, (float)m_EmpericalFWHM, new FakeIMeasuredObject(fit), null, null, false); isSaturated = m_Measurer.HasSaturatedPixels; return m_Measurer.TotalReading - m_Measurer.TotalBackground; }
public PlateConstStarPair AddStar(ImagePixel plateStar, IStar celestialPyramidStarEntry, StarMapFeature feature) { double detectionCertainty = plateStar.SignalNoise; PlateConstStarPair starPair = AddStar( plateStar.XDouble, celestialPyramidStarEntry.RADeg, plateStar.YDouble, celestialPyramidStarEntry.DEDeg, celestialPyramidStarEntry.Mag, plateStar.Brightness, detectionCertainty, plateStar.IsSaturated); #if ASTROMETRY_DEBUG Trace.Assert(m_Pairs.Find((pair) => pair.StarNo == celestialPyramidStarEntry.StarNo) == null); #endif starPair.StarNo = celestialPyramidStarEntry.StarNo; starPair.FeatureId = feature != null ? feature.FeatureId : -1; starPair.RADeg = celestialPyramidStarEntry.RADeg; starPair.DEDeg = celestialPyramidStarEntry.DEDeg; return starPair; }
public ImagePixel GetCenter() { if (m_Center == null) { if (m_MaxBrightnessPixels == 1) { int y = (int)(m_MaxBrightnessFirstKey / (ulong)m_Width); int x = (int)(m_MaxBrightnessFirstKey % (ulong)m_Width); m_Center = ImagePixel.CreateImagePixelWithFeatureId(this.FeatureId, (int)m_MaxBrightness, x, y); } else { int minX = int.MaxValue; int minY = int.MaxValue; int maxX = int.MinValue; int maxY = int.MinValue; foreach (ulong key in m_Pixels.Keys) { if (m_Pixels[key] < m_MaxBrightness) continue; int y = (int)(key / (ulong)m_Width); int x = (int)(key % (ulong)m_Width); if (minX > x) minX = x; if (minY > y) minY = y; if (maxX < x) maxX = x; if (maxY < y) maxY = y; } int midX = (maxX + minX) / 2; bool singleMidX = ((maxX + minX) % 2) == 0; int midY = (maxY + minY) / 2; bool singleMidY = ((maxY + minY) % 2) == 0; List<ImagePixel> checkPixels = new List<ImagePixel>(); if (singleMidX && singleMidY) { ulong midIdx = (ulong)(m_Width * midY + midX); if (!m_Pixels.ContainsKey(midIdx)) { // TODO: Send a warning of irregularly shaped feature } return ImagePixel.CreateImagePixelWithFeatureId(this.FeatureId, (int)m_MaxBrightness, midX, midY); } else if (singleMidX) { // Analyse 2 possible center points checkPixels.Add(ImagePixel.CreateImagePixelWithFeatureId(this.FeatureId, (int)m_MaxBrightness, midX, midY)); checkPixels.Add(ImagePixel.CreateImagePixelWithFeatureId(this.FeatureId, (int)m_MaxBrightness, midX, midY + 1)); } else if (singleMidY) { // Analyse 2 possible center points checkPixels.Add(ImagePixel.CreateImagePixelWithFeatureId(this.FeatureId, (int)m_MaxBrightness, midX, midY)); checkPixels.Add(ImagePixel.CreateImagePixelWithFeatureId(this.FeatureId, (int)m_MaxBrightness, midX + 1, midY)); } else { // Analyse 4 possible center points checkPixels.Add(ImagePixel.CreateImagePixelWithFeatureId(this.FeatureId, (int)m_MaxBrightness, midX, midY)); checkPixels.Add(ImagePixel.CreateImagePixelWithFeatureId(this.FeatureId, (int)m_MaxBrightness, midX, midY + 1)); checkPixels.Add(ImagePixel.CreateImagePixelWithFeatureId(this.FeatureId, (int)m_MaxBrightness, midX + 1, midY)); checkPixels.Add(ImagePixel.CreateImagePixelWithFeatureId(this.FeatureId, (int)m_MaxBrightness, midX + 1, midY + 1)); } m_Center = null; long centerBrightness = 0; foreach (ImagePixel pixel in checkPixels) { long totalBrightness = 0; for (int i = -1; i <= 1; i++) for (int j = -1; j <= 1; j++) { totalBrightness += this[pixel.X + i, pixel.Y + j]; } if (centerBrightness < totalBrightness) { centerBrightness = totalBrightness; m_Center = pixel; } } } } return m_Center; }
private bool CheckTrianglesWithRatiosByMagnitude(int i, int j, int k, ImagePixel iCenter, ImagePixel jCenter, ImagePixel kCenter, double toleranceInArcSec) { if (iCenter == null || jCenter == null || kCenter == null) return false; double dijMax = m_PlateConfig.GetDistanceInArcSec(iCenter.XDouble, iCenter.YDouble, jCenter.XDouble, jCenter.YDouble, (1 - m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); double dijMin = m_PlateConfig.GetDistanceInArcSec(iCenter.XDouble, iCenter.YDouble, jCenter.XDouble, jCenter.YDouble, (1 + m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); double dikMax = m_PlateConfig.GetDistanceInArcSec(iCenter.XDouble, iCenter.YDouble, kCenter.XDouble, kCenter.YDouble, (1 - m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); double dikMin = m_PlateConfig.GetDistanceInArcSec(iCenter.XDouble, iCenter.YDouble, kCenter.XDouble, kCenter.YDouble, (1 + m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); double djkMax = m_PlateConfig.GetDistanceInArcSec(jCenter.XDouble, jCenter.YDouble, kCenter.XDouble, kCenter.YDouble, (1 - m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); double djkMin = m_PlateConfig.GetDistanceInArcSec(jCenter.XDouble, jCenter.YDouble, kCenter.XDouble, kCenter.YDouble, (1 + m_Settings.PyramidFocalLengthAllowance) * m_PlateConfig.EffectiveFocalLength); List<DistanceEntry> ijCandidates = m_DistancesByMagnitude .Where(e => e.DistanceArcSec > dijMin && e.DistanceArcSec < dijMax).ToList(); if (m_ManualPairs != null && m_ManualPairs.Count <= 3) LimitIJtoManualPairs(ijCandidates); bool debugFieldIdentified = true; bool debug = false; ulong debugiStarNo = 0; ulong debugjStarNo = 0; ulong debugkStarNo = 0; if (DebugResolvedStars != null) { if (DebugResolvedStars.ContainsKey(i) && DebugResolvedStars.ContainsKey(j) && DebugResolvedStars.ContainsKey(k)) { debugiStarNo = DebugResolvedStars[i]; debugjStarNo = DebugResolvedStars[j]; debugkStarNo = DebugResolvedStars[k]; debug = true; debugFieldIdentified = false; } } try { if (debug) { // The ijCandidates must contain the IJ pair DistanceEntry rightijEntry = ijCandidates.FirstOrDefault(c => (c.Star1.StarNo == debugiStarNo && c.Star2.StarNo == debugjStarNo) || (c.Star1.StarNo == debugjStarNo && c.Star2.StarNo == debugiStarNo)); if(rightijEntry == null) { DistanceEntry masterijEntry = m_DistancesByMagnitude.FirstOrDefault(c => (c.Star1.StarNo == debugiStarNo && c.Star2.StarNo == debugjStarNo) || (c.Star1.StarNo == debugjStarNo && c.Star2.StarNo == debugiStarNo)); Trace.Assert(masterijEntry != null); } } foreach (DistanceEntry ijEntry in ijCandidates) { List<DistanceEntry> ikCandidates = m_DistancesByMagnitude .Where(e => (e.Star1.StarNo == ijEntry.Star1.StarNo || e.Star2.StarNo == ijEntry.Star1.StarNo || e.Star1.StarNo == ijEntry.Star2.StarNo || e.Star2.StarNo == ijEntry.Star2.StarNo) && e.DistanceArcSec > dikMin && e.DistanceArcSec < dikMax) .ToList(); if (m_ManualPairs != null && m_ManualPairs.Count == 3) LimitIKtoManualPairs(ikCandidates); if (debug && ( (debugiStarNo == ijEntry.Star1.StarNo && debugjStarNo == ijEntry.Star2.StarNo) || (debugiStarNo == ijEntry.Star2.StarNo && debugjStarNo == ijEntry.Star1.StarNo))) { // The ikCandidates must contain the IK pair DistanceEntry rightikEntry = ikCandidates.FirstOrDefault(c => (c.Star1.StarNo == debugkStarNo || c.Star2.StarNo == debugkStarNo)); if (rightikEntry == null) { rightikEntry = m_DistancesByMagnitude.FirstOrDefault(c => (c.Star1.StarNo == debugiStarNo && c.Star2.StarNo == debugkStarNo) || (c.Star1.StarNo == debugkStarNo && c.Star2.StarNo == debugiStarNo)); if (rightikEntry != null) Trace.Assert(rightikEntry.DistanceArcSec > dikMin && rightikEntry.DistanceArcSec < dikMax); else Trace.Assert(false, string.Format("Cannot find the ik pair ({0}, {1}) in the area distances.", debugiStarNo, debugkStarNo)); } } foreach (DistanceEntry ikEntry in ikCandidates) { bool debugTrippleFound = false; if (debug && ((debugiStarNo == ijEntry.Star1.StarNo && debugjStarNo == ijEntry.Star2.StarNo) || (debugiStarNo == ijEntry.Star2.StarNo && debugjStarNo == ijEntry.Star1.StarNo)) && (debugkStarNo == ikEntry.Star1.StarNo || debugkStarNo == ikEntry.Star2.StarNo)) { debugTrippleFound = true; } // Ratios are preserved when changing the focal length (with linear fit) so check the ratios here double fittedFocalLength = m_PlateConfig.GetFocalLengthFromMatch( ijEntry.DistanceArcSec, ikEntry.DistanceArcSec, iCenter, jCenter, kCenter, toleranceInArcSec, m_Settings.PyramidFocalLengthAllowance); if (double.IsNaN(fittedFocalLength)) { Trace.Assert(!debugTrippleFound); continue; } double djk = m_PlateConfig.GetDistanceInArcSec(jCenter.XDouble, jCenter.YDouble, kCenter.XDouble, kCenter.YDouble, fittedFocalLength); ulong iStarNo = uint.MaxValue; ulong needIdx1 = uint.MaxValue; ulong needIdx2 = uint.MaxValue; if (ikEntry.Star1.StarNo == ijEntry.Star1.StarNo) { // ik_1 = ij_1 = (i) iStarNo = ikEntry.Star1.StarNo; needIdx1 = ikEntry.Star2.StarNo; needIdx2 = ijEntry.Star2.StarNo; } else if (ikEntry.Star1.StarNo == ijEntry.Star2.StarNo) { // ik_1 = ij_2 = (i) iStarNo = ikEntry.Star1.StarNo; needIdx1 = ikEntry.Star2.StarNo; // (k) needIdx2 = ijEntry.Star1.StarNo; // (j) } else if (ikEntry.Star2.StarNo == ijEntry.Star1.StarNo) { // ik_2 = ij_1 = (i) iStarNo = ikEntry.Star2.StarNo; needIdx1 = ikEntry.Star1.StarNo; // (k) needIdx2 = ijEntry.Star2.StarNo; // (j) } else if (ikEntry.Star2.StarNo == ijEntry.Star2.StarNo) { // ik_2 = ij_2 = (i) iStarNo = ikEntry.Star2.StarNo; needIdx1 = ikEntry.Star1.StarNo; // (k) needIdx2 = ijEntry.Star1.StarNo; // (j) } else { Trace.Assert(!debugTrippleFound); continue; } if (needIdx1 == needIdx2) { Trace.Assert(!debugTrippleFound); continue; } DistanceEntry jkEntry = m_DistancesByMagnitude.Where(e => (e.Star1.StarNo == needIdx1 && e.Star2.StarNo == needIdx2) || (e.Star1.StarNo == needIdx2 && e.Star2.StarNo == needIdx1)).FirstOrDefault(); if (jkEntry != null) { ulong jStarNo = uint.MaxValue; ulong kStarNo = uint.MaxValue; if (jkEntry.DistanceArcSec + toleranceInArcSec < djkMin) { Trace.Assert(!debugTrippleFound); continue; } if (jkEntry.DistanceArcSec - toleranceInArcSec > djkMax) { Trace.Assert(!debugTrippleFound); continue; } if (jkEntry.DistanceArcSec + toleranceInArcSec < djk) { Trace.Assert(!debugTrippleFound); continue; } if (jkEntry.DistanceArcSec - toleranceInArcSec > djk) { Trace.Assert(!debugTrippleFound); continue; } if (jkEntry.Star1.StarNo == needIdx1 && jkEntry.Star2.StarNo == needIdx2) { m_Solution = IsSuccessfulMatch(m_StarMap, i, j, k, ijEntry, ikEntry, jkEntry, iStarNo, needIdx1, needIdx2, fittedFocalLength, true, toleranceInArcSec); if (m_Solution != null) { jStarNo = needIdx1; kStarNo = needIdx2; debugFieldIdentified = true; } else { Trace.Assert(!debugTrippleFound); continue; } } if (jkEntry.Star1.StarNo == needIdx2 && jkEntry.Star2.StarNo == needIdx1) { m_Solution = IsSuccessfulMatch(m_StarMap, i, j, k, ijEntry, ikEntry, jkEntry, iStarNo, needIdx1, needIdx2, fittedFocalLength, true, toleranceInArcSec); if (m_Solution != null) { jStarNo = needIdx2; kStarNo = needIdx1; debugFieldIdentified = true; } else { Trace.Assert(!debugTrippleFound); continue; } } if (m_Solution != null) { if (TangraConfig.Settings.Astrometry.PyramidNumberOfPivots == 3) // Exist the initial alignment with only 3 candidate pivots return true; for (int l = 0; l < m_StarMap.Features.Count; l++) { var piramid = m_StarMap.Features[l]; if (piramid.FeatureId == i || piramid.FeatureId == j || piramid.FeatureId == k) continue; var lCenter = piramid.GetCenter(); // NOTE: Continue until a set of distances is found in the cache for the 4-th pivot double dli = m_PlateConfig.GetDistanceInArcSec(lCenter.XDouble, lCenter.YDouble, iCenter.XDouble, iCenter.YDouble, fittedFocalLength); double dlj = m_PlateConfig.GetDistanceInArcSec(lCenter.XDouble, lCenter.YDouble, jCenter.XDouble, jCenter.YDouble, fittedFocalLength); double dlk = m_PlateConfig.GetDistanceInArcSec(lCenter.XDouble, lCenter.YDouble, kCenter.XDouble, kCenter.YDouble, fittedFocalLength); List<DistanceEntry> ilCandidates = m_DistancesByMagnitude .Where(e => (e.Star1.StarNo == iStarNo || e.Star2.StarNo == iStarNo) && e.DistanceArcSec < dli + toleranceInArcSec && e.DistanceArcSec > dli - toleranceInArcSec) .ToList(); foreach (var cand_il in ilCandidates) { var lStar = cand_il.Star1.StarNo == iStarNo ? cand_il.Star2 : cand_il.Star1; List<DistanceEntry> jlCandidates = m_DistancesByMagnitude .Where(e => ((e.Star1.StarNo == jStarNo && e.Star2.StarNo == lStar.StarNo) || (e.Star1.StarNo == lStar.StarNo && e.Star2.StarNo == jStarNo)) && e.DistanceArcSec < dlj + toleranceInArcSec && e.DistanceArcSec > dlj - toleranceInArcSec) .ToList(); List<DistanceEntry> klCandidates = m_DistancesByMagnitude .Where(e => ((e.Star1.StarNo == kStarNo && e.Star2.StarNo == lStar.StarNo) || (e.Star1.StarNo == lStar.StarNo && e.Star2.StarNo == kStarNo)) && e.DistanceArcSec < dlk + toleranceInArcSec && e.DistanceArcSec > dlk - toleranceInArcSec) .ToList(); if (jlCandidates.Count > 0 && klCandidates.Count > 0) { if (klCandidates.Count > 0) return true; } } } } } } } } finally { if (debug && !debugFieldIdentified) { DebugCheckUnidentifiedStars( dijMin, dijMax, dikMin, dikMax, djkMin, djkMax, debugiStarNo, debugjStarNo, debugkStarNo, i, j, k); } } return false; }
internal void AddPixel(int x, int y, uint brightness) { uint idx = (uint)m_Width * (uint)y + (uint)x; if (m_Pixels.ContainsKey(idx)) { #if ASTROMETRY_DEBUG Trace.Assert(m_Pixels[idx] == brightness); #endif } else { m_Pixels.Add(idx, brightness); if (brightness > m_MaxBrightness) { m_MaxBrightness = brightness; m_MaxBrightnessFirstKey = idx; m_MaxBrightnessPixels = 1; } else if (brightness == m_MaxBrightness) m_MaxBrightnessPixels++; } m_Center = null; m_Intencity = UInt32.MaxValue; }
private bool RegisterRecognizedPair(ImagePixel starCenter, IStar celestialStar, int featureId) { if (m_MatchedPairs.ContainsKey(starCenter)) { // The feature has been already matched with a different star (from a different triangle) // Probably the two stars are very close to each other. In this case we don't add the second match // and mark the first match as ambigous. Then later on if there is sufficient amount of pairs // the first match may be removed as well. if (m_AmbiguousMatches.IndexOf(starCenter) == -1) m_AmbiguousMatches.Add(starCenter); return false; } m_MatchedPairs.Add(starCenter, celestialStar); m_MatchedFeatureIdToStarIdIndexes.Add(featureId, celestialStar.StarNo); return true; }
public static Dictionary<ImagePixel, double> LocateHotPixels(AstroImage image, uint[,] model, uint modelMedian) { var rv = new Dictionary<ImagePixel, double>(); if (s_NumSamplesCombined > 0) { int width = image.Pixelmap.Width; int height = image.Pixelmap.Height; uint abv = model[3, 3] - modelMedian; uint minPeakLevel = (uint)(modelMedian + PEAK_PIXEL_LEVEL_REQUIRED * abv); EnumeratePeakPixels(image.Pixelmap.GetPixelsCopy(), width, height, minPeakLevel, Rectangle.Empty, (x, y, z) => { if (x >= 3 && x < width - 3 && y >= 3 && y < height - 3) { var newPix = new ImagePixel((int) z, x, y); if (!rv.Keys.ToArray().Any(p => p.DistanceTo(newPix) < 5)) rv.Add(newPix, long.MinValue); } }); foreach (ImagePixel center in rv.Keys.ToArray()) { uint[,] testArea = image.GetPixelsArea(center.X, center.Y, 7); var score = ScoreArea(testArea); rv[center] = score.Item1; } var positions = rv.Keys.ToArray(); var scores = rv.Values.ToArray(); Array.Sort(scores, positions); s_Candidates = positions; s_CandidateScores = scores; } return rv; }
public ImagePixel(ImagePixel clone) : this(clone.Brightness, clone.XDouble, clone.YDouble) { }