// Todo: prevFile isn't necessary. Instead store the features of the current scan to be used on the next. // That could cause sync problems so it needs to be investigated. private void NewRun(Scan scan, int index) { var deltas = new double[CompiledFeatures.FeatureCount]; var benchmarks = new double[CompiledFeatures.FeatureCount]; var now = scan.CurrentFrame.DateTime; var fileImageBase = scan.CurrentFrame.Bitmap; var prevFileImageBase = CompiledFeatures.UsesDupeCheck(now) ? scan.PreviousFrame.Bitmap : null; try { foreach (var cWatchZone in CompiledFeatures.CWatchZones) { CropScan(ref deltas, ref benchmarks, now, fileImageBase, prevFileImageBase, cWatchZone); } } catch (Exception e) { scan.Dispose(); Log.Error(e, "Error scanning frame."); if (IsVideoSourceRunning() && !IsScannerLocked) { ScanningCount--; } } var scanEnd = TimeStamp.CurrentDateTime.Time; try { DeltaManager?.AddResult(index, scan, scanEnd, deltas, benchmarks); NewResult(this, new DeltaOutput(DeltaManager, index, CurrentFPS)); ScanningCount--; if (ScanFinished != null) { ScanFinished(this, scan); } //scan.Dispose(); // It's on its own thread so running it here should be okay. if (index % Math.Ceiling(AverageFPS) == 0) { RefreshBenchmarks(); } if (index >= DeltaManager.History.Count && AverageFPS > 70d) { Log.Warning("Framerate is abnormally high, usually an indicator the video feed is not active."); Restart(); } } catch (Exception e) { Log.Error(e, "Unknown Scanner Error."); } }
// @TODO: Break into separate methods? private async void RefreshThumbnailAsync(Scan scan, PreviewType previewType, PreviewFeature feature) { await Task.Delay(0); try { Geometry minGeo; MagickImage mi; string confidence = string.Empty; Geometry cropGeo = _CropGeometry; if (previewType == PreviewType.FullFrame) { minGeo = Geometry.Min(_VideoGeometry, GetScaledGeometry(_VideoGeometry)); mi = new MagickImage(scan.CurrentFrame.Bitmap); if (!_Selecting) { var roundGeo = cropGeo.Round(); mi.Composite(_ScreenOverlay, (int)roundGeo.X, (int)roundGeo.Y, CompositeOperator.Over); } else { var numRect = NumGeometry.ToRectangle(); using (var overlay = new MagickImage(SCREEN_COLOR, numRect.Width, numRect.Height)) { mi.Composite(overlay, numRect.X, numRect.Y, CompositeOperator.Over); } } } else if (previewType == PreviewType.FrameCrop) { minGeo = Geometry.Min(cropGeo, GetScaledGeometry(cropGeo)); if (!_VideoGeometry.Contains(cropGeo)) { mi = new MagickImage(scan.CurrentFrame.Bitmap); mi.Extent(cropGeo.ToMagick(), STANDARD_GRAVITY, EXTENT_COLOR); } else { mi = new MagickImage(scan.CurrentFrame.Bitmap.Clone(cropGeo.ToRectangle(), PixelFormat.Format24bppRgb)); } if (!_Selecting) { var roundGeo = cropGeo.Round(); var roundTrueGeo = _TrueCropGeometry.Round(); int xOffset = (int)(roundTrueGeo.X - cropGeo.X); int yOffset = (int)(roundTrueGeo.Y - cropGeo.Y); mi.Composite(_WatchZoneOverlay, xOffset, yOffset, CompositeOperator.Over); } } else if (previewType == PreviewType.Features && feature == null) { var trueGeo = _TrueCropGeometry; minGeo = Geometry.Min(trueGeo, GetScaledGeometry(trueGeo)); if (!_VideoGeometry.Contains(trueGeo)) { mi = new MagickImage(scan.CurrentFrame.Bitmap); mi.Extent(trueGeo.ToMagick(), STANDARD_GRAVITY, EXTENT_COLOR); } else { mi = new MagickImage(scan.CurrentFrame.Bitmap.Clone(trueGeo.ToRectangle(), PixelFormat.Format24bppRgb)); } if (!_Selecting) { mi.Composite(_WatchZoneOverlay, CompositeOperator.Over); } } else if (previewType == PreviewType.Features && feature != null) { var wzGeo = feature.WatchZone.Geometry; if (!ckbShowComparison.Checked) { var baseMGeo = new MagickGeometry(64, 64, (int)Math.Round(wzGeo.Width), (int)Math.Round(wzGeo.Height)); wzGeo.Adjust(-64, -64, 128, 128); minGeo = Geometry.Min(wzGeo, GetScaledGeometry(wzGeo)); if (!_VideoGeometry.Contains(wzGeo)) { mi = new MagickImage(scan.CurrentFrame.Bitmap); mi.Extent(wzGeo.ToMagick(), STANDARD_GRAVITY, EXTENT_COLOR); } else { mi = new MagickImage(scan.CurrentFrame.Bitmap.Clone(wzGeo.ToRectangle(), PixelFormat.Format24bppRgb)); } using (var baseM = new MagickImage( MagickColors.Transparent, baseMGeo.Width, baseMGeo.Height)) using (var overlay = new MagickImage( PREVIEW_EXTENT_COLOR, baseMGeo.Width + 128, baseMGeo.Height + 128)) { overlay.Composite(baseM, new PointD(baseMGeo.X, baseMGeo.Y), CompositeOperator.Alpha); mi.Composite(overlay, CompositeOperator.Atop); } } else { minGeo = Geometry.Min(wzGeo, GetScaledGeometry(wzGeo)); if (!_VideoGeometry.Contains(wzGeo)) { mi = new MagickImage(scan.CurrentFrame.Bitmap); mi.Extent(wzGeo.ToMagick(), STANDARD_GRAVITY, EXTENT_COLOR); } else { mi = new MagickImage(scan.CurrentFrame.Bitmap.Clone(wzGeo.ToRectangle(), PixelFormat.Format24bppRgb)); } // @TODO: Add previous frame stuff using (var deltaImage = feature.WatchImage.MagickImage.Clone()) { mi.ColorSpace = feature.Watcher.ColorSpace; deltaImage.ColorSpace = feature.Watcher.ColorSpace; if (feature.WatchImage.HasAlpha) { mi.Composite(feature.WatchImage.AlphaChannel, CompositeOperator.Over); } if (feature.Watcher.Equalize) { mi.Equalize(); } confidence = mi.Compare(deltaImage, feature.Watcher.ErrorMetric).ToString("F4"); mi.Composite(deltaImage, CompositeOperator.Difference); } } } else { throw new InvalidEnumArgumentException("PreviewType out of bounds? This shouldn't happen."); } var drawingSize = minGeo.Size.ToDrawing(); if (mi.Width > drawingSize.Width || mi.Height > drawingSize.Height) { var mGeo = minGeo.ToMagick(); mGeo.IgnoreAspectRatio = false; //mi.ColorSpace = ColorSpace.HCL; mi.FilterType = DEFAULT_SCALE_FILTER; mi.Resize(mGeo); } UpdatepictureBox(drawingSize, mi.ToBitmap(), confidence); } catch (Exception e) { Log.Error(e, "Thumbnail failed to render for the Scan Region."); scan.Dispose(); _RenderingFrame = false; } }
// lexer results keep available public virtual void Dispose() { scan.Dispose(); scan = null; Array.Fill(tokens, default, 0, tokenn);