private void CalculateAndDisplayBackground(uint[,] backgroundPixels) { if (backgroundPixels != null) { int bgWidth = backgroundPixels.GetLength(0); int bgHeight = backgroundPixels.GetLength(1); var bgPixels = new List <uint>(); for (int x = 0; x < bgWidth; x++) { for (int y = 0; y < bgHeight; y++) { if (m_PSFFit == null || !m_PSFFit.IsSolved || ImagePixel.ComputeDistance(m_PSFFit.XCenter, x + bgWidth - m_PSFFit.MatrixSize, m_PSFFit.YCenter, y + bgHeight - m_PSFFit.MatrixSize) > 3 * m_PSFFit.FWHM) { bgPixels.Add(backgroundPixels[x, y]); } } } bgPixels.Sort(); double background = 0; if (bgPixels.Count > 1) { background = m_Bpp < 12 ? bgPixels[bgPixels.Count / 2] // for 8 bit videos Median background works better : bgPixels.Average(x => x); // for 12+bit videos average background works better } double residualsSquareSum = 0; foreach (uint bgPixel in bgPixels) { residualsSquareSum += (background - bgPixel) * (background - bgPixel); } double noise = Math.Sqrt(residualsSquareSum / (bgPixels.Count - 1)); lblBackground.Text = background.ToString("0.0"); lblNoise.Text = noise.ToString("0.0"); if (m_PSFFit != null) { double snr = m_PSFFit.GetSNR(); lblSNR.Text = snr.ToString("0.0"); } else { lblSNR.Text = "N/A"; } if (m_PSFFit != null) { lblFitVariance.Text = m_PSFFit.GetVariance().ToString("0.0"); lblFWHM.Text = m_PSFFit.FWHM.ToString("0.0"); } else { lblFitVariance.Text = "N/A"; lblFWHM.Text = "N/A"; } } else { lblBackground.Text = "N/A"; lblNoise.Text = "N/A"; lblSNR.Text = "N/A"; } }
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); }