Исправление неэффективного преобразования изображения из изображения PIL в OpenCV Mat - PullRequest
1 голос
/ 08 февраля 2020

Я управляю нейронной сетью на прямом потоке скриншотов размером 800x600. Так как я получал только 3 кадра в секунду, я выполнил некоторые действия по устранению неполадок и выяснил, сколько приблизительно времени тратится на каждый шаг:

  • Снимок экрана: 12 мс
  • Обработка изображения: 280 мс
  • Обнаружение объекта и визуализация коробки: 16 мс
  • Отображение изображения: 0,5 мс

Я использую mss для снятия снимков экрана ( документация ).

Вот код без части обнаружения объекта:

import numpy as np
import cv2
from PIL import Image
import mss
monitor = {"top": 40, "left": 0, "width": 800, "height": 600}

with mss.mss() as sct:
    while True:

        # # Screenshot:
        image = sct.grab(monitor)

        # # Image processing:
        image = Image.frombytes("RGB", image.size, image.bgra, "raw", "RGBX")
        (im_width, im_height) = image.size
        image_np = np.array(image.getdata()).reshape((im_height, im_width, 3)).astype(np.uint8)

        # # Object detection and box visualisation:
        # ...

        # # Displaying image:
        cv2.imshow("Object Detection", image_np)

Есть идеи, как мне сделать это быстрее?

Ответы [ 3 ]

1 голос
/ 09 февраля 2020

Проблема в том, что ваш подход начинается с формата изображения BGRA. Это много данных и, вероятно, не нужно. Могут быть более эффективные способы получения снимка экрана и преобразования его в изображение OpenCV. Вот подход , который занимает около 56мс на моей медленной машине:

import ctypes
import datetime
import cv2
import numpy as np

from PIL import ImageGrab


# workaround to allow ImageGrab to capture the whole screen
user32 = ctypes.windll.user32
user32.SetProcessDPIAware()

# measure running time
start_time = datetime.datetime.now()

# take a full screenshot of the desktop
image = np.array(ImageGrab.grab( bbox= (40, 0, 800, 600) ))

# convert from RGB to BGR order so that colors are displayed correctly
mat = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)

# compute elapsed time
delta = datetime.datetime.now() - start_time
elapsed_time_ms = int(delta.total_seconds() * 1000)
print('* Elapsed time:', elapsed_time_ms, 'ms')

cv2.imshow('mat', mat)
cv2.waitKey()
1 голос
/ 09 февраля 2020

Использование этих строк вместо строк «Обработка изображений:» из моего первого поста решило мою проблему:

image = sct.grab(monitor)
image_np = np.array(image)
image_np = cv2.cvtColor(image_np, cv2.COLOR_RGBA2RGB)

Ранее я уже пытался использовать только первые 2 строки, но я получал эту ошибку :

ValueError: Cannot feed value of shape (1, 600, 800, 4) for Tensor 'image_tensor:0', which has shape '(?, ?, ?, 3)'

Мне не приходило в голову, что преобразование изображения из rgba в rgb исправит это. У меня сейчас около 30 кадров в секунду.

1 голос
/ 09 февраля 2020

При 280 мс обработки на кадр вы получите 3-4 кадра / с c. У вас есть всего 2 варианта.

Либо поделитесь кодом, и надеемся, что мы сможем его улучшить.

Или используйте многопроцессорную обработку, скажем, с 4 ядрами ЦП, и передайте первый кадр первому core, second to second и т. д., циклический перебор, и вы можете, возможно, получать кадр каждые 70 мс, приводя к 14 кадрам в секунду.

...