
Heute werden wir lernen, wie man den Straßenverkehr basierend auf Computer Vision und ohne umfangreiche Deep-Learning-Algorithmen zählt.
In diesem Tutorial verwenden wir nur Python und OpenCV mit der ziemlich einfachen Idee der Bewegungserkennung mithilfe des Hintergrund Subtraktionsalgorithmus.
Hier ist unser Plan:
- Verstehen Sie die Hauptidee von Hintergrund Subtraktionsalgorithmen, die für die Vordergrunderkennung verwendet werden.
- OpenCV-Bildfilter.
- Objekterkennung durch Konturen.
- Aufbau einer Verarbeitungspipeline zur weiteren Datenmanipulation.
Hintergrund Subtraktionsalgorithmen

Es gibt viele verschiedene Algorithmen für die Hintergrundsubtraktion, aber die Hauptidee davon ist sehr einfach.
Nehmen wir an, Sie haben ein Video von Ihrem Zimmer und in einigen Bildern dieses Videos sind keine Menschen und Haustiere zu sehen. Im Grunde genommen ist es statisch. Nennen wir es background_layer. Um Objekte zu erhalten, die sich auf dem Video bewegen, müssen wir nur:
foreground_objects = current_frame - background_layer
In einigen Fällen können wir jedoch keinen statischen Rahmen erhalten, da sich die Beleuchtung ändern kann oder einige Objekte von jemandem bewegt werden oder immer eine Bewegung vorhanden ist usw. In solchen Fällen speichern wir eine bestimmte Anzahl von Rahmen und versuchen herauszufinden, welches der Pixel sind für die meisten von ihnen gleich, dann werden diese Pixel Teil von background_layer. Unterschied im Allgemeinen, wie wir diese Hintergrundschicht erhalten, und zusätzliche Filterung, die wir verwenden, um die Auswahl genauer zu machen.
In dieser Lektion verwenden wir den MOG-Algorithmus für die Hintergrundsubtraktion. Nach der Verarbeitung sieht er folgendermaßen aus:


Filtern
Für unseren Fall benötigen wir folgende Filter: Threshold, Erode, Dilate, Opening, Closing. Bitte gehen Sie über Links und lesen Sie über jeden von ihnen und schauen Sie, wie sie funktionieren (um nicht zu kopieren / einfügen).
Jetzt werden wir sie verwenden, um etwas Rauschen auf dem Vordergrund zu entfernen. Zuerst verwenden wir Closing, um Lücken in Bereichen zu entfernen, dann Opening, um 1–2 px Punkte zu entfernen, und danach Dilate, um das Objekt mutiger zu machen.

Objekterkennung durch Konturen
Zu diesem Zweck verwenden wir die Standardmethode cv2.findContours mit folgenden Parametern:
cv2.CV_RETR_EXTERNAL — get only outer contours. cv2.CV_CHAIN_APPROX_TC89_L1 - use Teh-Chin chain approximation algorithm (faster)

Gebäudeverarbeitungspipeline
Sie müssen verstehen, dass es in ML und CV keinen magischen Algorithmus gibt, der insgesamt erstellt wird, selbst wenn wir uns vorstellen, dass ein solcher Algorithmus existiert, würden wir ihn dennoch nicht verwenden, da er im Maßstab nicht effektiv wäre. Zum Beispiel hat Netflix vor einigen Jahren einen Wettbewerb mit dem Preis von 3 Millionen Dollar für den besten Algorithmus für Filmempfehlungen ins Leben gerufen. Und eines der Teams hat ein solches Problem geschaffen, dass es einfach nicht in großem Maßstab funktionieren konnte und daher für das Unternehmen nutzlos war. Trotzdem hat Netflix 1 Million an sie gezahlt 🙂
Jetzt werden wir eine einfache Verarbeitungspipeline erstellen, die nicht nur aus praktischen Gründen skaliert werden soll, sondern auch die gleiche Idee hat.
Als Eingabekonstruktor wird eine Liste der Prozessoren verwendet, die der Reihe nach ausgeführt werden. Jeder Prozessor, der Teil des Auftrags ist.
Wir haben bereits die Countour Detection-Klasse, müssen sie nur leicht ändern, um den Kontext zu verwenden
Erstellen wir nun einen Prozessor, der erkannte Objekte in verschiedenen Frames verknüpft, Pfade erstellt und Fahrzeuge zählt, die die Ausgangszone erreicht haben.
Diese Klasse ist etwas kompliziert, also gehen wir sie nach Teilen durch.

Diese grüne Maske auf dem Bild ist die Ausgangszone, in der wir unsere Fahrzeuge zählen. Zum Beispiel zählen wir nur Pfade mit einer Länge von mehr als 3 Punkten (um etwas Rauschen zu entfernen) und den vierten in der grünen Zone. Wir verwenden Masken, da viele Operationen effektiver und einfacher sind als die Verwendung von Vektor-Algorithmen.
Verwenden Sie einfach die Operation “Binär und”, um diesen Punkt in der Umgebung zu überprüfen, und das ist alles. Und so stellen wir es ein:

Verknüpfen wir nun Punkte in Pfaden in Zeile 55
Im ersten Frame. Wir fügen einfach alle Punkte als neue Pfade hinzu.
Wenn len (path) == 1 ist, versuchen wir für jeden Pfad im Cache, den Punkt (Schwerpunkt) von neu erkannten Objekten zu finden, die den kleinsten euklidischen Abstand zum letzten Punkt des Pfads haben.
Wenn len(path)> 1 ist, sagen wir mit den letzten beiden Punkten im Pfad einen neuen Punkt auf derselben Linie voraus und ermitteln den minimalen Abstand zwischen ihm und dem aktuellen Punkt.
Der Punkt mit minimalem Abstand wird am Ende des aktuellen Pfads hinzugefügt und aus der Liste entfernt.
Wenn danach noch einige Punkte übrig sind, fügen wir sie als neue Pfade hinzu.
Außerdem begrenzen wir die Anzahl der Punkte im Pfad in Zeile 101
Jetzt werden wir versuchen, Fahrzeuge zu zählen, die in die Ausgangszone einfahren. Dazu nehmen wir nur 2 letzte Punkte im Pfad und überprüfen den letzten in der Ausgangszone und den vorherigen nicht. Außerdem überprüfen wir, ob len (Pfad) größer als der Grenzwert sein sollte. Der Teil nach sonst verhindert, dass neue Punkte mit den Punkten in der Ausgangszone rückverknüpft werden.
Die letzten beiden Prozessoren sind CSV-Writer zum Erstellen von CSV-Berichtsdateien und Visualisierungen zum Debuggen und für schöne Bilder / Videos.
CSV Writer speichert Daten nach Zeit, da wir sie für weitere Analysen benötigen. Also benutze ich diese Formel, um dem Unixtimestamp zusätzliches Frame-Timing hinzuzufügen:
time = ((self.start_time + int(frame_number / self.fps)) * 100 + int(100.0 / self.fps) * (frame_number % self.fps))
so with start time=1 000 000 000 and fps=10 i will get results like thisframe 1 = 1 000 000 000 010frame 1 = 1 000 000 000 020…
Nachdem Sie den vollständigen CSV-Bericht erhalten haben, können Sie diese Daten nach Ihren Wünschen zusammenfassen.
Conclusion
Wie Sie sehen, war es nicht so schwer, wie viele Leute denken.
Wenn Sie das Skript ausführen, werden Sie feststellen, dass diese Lösung nicht ideal ist und ein Problem mit überlappenden Vordergrundobjekten besteht. Außerdem gibt es keine Fahrzeugklassifizierung nach Typen (die Sie definitiv für echte Analysen benötigen). Bei guter Kameraposition (über der Straße) ergibt sich jedoch eine ziemlich gute Genauigkeit. Und das zeigt uns, dass selbst kleine und einfache Algorithmen, die richtig eingesetzt werden, gute Ergebnisse liefern können.