public void DetectExitTest() { var detector = new EntryDetector(Background) { CurrentState = DetectorState.Entry }; var images = Enumerable.Range(1, 4) .Select(i => new Image <Rgb, byte>($@"Resources\train-{i}.jpg")) .Select(image => image.Convert <Gray, byte>()) .Reverse() // just by reversing, the train exits :) .ToArray(); var emptyImages = Enumerable.Range(1, 1) .Select(i => new Image <Rgb, byte>(@"Resources\train-0.jpg")) .Select(image => image.Convert <Gray, byte>()) .ToArray(); detector.Tick(images); // Tick a few times with empty images should trigger exit for (var i = 0; i <= EntryDetector.ExitThreshold; i++) { detector.Tick(emptyImages); } Assert.AreEqual(DetectorState.Exit, detector.CurrentState); }
public void TestFull() { var timeProvider = new ExternalTimeProvider { CurrentTime = Year2000 }; var detector = new EntryDetector(Background, timeProvider); for (var k = 0; k < 2; k++) { var enterRaised = false; var exitRaised = false; detector.Enter += (sender, args) => enterRaised = true; detector.Exit += (sender, args) => exitRaised = true; detector.Abort += (sender, args) => Assert.Fail("Abort not expected"); // entry timeProvider.CurrentTime = timeProvider.CurrentTime.AddSeconds(5); detector.Tick(EntryImages); Assert.AreEqual(DetectorState.Entry, detector.CurrentState); Assert.IsTrue(enterRaised); // exit timeProvider.CurrentTime = timeProvider.CurrentTime.AddSeconds(5); for (var i = 0; i <= EntryDetector.ExitThreshold; i++) { detector.Tick(EmptyImages); } Assert.AreEqual(DetectorState.Exit, detector.CurrentState); Assert.IsTrue(exitRaised); } }
public void TestFastExitEntryRefusal() { var timeProvider = new ExternalTimeProvider(); var detector = new EntryDetector(Background, timeProvider); var enterRaised = false; var exitRaised = false; detector.Enter += (sender, args) => enterRaised = true; detector.Exit += (sender, args) => exitRaised = true; detector.Abort += (sender, args) => Assert.Fail("Abort not expected"); timeProvider.CurrentTime = Year2000; detector.Tick(EntryImages); Assert.AreEqual(DetectorState.Entry, detector.CurrentState); Assert.IsTrue(enterRaised); Assert.IsFalse(exitRaised); timeProvider.CurrentTime = timeProvider.CurrentTime.AddSeconds(EntryDetector.MinTimeAfterEntry + 1); for (var i = 0; i <= EntryDetector.ExitThreshold; i++) { detector.Tick(EmptyImages); } Assert.AreEqual(DetectorState.Exit, detector.CurrentState); Assert.IsTrue(exitRaised); enterRaised = false; timeProvider.CurrentTime = timeProvider.CurrentTime.AddSeconds(EntryDetector.MinTimeAfterExit - 1); detector.Tick(EntryImages); Assert.AreEqual(DetectorState.Exit, detector.CurrentState); Assert.IsFalse(enterRaised); }
public void DetectEntryTest() { var detector = new EntryDetector(Background); var images = Enumerable.Range(0, 2) .Select(i => new Image <Rgb, byte>(@"Resources\train-full.jpg")) .Select(train => train.Convert <Gray, byte>()) .ToArray(); detector.Tick(images); Assert.AreEqual(DetectorState.Entry, detector.CurrentState); }
public void TestBird() { var detector = new EntryDetector(Background); var images = Enumerable.Range(0, 1) .Select(i => new Image <Rgb, byte>(@"Resources\train-simulated-bird.jpg")) .Select(train => train.Convert <Gray, byte>()) .ToArray(); detector.Tick(images); Assert.AreEqual(DetectorState.Nothing, detector.CurrentState); }
public void TestBackgrounLazilyInitialized() { var detector = new EntryDetector(); var images = Enumerable.Range(0, 4) .Select(i => new Image <Rgb, byte>($@"Resources\train-{(i == 0 ? "0" : "full")}.jpg")) .Select(train => train.Convert <Gray, byte>()) .ToArray(); detector.Tick(images); Assert.AreEqual(DetectorState.Entry, detector.CurrentState); }
public void DetectNothingTest() { var detector = new EntryDetector(Background); // confusing the algorithm should just say "nothing" var image1 = new Image <Rgb, byte>(@"Resources\train-1.jpg"); var image2 = new Image <Rgb, byte>(@"Resources\train-2.jpg"); var image3 = new Image <Rgb, byte>(@"Resources\train-3.jpg"); var image4 = new Image <Rgb, byte>(@"Resources\train-2.jpg"); var images = new[] { image1, image2, image3, image4 } .Select(image => image.Convert <Gray, byte>()) .ToArray(); detector.CurrentState = DetectorState.Exit; detector.Tick(images); Assert.AreEqual(DetectorState.Nothing, detector.CurrentState); }
public void TestStopTooLong() { var timeProvider = new ExternalTimeProvider(); var detector = new EntryDetector(Background, timeProvider); var enterRaised = false; var exitRaised = false; detector.Enter += (sender, args) => enterRaised = true; detector.Exit += (sender, args) => exitRaised = true; detector.Abort += (sender, args) => Assert.Fail("Abort not expected"); timeProvider.CurrentTime = Year2000; detector.Tick(EntryImages); Assert.AreEqual(DetectorState.Entry, detector.CurrentState); Assert.IsTrue(enterRaised); Assert.IsFalse(exitRaised); timeProvider.CurrentTime = timeProvider.CurrentTime.AddSeconds(EntryDetector.MaxRecordingDuration + 1); detector.Tick(SlowlyMovingTrain); Assert.AreEqual(DetectorState.Exit, detector.CurrentState); Assert.IsTrue(exitRaised); }
private void DetectIncomingTrains() { _camera.StreamGrabber.Start(GrabStrategy.LatestImages, GrabLoop.ProvidedByUser); // Detection class var detector = new EntryDetector(() => { // correct exposure var exposureTime = _camera.Parameters[PLCamera.ExposureTime].GetValue(); var gain = _camera.Parameters[PLCamera.Gain].GetValue(); var formattedExposureTime = string.Format(CultureInfo.CurrentCulture, "{0:0,0}", exposureTime); var formattedGain = string.Format(CultureInfo.CurrentCulture, "{0:0,0}", gain); Log.Info($"Exposure is {formattedExposureTime}μs. Gain is {formattedGain}db. Automatically adjusting"); _camera.Parameters[PLCamera.ExposureAuto].SetValue(PLCamera.ExposureAuto.Off); _camera.Parameters[PLCamera.GainAuto].TrySetValue(PLCamera.GainAuto.Off); _camera.Parameters[PLCamera.ExposureAuto].SetValue(PLCamera.ExposureAuto.Once); _camera.Parameters[PLCamera.GainAuto].TrySetValue(PLCamera.GainAuto.Once); }); // Event handlers detector.Enter += (sender, args) => Publish(Commands.CaptureStart, FileUtil.GenerateTimestampFilename()); detector.Exit += (sender, args) => Publish(Commands.CaptureStop); detector.Abort += (sender, args) => Publish(Commands.CaptureAbort); // Array to contain images that will be collected until it's full and we analyze them. var images = new Image <Gray, byte> [AnalyzeSequenceImages]; // Analyze image array counter var i = 0; // Buffer to put debayered RGB image into (3 channels) var convertedBuffer = new byte[_size.Width * _size.Height * 3]; // Some precalculated constants that we'll use later var roi = new Rectangle(0, _size.Height - RoiY, _size.Width, RoiHeight); var downscaledSize = new Size(_size.Width / 2, RoiHeight / 2); // Count error frames var errorCount = 0; // Grab images. while (true) { HandleStateChange(); // Wait for an image and then retrieve it. A timeout of 5000 ms is used. var grabResult = _camera.StreamGrabber.RetrieveResult(5000, TimeoutHandling.ThrowException); using (grabResult) { // Image grabbed successfully? if (!grabResult.GrabSucceeded) { Log.Error($"Error: {grabResult.ErrorCode} {grabResult.ErrorDescription}"); errorCount++; if (errorCount > ErrorThreshold) { Log.Error("Too many errors. Exiting detection. Not exiting recoding."); break; } continue; } // Debayering RGB image _converter.Convert(convertedBuffer, grabResult); // Convert into EmguCV image type var image = new Image <Rgb, byte>(grabResult.Width, grabResult.Height) { Bytes = convertedBuffer }; // Write to recorder (if the recorder is not recording, it will discard it) _recorder.Write(image.Mat); // Convert to grayscale image for further analysis and cut down the region of interest var grayImage = image.Convert <Gray, byte>(); grayImage.ROI = roi; CvInvoke.Resize(grayImage, grayImage, downscaledSize); // Append to analyze array images[i] = grayImage; i++; // Skip analysation step until we collected a full array of images if (i != images.Length) { continue; } // Reset array counter i = 0; // Let the detector do it's thing (is a train entering? exiting?) detector.Tick(images); // dispose of references to lower memory consumption for (var k = 0; k < images.Length; k++) { images[k] = null; } } } }