Template match class keeps information about found template match. The class is used with template matching algorithms implementing ITemplateMatching interface.
        public String ProcessImage_Dif(Bitmap image, Bitmap template, TemplateMatch pMatch, bool bShow1)
        {
            // lock source and template images
            BitmapData imageData = image.LockBits(
                new Rectangle(0, 0, image.Width, image.Height),
                ImageLockMode.ReadOnly, image.PixelFormat);
            BitmapData templateData = template.LockBits(
                new Rectangle(0, 0, template.Width, template.Height),
                ImageLockMode.ReadOnly, template.PixelFormat);

            return(ProcessImage_Dif(new UnmanagedImage(imageData), new UnmanagedImage(templateData), pMatch, bShow1));
        }
        /// <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;

                /*trl
                 * PointF topP = new PointF(430, 70);
                 * PointF LeftP = new PointF(67, 333);
                 * PointF RightP = new PointF(787, 335);
                 * PointF BottomP = new PointF(430, 605);
                 * List<PointF> m_Points = new List<PointF>();
                 * m_Points.Add(topP);
                 * m_Points.Add(RightP);
                 * m_Points.Add(BottomP);
                 * m_Points.Add(LeftP);
                 * m_Points.Add(topP);
                 * Polygon CocArea = new Polygon(m_Points.ToArray());
                 */

                // 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++)
                    {
                        Point CurrPoint = new Point(x + startX, y + startY);     //trl
                        if (COCDiamond.PointInPolygon(CurrPoint.X, CurrPoint.Y)) //checks if point is in cocDiamond
                        {
                            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;
                            }
                        } //trl
                    }
                }
            }

            // 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;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="image"></param>
        /// <param name="template"></param>
        /// <param name="pItem"></param>
        /// <returns></returns>
        public String ProcessImage_Dif(
            UnmanagedImage image,
            UnmanagedImage template,
            TemplateMatch pItem, bool bShow1) // 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 = 0; //zone.X;
            int startY = 0; // zone.Y;

            // get source and template image size
            int sourceWidth    = image.Width;  // zone.Width;
            int sourceHeight   = image.Height; // 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
            // 后面找相似度是否是最大的,是在5*5区域里找的,所以四个方向都扩大两个像素,这样就不需要检查边界条件
            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); //iStep是步长,iStep个点里找一个点做比较,减少运算量

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

            StringBuilder pStr = new StringBuilder();

            // 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;


                int y = pItem.Rectangle.Y; // y < pItem.Rectangle.Y+pItem.Rectangle.Height; y++)
                // for each pixel of the source image
                int x = pItem.Rectangle.X; // x < pItem.Rectangle.X+pItem.Rectangle.Width; x++)

                byte *src = baseSrc + sourceStride * (y + startY) + pixelSize * (x + startX);
                byte *tpl = baseTpl;


                // for each row of the template
                for (int i = 0; i < templateHeight; i++)
                {
                    // for each pixel of the template
                    int j = 0;
                    for (j = 0; j < templateWidthInBytes; j += pixelSize, src += pixelSize, tpl += pixelSize) // j++, src++, tpl++)
                    {
                        //int d = *src - *tpl;
                        //d= Math.Abs(d);

                        int d = Math.Abs(*src - *tpl) + Math.Abs(*(src + 1) - *(tpl + 1)) + Math.Abs(*(src + 2) - *(tpl + 2));
                        if (bShow1)
                        {
                            if (d > 0)
                            {
                                pStr.Append("X");
                            }
                            else
                            {
                                pStr.Append(" ");
                            }
                        }
                        else
                        {
                            pStr.Append(d).Append(" ");
                        }
                    }
                    pStr.Append("\n");

                    src += sourceOffset;
                    tpl += templateOffset;
                }
            }


            return(pStr.ToString());
        }
        /// <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="iStep">步长</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 List <TemplateMatch> ProcessImage3(UnmanagedImage image, UnmanagedImage template, List <TemplateMatch> pList) // 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 = 0; //zone.X;
            int startY = 0; // zone.Y;

            // get source and template image size
            int sourceWidth    = image.Width;  // zone.Width;
            int sourceHeight   = image.Height; // 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
            // 后面找相似度是否是最大的,是在5*5区域里找的,所以四个方向都扩大两个像素,这样就不需要检查边界条件
            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); //iStep是步长,iStep个点里找一个点做比较,减少运算量

            // 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 (int k = 0; k < pList.Count; k++)
                {
                    TemplateMatch pItem = pList[k];
                    // for each row of the source image
                    int y = pItem.Rectangle.Y; // y < pItem.Rectangle.Y+pItem.Rectangle.Height; y++)
                    // for each pixel of the source image
                    int x = pItem.Rectangle.X; // x < pItem.Rectangle.X+pItem.Rectangle.Width; 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
                        int j = 0;
                        for (j = 0; j < templateWidthInBytes; j++, src++, tpl++)
                        {
                            int d = *src - *tpl;
                            dif += Math.Abs(d);
                        }
                        src += sourceOffset;
                        tpl += templateOffset;
                    }

                    // templates similarity
                    int sim = maxDiff - dif;

                    if (sim >= threshold)
                    {
                        map[y + 2, x + 2] = sim; //相似度实际存储的位置比实际位置增加2,2,后面要减去2,2
                    }
                }
            }

            // 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));
                    }
                }
            }


            return(matchingsList);
        }
        private bool checkSteadiness(TemplateMatch match)
        {
            if (match.Similarity < threshold)
            {
                if (--steady < -10) steady = -10;
            }
            else
            {
                if (++steady > 0) steady = 0;
            }

            return (steady != -10);
        }
Exemple #7
0
        public unsafe TemplateMatch[] ProcessImage(UnmanagedImage image, UnmanagedImage template, Rectangle searchZone)
        {
            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.");
            }
            Rectangle rectangle = searchZone;

            rectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height));
            int x      = rectangle.X;
            int y      = rectangle.Y;
            int width  = rectangle.Width;
            int height = rectangle.Height;
            int num5   = template.Width;
            int num6   = template.Height;

            if ((num5 > width) || (num6 > height))
            {
                throw new InvalidImagePropertiesException("Template's size should be smaller or equal to search zone.");
            }
            int num7   = (image.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3;
            int stride = image.Stride;
            int num9   = (width - num5) + 1;
            int num10  = (height - num6) + 1;

            int[,] numArray = new int[num10 + 4, num9 + 4];
            int   num11   = ((num5 * num6) * num7) * 0xff;
            int   num12   = (int)(this.similarityThreshold * num11);
            int   num13   = num5 * num7;
            byte *numPtr  = (byte *)image.ImageData.ToPointer();
            byte *numPtr2 = (byte *)template.ImageData.ToPointer();
            int   num14   = image.Stride - (num5 * num7);
            int   num15   = template.Stride - (num5 * num7);

            for (int i = 0; i < num10; i++)
            {
                for (int j = 0; j < num9; j++)
                {
                    byte *numPtr3 = (numPtr + (stride * (i + y))) + (num7 * (j + x));
                    byte *numPtr4 = numPtr2;
                    int   num18   = 0;
                    for (int k = 0; k < num6; k++)
                    {
                        int num20 = 0;
                        while (num20 < num13)
                        {
                            int num21 = numPtr3[0] - numPtr4[0];
                            if (num21 > 0)
                            {
                                num18 += num21;
                            }
                            else
                            {
                                num18 -= num21;
                            }
                            num20++;
                            numPtr3++;
                            numPtr4++;
                        }
                        numPtr3 += num14;
                        numPtr4 += num15;
                    }
                    int num22 = num11 - num18;
                    if (num22 >= num12)
                    {
                        numArray[i + 2, j + 2] = num22;
                    }
                }
            }
            List <TemplateMatch> list = new List <TemplateMatch>();
            int num23 = 2;
            int num24 = num10 + 2;

            while (num23 < num24)
            {
                int num25 = 2;
                int num26 = num9 + 2;
                while (num25 < num26)
                {
                    int num27 = numArray[num23, num25];
                    for (int m = -2; (num27 != 0) && (m <= 2); m++)
                    {
                        for (int n = -2; n <= 2; n++)
                        {
                            if (numArray[num23 + m, num25 + n] > num27)
                            {
                                num27 = 0;
                                break;
                            }
                        }
                    }
                    if (num27 != 0)
                    {
                        list.Add(new TemplateMatch(new Rectangle((num25 - 2) + x, (num23 - 2) + y, num5, num6), ((float)num27) / ((float)num11)));
                    }
                    num25++;
                }
                num23++;
            }
            TemplateMatch[] array = new TemplateMatch[list.Count];
            list.CopyTo(array);
            Array.Sort(array, new MatchingsSorter());
            return(array);
        }
Exemple #8
0
        /// <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
            var zone = searchZone;

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

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

            // get source and template image size
            var sourceWidth    = zone.Width;
            var sourceHeight   = zone.Height;
            var templateWidth  = template.Width;
            var 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.");
            }

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

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

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

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

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

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

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

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

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

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

                        // templates similarity
                        var sim = maxDiff - dif;

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

            // collect interesting points - only those points, which are local maximums
            var 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++)
                {
                    var currentValue = map[y, x];

                    // for each windows' row
                    for (var i = -2; (currentValue != 0) && (i <= 2); i++)
                    {
                        // for each windows' pixel
                        for (var 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
            var matchings = new TemplateMatch[matchingsList.Count];

            matchingsList.CopyTo(matchings);
            // sort in descending order
            Array.Sort(matchings, new MatchingsSorter());

            return(matchings);
        }
Exemple #9
0
        public unsafe TemplateMatch[] ProcessImage(UnmanagedImage image, UnmanagedImage template, Rectangle searchZone)
        {
            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.");
            }
            Rectangle rectangle = searchZone;

            rectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height));
            int x       = rectangle.X;
            int y       = rectangle.Y;
            int width   = rectangle.Width;
            int height  = rectangle.Height;
            int width2  = template.Width;
            int height2 = template.Height;

            if (width2 > width || height2 > height)
            {
                throw new InvalidImagePropertiesException("Template's size should be smaller or equal to search zone.");
            }
            int num    = (image.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3;
            int stride = image.Stride;
            int num2   = width - width2 + 1;
            int num3   = height - height2 + 1;

            int[,] array = new int[num3 + 4, num2 + 4];
            int   num4 = width2 * height2 * num * 255;
            int   num5 = (int)(similarityThreshold * (float)num4);
            int   num6 = width2 * num;
            byte *ptr  = (byte *)image.ImageData.ToPointer();
            byte *ptr2 = (byte *)template.ImageData.ToPointer();
            int   num7 = image.Stride - width2 * num;
            int   num8 = template.Stride - width2 * num;

            for (int i = 0; i < num3; i++)
            {
                for (int j = 0; j < num2; j++)
                {
                    byte *ptr3 = ptr + (long)stride * (long)(i + y) + (long)num * (long)(j + x);
                    byte *ptr4 = ptr2;
                    int   num9 = 0;
                    for (int k = 0; k < height2; k++)
                    {
                        int num10 = 0;
                        while (num10 < num6)
                        {
                            int num11 = *ptr3 - *ptr4;
                            num9 = ((num11 <= 0) ? (num9 - num11) : (num9 + num11));
                            num10++;
                            ptr3++;
                            ptr4++;
                        }
                        ptr3 += num7;
                        ptr4 += num8;
                    }
                    int num12 = num4 - num9;
                    if (num12 >= num5)
                    {
                        array[i + 2, j + 2] = num12;
                    }
                }
            }
            List <TemplateMatch> list = new List <TemplateMatch>();
            int l = 2;

            for (int num13 = num3 + 2; l < num13; l++)
            {
                int m = 2;
                for (int num14 = num2 + 2; m < num14; m++)
                {
                    int num15 = array[l, m];
                    int num16 = -2;
                    while (num15 != 0 && num16 <= 2)
                    {
                        for (int n = -2; n <= 2; n++)
                        {
                            if (array[l + num16, m + n] > num15)
                            {
                                num15 = 0;
                                break;
                            }
                        }
                        num16++;
                    }
                    if (num15 != 0)
                    {
                        list.Add(new TemplateMatch(new Rectangle(m - 2 + x, l - 2 + y, width2, height2), (float)num15 / (float)num4));
                    }
                }
            }
            TemplateMatch[] array2 = new TemplateMatch[list.Count];
            list.CopyTo(array2);
            Array.Sort(array2, new MatchingsSorter());
            return(array2);
        }
        public TemplateMatch[] ProcessImage(UnmanagedImage image, UnmanagedImage template, Rectangle searchZone)
        {
            // Normalized Cross Correlation.

            // 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 in both dimensions to increase performance of non-maximum suppresion.
            int mapWidth  = sourceWidth - templateWidth + 1;
            int mapHeight = sourceHeight - templateHeight + 1;

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

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

            // Algorithm:
            // 1. compute mean of template.
            // 2. for each candidate in the search zone:
            //  2.a. Compute mean of candidate.
            //  2.b. Compute correlation coefficient.
            // 3. Suppress non-maxima and sort by correlation coeff.

            unsafe
            {
                // 1. compute mean of template.
                byte *baseTpl        = (byte *)template.ImageData.ToPointer( );
                byte *tpl            = baseTpl;
                int   templateOffset = template.Stride - templateWidthInBytes;
                int   iTemplateTotal = 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++, tpl++)
                    {
                        iTemplateTotal += *tpl;
                    }
                    tpl += templateOffset;
                }

                double fMeanTemplate = (double)iTemplateTotal / (double)(templateHeight * templateWidthInBytes);

                // 2. Compute correlation coeff for each candidate in the search zone

                byte *baseSrc      = (byte *)image.ImageData.ToPointer( );
                int   sourceOffset = image.Stride - templateWidth * pixelSize;

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

                        // 2.a. Compute mean of candidate.
                        int iCandidateTotal = 0;

                        // for each row of the candidate
                        for (int i = 0; i < templateHeight; i++)
                        {
                            // for each pixel of the candidate
                            for (int j = 0; j < templateWidthInBytes; j++, src++)
                            {
                                iCandidateTotal += *src;
                            }
                            src += sourceOffset;
                        }

                        double fMeanCandidate = (double)iCandidateTotal / (double)(templateHeight * templateWidthInBytes);

                        // 2.b Denominator.
                        tpl = baseTpl;
                        src = baseSrc + sourceStride * (y + startY) + pixelSize * (x + startX);

                        double sit  = 0;
                        double sisq = 0;
                        double stsq = 0;

                        // for each row of the candidate
                        for (int i = 0; i < templateHeight; i++)
                        {
                            // for each pixel of the candidate
                            for (int j = 0; j < templateWidthInBytes; j++, tpl++, src++)
                            {
                                sit  += ((*src - fMeanCandidate) * (*tpl - fMeanTemplate));
                                sisq += ((*src - fMeanCandidate) * (*src - fMeanCandidate));
                                stsq += ((*tpl - fMeanTemplate) * (*tpl - fMeanTemplate));
                            }
                            src += sourceOffset;
                            tpl += templateOffset;
                        }

                        // Correlation coeff for candidate x,y.
                        // Map has a 2-pixel black border for non local-maxima suppression.
                        map[y + 2, x + 2] = 0;
                        if (sisq != 0 && stsq != 0)
                        {
                            // Add to map, filter out lower-than-threshold results.
                            float fCorrCoeff = (float)(sit / System.Math.Sqrt(sisq * stsq));
                            if (fCorrCoeff >= similarityThreshold)
                            {
                                map[y + 2, x + 2] = fCorrCoeff;
                            }
                        }
                    }
                }
            }

            // Reparse all results to suppress those that are not local maxima.
            List <TemplateMatch> matchingsList = new List <TemplateMatch>( );

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

                    // Look for a better match in the 5² surrounding window.
                    for (int i = -2; (currentValue != 0) && (i <= 2); i++)
                    {
                        for (int j = -2; j <= 2; j++)
                        {
                            if (map[y + i, x + j] > currentValue)
                            {
                                currentValue = 0;
                                break;
                            }
                        }
                    }

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

            // convert list to array
            TemplateMatch[] matchings = new TemplateMatch[matchingsList.Count];
            matchingsList.CopyTo(matchings);

            // sort in descending order
            Array.Sort(matchings, new MatchingsSorter( ));

            return(matchings);
        }