public void SetMagickImage(bool extremePrecision) { var mi = new MagickImage((Bitmap)Image) { ColorSpace = Watcher.ColorSpace }; if (!extremePrecision) { var mGeo = new MagickGeometry( (int)Math.Round(WatchZone.CropGeometry.Width), (int)Math.Round(WatchZone.CropGeometry.Height)) { IgnoreAspectRatio = true }; mi.Scale(mGeo); mi.RePage(); } else { var underlay = new MagickImage(MagickColor.FromRgba(0, 0, 0, 0), (int)Screen.Geometry.Width, (int)Screen.Geometry.Height); underlay.Composite(mi, new PointD(WatchZone.Geometry.Width, WatchZone.Geometry.Height), CompositeOperator.Copy); underlay.RePage(); var mGeo = Scanner.CropGeometry.ToMagick(false); mGeo.IgnoreAspectRatio = true; underlay.Resize(mGeo); underlay.RePage(); underlay.Trim(); mi = underlay; } if (Watcher.Equalize) { mi.Equalize(); } MagickImage = mi; }
public static Geometry AutoAlign(Bitmap needle, Bitmap haystack, double retryThreshold = 1, int retryLimit = 10) { IntPoint[] harrisPoints1; IntPoint[] harrisPoints2; IntPoint[] correlationPoints1; IntPoint[] correlationPoints2; MatrixH homography; var mi1 = new MagickImage(needle); mi1.Equalize(); needle = mi1.ToBitmap(); var mi2 = new MagickImage(haystack); mi2.Equalize(); haystack = mi2.ToBitmap(); HarrisCornersDetector harris = new HarrisCornersDetector(0.04f, 20000f); harrisPoints1 = harris.ProcessImage(needle).ToArray(); harrisPoints2 = harris.ProcessImage(haystack).ToArray(); CorrelationMatching matcher = new CorrelationMatching(9, needle, haystack); IntPoint[][] matches = matcher.Match(harrisPoints1, harrisPoints2); correlationPoints1 = matches[0]; correlationPoints2 = matches[1]; RansacHomographyEstimator ransac = new RansacHomographyEstimator(0.001, 0.999); homography = ransac.Estimate(correlationPoints1, correlationPoints2); IntPoint[] inliers1 = correlationPoints1.Get(ransac.Inliers); IntPoint[] inliers2 = correlationPoints2.Get(ransac.Inliers); Concatenate concat = new Concatenate(needle); Bitmap img3 = concat.Apply(haystack); PairsMarker pairs = new PairsMarker( inliers1, inliers2.Apply(p => new IntPoint(p.X + needle.Width, p.Y))); var Image = pairs.Apply(img3); Image.Save(@"C:\AutoAlignDebug.png"); var pointCount = inliers1.Length; int[] xList1 = new int[pointCount]; int[] yList1 = new int[pointCount]; int[] xList2 = new int[pointCount]; int[] yList2 = new int[pointCount]; for (int n = 0; n < pointCount; n++) { xList1[n] = inliers1[n].X; yList1[n] = inliers1[n].Y; xList2[n] = inliers2[n].X; yList2[n] = inliers2[n].Y; } var f = new double[8] { xList1.Min(), yList1.Min(), xList1.Max(), yList1.Max(), xList2.Min(), yList2.Min(), xList2.Max(), yList2.Max() }; double distFromX1 = f[0] / needle.Width; double distFromX2 = f[2] / needle.Width; double leftRatio = f[0] / (f[2] - f[0]); double rightRatio = (needle.Width - f[2]) / (f[2] - f[0]); double distFromY1 = f[1] / needle.Height; double distFromY2 = f[3] / needle.Height; double topRatio = f[1] / (f[3] - f[1]); double bottomRatio = (needle.Height - f[3]) / (f[3] - f[1]); double leftDist = (f[6] - f[4]) * leftRatio; double rightDist = (f[6] - f[4]) * rightRatio; double topDist = (f[7] - f[5]) * topRatio; double bottomDist = (f[7] - f[5]) * bottomRatio; double x = f[4] - leftDist; double y = f[5] - topDist; double width = leftDist + (f[6] - f[4]) + rightDist; double height = topDist + (f[7] - f[5]) + bottomDist; mi1.Resize(new MagickGeometry((int)Math.Round(width), (int)Math.Round(height)) { IgnoreAspectRatio = true }); var mg = new MagickGeometry((int)Math.Round(x), (int)Math.Round(y), (int)Math.Round(width), (int)Math.Round(height)) { IgnoreAspectRatio = true }; mi2.Extent(mg, Gravity.Northwest, MagickColor.FromRgba(0, 0, 0, 0)); double delta = mi1.Compare(mi2, ErrorMetric.NormalizedCrossCorrelation); Geometry outGeo = new Geometry(x, y, width, height); if (delta < retryThreshold && retryLimit > 0) { retryLimit--; outGeo = AutoAlign(needle, haystack, delta, retryLimit); } return(outGeo); }
private void RefreshThumbnail() { Geometry minGeo = Geometry.Min(Scanner.CropGeometry, GetScaledGeometry(Geometry.Blank)); MagickImage mi = new MagickImage(CurrentFrame); if (!Scanner.VideoGeometry.Contains(Scanner.CropGeometry)) { mi.Extent(Scanner.CropGeometry.ToMagick(), STANDARD_GRAVITY, EXTENT_COLOR); } else { mi.Crop(Scanner.CropGeometry.ToMagick(), STANDARD_GRAVITY); } mi.RePage(); if (DdlWatchZone.SelectedIndex > 0) { var wi = (WatchImage)DdlWatchZone.SelectedItem; var tGeo = wi.WatchZone.CropGeometry; tGeo.Update(-Scanner.CropGeometry.X, -Scanner.CropGeometry.Y); var baseMGeo = new MagickGeometry(100, 100, (int)Math.Round(tGeo.Width), (int)Math.Round(tGeo.Height)); tGeo.Update(-100, -100, 200, 200); mi.Extent(tGeo.ToMagick(), STANDARD_GRAVITY, EXTENT_COLOR); using (var baseM = new MagickImage( MagickColor.FromRgba(0, 0, 0, 0), baseMGeo.Width, baseMGeo.Height)) using (var overlay = new MagickImage( MagickColor.FromRgba(170, 170, 170, 223), baseMGeo.Width + 200, baseMGeo.Height + 200)) { baseM.ColorSpace = ColorSpace.RGB; overlay.ColorSpace = ColorSpace.RGB; overlay.Composite(baseM, new PointD(baseMGeo.X, baseMGeo.Y), CompositeOperator.Alpha); mi.Composite(overlay, CompositeOperator.Atop); } mi.RePage(); minGeo = minGeo.Min(GetScaledGeometry(tGeo)); if (CkbViewDelta.Checked) { using (var deltaImage = wi.MagickImage.Clone()) { mi.ColorSpace = wi.Watcher.ColorSpace; deltaImage.ColorSpace = wi.Watcher.ColorSpace; mi.Crop(baseMGeo, STANDARD_GRAVITY); //mi.Write(@"E:\fuck0.png"); //deltaImage.Write(@"E:\fuck1.png"); mi.Alpha(AlphaOption.Off); // Why is this necessary? It wasn't necessary before. //mi.Write(@"E:\fuck2.png"); if (wi.Watcher.Equalize) { deltaImage.Equalize(); mi.Equalize(); } deltaImage.RePage(); mi.RePage(); //mi.Write(@"E:\fuck3.png"); //deltaImage.Write(@"E:\fuck4.png"); LblDeltas.Text = mi.Compare(deltaImage, ErrorMetric.PeakSignalToNoiseRatio).ToString("0.####") + "\r\n" + mi.Compare(deltaImage, ErrorMetric.NormalizedCrossCorrelation).ToString("0.####") + "\r\n" + mi.Compare(deltaImage, ErrorMetric.Absolute).ToString("0.####") + "\r\n" + mi.Compare(deltaImage, ErrorMetric.Fuzz).ToString("0.####") + "\r\n" + mi.Compare(deltaImage, ErrorMetric.MeanAbsolute).ToString("0.####") + "\r\n" + mi.Compare(deltaImage, ErrorMetric.MeanSquared).ToString("0.####") + "\r\n" + mi.Compare(deltaImage, ErrorMetric.StructuralDissimilarity).ToString("0.####") + "\r\n" + mi.Compare(deltaImage, ErrorMetric.StructuralSimilarity).ToString("0.####"); mi.Composite(deltaImage, CompositeOperator.Difference); //mi.Write(@"E:\fuck5.png"); //deltaImage.Write(@"E:\fuck6.png"); } minGeo = minGeo.Min(GetScaledGeometry(wi.WatchZone.CropGeometry)); } } if (mi.Width > minGeo.Size.ToDrawing().Width || mi.Height > minGeo.Size.ToDrawing().Height) { var mGeo = minGeo.ToMagick(); mGeo.IgnoreAspectRatio = false; mi.ColorSpace = ColorSpace.Lab; mi.FilterType = DEFAULT_SCALE_FILTER; mi.Resize(mGeo); } ThumbnailBox.Size = minGeo.Size.ToDrawing(); ThumbnailBox.Image = mi.ToBitmap(System.Drawing.Imaging.ImageFormat.MemoryBmp); }
public CompiledFeatures(GameProfile gameProfile, Geometry cropGeometry, int pixelLimit = INIT_PIXEL_LIMIT) { CaptureGeometry = cropGeometry; _HasDupeCheck = false; PixelLimit = pixelLimit; // Todo: Implement resizing when (total) PixelCount exceeds PixelLimit. It won't be easy. PixelCount = 0; var nameDictionary = new Dictionary <string, List <int> >(); var cWatchZones = new CWatchZone[gameProfile.WatchZones.Count]; var indexCount = 0; // Using this until full implementation of multiple screens. foreach (var s in gameProfile.Screens) { s.CropGeometry = CaptureGeometry; } for (int i1 = 0; i1 < gameProfile.WatchZones.Count; i1++) { WatchZone watchZone = gameProfile.WatchZones[i1]; Screen screen = watchZone.Screen; var CWatches = new CWatcher[watchZone.Watches.Count]; var gameGeo = screen.GameGeometry.HasSize ? screen.GameGeometry : screen.Geometry; var wzCropGeo = watchZone.WithoutScale(gameGeo); wzCropGeo.RemoveAnchor(gameGeo); wzCropGeo.ResizeTo(screen.CropGeometry, gameGeo); wzCropGeo.Adjust(screen.CropGeometry.X, screen.CropGeometry.Y); wzCropGeo = wzCropGeo.Clamp(MIN_GEOMETRY, MAX_GEOMETRY); for (int i2 = 0; i2 < watchZone.Watches.Count; i2++) { Watcher watcher = watchZone.Watches[i2]; if (watcher.WatcherType == WatcherType.Standard) { var wiCount = watcher.WatchImages.Count; var CWatchImages = new CWatchImage[wiCount]; if (wiCount <= 0) { throw new ArgumentException("Standard Watchers require at least one image to compare against."); } for (int i3 = 0; i3 < wiCount; i3++) { WatchImage watchImage = watcher.WatchImages[i3]; var mi = new MagickImage(watchImage.Image) { ColorSpace = watcher.ColorSpace }; GetComposedImage(ref mi, watcher.Channel); StandardResize(ref mi, wzCropGeo); //PreciseResize(ref mi, watchZone.Geometry, gameGeo, screen.CropGeometry, watcher.ColorSpace); if (watcher.Equalize) { mi.Equalize(); } PixelCount += (int)Math.Round(wzCropGeo.Width) * (int)Math.Round(wzCropGeo.Height); // Todo: Un-hardcode the rounding var metricUpperBound = watcher.ErrorMetric.UpperBound(PixelCount, mi.ChannelCount); CWatchImages[i3] = new CWatchImage(watchImage.Name, indexCount, mi, metricUpperBound); AddIndexName(nameDictionary, indexCount, watchZone.Name, watcher.Name, watchImage.FileName); indexCount++; } CWatches[i2] = new CWatcher(CWatchImages, watcher); } else if (watcher.WatcherType == WatcherType.DuplicateFrame) { _HasDupeCheck = true; CWatches[i2] = new CWatcher(new CWatchImage[] { new CWatchImage(watcher.Name, indexCount) }, watcher); AddIndexName(nameDictionary, indexCount, watchZone.Name, watcher.Name, string.Empty); PixelCount += (int)Math.Round(wzCropGeo.Width) * (int)Math.Round(wzCropGeo.Height); // Todo: Un-hardcode the rounding indexCount++; } else { throw new NotImplementedException("WatcherType is not set or does not exist. This really shouldn't happen."); } } cWatchZones[i1] = new CWatchZone(watchZone.Name, wzCropGeo, CWatches); } var nameDicArray = new Dictionary <string, IEnumerable <int> >(); foreach (var entry in nameDictionary) { nameDicArray.Add(entry.Key, entry.Value.Distinct().OrderBy(x => x)); } IndexNames = nameDicArray; FeatureCount = indexCount; CWatchZones = cWatchZones; }
public void Apply(MagickImage image) { image.Equalize(); }
public static void Compile(GameProfile gameProfile, bool useExtremePrecision) { if (CWatchZones != null) { foreach (var cWatchZone in CWatchZones) { cWatchZone.Dispose(); } Array.Clear(CWatchZones, 0, CWatchZones.Length); } HasDupeCheck = false; UseExtremePrecision = useExtremePrecision; var cWatchZones = new CWatchZone[gameProfile.WatchZones.Count]; var indexCount = 0; for (int i1 = 0; i1 < gameProfile.WatchZones.Count; i1++) { WatchZone watchZone = gameProfile.WatchZones[i1]; Screen screen = watchZone.Screen; var CWatches = new CWatcher[watchZone.Watches.Count]; var gameGeo = screen.GameGeometry.HasSize ? screen.GameGeometry : screen.Geometry; var wzCropGeo = watchZone.WithoutScale(gameGeo); wzCropGeo.RemoveAnchor(gameGeo); wzCropGeo.ResizeTo(screen.CropGeometry, gameGeo); wzCropGeo.Update(screen.CropGeometry.X, screen.CropGeometry.Y); for (int i2 = 0; i2 < watchZone.Watches.Count; i2++) { Watcher watcher = watchZone.Watches[i2]; if (watcher.WatcherType == WatcherType.Standard) { var CWatchImages = new CWatchImage[watcher.WatchImages.Count]; for (int i3 = 0; i3 < watcher.WatchImages.Count; i3++) { WatchImage watchImage = watcher.WatchImages[i3]; var mi = new MagickImage(watchImage.Image) { ColorSpace = watcher.ColorSpace }; GetComposedImage(ref mi, watcher.Channel); if (!UseExtremePrecision) { StandardResize(ref mi, wzCropGeo.ToMagick(false)); } else { PreciseResize(ref mi, watchZone.Geometry, gameGeo); } if (watcher.Equalize) { mi.Equalize(); } CWatchImages[i3] = new CWatchImage(watchImage.Name, indexCount, mi); indexCount++; } CWatches[i2] = new CWatcher(CWatchImages, watcher); } else if (watcher.WatcherType == WatcherType.BestMatch) { var mic = new MagickImageCollection(); for (int i3 = 0; i3 < watcher.WatchImages.Count; i3++) { WatchImage watchImage = watcher.WatchImages[i3]; var mi = new MagickImage(watchImage.FilePath) { ColorSpace = watcher.ColorSpace }; GetComposedImage(ref mi, watcher.Channel); if (!UseExtremePrecision) { StandardResize(ref mi, wzCropGeo.ToMagick(false)); } else { PreciseResize(ref mi, watchZone.Geometry, gameGeo); } if (watcher.Equalize) { mi.Equalize(); } //CWatchImages[i3] = new CWatchImage(watchImage.Name, indexCount, mi); indexCount++; } } else if (watcher.WatcherType == WatcherType.DuplicateFrame) { HasDupeCheck = true; } } cWatchZones[i1] = new CWatchZone(watchZone.Name, wzCropGeo, CWatches); } CWatchZones = cWatchZones; }
public override void Apply(MagickImage image) { image.Equalize(); }