开发者

Optimizing code using PIL

Firstly sorry for the long piece of code pasted below. This is my first time actually having to worry about performance of an application so I haven't really ever worried about performance. This piece of code pretty much searches for an image inside another image, it takes 30 seconds to run on my computer, converting the images to greyscale and other changes shaved of 15 seconds, I need another 15 shaved off. I did read a bunch of pages and looked at examples but I couldn't find the same problems in my code. So any help would be greatly appreciated.

From the looks of it (cProfile) 25 seconds is spent within the Image module, and only 5 seconds in my code.

from PIL import Image
import os, ImageGrab, pdb, time, win32api, win32con
import cProfile

def GetImage(name):
    name = name + '.bmp'
    try:
        print(os.path.join(os.getcwd(),"Images",name))
        image = Image.open(os.path.join(os.getcwd(),"Images",name))
    except:
        print('error opening image;', name)
    return image

def Find(name):
    image = GetImage(name)
    imagebbox = image.getbbox()
    screen = ImageGrab.grab()
    #screen = Image.open(os.path.join(os.getcwd(),"Images","Untitled.bmp"))
    YLimit =  screen.getbbox()[3] - imagebbox[3]
    XLimit = screen.getbbox()[2] - im开发者_开发问答agebbox[2]
    image = image.convert("L")
    Screen = screen.convert("L")
    Screen.load()
    image.load()
    #print(XLimit, YLimit)
    Found = False
    image = image.getdata()
    for y in range(0,YLimit):
        for x in range(0,XLimit):
            BoxCoordinates = x, y, x+imagebbox[2], y+imagebbox[3]
            ScreenGrab = screen.crop(BoxCoordinates)
            ScreenGrab = ScreenGrab.getdata()
            if image == ScreenGrab:
                Found = True
                #print("woop")
                return x,y
    if Found == False:
        return "Not Found"
cProfile.run('print(Find("Login"))')


while not directly performance related you could do some things to improve your code:

if not Found:
    return "Not Found"

is idiomatic way to write condition in Python. You don't need this clause, however, since this return statement could be reached only if image wasn't found.

in GetImage you should create filename once with os.path.join(os.getcwd(),"Images",name) to minimize errors and not to repeat yourself. Also it wouldn't normally work if you don't have the image file. Since you're not handling error in the Find, I'd suggest the following:

def Find(name):
    fname = os.path.join(os.getcwd(), "Images", name + '.bmp')
    image = Image.open(fname)
    imagebbox = image.getbbox()
    screen = ImageGrab.grab()
    YLimit =  screen.getbbox()[3] - imagebbox[3]
    XLimit = screen.getbbox()[2] - imagebbox[2]
    image = image.convert("L")
    Screen = screen.convert("L")
    Screen.load()
    image.load()
    image = image.getdata()
    for y in range(0, YLimit):
        for x in range(0, XLimit):
            BoxCoordinates = x, y, x+imagebbox[2], y+imagebbox[3]
            ScreenGrab = screen.crop(BoxCoordinates)
            ScreenGrab = ScreenGrab.getdata()
            if image == ScreenGrab:
                return x, y
    # returns None implicitly

Your major problem is that you're doing pixel by pixel search, it's going to be slow on any meaningful size image.


This algorithm is quite computation intensive, I don't believe you can speed it up without changing the approach.

Lets do some math : Say the screen is 1024x768 (we're still in the year 2000) Say your test image is 100x100 Then you end up doing 924*668 blits of 100x100 Thats equivalent to about 7848 full screen blits.

It's bound to be slow with this brute force approach.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜