/// <summary> /// Calls the algorithm code (depending on its type). /// </summary> static void CallAlgorithm(RunDetails Details, ImageData[] Inputs, ImageData Output) { switch (Details.Type) { case AlgorithmType.SimpleMap_T: Details.Algorithm.DynamicInvoke(Inputs[0].Data, Output.Data, Details.Parameters[0]); break; case AlgorithmType.SimpleMap_TU: Details.Algorithm.DynamicInvoke(Inputs[0].Data, Output.Data, Details.Parameters[0], Details.Parameters[1]); break; case AlgorithmType.SimpleMap_TUV: Details.Algorithm.DynamicInvoke(Inputs[0].Data, Output.Data, Details.Parameters[0], Details.Parameters[1], Details.Parameters[2]); break; case AlgorithmType.PositionMap: ImageSegmentPosition pmIP = GetPosition(Inputs[0]); ImageSegmentPosition pmOP = GetPosition(Output); Details.Algorithm.DynamicInvoke(Inputs[0].Data, Output.Data, pmIP, pmOP, Details.Parameters[0]); break; case AlgorithmType.Combiner: ImageSegmentPosition[] cIP = Inputs.Select(GetPosition).ToArray(); ImageSegmentPosition cOP = GetPosition(Output); Details.Algorithm.DynamicInvoke(Inputs.Select((x) => x.Data).ToArray(), Output.Data, cIP, cOP, Details.Parameters[0]); break; case AlgorithmType.Extractor: Details.Algorithm.DynamicInvoke(Inputs[0].Data, Details.Parameters[0]); break; case AlgorithmType.PositionExtractor: Details.Algorithm.DynamicInvoke(Inputs[0].Data, GetPosition(Inputs[0]), Details.Parameters[0]); break; } }
static void DetectSources(double[,] Input, ImageSegmentPosition Position, BitArray[] Mask) { for (int i = 0; i < Input.GetLength(0); i++) { for (int j = 0; j < Input.GetLength(1); j++) { int Y = i + (int)System.Math.Round(Position.Alignment.Y); int X = j + (int)System.Math.Round(Position.Alignment.X); Mask[Y][X] = (Input[i, j] != 0); } } }
/// <summary> /// Actual detection function for trailless light sources. /// </summary> /// <param name="Input">Input image data.</param> /// <param name="Position">Data position in the image.</param> /// <param name="Instance">DotDetector instance in which this is called.</param> static void DetectSources(double[,] Input, ImageSegmentPosition Position, DotDetector Instance) { int OW = Input.GetLength(1); int OH = Input.GetLength(0); int i, j; bool[,] Mask = new bool[OH, OW]; List <DotDetection> ldot = new List <DotDetection>(); /* Local mean & variance computation */ double Mean = 0, Var = 0; double NThSq = Instance.NonrepresentativeThreshold * Instance.NonrepresentativeThreshold; int cnt = 0; for (i = 0; i < OH; i++) { for (j = 0; j < OW; j++) { if (Input[i, j] * Input[i, j] < NThSq) { Mean += Input[i, j]; Var += Input[i, j] * Input[i, j]; cnt++; } } } Mean /= cnt; Var /= cnt; Var -= Mean * Mean; double StDev = Sqrt(Var); double HighThreshold = Instance.HighThresholdMultiplier * StDev + Mean; double LowThreshold = Instance.LowThresholdMultiplier * StDev + Mean; /* Hysteresis-based detection */ for (i = 0; i < OH; i++) { for (j = 0; j < OW; j++) { if (Mask[i, j]) { continue; } if (Input[i, j] > HighThreshold) { ldot.Add(BitmapFill(Input, new IntPoint() { X = j, Y = i }, Mask, LowThreshold, (int)Position.Alignment.X, (int)Position.Alignment.Y)); } } } ldot.RemoveAll((x) => x.Pixels.Count < Instance.MinPix); lock (Instance.Detections) Instance.Detections.AddRange(ldot); }
static void CoreFilterAlgorithm(double[,] Input, double[,] Output, ImageSegmentPosition InputPosition, ImageSegmentPosition OutPos, CoreFilterParameters FilterParameters) { int OW = Output.GetLength(1); int OH = Output.GetLength(0); int i, j, k, l; int Size = (int)Math.Round(Math.Sqrt(FilterParameters.PSF.Length)); int XSz = Size / 2; double[] MedValues = new double[FilterParameters.PSF.Length]; double[] DPSF = new double[FilterParameters.PSF.Length]; int cnt; double s; int SzD = Size / 2; for (i = 0; i < OH; i++) { for (j = 0; j < OW; j++) { cnt = 0; for (k = 0; k < Size; k++) { for (l = 0; l < Size; l++) { int Y = i + k + ((int)Math.Round(InputPosition.Alignment.Y)); int X = j + l + ((int)Math.Round(InputPosition.Alignment.X)); if (X < 0 || X >= FilterParameters.Mask[0].Length || Y < 0 || Y >= FilterParameters.Mask.Length) { continue; } DPSF[cnt] = FilterParameters.PSF[k * Size + l]; if (!FilterParameters.Mask[Y][X]) { MedValues[cnt] = Input[i + k, j + l]; cnt++; } } } if (cnt <= 2 * Size + 1) { Output[i, j] = 0; } else { Array.Sort(MedValues, DPSF, 0, cnt); double w; for (s = 0, w = 0, k = Size; k <= cnt - Size; k++) { s += MedValues[k] * DPSF[k]; w += DPSF[k]; } Output[i, j] = s / w; } } } }
/// <summary>Mesh generation function.</summary> static void RunMesh(double[,] Input, ImageSegmentPosition Position, Point4Distance Mesh) { /* Find median of input block */ double[] V = new double[Input.Length]; Buffer.BlockCopy(Input, 0, V, 0, V.Length * sizeof(double)); Array.Sort(V); /* In very bright regions, keep image's zero level as the median, thus avoiding background stretching by stars */ if (Abs(V[V.Length / 2] - Mesh.InputStat.ZeroLevel) > 10 * Mesh.InputStat.StDev) { V[V.Length / 2] = Mesh.InputStat.ZeroLevel; } /* Load the median as a mesh point */ Mesh.MedianPoints[(int)Round(Position.Alignment.Y) / Mesh.MeshSize, (int)Round(Position.Alignment.X) / Mesh.MeshSize] = V[V.Length / 2]; }
static void MaskBadpixel(double[,] Input, double[,] Output, ImageSegmentPosition InputPosition, ImageSegmentPosition OutputPosition, BitArray[] Mask) { System.Diagnostics.Debug.Assert(InputPosition.Alignment.X == OutputPosition.Alignment.X); System.Diagnostics.Debug.Assert(InputPosition.Alignment.Y == OutputPosition.Alignment.Y); for (int i = 0; i < Input.GetLength(0); i++) { for (int j = 0; j < Input.GetLength(1); j++) { int Y = i + (int)System.Math.Round(InputPosition.Alignment.Y); int X = j + (int)System.Math.Round(InputPosition.Alignment.X); Output[i, j] = (Mask[Y][X] ? 0.0 : Input[i, j]); } } }
/// <summary> /// Creates a mask from an image. All light sources are detected via a hysteresis algorithm and flagged in the mask. /// </summary> /// <param name="Input">Input image data.</param> /// <param name="Position">Data position in the image.</param> /// <param name="Properties">Bag of mask data.</param> static void GenerateMask(double[,] Input, ImageSegmentPosition Position, MaskProperties Properties) { int Width = Input.GetLength(1); int Height = Input.GetLength(0); int i, j; PixelPoint pxp = new PixelPoint(); /* Compute masking thresholds */ double UpperThreshold = Properties.UTM * Properties.StDev + Properties.Mean; double LowerThreshold = Properties.LTM * Properties.StDev + Properties.Mean; for (i = 0; i < Height; i++) { for (j = 0; j < Width; j++) { pxp.X = j + Position.Alignment.X; pxp.Y = i + Position.Alignment.Y; if (pxp.Y >= Properties.MaskData.Length) { break; } if (pxp.X >= Properties.MaskData[(int)pxp.Y].Length) { break; } if (Properties.MaskData[(int)pxp.Y][(int)pxp.X]) { continue; } if (Input[i, j] > UpperThreshold) { BitmapFill(Properties.MaskData, Input, Position.Alignment, pxp, LowerThreshold, Properties.MaskRadiusMultiplier, Properties.ExtraMaskRadius, out Filtering.Star? Star); if (Star != null) { Filtering.Star S = Star.Value; S.EqCenter = Position.WCS.GetEquatorialPoint(S.PixCenter); lock (Properties.StarList) Properties.StarList.FixedStarList.Add(S); } } } } }
/// <summary> /// Masks the input image with a given mask. Masked pixels are set to -1 standard deviation. /// </summary> /// <param name="Input">Input image data.</param> /// <param name="Output">Output image data.</param> /// <param name="InputPosition">Input data position.</param> /// <param name="OutputPosition">Output data position.</param> /// <param name="Properties">Mask data.</param> static void MaskImage(double[,] Input, double[,] Output, ImageSegmentPosition InputPosition, ImageSegmentPosition OutputPosition, MaskProperties Properties) { int Width = Output.GetLength(1); int Height = Output.GetLength(0); int i, j; PixelPoint pxp = new PixelPoint(); for (i = 0; i < Height; i++) { for (j = 0; j < Width; j++) { pxp.X = j + OutputPosition.Alignment.X; pxp.Y = i + OutputPosition.Alignment.Y; EquatorialPoint ep = OutputPosition.WCS.GetEquatorialPoint(pxp); PixelPoint mpt = Properties.MaskTransform.GetPixelPoint(ep); mpt.X = Math.Round(mpt.X); mpt.Y = Math.Round(mpt.Y); if (mpt.X < 0 || mpt.X >= Properties.MaskData[0].Length) { continue; } if (mpt.Y < 0 || mpt.Y >= Properties.MaskData.Length) { continue; } PixelPoint ipt = InputPosition.WCS.GetPixelPoint(ep); ipt.X = Math.Round(ipt.X - InputPosition.Alignment.X); ipt.Y = Math.Round(ipt.Y - InputPosition.Alignment.Y); if (Properties.MaskData[(int)mpt.Y][(int)mpt.X]) { Output[i, j] = -Properties.StDev; } else { Output[i, j] = Input[(int)ipt.Y, (int)ipt.X] - Properties.Mean; } } } }
/// <summary> /// Output normalization function. /// </summary> static void Normalize(double[,] Input, double[,] Output, ImageSegmentPosition InputPosition, ImageSegmentPosition OutputPosition, Point4Distance Mesh) { int OH = Input.GetLength(0), OW = Input.GetLength(1); int i, j; /* Deal with image edges */ if (InputPosition.Alignment.Y <= Mesh.MeshSize) { for (i = 0; i < OH; i++) { for (j = 0; j < Mesh.MeshSize; j++) { Output[i, j] = Input[i, j] - Mesh.MedianPoints[2, 2]; } for (; j < OW - Mesh.MeshSize; j++) { Output[i, j] = Input[i, j] - Mesh.MedianPoints[2, j / Mesh.MeshSize]; } for (; j < OW; j++) { Output[i, j] = Input[i, j] - Mesh.MedianPoints[2, Mesh.MedianPoints.GetLength(1) - 3]; } } return; } if (InputPosition.Alignment.Y + 2 * Mesh.MeshSize >= Mesh.Input.Height) { for (i = 0; i < OH; i++) { for (j = 0; j < Mesh.MeshSize; j++) { Output[i, j] = Input[i, j] - Mesh.MedianPoints[Mesh.MedianPoints.GetLength(0) - 2, 2]; } for (; j < OW - Mesh.MeshSize; j++) { Output[i, j] = Input[i, j] - Mesh.MedianPoints[Mesh.MedianPoints.GetLength(0) - 2, j / Mesh.MeshSize]; } for (j = 0; j < Mesh.MeshSize; j++) { Output[i, j] = Input[i, j] - Mesh.MedianPoints[Mesh.MedianPoints.GetLength(0) - 2, Mesh.MedianPoints.GetLength(1) - 3]; } } return; } for (i = 0; i < OH; i++) { for (j = 0; j < 3 * Mesh.MeshSize / 2; j++) { Output[i, j] = Input[i, j] - Mesh.MedianPoints[(i + (int)InputPosition.Alignment.Y) / Mesh.MeshSize, 2]; } /* Perform main loop */ for (; j < OW - 3 * Mesh.MeshSize / 2; j++) { int PX = (int)InputPosition.Alignment.X + j; int PY = (int)InputPosition.Alignment.Y + i; double[] Distances = new double[4]; double DistSum, ValSum; /* Find nearest mesh points and the distances to them */ int dPX = PX % Mesh.MeshSize; int dPY = PY % Mesh.MeshSize; int kPX = PX / Mesh.MeshSize; int kPY = PY / Mesh.MeshSize; Distances[0] = Sqrt(dPX * dPX + dPY * dPY); Distances[1] = Sqrt((Mesh.MeshSize - dPX) * (Mesh.MeshSize - dPX) + dPY * dPY); Distances[2] = Sqrt((Mesh.MeshSize - dPY) * (Mesh.MeshSize - dPY) + dPX * dPX); Distances[3] = Sqrt((Mesh.MeshSize - dPX) * (Mesh.MeshSize - dPX) + (Mesh.MeshSize - dPY) * (Mesh.MeshSize - dPY)); DistSum = Distances[0] + Distances[1] + Distances[2] + Distances[3]; /* Interpolate based on the distance to each mesh point */ ValSum = (DistSum - Distances[0]) * Mesh.MedianPoints[kPY, kPX] + (DistSum - Distances[1]) * Mesh.MedianPoints[kPY, kPX + 1]; ValSum += (DistSum - Distances[2]) * Mesh.MedianPoints[kPY + 1, kPX] + (DistSum - Distances[3]) * Mesh.MedianPoints[kPY + 1, kPX + 1]; double Interpolated = ValSum / DistSum / 3; /* Remove background */ Output[i, j] = Input[i, j] - Interpolated; } for (; j < OW; j++) { Output[i, j] = Input[i, j] - Mesh.MedianPoints[(i + (int)InputPosition.Alignment.Y) / Mesh.MeshSize, Mesh.MedianPoints.GetLength(1) - 3]; } } }