1

I'm writing an image detection bot and as per the advice from a few members, I refactored some code and separated this section into its own function objectDetection I'm trying to do two things with the array image_list

  1. Iterate through the array and if any image is detected I want to immediately print "Avoided" to the terminal and restart the objectDetection function from the beginning of the array.

I've tried to do this with the flag variable found_anything = True and break it hasn't worked.

  1. Iterate through the full array of images and if nothing at all is found, execute functionTwo()

I tried to do this with the break at the end of my for i in image_list: loop, it also hasn't worked.

So far I've tried....

Reading through these three pages: Break out of two loops and two if statements - Python break out of two loops without disturbing the if statements after it in python Accessing the index in 'for' loops? and I tried both the variable flags and break statements but I can't get either to work.

I also had a look at this: How to break out of multiple loops? but what is the difference between return and break in python? made me think in my case the top answer wouldn't be appropriate as I don't think I'm returning data outside of my function.

Is there a way I can adapt this code to achieve my two uses cases above? Am I missing something obvious? I've been thought all the loop tutorials I can find and I'm still struggling, is this simply a difficult way I'm trying to design things? Or am I simply not getting it and should go back over some tutorials.

def objectDetection(image_list, threshold, haystack, a):
    for x in range (0, a):

        found_anything = False
        while found_anything is False:

            for i in image_list:
                needle_img = i[0]
                result = cv.matchTemplate(haystack, needle_img, cv.TM_CCORR_NORMED)
    
                # Get the best match position
                min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)

                # Define top left and bottom right and threshold
                (H, W) = i[0].shape[:2] 
                top_left = max_loc
                bottom_right = (top_left[0] + W, top_left[1] + H)

                if max_val >= threshold:
                    cv.rectangle(haystack, top_left, bottom_right, 255, 2)
                    print("Avoided")
                    found_anything = True
                    break
            break                              
            functionTwo()


while True:
    
    # Listener to check if on the correct screen
    if py.locateCenterOnScreen('!.jpg') != None:
        objectDetection(ships_to_avoid, 0.92, window, 10)
        break
Stevphen
  • 205
  • 1
  • 8
  • your function is doing far too many things, which is mostly why you're struggling, break it down into one function per operation and you will find this much easier to solve. Please also fix the indentation in your code in the question, I assume the while loop is outside the function, for instance. – JeffUK Feb 09 '22 at 16:00
  • Would you believe I cut a lot out to make it into a function? I was given the advice to have the function only do the detection and I thought that was the case here. But are you saying move out even the `if max_val` section and simply return from the object detection the result of the object detection itself? – Stevphen Feb 09 '22 at 16:07
  • I don't understand why you have most of the loops in there to be honest, none of them really make a lot of sense.. But each loop could be put into it's own function, and where you use a line break and a comment to introduce the next thing you're doing, that's a good sign it should be a separate function too. – JeffUK Feb 09 '22 at 16:11

1 Answers1

1

I'd refactor the whole thing but something like this answers the main question: Refactor your functions such that you can use 'Return' instead of 'Break'

def objectDetection(image_list, threshold, haystack, a):
    for i in image_list:
 
        max_val, top_left = find_needle_in_haystack(haystack, i[0])

        if max_val >= threshold:
            draw_rectangle(i,top_left,haystack)
            print("Avoided")
            return True

    return False


while True:
    if py.locateCenterOnScreen('!.jpg') != None:
        if not objectDetection(ships_to_avoid, 0.92, window, 10):
            function_two()
JeffUK
  • 4,107
  • 2
  • 20
  • 34
  • Thanks @JeffUK that works perfectly when `max_val >= threshold:` is false. However, when it's true, it ends the script entirely. Does the `while True:` literally take direction from return true/false? – Stevphen Feb 09 '22 at 17:57
  • I don't understand why you want to repeatedly search the same array from the start, it will be exactly the same and stop on exactly the same 'detection' each time it runs... – JeffUK Feb 10 '22 at 10:17
  • Because the template has subtle variations that update in real-time and I was using it as a hedge to try and find a match. I haven't learned about more complicated object detection yet, only match template. This method is catching about 90% of the time which has been good enough so far, it's only for a 2d game as a learning project so good enough works for now. – Stevphen Feb 10 '22 at 10:22
  • All I really need this bot to do is determine if it wants to click button A or button B – Stevphen Feb 10 '22 at 10:24
  • Oh also, swapping the break to continue fixed things! Thanks! I'm sorry for the poor question, struggling with those. – Stevphen Feb 10 '22 at 10:26
  • 1
    In that case you don't need it at all, just do "If not objectdetection: funciton2()" continue will just happen – JeffUK Feb 10 '22 at 10:49
  • Thanks, appreciate that! I expect there's probably much better ways of just detecting the images correctly first time round but that feels like a lot more learning before I figure that out. – Stevphen Feb 10 '22 at 11:02
  • Once you have it working, codereview.stackexchange.com might be able to help give you some pointers on improving it. Please read the 'how to ask' on there first. – JeffUK Feb 10 '22 at 11:15