Beispiel #1
0
        /// <summary>
        /// Find all instances of a subimage in this image.
        /// </summary>
        /// <param name="subimage">The subimage to find in the larger image. Must be smaller than the image in both dimensions.</param>
        /// <param name="verifier">Custom SnapshotVerifier, used to compare the subimages.</param>
        /// <returns>A Collection of rectangles indicating the matching locations.
        /// If there is no match, the Collection returned will be empty.</returns>
        public Collection <Rectangle> Find(Snapshot subimage, SnapshotVerifier verifier)
        {
            if (Width < subimage.Width || Height < subimage.Height)
            {
                throw new InvalidOperationException("Subimage snapshot must fit into larger snapshot to be found.");
            }

            Collection <Rectangle> resultList = new Collection <Rectangle>();

            // This is a binary 2D convolve with early exit on any imperfect match.
            // Future optimisations will test the middle pixel first, then a diagonal through the subarea, then the full image.
            // This will make pathological cases much faster.
            for (int row = 0; row < Height - subimage.Height; row++)
            {
                for (int column = 0; column < Width - subimage.Width; column++)
                {
                    // This is our success condition, add this location to the Collection.
                    if (CompareSubImage(subimage, row, column, verifier))
                    {
                        resultList.Add((new Rectangle(column, row, subimage.Width, subimage.Height)));
                    }
                }
            }

            return(resultList);
        }
Beispiel #2
0
        /// <summary>
        /// Private subimage comparer to help FindSubImage. This performs the actual work of comparing pixels.
        /// </summary>
        /// <param name="subimage">The subimage to find.</param>
        /// <param name="startingRow">The row offset into this snapshot to look for the subimage.</param>
        /// <param name="startingColumn">The column offset into this snapshot to look for the subimage.</param>
        /// <param name="verifier">Custom subimage comparison verifier, if specified.</param>
        /// <returns></returns>
        private bool CompareSubImage(
            Snapshot subimage,
            int startingRow,
            int startingColumn,
            SnapshotVerifier verifier)
        {
            //compare pixel-by-pixel
            for (int row = 0; row < subimage.Height; row++)
            {
                for (int column = 0; column < subimage.Width; column++)
                {
                    // Use the custom verifier if the user has specified one
                    if (verifier != null)
                    {
                        //verify this pixel
                        Snapshot           thisPixelImage   = this.Crop(new Rectangle(startingColumn + column, startingRow + row, 1, 1));
                        Snapshot           thatPixelImage   = subimage.Crop(new Rectangle(column, row, 1, 1));
                        VerificationResult subCompareResult = verifier.Verify(thisPixelImage.CompareTo(thatPixelImage, false));
                        if (subCompareResult == VerificationResult.Fail)
                        {
                            //mismatch
                            return(false);
                        }
                    }
                    else
                    {
                        Color thisPixel = this[startingRow + row, startingColumn + column];
                        Color thatPixel = subimage[row, column];
                        int   R         = thisPixel.R - thatPixel.R;
                        int   G         = thisPixel.G - thatPixel.G;
                        int   B         = thisPixel.B - thatPixel.B;
                        int   A         = thisPixel.A - thatPixel.A;

                        if (R != 0x00 || G != 0x00 || B != 0x00)
                        {
                            //mismatch.
                            return(false);
                        }
                    }
                }
            }

            return(true);
        }