0

Using pyautogui, I'm trying to locate an image on screen.

This finds the image (on primary monitor w/ 2560x1440 resolution), but takes nearly 5 sec:

icon1 = pyautogui.locateOnScreen('[filepath]\\icon1.png', grayscale=True)

To reduce search time, I provide a region parameter, but this doesn't find the image. It executes in ~0.7 sec

icon1 = pyautogui.locateOnScreen('[filepath]\\icon1.png', region=(1500,100,950,1100), grayscale=True)

Eliminating the grayscale parameter doesn't change the result - still ~0.7 execution time and image not found:

icon1 = pyautogui.locateOnScreen('[filepath]\\icon1.png', region=(1500,100,950,1100))

Then I tried setting the region parameter to the entire screen, but image not found and execution time is ~1.5sec, so it's searching (judging by longer execution time w/ larger region), just not finding.

icon1 = pyautogui.locateOnScreen('[filepath]\\icon1.png', region=(0,0,2559,1439))

Any suggestions on what to try next? Thanks.

jub
  • 377
  • 1
  • 2
  • 14
  • 1
    Your region is set wrong. Use (0,0,2559,1439) – Claudio Sep 03 '22 at 21:17
  • Not really on topic, but good to know: https://stackoverflow.com/a/72412210/7711283 that there is the mss module there for taking screenshots in Python. – Claudio Sep 03 '22 at 23:46

2 Answers2

2

I figured out what's happening. As a preface, I am working with multiple monitors, and have made modifications to pyautogui and pyscreeze as described in these 2 pyautogui github comments: https://github.com/asweigart/pyautogui/issues/9#issuecomment-527236475 https://github.com/asweigart/pyautogui/issues/321#issuecomment-629819495

With these modifications, pyautogui works with multiple monitors, and pyautogui.position() and pyautogui.moveTo() treat the upper left corner of the primary monitor as coordinate (0,0) - this means monitors above or to the left of primary monitor will have at least one negative coordinate.

But pyscreeze is returning image search results based on treatment of the upper left corner of the upper left monitor as coordinate (0,0) - so all coordinates on extended desktop are positive.

The region parameter I was passing to locateOnScreen() was based on using pyautogui.position() reported coordinates, so the search was being executed on an incorrect area of the screen.

Once I figured that out, I was able to pass the correct region specification.

To illustrate, I inserted a print statement in pyscreeze to show where the image is found. And a print of the image search return. And in my code, I printed pyautogui.position().

retVal = Box(left=8008, top=3171, width=29, height=31)

Point(x=4182, y=1026)

mouse position:
Point(x=4182, y=1026)

So you can see that coordinates are quite different. Pyscreeze is showing coordinates based on 0,0 being upper left corner of upper left monitor, while the image search return variable are coordinates based on 0,0 being upper left corner of primary monitor, so I'm able to take the image search result variable and pass that to pyautogui.moveTo() and move the mouse there (moveTo needs coordinates based on 0,0 being upper left corner of primary monitor).

The issue stems from adopting changes from two different people to pyautogui and pyscreeze. I suppose I could adjust the changes to one of these packages to offset the coordinates so that both are referencing the same monitor's upper left corner as coordinate (0,0).

jub
  • 377
  • 1
  • 2
  • 14
1

Your region is set wrong. Use (0,0,2559,1439).

And if this doesn't work make a new screenshot specifying the region for it, save it and look if that just captured screenshot would be found on the screen.

The code below should always work as expected:

from time import perf_counter as T
import pyautogui
# NOTICE that in pyautogui: region=(left, top, width, height)
pyautogui.screenshot('pyautogui_region_screenshot.png', region=(300, 500, 300, 200))
sT = T()
img = pyautogui.locateOnScreen('pyautogui_region_screenshot.png', region=(300, 500, 300, 200))
eT = T()
print(f'img = pyautogui.locateOnScreen took: {eT-sT:9.5f} seconds')
print(img)

By the way: check out https://stackoverflow.com/questions/72410958/taking-a-screenshot-of-a-specific-portion-of-the-screen-in-python to switch to another Python module ( mss ) for doing screenshots of small regions of the screen.

https://pyautogui.readthedocs.io/en/latest/screenshot.html

Claudio
  • 7,474
  • 3
  • 18
  • 48
  • Whoops. Thanks. so with region=(0,0,2559,1439), image is not found, but it takes ~1.5 sec, so I guess it is actually searching, but just not finding. The other region parameters in the OP are correct - I widened out the region b/c it wasn't finding when I tried much smaller region earlier. – jub Sep 03 '22 at 21:24
  • sorry, I don't follow - what do you mean by "accept the question"? Re: updating the image, I'm switching back and forth on the search w/ and w/o the region parameter and the image is reliably found w/o region and reliably not found w/ region, so I don't think the display is changing between these runs, which are just seconds apart. – jub Sep 03 '22 at 21:31
  • If I click on the 'V', I'd be indicating the answer is not useful. It was useful b/c I had region wrong for full screen search, and fixing it allowed me to determine that the search is actually executing (b/c I can see search time varies with region size), but just not finding the image. – jub Sep 03 '22 at 21:37
  • I don't follow why you are suggesting the search image isn't on screen. When I omit the region parameter, locateOnScreen is reliably finding the image. And I confirmed it is correct by having the mouse click on the found coordinates. So I don't understand how redoing the screenshot of the search image would change anything? The actual image I'm searching for is small - it's just an icon in an app. I created it by taking a Windows screenshot via Alt+PrtScn and then cropping. – jub Sep 03 '22 at 21:59
  • Modern desktops with switched on effects change the lightness of what is displayed depending on actions. You can see this hovering with the mouse over tabs or doing another actions. Just try redoing the screenshot of the region. – Claudio Sep 03 '22 at 22:09
  • If the code in the answer runs without problems and the image is found, you can see that not the region specification was the problem. – Claudio Sep 03 '22 at 22:10
  • I have been there ... just wondering ... but icons can change their color values on the screen for many reasons ... so what you captured before is no more there exactly as it was ... hard to believe ... but I have experienced it many times wondering myself how it comes as you can't see the change with your eye ... you must do another screenshot and compare the old and new image to become 'enlightened'. – Claudio Sep 03 '22 at 22:13
  • By the way: I did a screenshot of part of my editor ... and was surprised that the image was not found ... the reason was that I moved the cursor to another line ... this changed the line highlight I have captured the image with before. So I become victim myself of such effect some minutes ago thinking: "uuupsss ... it doesn't work ... but should ... hmmm ..." – Claudio Sep 03 '22 at 22:20
  • Another effect ... you are getting the focus from an app to the environment you execute your pyautogui code. This changes the highlight of the icon of the app which is no more highlighted and you are wondering why it is not found ... blaming pyautogui ... or you just cover the icon at the time of the script execution by the window you use to run the script ... – Claudio Sep 03 '22 at 22:27
  • Claudio, wow, I didn't realize the image search was so sensitive. Good to know, thanks! – jub Sep 03 '22 at 23:09
  • Is pyautogui now working as expected and your problem solved? – Claudio Sep 03 '22 at 23:12
  • Claudio, yes, I have added an answer that explains the problem. – jub Sep 03 '22 at 23:13
  • please check all your questions and answers for wrong use of the walrus operator. you need to learn what it is, and why you're using it wrong here. – Christoph Rackwitz Sep 05 '22 at 12:06
  • you don't realize that the walrus operator _defines_ variables. that's a needless and potentially harmful side-effect of this abuse of python syntax. – Christoph Rackwitz Sep 05 '22 at 12:40
  • so you're intentionally using it, in spite of the side effects? why not use a `namedtuple`? or, if possible, the `pyscreeze.Box()` that's been mentioned in the other answer? – Christoph Rackwitz Sep 05 '22 at 12:42
  • @ChristophRackwitz : I have updated my answer. Thanks for pointing this out. After digging deeper into the side-effects it turned out they go much deeper as I initially thought they do . – Claudio Sep 05 '22 at 13:09
  • By the way: how can I easily get the texts of all my questions and answers here in stackoverflow along with a list with all the links to them in order to search in them for `:=`? – Claudio Sep 05 '22 at 13:12