加快屏幕截图功能-Python

时间:2019-03-02 16:56:30

标签: python numpy python-imaging-library python-mss

我需要我的屏幕截图功能尽可能快,现在每次调用该功能大约需要0.2秒。

这是功能:

    def get_screenshot(self, width, height):

        image = self.screen_capture.grab(self.monitor)
        image = Image.frombuffer('RGB', image.size, image.bgra, 'raw', 'BGRX')
        image = image.resize((int(width), int(height)), Image.BICUBIC) # Resize to the size of 0.8 from original picture
        image = np.array(image)
        image = np.swapaxes(image, 0, 1)

        # This code below supposed to replace each black color ([0,0,0]) to the color of [0,0,1]
        # r1,g1,b1 = [0,0,0] and r2,g2,b2 = [0,0,1]

        red, green, blue = image[:, :, 0], image[:, :, 1], image[:, :, 2]
        mask = (red == r1) & (green == g1) & (blue == b1)
        image[:, :, :3][mask] = [r2, g2, b2]

        return image

您注意到我可以做些什么来使功能更快吗?

编辑:我忘记提及的一些细节:

  1. 我的屏幕尺寸为1920 * 1080

  2. 此功能是我当前正在处理的实时项目的一部分。 Carlo提出的以下解决方案在这种情况下不合适,因为远程计算机将不会与我们的计算机屏幕同步。

2 个答案:

答案 0 :(得分:2)

由于您的代码不完整,我只能猜测有什么用,所以这里有一些想法...

我从1200x1200的图片开始,因为我不知道您的图片有多大,并由于代码中的注释而将其缩小了0.8x到960x960。

我加快速度的想法是基于使用其他插值方法,或者是使用高度优化的SIMD代码OpenCV。也许两者都合适,但由于我不知道您的图像是什么样,所以只能说。

因此,我们首先使用PIL resize()和不同的插值方法:

# Open image with PIL
i = Image.open('start.png').convert('RGB')

In [91]: %timeit s = i.resize((960,960), Image.BICUBIC)                                             
16.2 ms ± 28 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [92]: %timeit s = i.resize((960,960), Image.BILINEAR)                                            
10.9 ms ± 87.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [93]: %timeit s = i.resize((960,960), Image.NEAREST)                                             
440 µs ± 10.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

因此,BILINEAR比BICUBIC快1.5倍,而真正的赢家是NEAREST,快32倍。

现在,转换为一个Numpy数组(无论如何都要做),并使用高度优化的OpenCV SIMD代码来调整大小:

# Now make into Numpy array for OpenCV methods
n = np.array(i)

In [100]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_CUBIC)                     
806 µs ± 9.81 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [101]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_LINEAR)                    
3.69 ms ± 29 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [102]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_AREA)                      
12.3 ms ± 136 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [103]: %timeit s = cv2.resize(n, (960,960), interpolation = cv2.INTER_NEAREST)                   
692 µs ± 448 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

这里的获胜者看起来像INTER_CUBIC,比PIL的resize()快20倍。

请全部尝试一下,看看有什么适合您的!只需删除该行开头的Python魔术%timeit并运行剩下的内容即可。

答案 1 :(得分:1)

这只是我的意思的一个例子。 如果能解决问题,请告诉我。

您可以创建两个不同的线程。一个截屏,另一个截屏。两者都将结果添加到列表中。 这样可以提高get_screenshot函数的速度。但为了详细说明,您需要执行函数所需的时间。

import threading
#import your stuff

class your_class(object):
        def __init__(self):

                self.images = list()
                self.elaborated_images = list()

                threading.Thread(name="Take_Screen", target=self.get_screenshot, args=(width, height))
                threading.Thread(name="Elaborate_Screen", target=self.elaborate_screenshot)

        def get_screenshot(self, width, height):
                while True:
                        images.append(self.screen_capture.grab(self.monitor))

        def elaborate_screenshot(self):
                while True:
                        image = self.images[0]
                        image = Image.frombuffer('RGB', image.size, image.bgra, 'raw', 'BGRX')
                        image = image.resize((int(width), int(height)), Image.BICUBIC) # Resize to the size of 0.8 from original picture
                        image = np.array(image)
                        image = np.swapaxes(image, 0, 1)

                        # This code below supposed to replace each black color ([0,0,0]) to the color of [0,0,1]
                        # r1,g1,b1 = [0,0,0] and r2,g2,b2 = [0,0,1]

                        red, green, blue = image[:, :, 0], image[:, :, 1], image[:, :, 2]
                        mask = (red == r1) & (green == g1) & (blue == b1)
                        image[:, :, :3][mask] = [r2, g2, b2]

                        del self.images[0]

                        self.elaborated_images.append(image)

your_class()

因为我没有完整的代码,所以我无法尽可能地构建它。