Home > Net >  How to stop iterating through a 2D array once matches are found?
How to stop iterating through a 2D array once matches are found?

Time:06-02

Im doing image template matching using EMGU and C#. EMGU's method of finding matches was a bit slow, so I tried iterating through the image (2D array) to find matches. It works great and very fast. But for some reason, it finds multiple matches of same template on same location and draws multiple times over it. For example, if in my image there are 4 matches of given template, it will draw 10 rectangle each on each matched area for those 4 matches, so the rectangle thickness increases and the total match count is never correct.

Here is the code :

         for (int y = 0; y < Matches.Data.GetLength(0); y  )
            {
                for (int x = 0; x < Matches.Data.GetLength(1); x  )
                {
                    if (Matches.Data[y, x, 0] >= Threshold) //Set at 0.9
                    {
                        Rectangle r = new Rectangle(new Point(x, y), template.Size);
                        CvInvoke.Rectangle(imgres, r, new MCvScalar(255, 0, 0), 1, LineType.EightConnected, 0);
                        listBox1.Items.Add(r.Size); // more than 80 rectangles are drawn for 4 matches
                    }                       
                }                    
            }

How do I stop the iterations once each matches have been found once?

CodePudding user response:

Use a return statement.

For that to be tidy, keep the loop and action in separate, short methods.

for (int y = 0; y < Matches.Data.GetLength(0); y  )
{
    for (int x = 0; x < Matches.Data.GetLength(1); x  )
    {
        if (Matches.Data[y, x, 0] >= Threshold)
        {
            DoSomethingWithMatch(x, y);

            return;
        }
    }
}

CodePudding user response:

You could use break; but this gets messy fast in nested loops.

Lets go over for loops quick, they are structured like this:

for (declaration; condition; execute after) 
{
  // code block
}

Since the middle part is a simple condition, you can just add another condition indicating that it is done (or still searching). In this case just a boolean:

bool stillSearching = true;
    for (int i = 0; i < 100 && stillSearching; i  )
    {
        if (i > 50) //You found your match
        {
            stillSearching = false;
        }
    }

This will simply count to 51, then the if sets the boolean to false. It than goes back to the for loop, executes the i . Then it checks the both conditions: i < 100 is still true stillSearching is false

Since there is an && the whole condition is false and the loop stops.

Edit: Since I'm not sure what conditions you need to satisfy, I'll just add an if

bool searching = true;

for (int y = 0; y < Matches.Data.GetLength(0) && searching; y  )
        {
            for (int x = 0; x < Matches.Data.GetLength(1) && searching; x  )
            {
                if (Matches.Data[y, x, 0] >= Threshold) 
                {
                    Rectangle r = new Rectangle(new Point(x, y), template.Size);
                    CvInvoke.Rectangle(imgres, r, new MCvScalar(255, 0, 0), 1, LineType.EightConnected, 0);
                    listBox1.Items.Add(r.Size); 
                }

                if ( /*your condtion here*/ )
                {
                   searching = false;
                }   
            }                    
        }

CodePudding user response:

You can use break to get out of a loop, but it only gets you out of the closest loop you're in. The way around this is to set flag to indicate whether you should break out of the outer loop. Consider the following:

     for (int y = 0; y < Matches.Data.GetLength(0); y  )
        {
            bool matchFound = false;
            for (int x = 0; x < Matches.Data.GetLength(1); x  )
            {
                if (Matches.Data[y, x, 0] >= Threshold) //Set at 0.9
                {
                    Rectangle r = new Rectangle(new Point(x, y), template.Size);
                    CvInvoke.Rectangle(imgres, r, new MCvScalar(255, 0, 0), 1, LineType.EightConnected, 0);
                    listBox1.Items.Add(r.Size); // more than 80 rectangles are drawn for 4 matches
                    matchFound = true;
                    break;
                }                       
            }
            if(matchFound) 
            {
                break;
            }               
        }
  • Related