예제 #1
0
        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;
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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;
        }
예제 #5
0
 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;
        }
예제 #7
0
 public override void Apply(MagickImage image)
 {
     image.Equalize();
 }