1

This is my first question and I'm relatively new to C#. (Excuse my bad English)

I'm writing a template matching algorithm in C# using the .NET Framework with a WindowsForms Application in Visual Studio. Sadly the new indices and ranges functions from C#8.0, especially the range operator (..), didn't get implemented in the .NET Framework. I know there is a workaround for this as you can see in this thread but it is not supported by Microsoft. So I'm searching for another way to parallelize my elementwise 2dArray (matrix) calculations to make my program faster.

In my program, I'm calculating the differential square (ds) of an area (with the size of my template) inside a 2dArray (my image) and a 2dArray (my template). These values a written to a new 2dAary (DS) which holds all differential squares in the corresponding positions to the image. I can search the indices of DS where the differential square is minimal which is equal to the matching position (highest correspondence between template and image) of the template inside the image.

In python the calculation of DS is very quick using the index range operator (:) and will look like this:

H,W = I.shape                                # read out Height H & Width W from Image I
h,w = T.shape                                # read out Height h & Width w from Template T

for i in range(H-h+1):
        for j in range(W-w+1):
            DS[i,j] = np.sum((I[i:i+h,j:j+w] - T)**2)

But in C# I have to make the calculation of DS elementwise therefore it looks like this and takes for ever:

int Tw = template.Width;
int Th = template.Height;
int Iw = image.Width;
int Ih = image.Height;

int d = 0;
int[,] ds = new int[Tw, Th];
int[,] DS = new int[Iw - Tw + 1, Ih - Th + 1];
         
for (int y = 0; y < Ih - Th + 1; y++)
        {
            for (int x = 0; x < Iw - Tw + 1; x++)
            {
                for (int yT = 0; yT < Th; yT++)
                {
                    for (int xT = 0; xT < Tw; xT++)
                    {
                        d = I[x + xT, y + yT] - T[xT, yT];
                        ds[xt, yt] = d * d;
                    }
                }

                int sum = ds.Cast<int>().Sum();
                DS[x, y] = sum;
            }
        }

I know that I could use threads but that would be a little complex for me. Or maybe I could use CUDA with my Nvidia GPU to speed things up a little.

But I am asking you and myself is there another way to parallelize (optimize) my elementwise 2dArray calculations?

I look forward to any help. Many thanks in advance!!!

EDIT:

Here I have a working example of my code for a .NET Framework Console App. As you can see I make a lot of elementwise 2d and 3d Array calculations which I would like to process in parallel (or perform them faster in any other way):

using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TemplateMatcher_Console
{
    class Program
    {
        public static int[,,] bitmapToMatrix(Bitmap bmp)
        {
            int[,,] I = new int[bmp.Width, bmp.Height, 3];

            for (int y = 0; y < bmp.Height; y++)
            {
                for (int x = 0; x < bmp.Width; x++)
                {
                    Color pix = bmp.GetPixel(x, y);

                    I[x, y, 0] = Convert.ToInt32(pix.R);
                    I[x, y, 1] = Convert.ToInt32(pix.G);
                    I[x, y, 2] = Convert.ToInt32(pix.B);
                }
            }

            return I;
        }

        public static int[] indexOfMiniumValue(int[,] matrix)
        {
            int value = 0;
            int minValue = 999999999;
            int minFirstIndex = 0;
            int minSecondIndex = 0;

            int[] ij = new int[2];

            for (int i = 0; i < matrix.GetLength(0); i++)
            {
                for (int j = 0; j < matrix.GetLength(1); j++)
                {
                    value = matrix[i, j];

                    if (value < minValue)
                    {
                        minValue = value;

                        minFirstIndex = i;
                        minSecondIndex = j;
                    }
                }
            }

            ij[0] = minFirstIndex;
            ij[1] = minSecondIndex;

            return ij;
        }

        public static void Print2DArray<T>(T[,] matrix)
        {
            for (int i = 0; i < matrix.GetLength(0); i++)
            {
                for (int j = 0; j < matrix.GetLength(1); j++)
                {
                    Console.Write(matrix[i, j] + "\t");
                }
                Console.WriteLine();
            }
        }

        static void Main(string[] args)
        {
            // Deklaration & Eingabe

            Console.WriteLine("Type the filepath for your image and then press Enter");
            string im = Console.ReadLine();

            Console.WriteLine("\nType the filepath for your template and then press Enter");
            string temp = Console.ReadLine();

            Bitmap template = new Bitmap(@temp);
            Bitmap image = new Bitmap(@im);

            int Tw = template.Width;
            int Th = template.Height;
            int Iw = image.Width;
            int Ih = image.Height;

            int[,] ds = new int[Tw, Th];
            int[,] DS = new int[Iw - Tw + 1, Ih - Th + 1];
            int[,,] DS_rgb = new int[Iw - Tw + 1, Ih - Th + 1, 3];

            int[] xy = new int[2];


            // Verarbeitung
            // int[,,] I = Array.ConvertAll(image_I, new Converter<byte, int>(Convert.ToInt32));
            int[,,] I = bitmapToMatrix(image);
            int[,,] T = bitmapToMatrix(template);


            for (int rgb = 0; rgb < 3; rgb++)
            {
                for (int y = 0; y < Ih - Th + 1; y++)
                {
                    for (int x = 0; x < Iw - Tw + 1; x++)
                    {
                        //DS_rgb[x, y, rgb] = (I[x .. x + template.Width, y .. y + template.Height, rgb] - T[0 .. template.Width, 0 .. template.Height, rgb]);
                        for (int yT = 0; yT < Th; yT++)
                        {
                            for (int xT = 0; xT < Tw; xT++)
                            {
                                ds[xT, yT] = (I[x + xT, y + yT, rgb] - T[xT, yT, rgb]) * (I[x + xT, y + yT, rgb] - T[xT, yT, rgb]);
                            }
                        }

                        int sum = ds.Cast<int>().Sum();
                        DS_rgb[x, y, rgb] = sum;
                    }
                }
            }


            //DS[.., ..] = DS_rgb[.., .., 0] + DS_rgb[.., .., 1] + DS_rgb[.., .., 2];
            for (int y = 0; y < Ih - Th + 1; y++)
            {
                for (int x = 0; x < Iw - Tw + 1; x++)
                {
                    DS[x, y] = DS_rgb[x, y, 0] + DS_rgb[x, y, 1] + DS_rgb[x, y, 2];
                }
            }

            //xy = DS.FindIndex(z => z == Math.Min(DS));
            xy = indexOfMiniumValue(DS);

            // Ausgabe

            // Ausgeben der Matrix DS
            /*
            Console.WriteLine("\nMatrix with all differtial squares:");
            Print2DArray(DS);
            */

            Console.WriteLine($"\nPosition of your template in your image (upper left corner): ({xy[0]}, {xy[1]})");
            Console.Write("\nPress any key to close the TemplateMatcher console app...");
            Console.ReadKey();
        }
    }
}
  • Its surprising how much underscores make such code hard to read – TheGeneral Dec 21 '20 at 23:34
  • Also, it would be nice to have some sort of reproducible example, so we can use benchmarkers (if we wanted to), and test results for mistakes – TheGeneral Dec 21 '20 at 23:39
  • Thanks for your advices. I removed the underscores and created a working example for .NET Framework Console App. I hope it helps! – user14832843 Dec 22 '20 at 21:40
  • `Bitmap.GetPixel` method is very slow. Use [LockBits](https://learn.microsoft.com/en-us/dotnet/api/system.drawing.bitmap.lockbits?view=dotnet-plat-ext-5.0) – Alexander Petrov Dec 23 '20 at 21:40
  • .NET Framework is almost dead. Switch to .NET Core. As a result, you will get better performance. And many goodies like [linq2d](https://github.com/evilguest/linq2d) library. – Alexander Petrov Dec 23 '20 at 21:48

0 Answers0