使用PIL优化代码

时间:2010-04-14 10:06:16

标签: python performance image

首先抱歉下面贴了很长一段代码。 这是我第一次真的不得不担心应用程序的性能,所以我真的不担心性能。 这段代码几乎在另一个图像中搜索图像,在我的计算机上运行需要30秒,将图像转换为灰度和其他15秒的变化,我还需要另外15次剃光。我确实阅读了一堆页面并查看了示例,但我在代码中找不到相同的问题。所以任何帮助都将不胜感激。

从它的外观(cProfile)在Image模块中花费了25秒,在我的代码中只花了5秒。

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] - imagebbox[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"))')

2 个答案:

答案 0 :(得分:1)

虽然没有直接与性能相关,但您可以做一些改进代码的事情:

if not Found:
    return "Not Found"

是在Python中编写条件的惯用方法。但是,您不需要此子句,因为只有在找不到图像时才能访问此返回语句。

GetImage中的

您应该使用os.path.join(os.getcwd(),"Images",name)创建一次文件名,以尽量减少错误,不要重复自己。如果你没有图像文件,它通常也不会起作用。由于您未在Find处理错误,我建议如下:

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

你的主要问题是你正在逐像素搜索,在任何有意义的大小图像上都会很慢。

答案 1 :(得分:1)

这个算法计算量很大,我不相信你可以在不改变方法的情况下加速它。

让我们做一些数学: 说屏幕是1024x768(我们仍然在2000年) 说你的测试图像是100x100 然后你最终做了924 * 668 blits 100x100 这相当于大约7848全屏幕。

这种蛮力的做法一定会很慢。