/// <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); }
/// <summary> /// Attempts to recover a detection on an image. /// </summary> /// <returns>The recovered object.</returns> /// <param name="Location">Location which to check.</param> /// <param name="Radius">Maximum radius of the detection.</param> /// <param name="RecoveryImage">Image on which to perform the recovery.</param> private DotDetector.DotDetection Recover(PixelPoint Location, double Radius, Image RecoveryImage) { /* Area in the image to retrieve */ System.Drawing.Rectangle r = new System.Drawing.Rectangle((int)Math.Round(Location.X) - HalfLength, (int)Math.Round(Location.Y) - HalfLength, 2 * HalfLength, 2 * HalfLength); bool[,] Mask = new bool[2 * HalfLength, 2 * HalfLength]; /* Mask areas outside Radius */ for (int i = 0; i < 2 * HalfLength; i++) { for (int j = 0; j < 2 * HalfLength; j++) { if (!InDisk(i, j, Radius)) { Mask[i, j] = true; } } } ImageData dt = RecoveryImage.LockData(r, true); /* Compute background level of the area */ var sts = RecoveryImage.GetProperty <ImageStatistics>(); ComputeSmartStats(dt.Data, 10 * sts.StDev, out double Median, out double MedSigma); /* Perform recovery */ DotDetector.IntPoint Position = new DotDetector.IntPoint() { X = HalfLength, Y = HalfLength }; var det = DotDetector.BitmapFill(dt.Data, Position, Mask, ThresholdMultiplier * MedSigma, r.X, r.Y); RecoveryImage.ExitLock(dt); return(det); }