0

I'm having a little performance trouble here. My Professor of image processing asked me to make an template match without any library, so I did it in c# ... it's doing the work perfectly, but very very, veery slow to find an template 80x80 in an image 500x500 it's taking several minutes and isn't using more than 20% of my cpu

Am I doing something wrong?

here is my code, all the images are gray.

    public Task<Point[]> MatchImage(Bitmap orig, Bitmap template, int limit = 30)
    {
        Task<Point[]> tsk = 
        new Task<Point[]>(() =>
        {
            Point p;
            List<Point> l = new List<Point>();
            int oh = orig.Height, ow = orig.Width;
            int th = template.Height, tw = template.Width;

            for (int x = 0; x < oh - th; x++)
                for (int y = 0; y < ow - tw; y++)
                {
                    p = new Point(x, y);
                    if (sumBitArea(orig, template, p) <= limit)
                        l.Add(p);
                }
                return l.ToArray();
        });

        tsk.Start();
        return tsk;
    }


    /// <summary>
    /// Soma os pixels de uma determinada imagem
    /// PS PARA USAR MANDE A IMAGEM RECORTADA !
    /// SE MANDAR INTEIRA VAI RETORNAR O VALOR TOTAL.
    /// USEM A GRAPHCS E UM RECTANGLE !
    /// </summary>
    /// <param name="image">treixo da imagem original</param>
    /// <param name="template">imagem template</param>
    /// <param name="p">ponto inicial de referencia</param>
    /// <returns>o valor da soma</returns>
    private int sumBitArea(Bitmap image, Bitmap template, Point p)
    {
        int value = 0;

        int height = p.X + template.Height;
        int width = p.Y + template.Width;

        for (int x = p.X, xt = 0; x < height; x++, xt++)
            for (int y = p.Y, yt = 0; y < width; y++,yt++)
            {
                int tmp = Math.Abs(image.GetPixel(y, x).R - template.GetPixel(yt, xt).R);
                value += tmp;
            }

        return value;
    }

Solution - SOLVED LOCKING BIT

Here is the solution code

    public Task<Point[]> MatchImage(Bitmap orig, Bitmap template, int limit = 30)
    {
        Task<Point[]> tsk =
        new Task<Point[]>(() =>
        {
            BitmapData lockedOrig = orig.LockBits(
               new Rectangle(0, 0, orig.Width, orig.Height),
               ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            //bloqueando a leitura da memoria em que a imagem nova sera colocada
            BitmapData lockedTemplate = template.LockBits(
               new Rectangle(0, 0, template.Width, template.Height),
               ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

            Point p;
            List<Point> l = new List<Point>();
            int oh = orig.Height, ow = orig.Width;
            int th = template.Height, tw = template.Width;

            for (int y = 0; y < oh - th; y++)
            {
                for (int x = 0; x < ow - tw; x++)
                {
                    p = new Point(x, y);
                    if (sumBitArea(lockedOrig, lockedTemplate, p) <= limit)
                        l.Add(p);
                }
            }

            orig.UnlockBits(lockedOrig);
            template.UnlockBits(lockedTemplate);
            return l.ToArray();
        });

        tsk.Start();
        return tsk;
    }

    unsafe private int sumBitArea(BitmapData image, BitmapData template, Point p)
    {
        int value = 0;
        int pixelSize = 3;

        int height = p.Y + template.Height;
        int width = p.X + template.Width;
        int x = p.X, xt = 0;
        int y = p.Y, yt = 0;
        byte* tRow;
        byte* oRow;

        for (yt = 0 ; y < height; y++, yt++)
        {
            //criando um ponteiro para a imagem original
            oRow = (byte*)image.Scan0 + (y * image.Stride);

            //criando um ponteiro para a nova imagem
            tRow = (byte*)template.Scan0 + (yt * template.Stride);

            for (xt = 0; x < width; x++, xt++)
            {
                int tmp = Math.Abs((byte)oRow[x * pixelSize + 2] - (byte)tRow[xt * pixelSize + 2]);
                value += tmp;
            }
        }
        return value;
    }
Cœur
  • 37,241
  • 25
  • 195
  • 267
Nicollas Braga
  • 802
  • 7
  • 27
  • Did you try locking bits or using [FastBitmap](https://github.com/LuizZak/FastBitmap) implementation? You should be able to find tons of implementations like this one. It should speed up getting pixels multiple times. You just need to take care of properly disposing it. – Nikola Davidovic Jun 04 '15 at 23:25
  • WOW IT did instantly ! TX @NikolaDavidovic I'll update to answered – Nicollas Braga Jun 04 '15 at 23:55
  • Hi, good algorithm. Is there any way to get the coordinates of the match? to draw the result? – user3177511 May 18 '22 at 11:29

1 Answers1

1

Did you try locking bits or using FastBitmap implementation? You should be able to find tons of implementations like this one. It should speed up getting pixels multiple times. You just need to take care of properly disposing it.

Nikola Davidovic
  • 8,556
  • 1
  • 27
  • 33