I only managed to do this with PIL.
Some reservations:
- This is a perfect pixel search. It just searches for matching RGB pixels.
- For simplicity, I remove the alpha / transparency channel. I am only looking for RGB pixels.
- This code loads the entire array of pixels in pixels into memory, storing a large image out of memory. On my system, Python supported about 26 megabytes of memory for a tiny 40mm image viewing a 1920x1200 screenshot.
- This simple example is not very effective, but increasing efficiency will add complexity. Here I keep everything straight and easy to understand.
- This example works on Windows and OSX. Not tested on Linux. It takes a screenshot of only the main display (for settings of multiple monitors).
Here is the code:
import os from itertools import izip from PIL import Image, ImageGrab def iter_rows(pil_image): """Yield tuple of pixels for each row in the image. From: http://stackoverflow.com/a/1625023/1198943 :param PIL.Image.Image pil_image: Image to read from. :return: Yields rows. :rtype: tuple """ iterator = izip(*(iter(pil_image.getdata()),) * pil_image.width) for row in iterator: yield row def find_subimage(large_image, subimg_path): """Find subimg coords in large_image. Strip transparency for simplicity. :param PIL.Image.Image large_image: Screen shot to search through. :param str subimg_path: Path to subimage file. :return: X and Y coordinates of top-left corner of subimage. :rtype: tuple """
Speed:
$ python -m timeit -n1 -s "from tests.screenshot import find" "find('subimg.png')" (429, 361) (465, 388) (536, 426) 1 loops, best of 3: 316 msec per loop
During the execution of the above command, I moved the window containing the prototype diagonally when timeit was timeit .
source share