В этом уроке я покажу вам, как быстрее захватить экран вашего компьютера с помощью многопроцессорной обработки Python в библиотеке MSS.

Приветствуем всех в части 9 нашей серии API обнаружения объектов TensorFlow. Во-первых, Вы можете скачать код на моей странице GitHub. Этот урок будет немного отличаться от предыдущих уроков.

В 8-й части мне сказали, что я буду работать с многопроцессорностью Python, чтобы заставить код работать параллельно с другими процессами. Поэтому я часами учился использовать многопроцессорность (раньше я ее не использовал).

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

Сначала я делю весь код на две части; первую часть мы назовем GRABMSS_screen. Затем нам нужно поместить весь код в цикл while, чтобы запускать его снова и снова. Когда у нас есть наш экран, мы вызываем команду q.put_nowait(img), в которой мы помещаем наше изображение в общую очередь, и следующей строкой q.join() мы говорим «подождите, так как изображение будет скопировано в очередь».

def GRABMSS_screen(q):
    while True:
        # Get raw pixels from the screen, save it to a Numpy array
        img = numpy.array(sct.grab(monitor))
        # To get real color we do this:
        #img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        q.put_nowait(img)
        q.join()

Вторую функцию мы назовем SHOWMSS_screen. После этого делаем то же самое, что и раньше, показывая захваченное изображение и измеряя FPS. Эта функция также будет выполняться в цикле while, и мы всегда проверяем, не пуста ли наша очередь. Когда у нас есть что-то в очереди, мы вызываем команду q.get_nowait(), которая забирает все из очереди, а с помощью q.task_done() мы блокируем процесс, чтобы не прерывать очередь, если мы не закончили забирать все данные.

def SHOWMSS_screen(q):
    global fps, start_time
    while True:
        if not q.empty():
            img = q.get_nowait()
            q.task_done()
            # To get real color we do this:
            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            # Display the picture
            cv2.imshow(title, cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
            # Display the picture in grayscale
            fps+=1
            TIME = time.time() - start_time
            if (TIME) >= display_time :
                print("FPS: ", fps / (TIME))
                fps = 0
                start_time = time.time()
            # Press "q" to quit
            if cv2.waitKey(25) & 0xFF == ord("q"):
                cv2.destroyAllWindows()
                break

Прямо сейчас у нас есть две разные функции, и мы будем использовать их в параллельных процессах.

Если мы хотим запустить наш код в многопроцессорном режиме, мы должны начать наш код с if name=="main": и запустить скрипт Python из командной строки; в противном случае, если мы запустим его из оболочки Python, мы не получим никаких отпечатков, необходимых здесь для измерения FPS. Итак, наша полная третья часть кода выглядит так:

if __name__=="__main__":
    # Queue
    q = multiprocessing.JoinableQueue()

    # creating new processes
    p1 = multiprocessing.Process(target=GRABMSS_screen, args=(q, ))
    p2 = multiprocessing.Process(target=SHOWMSS_screen, args=(q, ))

    # starting our processes
    p1.start()
    p2.start()

Подробнее о многопроцессорности и очередях в Python вы можете узнать по этой ссылке. Объяснение шорткода: мы начинаем с создания очереди chared.

# Queue
q = multiprocessing.JoinableQueue()

Мы создаем процессы p1 и p2 со следующими строками, которые будут работать в фоновом режиме. Функция p1 вызовет функцию GRABMSS_screen(), а p2 вызовет функцию SHOWMSS_screen(). В качестве аргумента для этих функций мы должны привести аргументы, мы даем там q.

# creating new processes
p1 = multiprocessing.Process(target=GRABMSS_screen, args=(q, ))
p2 = multiprocessing.Process(target=SHOWMSS_screen, args=(q, ))

Последний шаг — запустить наши процессы. После этих команд наша функция захвата экрана будет работать в фоновом режиме.

# starting our processes
p1.start()
p2.start()

Для сравнения, я запускал старый код без многопроцессорности и с многопроцессорностью. Вот результаты без многопроцессорности:

Мы видим, что среднее значение составляет около 19–20 FPS. Вот результаты с многопроцессорной обработкой:

Захват экрана с многопроцессорными конвейерами

Обновлено Рокасом Балсисом 18 декабря 2018 г.

Вот аналогичный код, в котором я использую многопроцессорные каналы для связи «один к одному» между процессами:

import multiprocessing
from multiprocessing import Pipe
import time
import cv2
import mss
import numpy as np
import datetime

title = "FPS benchmark"
start_time = time.time()
display_time = 2 # displays the frame rate every 2 second
fps = 0
sct = mss.mss()
# Set monitor size to capture
monitor = {"top": 40, "left": 0, "width": 800, "height": 640}

def GRABMSS_screen(p_input):
    while True:
        #Grab screen image
        img = np.array(sct.grab(monitor))
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

        # Put image from pipe
        p_input.send(img)
    
def SHOWMSS_screen(p_output):
    global fps, start_time
    while True:
        # Get image from pipe
        img = p_output.recv()
        
        # Display the picture
        cv2.imshow(title, img)
        
        # Calculate FPS
        fps+=1
        TIME = time.time() - start_time
        if (TIME) >= display_time :
            print("FPS: ", fps / (TIME))
            fps = 0
            start_time = time.time()
            
        # Press "q" to quit
        if cv2.waitKey(25) & 0xFF == ord("q"):
            cv2.destroyAllWindows()
            break
        

if __name__=="__main__":
    # Pipes
    p_output, p_input = Pipe()

    # creating new processes
    p1 = multiprocessing.Process(target=GRABMSS_screen, args=(p_input,))
    p2 = multiprocessing.Process(target=SHOWMSS_screen, args=(p_output,))

    # starting our processes
    p1.start()
    p2.start()

Мы видим, что среднее значение составляет около 32 кадров в секунду. Таким образом, наш окончательный результат заключается в том, что наш экран захвата улучшился примерно на 50%. Я хочу улучшить его еще больше, но у меня пока нет идей, как это сделать. Во всяком случае, результаты намного лучше, чем раньше! Далее я попытаюсь интегрировать это с кодом обнаружения объектов CSGO.

Первоначально опубликовано на https://pylessons.com/Tensorflow-object-detection-grab-screen-multiprocessing

Больше контента на plainenglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Получите эксклюзивный доступ к возможностям написания и советам в нашем сообществе Discord.