0

I've run into issues with win32gui when trying to grab a real-time video stream of an application. I've seen I can use ImageGrab from PIL and based on this video Computer Screen Recording using Python & OpenCV I think I can use it instead of win32gui

I'm trying to learn python by writing a bot, the below code should grab images from a specified folder, load them into an array, converts them into a format OpenCV can use and then attempts to find any or all of them on my application window haystack

I can't find any details on google of the error I'm getting:

C:\Users\coyle\OneDrive\froggy-pirate-master\avoidShips>C:/Users/coyle/AppData/Local/Programs/Python/Python39/python.exe c:/Users/coyle/OneDrive/froggy-pirate-master/avoidShips/avoidships4.py
Traceback (most recent call last):
  File "c:\Users\coyle\OneDrive\froggy-pirate-master\avoidShips\avoidships4.py", line 41, in <module>
    loadImages()
  File "c:\Users\coyle\OneDrive\froggy-pirate-master\avoidShips\avoidships4.py", line 22, in loadImages
    return matchTemplate(image_list)
  File "c:\Users\coyle\OneDrive\froggy-pirate-master\avoidShips\avoidships4.py", line 32, in matchTemplate
    result = cv.matchTemplate(haystack, needle_img, cv.TM_CCOEFF_NORMED)
cv2.error: OpenCV(4.5.1) C:\Users\appveyor\AppData\Local\Temp\1\pip-req-build-wvn_it83\opencv\modules\imgproc\src\templmatch.cpp:588: error: (-215:Assertion failed) corr.rows <= img.rows + templ.rows - 1 && corr.cols <= img.cols + templ.cols - 1 in function 'cv::crossCorr'

And my code:

def loadImages():
    # Intialise empty array
    image_list = []
    # Get list of all images in directory
    directory = glob.glob(r"C:\Users\*.png")

    # Add images to image_list
    for img in directory:
        ship_img = cv.imread(img, 0)
        image_list.append(ship_img)
    return matchTemplate(image_list)

def matchTemplate(image_list):
    # Video Loop
    while True:
        haystack_img = ImageGrab.grab()
        haystack_img_np = np.array(haystack_img)
        haystack = cv.cvtColor(haystack_img_np, cv.COLOR_BGR2GRAY)
        
        # Object Detection
        for ships in image_list:
            needle_img = cv.imread(str(image_list), cv.IMREAD_UNCHANGED)
            result = cv.matchTemplate(haystack, needle_img, cv.TM_CCOEFF_NORMED)
            cv.imshow('Result', haystack)

            if cv.waitKey(1) == 27:
                break

        cv.destroyAllWindows()

loadImages()
matchTemplate()

As a test, I've tried doing the same thing using static images and it works so I'm not sure where I'm going wrong.

import cv2 as cv
import glob

# load source images
directory = glob.glob(r'C:\Users\*.jpg')
# empty list to store the source images
image_list = []

for img in directory:
    ships_img = cv.imread(img, 0)
    image_list.append(ships_img)

haystack_img = cv.imread(r'C:\Users\both.jpg')
haystack_img = cv.cvtColor(haystack_img, cv.COLOR_BGR2GRAY)

#loop for matching
for ships in image_list:
    
    #save the dimensions of the needle images
    (H, W) = ships.shape[:2]
    result = cv.matchTemplate(haystack_img, ships, cv.TM_CCOEFF)
    min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
    top_left = max_loc
    
    bottom_right = (top_left[0] + W, top_left[1] + H)
    cv.rectangle(haystack_img, top_left, bottom_right, 255, 2)

cv.imshow('Result', haystack_img)
cv.waitKey(0)
Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
  • the exception says that the template is too large, or the haystack is too small. check the shapes of haystack and needle_img at the time of the exception (just print them always before the call) – Christoph Rackwitz Oct 06 '21 at 00:37
  • previous question (*with no accepted answer* and lots of confusion...), with a title identical to what I would have given this question: https://stackoverflow.com/questions/68225508/matchtemplate-215assertion-failed-corr-rows-img-rows-templ-rows-1 – Christoph Rackwitz Oct 06 '21 at 00:40
  • I'm dumped `cv.imshow("Screen", haystack_img_np)` after I convert the `ImageGrab` to my np array and the python window opens up correctly but it immediately (doesn't show anything) goes not responding. Any ideas @ChristophRackwitz –  Oct 06 '21 at 10:15
  • I've done some testing outside of my functions in a new script (functions always seem to cause me issues) and the issue is definitely `result = cv.matchTemplate(haystack, needle_img, cv.TM_CCOEFF_NORMED)` When I print(needle_img) as you've suggested I get back `none` so I think my problem is how I'm reading the images because `image_list` shows as an array in the debugger I.e. `array([[70, 70, 70, ..., 46, 46, 46],` –  Oct 06 '21 at 10:29
  • so? continue investigating the None result. use `os.path.isfile`. keep going. – Christoph Rackwitz Oct 06 '21 at 12:58
  • you use `imread(str(image_lst))` so you try to send list with many elements but it needs single element - single filename. Other problem is that this list has aready loaded images you try to use image data to load it again in `imread()` - it is wrong. You should use directly `needle_img = ship` instead of `needle_img = cv.imread(str(image_list), ...)` – furas Oct 06 '21 at 17:48

1 Answers1

0

I can't test it but you simply try to load image which you already have in memory

You have

needle_img = cv.imread(str(image_list), cv.IMREAD_UNCHANGED)

but image_list has already loaded image, not filenames.
Besides imread() needs sinlge filename but you try use it with some list converted to string.

You should use directly

needle_img = ships

I think it should be

def loadImages():
    # Intialise empty array
    image_list = []
    
    # Get list of all images in directory
    directory = glob.glob(r"C:\Users\*.png")

    # Add images to image_list
    for img in directory:
        ship_img = cv.imread(img, 0)  # <-- here you load all images
        image_list.append(ship_img)
        
    return image_list   # I preferr to send back data instead of running `matchTemplate`


def matchTemplate(image_list):
    # Video Loop
    while True:
        haystack_img = ImageGrab.grab()
        haystack_img_np = np.array(haystack_img)
        haystack = cv.cvtColor(haystack_img_np, cv.COLOR_BGR2GRAY)
        
        # Object Detection
        for ships in image_list:
            # you don't have to load images because you already have them in `image_list`
            #needle_img = cv.imread(str(image_list), cv.IMREAD_UNCHANGED)
            
            needle_img = ships
            
            result = cv.matchTemplate(haystack, needle_img, cv.TM_CCOEFF_NORMED)
            cv.imshow('Result', haystack)

            if cv.waitKey(1) == 27:
                break

        cv.destroyAllWindows()

# --- main ---

image_list = loadImages()
matchTemplate(image_list)

BTW:

In normal open(), read() you get error if it has problem to open or read file but in OpenCV imread() does't raise error when it can't load image but it gives None - but you don't check if you get None - and you don't know that there was problem to load it - and later when you try to use this value in next command (matchTemplate) then it shows error. But real problem was with imread()

furas
  • 134,197
  • 12
  • 106
  • 148
  • Thanks for the detail @Furas I'll take a look at this a little later today but that all makes sense for now! Thank you! –  Oct 07 '21 at 08:57
  • Yup, nailed it. That all makes sense. It's working! Not to figure out how to speed up the window capture, it's deathly slow. Thank you! –  Oct 08 '21 at 09:54