Ускорение функции скриншота - Python - PullRequest
0 голосов
/ 02 марта 2019

Мне нужно, чтобы моя функция скриншота была максимально быстрой, и теперь каждый вызов этой функции занимает около 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* 1014 *

  2. Эта функция является частью проекта прямой трансляции, над которым я сейчас работаю.Решение, предложенное Карло ниже, в этом случае не подходит, поскольку удаленный компьютер не будет синхронизирован с экраном нашего компьютера.

Ответы [ 2 ]

0 голосов
/ 02 марта 2019

Поскольку ваш код неполон, я могу только догадываться, что может помочь, поэтому вот несколько мыслей ...

Я начал с изображения 1200x1200, потому что я не знаю, насколько велик ваш,и уменьшил его в 0,8x раз до 960x960 из-за комментариев в вашем коде.

Мои идеи по его ускорению основаны либо на использовании другого метода интерполяции, либо на использовании OpenCV, который является высоко оптимизированным SIMD-кодом,Либо, либо оба могут быть подходящими, но, поскольку я не знаю, как выглядят ваши изображения, только вы можете сказать.

Итак, начнем с 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 в 1,5 раза быстрее, чем BICUBIC, и реальный победитель здесь - БЛИЖАЙШИЙ в 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, который в 20 раз быстрее PIL resize().

Пожалуйста, попробуйте их все и посмотрите, что работаетдля тебя!Просто удалите магию Питона %timeit в начале строки и запустите то, что осталось.

0 голосов
/ 02 марта 2019

Это всего лишь пример того, что я имею в виду.Если это решит проблему, дайте мне знать.

Вы можете создать два разных потока.Один, который делает снимок экрана, другой, который детализирует экран позже.Оба добавляют результат в список.Это улучшит скорость функции 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()

Поскольку у меня нет вашего полного кода, я не могу построить его как можно лучше.

...