Ich verwende ein neuronales Netzwerk in einem Live-Stream von Screenshots mit einer Größe von 800 x 600. Da ich nur ungefähr 3 fps bekam, habe ich einige Fehlerbehebungsmaßnahmen durchgeführt und herausgefunden, wie viel Zeit ungefähr für jeden Schritt aufgewendet wird:

  • Screenshot: 12ms
  • Bildverarbeitung: 280ms
  • Objekterkennung und Boxvisualisierung: 16ms
  • Anzeigebild: 0,5 ms

Ich verwende mss zum Aufnehmen der Screenshots (Dokumentation).

Hier ist der Code ohne den Objekterkennungsteil:

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)

Irgendwelche Ideen, wie ich das schneller machen kann?

1
Cecemel 8 Feb. 2020 im 16:57

3 Antworten

Beste Antwort

Das Problem ist, dass Ihr Ansatz mit einem BGRA-Bildformat beginnt. Das sind viele Daten und wahrscheinlich unnötig. Es gibt möglicherweise effizientere Möglichkeiten, den Screenshot aufzunehmen und in ein OpenCV-Bild zu konvertieren. Hier ist ein Ansatz, der auf meinem langsamen Computer ungefähr 56 ms dauert:

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
karlphillip 9 Feb. 2020 im 09:26

Mit 280 ms Verarbeitung pro Frame erhalten Sie 3-4 Frames / Sek. Sie haben so ziemlich nur zwei Möglichkeiten.

Teilen Sie entweder Ihren Code mit und hoffen Sie, dass wir ihn verbessern können.

Oder verwenden Sie Multiprocessing mit beispielsweise 4 CPU-Kernen und geben Sie den ersten Frame an den ersten Kern, den zweiten an den zweiten usw., Round-Robin, und Sie können möglicherweise alle 70 ms einen Frame herausbringen, was zu 14 fps führt.

1
Mark Setchell 8 Feb. 2020 im 21:37

Die Verwendung dieser Zeilen anstelle der Zeilen "Bildverarbeitung:" aus meinem ersten Beitrag löste mein Problem:

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

Ich hatte zuvor bereits versucht, nur die ersten beiden Zeilen zu verwenden, aber es wurde folgende Fehlermeldung angezeigt:

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

Mir war nicht in den Sinn gekommen, dass das Konvertieren des Bildes von rgba in rgb dies beheben würde. Ich bekomme jetzt ungefähr 30fps.

1
Cecemel 9 Feb. 2020 im 13:01