/// <summary> /// Creates a new ImageDetection from a given image, set of points and values. It also populates it with <see cref="ObjectPhotometry"/>, <see cref="ObjectPoints"/>, /// and <see cref="ObjectSize"/> properties. /// </summary> /// <param name="Image">Image on which the object was detected.</param> /// <param name="Points">The set of points on the image where it has been detected.</param> /// <param name="Values">The set of pixel intensitities.</param> /// <returns>A new instance of ImageDetection with the specified extension properties.</returns> public static ImageDetection CreateDetection(Image Image, IEnumerable <PixelPoint> Points, IEnumerable <double> Values) { IWCSProjection Transform = Image.Transform; PixelPoint[] PixPoints = Points.ToArray(); double[] PixValues = Values.ToArray(); EquatorialPoint[] EquatorialPoints = Transform.GetEquatorialPoints(PixPoints); double Xmean = 0, Ymean = 0; double XXP = 0, XYP = 0, YYP = 0; double XXB = 0, XYB = 0, YYB = 0; double Flux = 0; double XBmean = 0, YBmean = 0; for (int i = 0; i < PixPoints.Length; i++) { PixelPoint pt = PixPoints[i]; double Val = PixValues[i]; Xmean += pt.X; Ymean += pt.Y; XBmean += Val * pt.X; YBmean += Val * pt.Y; XXB += pt.X * pt.X * Val; XYB += pt.X * pt.Y * Val; YYB += pt.Y * pt.Y * Val; XXP += pt.X * pt.X; XYP += pt.X * pt.Y; YYP += pt.Y * pt.Y; Flux += Val; } Xmean /= PixPoints.Length; Ymean /= PixPoints.Length; XBmean /= Flux; YBmean /= Flux; XXB /= Flux; XYB /= Flux; YYB /= Flux; XXP /= PixPoints.Length; XYP /= PixPoints.Length; YYP /= PixPoints.Length; XXB -= XBmean * XBmean; XYB -= XBmean * YBmean; YYB -= YBmean * YBmean; XXP -= Xmean * Xmean; XYP -= Xmean * Ymean; YYP -= Ymean * Ymean; PixelPoint BarycenterPP = new PixelPoint() { X = XBmean, Y = YBmean }; EquatorialPoint BarycenterEP = Transform.GetEquatorialPoint(BarycenterPP); Position Pos = new Position(BarycenterEP, BarycenterPP); SourceEllipse BarycentricEllipse = new SourceEllipse(XXB, XYB, YYB); SourceEllipse PixelEllipse = new SourceEllipse(XXP, XYP, YYP); ObjectSize Shape = new ObjectSize() { BarycentricEllipse = BarycentricEllipse, PixelEllipse = PixelEllipse }; ImageDetection Detection = new ImageDetection(Pos, Image.GetProperty <ObservationTime>(), Image); Detection.AppendProperty(Shape); Detection.AppendProperty(new ObjectPhotometry() { Flux = Flux }); Detection.AppendProperty(new ObjectPoints() { PixelPoints = PixPoints, PixelValues = PixValues, EquatorialPoints = EquatorialPoints }); return(Detection); }
public bool PairPossible(ImageDetection a, ImageDetection b) { PairingProperties App = a.FetchOrCreate <PairingProperties>(), Bpp = b.FetchOrCreate <PairingProperties>(); if (App.IsPaired || Bpp.IsPaired) { return(false); } if (App.StarPolluted || Bpp.StarPolluted) { return(false); } if (a.Time.Time == b.Time.Time) { return(false); } TimeSpan DeltaTime = a.Time.Time - b.Time.Time; //if ((a.LargestDistance + b.LargestDistance) * Math.Abs(DeltaTime.TotalSeconds) < (a.Barycenter.EP ^ b.Barycenter.EP) * (a.Time.Exposure.TotalSeconds + b.Time.Exposure.TotalSeconds) / 2) return false; SourceEllipse aPel = a.FetchProperty <ObjectSize>().PixelEllipse, bPel = b.FetchProperty <ObjectSize>().PixelEllipse; if (aPel.SemiaxisMajor > LongTrailHighThreshold * LongTrailHighThreshold) { if (bPel.SemiaxisMajor < LongTrailLowThreshold * LongTrailLowThreshold) { return(false); } } double DeltaAngle = aPel.SemiaxisMajorAngle - bPel.SemiaxisMajorAngle; double Length = aPel.SemiaxisMajor + bPel.SemiaxisMajor; if (DeltaAngle * DeltaAngle * Math.Sqrt(Length) > AngleDistanceDifferenceThreshold) { return(false); } return(true); }
/// <summary> /// Runs the hysteresis connected component detection algorithm for light sources. At the end also applies the extra circular masking. /// </summary> /// <param name="Mask">Mask array.</param> /// <param name="MaskData">Masking image data.</param> /// <param name="Alignment">Position of data in the image.</param> /// <param name="DPoint">Starting point for the connected component algorithm.</param> /// <param name="LowerThreshold">Lower hysteresis threshold.</param> /// <param name="RadiusMultiplier">Ratio between extra masking circle radius and light source radius.</param> /// <param name="ExtraRadius">Extra radius for the masking circle.</param> /// <param name="Star">The potential output star.</param> static void BitmapFill(BitArray[] Mask, double[,] MaskData, PixelPoint Alignment, PixelPoint DPoint, double LowerThreshold, double RadiusMultiplier, double ExtraRadius, out Filtering.Star?Star) { Queue <PixelPoint> PointQ = new Queue <PixelPoint>(); PointQ.Enqueue(DPoint); double XMean = 0, YMean = 0, XSquare = 0, YSquare = 0, XY = 0; int PCount = 0; double Flux = 0; while (PointQ.Count > 0) { PixelPoint pt = PointQ.Dequeue(); if (pt.X < 0 || pt.X >= Mask[0].Length) { continue; } if (pt.Y < 0 || pt.Y >= Mask.Length) { continue; } if (Mask[(int)pt.Y][(int)pt.X]) { continue; } double dX = pt.X - Alignment.X; double dY = pt.Y - Alignment.Y; dX = Math.Round(dX); dY = Math.Round(dY); if (dX < 0 || dX >= MaskData.GetLength(1)) { continue; } if (dY < 0 || dY >= MaskData.GetLength(0)) { continue; } if (MaskData[(int)dY, (int)dX] > LowerThreshold) { Mask[(int)pt.Y][(int)pt.X] = true; PointQ.Enqueue(new PixelPoint() { X = pt.X - 1, Y = pt.Y }); PointQ.Enqueue(new PixelPoint() { X = pt.X + 1, Y = pt.Y }); PointQ.Enqueue(new PixelPoint() { X = pt.X, Y = pt.Y - 1 }); PointQ.Enqueue(new PixelPoint() { X = pt.X, Y = pt.Y + 1 }); XMean += pt.X; YMean += pt.Y; XSquare += pt.X * pt.X; YSquare += pt.Y * pt.Y; XY += pt.X * pt.Y; PCount++; Flux += MaskData[(int)dY, (int)dX]; } } /* Computes size of and shape of the light source */ XMean /= PCount; YMean /= PCount; XSquare /= PCount; YSquare /= PCount; XY /= PCount; XSquare -= XMean * XMean; YSquare -= YMean * YMean; XY -= XMean * YMean; double Radius = Math.Sqrt(XSquare + YSquare); SourceEllipse Shape = new SourceEllipse(XSquare, XY, YSquare); /* If not to irregular, suppose it is a star and apply extra masking. */ if (Shape.SemiaxisMajor < 3 * Shape.SemiaxisMinor) { FillMarginsExtra(Mask, new PixelPoint() { X = XMean, Y = YMean }, Radius * RadiusMultiplier + ExtraRadius); Star = new Filtering.Star() { Shape = Shape, PixCenter = new PixelPoint() { X = XMean, Y = YMean }, PixRadius = Radius, Flux = Flux }; } else { Star = null; } }