Unterscheidet sich die Leistung zwischen der Python- oder C ++ - Codierung von OpenCV?

75

Ich möchte opencv nach und nach starten, aber zuerst muss ich entscheiden, welche API von OpenCV nützlicher ist. Ich gehe davon aus, dass die Python-Implementierung kürzer ist, die Laufzeit jedoch im Vergleich zu den nativen C ++ - Implementierungen dichter und langsamer sein wird. Gibt es irgendwelche bekannten Kommentare zu Leistungs- und Codierungsunterschieden zwischen diesen beiden Perspektiven?

erogol
quelle
4
Der größte Teil der eigentlichen Arbeit wird Cohnehin hinter den Kulissen vom OpenCV- Code erledigt. Vorausgesetzt , Ihr eigener Code ist nicht zu aufwendig, sollte der Unterschied nicht so groß sein, wie Sie es naiv erwarten würden.
Juanchopanza

Antworten:

158

Wie bereits in früheren Antworten erwähnt, ist Python im Vergleich zu C ++ oder C langsamer. Python wurde aufgrund seiner Einfachheit, Portabilität und Kreativität entwickelt, bei der sich Benutzer nur um ihren Algorithmus und nicht um Programmierprobleme kümmern müssen.

Aber hier in OpenCV gibt es etwas anderes. Python-OpenCV ist nur ein Wrapper um den ursprünglichen C / C ++ - Code. Es wird normalerweise verwendet, um die besten Funktionen beider Sprachen, die Leistung von C / C ++ und die Einfachheit von Python , zu kombinieren .

Wenn Sie also eine Funktion in OpenCV von Python aus aufrufen, liegt tatsächlich die zugrunde liegende C / C ++ - Quelle zugrunde. Es wird also keinen großen Unterschied in der Leistung geben. (Ich erinnere mich, dass ich irgendwo gelesen habe, dass die Leistungsstrafe <1% ist, weiß nicht, wo. Eine grobe Schätzung mit einigen Grundfunktionen in OpenCV zeigt eine Strafe im schlimmsten Fall von <4%. Dh penalty = [maximum time taken in Python - minimum time taken in C++]/minimum time taken in C++) .

Das Problem tritt auf, wenn Ihr Code viele native Python-Codes enthält. Wenn Sie beispielsweise eigene Funktionen erstellen, die in OpenCV nicht verfügbar sind, wird es schlimmer. Solche Codes werden nativ in Python ausgeführt, was die Leistung erheblich verringert.

Die neue OpenCV-Python-Oberfläche unterstützt Numpy jedoch vollständig. Numpy ist ein Paket für wissenschaftliches Rechnen in Python. Es ist auch ein Wrapper um nativen C-Code. Es handelt sich um eine hochoptimierte Bibliothek, die eine Vielzahl von Matrixoperationen unterstützt und sich hervorragend für die Bildverarbeitung eignet. Wenn Sie also sowohl OpenCV-Funktionen als auch Numpy-Funktionen korrekt kombinieren können, erhalten Sie einen sehr schnellen Code.

Denken Sie immer daran, Schleifen und Iterationen in Python zu vermeiden. Verwenden Sie stattdessen Array-Manipulationsfunktionen, die in Numpy (und OpenCV) verfügbar sind. Das einfache Hinzufügen von zwei Numpy-Arrays mit C = A+Bist viel schneller als das Verwenden von Doppelschleifen.

Zum Beispiel können Sie diese Artikel überprüfen:

  1. Schnelle Array-Manipulation in Python
  2. Leistungsvergleich der OpenCV-Python-Schnittstellen cv und cv2
Abid Rahman K.
quelle
14

Alle Google-Ergebnisse für openCV geben den gleichen Status an: Dieser Python ist nur geringfügig langsamer. Aber ich habe kein einziges Mal ein Profiling dazu gesehen. Also entschied ich mich für einige und entdeckte:

Python ist mit opencv deutlich langsamer als C ++, selbst für triviale Programme.

Das einfachste Beispiel, das ich mir vorstellen konnte, war, die Ausgabe einer Webcam auf dem Bildschirm anzuzeigen und die Anzahl der Bilder pro Sekunde anzuzeigen. Mit Python erreichte ich 50 FPS (auf einem Intel-Atom). Mit C ++ habe ich 65 FPS erhalten, eine Steigerung von 25%. In beiden Fällen verwendete die CPU-Auslastung einen einzigen Kern und war meines Wissens an die Leistung der CPU gebunden. Außerdem stimmt dieser Testfall mit dem überein, was ich in Projekten gesehen habe, die ich in der Vergangenheit von einem zum anderen portiert habe.

Woher kommt dieser Unterschied? In Python geben alle openCV-Funktionen neue Kopien der Bildmatrizen zurück. Wann immer Sie ein Bild aufnehmen oder dessen Größe ändern - in C ++ können Sie den vorhandenen Speicher wiederverwenden. In Python können Sie nicht. Ich vermute, dass diese Zeit für die Zuweisung von Speicher der Hauptunterschied ist, denn wie andere gesagt haben: Der zugrunde liegende Code von openCV ist C ++.

Bevor Sie Python aus dem Fenster werfen: Python lässt sich viel schneller entwickeln. Wenn Sie nicht auf Hardwareeinschränkungen stoßen oder wenn die Entwicklungsgeschwindigkeit wichtiger ist als die Leistung, verwenden Sie Python. In vielen Anwendungen, die ich mit openCV ausgeführt habe, habe ich in Python begonnen und später nur die Computer Vision-Komponenten in C ++ konvertiert (z. B. mithilfe des ctype-Moduls von Python und Kompilieren des CV-Codes in eine gemeinsam genutzte Bibliothek).

Python-Code:

import cv2
import time

FPS_SMOOTHING = 0.9

cap = cv2.VideoCapture(2)
fps = 0.0
prev = time.time()
while True:
    now = time.time()
    fps = (fps*FPS_SMOOTHING + (1/(now - prev))*(1.0 - FPS_SMOOTHING))
    prev = now

    print("fps: {:.1f}".format(fps))

    got, frame = cap.read()
    if got:
        cv2.imshow("asdf", frame)
    if (cv2.waitKey(2) == 27):
        break

C ++ - Code:

#include <opencv2/opencv.hpp>
#include <stdint.h>

using namespace std;
using namespace cv;

#define FPS_SMOOTHING 0.9

int main(int argc, char** argv){
    VideoCapture cap(2);
    Mat frame;

    float fps = 0.0;
    double prev = clock(); 
    while (true){
        double now = (clock()/(double)CLOCKS_PER_SEC);
        fps = (fps*FPS_SMOOTHING + (1/(now - prev))*(1.0 - FPS_SMOOTHING));
        prev = now;

        printf("fps: %.1f\n", fps);

        if (cap.isOpened()){
            cap.read(frame);
        }
        imshow("asdf", frame);
        if (waitKey(2) == 27){
            break;
        }
    }
}

Mögliche Benchmark-Einschränkungen:

  • Bildrate der Kamera
  • Timer Messgenauigkeit
  • Zeitaufwand für die Druckformatierung
sdfgeoff
quelle
2
Ihr Testfall ist zufällig derjenige, der den größten Unterschied zwischen Python und C ++ zeigt. Es könnte also nicht realistisch sein. Ein besserer Test würde sich den Videorahmen ansehen und vielleicht versuchen, das Ziel eines Raods für ein selbstfahrendes Auto zu berechnen. Dies wäre fast die gleiche Laufzeit für C ++ oder Python. Der Fall ohne Druckmaschine zeigt, wie lange es dauert, Frame-Puffer zu laden, ohne echte Arbeit zu leisten. Das Laden von SO-Frames dominiert die Zeit. Wenn Sie echte Arbeit leisten, beträgt das Frame-Buffing nur 2% der Gesamtmenge, nicht 100% der Gesamtmenge.
user3150208
1
Obwohl ich derzeit keine Benchmarks habe, vermute ich, dass diese wichtiger sind als Sie vorhersagen. Wenn Sie beispielsweise in Python ausführen, dst = cv2.filter2D(img, -1, kernel)erstellt der Computer eine Kopie von imgund gibt sie als zurück dst. Wenn Sie nicht verwenden, imgkommt der GC und bereinigt das alte Bild. Mit der openCV-Python-API führt kein Weg daran vorbei. In C / C ++ können Sie problemlos einen statischen Bildpuffer mit der richtigen Größe erstellen, der nicht bei jedem Frame erstellt / zerstört wird. Die Zeit für Speicherzuweisungen und Freigabe ist nicht Null.
sdfgeoff
Wäre eine Erhöhung der Bildrate von 50 auf 65 nicht eine Verbesserung um 30% (statt um 25%)?
AmigoNico
6

Der Antwort von sdfgeoff fehlt die Tatsache, dass Sie Arrays in Python wiederverwenden können . Ordnen Sie sie vor und geben Sie sie weiter, und sie werden sich daran gewöhnen. Damit:

    image = numpy.zeros(shape=(height, width, 3), dtype=numpy.uint8)
    #....
    retval, _ = cv.VideoCapture.read(image)
Paul Rensing
quelle
Soweit ich das beurteilen kann, verwenden viele Funktionen (wie z. B. filter2D) keine Zielarrays als Parameter. Wenn Sie mich jedoch auf einige Dokumente verweisen können, die etwas anderes aussagen, werde ich meine Antwort gerne ändern. Es würde mich auch sehr interessieren, einen Leistungsvergleich mit dieser Technik zu sehen.
sdfgeoff
2
Ich bin mir nicht sicher, warum du das sagst. Hier ist doc für filter2d: docs.opencv.org/3.4/d4/d86/… Beachten Sie, dass der 4. Parameter in Python "dst" ist, das Zielarray. Ich habe nicht überall nachgesehen, aber der Standard ist, dass wenn es in C ++ ein Zielargument gibt, es dort in Python ist
Paul Rensing
Huh, du hast recht. Das hatte ich vorher nicht bemerkt. Ich denke, ich muss meinen Leistungsvergleich wiederholen
sdfgeoff
Können Sie näher erläutern, wie die Vorbelegung den Prozess beschleunigt? Ich habe diesen Teil nicht ganz verstanden, weil es für mich so aussieht, als würde ich den Platz nur an einem anderen Punkt
zuweisen
Die Einsparungen bei der Vorzuweisung würden sich aus der einmaligen Zuweisung des Arrays ergeben, dann aber aus dem Aufruf von VideoCapture.read () oder filter2d () innerhalb einer Schleife. Eine übliche Verwendung könnte darin bestehen, ein Bild von der Kamera zu initialisieren und dann für immer zu wiederholen, es zu lesen und zu verarbeiten. Durch die Vorbelegung würde bei jeder Iteration etwa eine Millisekunde eingespart.
Paul Rensing
4

Sie haben Recht, Python ist fast immer deutlich langsamer als C ++, da es einen Interpreter erfordert, was C ++ nicht tut. Dies erfordert jedoch eine starke Typisierung von C ++, wodurch eine viel geringere Fehlerquote verbleibt. Einige Leute ziehen es vor, strikt zu codieren, während andere Pythons inhärente Nachsicht genießen.

Wenn Sie einen vollständigen Diskurs über Python-Codierungsstile im Vergleich zu C ++ - Codierungsstilen wünschen, ist dies nicht der beste Ort. Versuchen Sie, einen Artikel zu finden.

BEARBEITEN: Da Python eine interpretierte Sprache ist, während C ++ im Allgemeinen zu Maschinencode kompiliert wird , können Sie mit C ++ Leistungsvorteile erzielen. In Bezug auf die Verwendung von OpenCV sind die OpenCV-Kernbibliotheken jedoch bereits zu Maschinencode kompiliert, sodass der Python-Wrapper um die OpenCV-Bibliothek kompilierten Code ausführt. Mit anderen Worten, wenn es darum geht, rechenintensive OpenCV-Algorithmen aus Python auszuführen, werden Sie keinen großen Leistungseinbruch feststellen, da diese bereits für die spezifische Architektur kompiliert wurden, mit der Sie arbeiten.

Callum McLean
quelle
1
Ja, Python wird interpretiert. Aber fast die gesamte Arbeit wird in openCV erledigt. Angenommen, es gibt eine Aufteilung von 20/80. 80% der in openCV geleisteten Arbeit wird in kompiliertem C geschrieben. Wir sprechen hier davon, wie schnell die verbleibenden 20% des Codes ausgeführt werden. Selbst wenn Python 4X langsamer ist, erhöht sich die Ausführungszeit nur um 30%. Viele OpenCV-Apps sind 5/95 aufgeteilt, so dass Python fast keinen Unterschied macht
user3150208