Template match class keeps information about found template match. The class is used with template matching algorithms implementing ITemplateMatching interface.
Example #1
0
        private bool checkSteadiness(TemplateMatch match)
        {
            if (match.Similarity < threshold)
            {
                if (--steady < -10) steady = -10;
            }
            else
            {
                if (++steady > 0) steady = 0;
            }

            return (steady != -10);
        }
        /// <summary>
        /// Process image looking for matchings with specified template.
        /// </summary>
        ///
        /// <param name="image">Unmanaged source image to process.</param>
        /// <param name="template">Unmanaged template image to search for.</param>
        /// <param name="searchZone">Rectangle in source image to search template for.</param>
        ///
        /// <returns>Returns array of found template matches. The array is sorted by similarity
        /// of found matches in descending order.</returns>
        ///
        /// <exception cref="UnsupportedImageFormatException">The source image has incorrect pixel format.</exception>
        /// <exception cref="InvalidImagePropertiesException">Template image is bigger than search zone.</exception>
        ///
        public TemplateMatch[] ProcessImage(UnmanagedImage image, UnmanagedImage template, Rectangle searchZone)
        {
            // check image format
            if (
                ((image.PixelFormat != PixelFormat.Format8bppIndexed) &&
                 (image.PixelFormat != PixelFormat.Format24bppRgb)) ||
                (image.PixelFormat != template.PixelFormat))
            {
                throw new UnsupportedImageFormatException("Unsupported pixel format of the source or template image.");
            }

            // clip search zone
            Rectangle zone = searchZone;

            zone.Intersect(new Rectangle(0, 0, image.Width, image.Height));

            // search zone's starting point
            int startX = zone.X;
            int startY = zone.Y;

            // get source and template image size
            int sourceWidth    = zone.Width;
            int sourceHeight   = zone.Height;
            int templateWidth  = template.Width;
            int templateHeight = template.Height;

            // check template's size
            if ((templateWidth > sourceWidth) || (templateHeight > sourceHeight))
            {
                throw new InvalidImagePropertiesException("Template's size should be smaller or equal to search zone.");
            }

            int pixelSize    = (image.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3;
            int sourceStride = image.Stride;

            // similarity map. its size is increased by 4 from each side to increase
            // performance of non-maximum suppresion
            int mapWidth  = sourceWidth - templateWidth + 1;
            int mapHeight = sourceHeight - templateHeight + 1;

            int[,] map = new int[mapHeight + 4, mapWidth + 4];

            // maximum possible difference with template
            int maxDiff = templateWidth * templateHeight * pixelSize * 255;

            // integer similarity threshold
            int threshold = (int)(similarityThreshold * maxDiff);

            // width of template in bytes
            int templateWidthInBytes = templateWidth * pixelSize;

            // do the job
            unsafe
            {
                byte *baseSrc = (byte *)image.ImageData.ToPointer();
                byte *baseTpl = (byte *)template.ImageData.ToPointer();

                int sourceOffset   = image.Stride - templateWidth * pixelSize;
                int templateOffset = template.Stride - templateWidth * pixelSize;

                // for each row of the source image
                for (int y = 0; y < mapHeight; y++)
                {
                    // for each pixel of the source image
                    for (int x = 0; x < mapWidth; x++)
                    {
                        byte *src = baseSrc + sourceStride * (y + startY) + pixelSize * (x + startX);
                        byte *tpl = baseTpl;

                        // compare template with source image starting from current X,Y
                        int dif = 0;

                        // for each row of the template
                        for (int i = 0; i < templateHeight; i++)
                        {
                            // for each pixel of the template
                            for (int j = 0; j < templateWidthInBytes; j++, src++, tpl++)
                            {
                                int d = *src - *tpl;
                                if (d > 0)
                                {
                                    dif += d;
                                }
                                else
                                {
                                    dif -= d;
                                }
                            }
                            src += sourceOffset;
                            tpl += templateOffset;
                        }

                        // templates similarity
                        int sim = maxDiff - dif;

                        if (sim >= threshold)
                        {
                            map[y + 2, x + 2] = sim;
                        }
                    }
                }
            }

            // collect interesting points - only those points, which are local maximums
            List <TemplateMatch> matchingsList = new List <TemplateMatch>();

            // for each row
            for (int y = 2, maxY = mapHeight + 2; y < maxY; y++)
            {
                // for each pixel
                for (int x = 2, maxX = mapWidth + 2; x < maxX; x++)
                {
                    int currentValue = map[y, x];

                    // for each windows' row
                    for (int i = -2; (currentValue != 0) && (i <= 2); i++)
                    {
                        // for each windows' pixel
                        for (int j = -2; j <= 2; j++)
                        {
                            if (map[y + i, x + j] > currentValue)
                            {
                                currentValue = 0;
                                break;
                            }
                        }
                    }

                    // check if this point is really interesting
                    if (currentValue != 0)
                    {
                        matchingsList.Add(new TemplateMatch(
                                              new Rectangle(x - 2 + startX, y - 2 + startY, templateWidth, templateHeight),
                                              (float)currentValue / maxDiff));
                    }
                }
            }

            // convert list to array
            TemplateMatch[] matchings = new TemplateMatch[matchingsList.Count];
            matchingsList.CopyTo(matchings);
            // sort in descending order
            Array.Sort(matchings, new MatchingsSorter());

            return(matchings);
        }
        /// <summary>
        /// Process image looking for matchings with specified template.
        /// </summary>
        /// 
        /// <param name="image">Unmanaged source image to process.</param>
        /// <param name="template">Unmanaged template image to search for.</param>
        /// <param name="searchZone">Rectangle in source image to search template for.</param>
        /// 
        /// <returns>Returns array of found template matches. The array is sorted by similarity
        /// of found matches in descending order.</returns>
        /// 
        /// <exception cref="UnsupportedImageFormatException">The source image has incorrect pixel format.</exception>
        /// <exception cref="InvalidImagePropertiesException">Template image is bigger than search zone.</exception>
        ///
        public TemplateMatch[] ProcessImage( UnmanagedImage image, UnmanagedImage template, Rectangle searchZone )
        {
            // check image format
            if (
                ( ( image.PixelFormat != PixelFormat.Format8bppIndexed ) &&
                  ( image.PixelFormat != PixelFormat.Format24bppRgb ) ) ||
                ( image.PixelFormat != template.PixelFormat ) )
            {
                throw new UnsupportedImageFormatException( "Unsupported pixel format of the source or template image." );
            }

            // clip search zone
            Rectangle zone = searchZone;
            zone.Intersect( new Rectangle( 0, 0, image.Width, image.Height ) );

            // search zone's starting point
            int startX = zone.X;
            int startY = zone.Y;

            // get source and template image size
            int sourceWidth    = zone.Width;
            int sourceHeight   = zone.Height;
            int templateWidth  = template.Width;
            int templateHeight = template.Height;

            // check template's size
            if ( ( templateWidth > sourceWidth ) || ( templateHeight > sourceHeight ) )
            {
                throw new InvalidImagePropertiesException( "Template's size should be smaller or equal to search zone." );
            }

            int pixelSize = ( image.PixelFormat == PixelFormat.Format8bppIndexed ) ? 1 : 3;
            int sourceStride = image.Stride;

            // similarity map. its size is increased by 4 from each side to increase
            // performance of non-maximum suppresion
            int mapWidth  = sourceWidth - templateWidth + 1;
            int mapHeight = sourceHeight - templateHeight + 1;
            int[,] map = new int[mapHeight + 4, mapWidth + 4];

            // maximum possible difference with template
            int maxDiff = templateWidth * templateHeight * pixelSize * 255;

            // integer similarity threshold
            int threshold = (int) ( similarityThreshold * maxDiff );

            // width of template in bytes
            int templateWidthInBytes = templateWidth * pixelSize;

            // do the job
            unsafe
            {
                byte* baseSrc = (byte*) image.ImageData.ToPointer( );
                byte* baseTpl = (byte*) template.ImageData.ToPointer( );

                int sourceOffset = image.Stride - templateWidth * pixelSize;
                int templateOffset = template.Stride - templateWidth * pixelSize;

                // for each row of the source image
                for ( int y = 0; y < mapHeight; y++ )
                {
                    // for each pixel of the source image
                    for ( int x = 0; x < mapWidth; x++ )
                    {
                        byte* src = baseSrc + sourceStride * ( y + startY ) + pixelSize * ( x + startX );
                        byte* tpl = baseTpl;

                        // compare template with source image starting from current X,Y
                        int dif = 0;

                        // for each row of the template
                        for ( int i = 0; i < templateHeight; i++ )
                        {
                            // for each pixel of the template
                            for ( int j = 0; j < templateWidthInBytes; j++, src++, tpl++ )
                            {
                                int d = *src - *tpl;
                                if ( d > 0 )
                                {
                                    dif += d;
                                }
                                else
                                {
                                    dif -= d;
                                }
                            }
                            src += sourceOffset;
                            tpl += templateOffset;
                        }

                        // templates similarity
                        int sim = maxDiff - dif;

                        if ( sim >= threshold )
                            map[y + 2, x + 2] = sim;
                    }
                }
            }

            // collect interesting points - only those points, which are local maximums
            List<TemplateMatch> matchingsList = new List<TemplateMatch>( );

            // for each row
            for ( int y = 2, maxY = mapHeight + 2; y < maxY; y++ )
            {
                // for each pixel
                for ( int x = 2, maxX = mapWidth + 2; x < maxX; x++ )
                {
                    int currentValue = map[y, x];

                    // for each windows' row
                    for ( int i = -2; ( currentValue != 0 ) && ( i <= 2 ); i++ )
                    {
                        // for each windows' pixel
                        for ( int j = -2; j <= 2; j++ )
                        {
                            if ( map[y + i, x + j] > currentValue )
                            {
                                currentValue = 0;
                                break;
                            }
                        }
                    }

                    // check if this point is really interesting
                    if ( currentValue != 0 )
                    {
                        matchingsList.Add( new TemplateMatch(
                            new Rectangle( x - 2 + startX, y - 2 + startY, templateWidth, templateHeight ),
                            (float) currentValue / maxDiff ) );
                    }
                }
            }

            // convert list to array
            TemplateMatch[] matchings = new TemplateMatch[matchingsList.Count];
            matchingsList.CopyTo( matchings );
            // sort in descending order
            Array.Sort( matchings, new MatchingsSorter( ) );

            return matchings;
        }