Ich arbeite gerade an einem Augmented-Reality-Spiel. Der Controller, den das Spiel verwendet (ich spreche hier über das physische Eingabegerät), ist ein monofarbiges, rechteckiges Papierstück. Ich muss die Position, Drehung und Größe dieses Rechtecks im Aufnahmestrom der Kamera erkennen. Die Erkennung sollte für die Skalierung invariant und für die Drehung entlang der X- und Y-Achse invariant sein.
Die Skalierungsinvarianz wird benötigt, falls der Benutzer das Papier weg oder in Richtung der Kamera bewegt. Ich muss den Abstand des Rechtecks nicht kennen, damit die Skaleninvarianz in Größeninvarianz umwandelt.
Die Rotationsinvarianz wird benötigt, wenn der Benutzer das Rechteck entlang seiner lokalen X- und / oder Y-Achse neigt. Eine solche Drehung verändert die Form des Papiers von Rechteck zu Trapez. In diesem Fall kann die objektorientierte Begrenzungsbox verwendet werden, um die Größe des Papiers zu messen.
Zu Beginn gibt es einen Kalibrierungsschritt. Ein Fenster zeigt den Kamera-Feed und der Benutzer muss auf das Rechteck klicken. Beim Klicken wird die Farbe des Pixels, auf das die Maus zeigt, als Referenzfarbe verwendet. Die Rahmen werden in einen HSV-Farbraum umgewandelt, um die Farbunterscheidung zu verbessern. Ich habe 6 Schieberegler, die die oberen und unteren Schwellenwerte für jeden Kanal einstellen. Diese Schwellenwerte werden verwendet, um das Bild zu digitalisieren (mit der Funktion inRange
von opencv).
Danach erodiere und dehne ich das Binärbild, um Rauschen zu entfernen und Nerby-Chunks zu vereinen (mit den Funktionen erode
und dilate
von opencv).
Der nächste Schritt ist das Auffinden von Konturen (mit der Funktion findContours
von opencv) im Binärbild. Diese Konturen werden verwendet, um die kleinsten orientierten Rechtecke zu erkennen (mit Hilfe der Funktion minAreaRect
von opencv). Als Endergebnis verwende ich das Rechteck mit der größten Fläche.
Ein kurzer Abschluss des Verfahrens:
Wie Sie vielleicht bemerkt haben, mache ich keinen Vorteil aus dem Wissen über die tatsächliche Form des Papiers, einfach weil ich nicht weiß, wie man diese Informationen richtig benutzt.
Ich habe auch über die Tracking-Algorithmen von opencv nachgedacht. Aber es gab drei Gründe, die mich daran hinderten, sie zu benutzen:
Hier ist ein - relativ - guter Fang (Binärbild nach erodieren und erweitern)
Wie kann ich die Erkennung im Allgemeinen verbessern und insbesondere widerstandsfähiger gegenüber Lichtveränderungen sein?
Hier sind einige rohe Bilder zum Testen.
Können Sie nicht dickeres Material verwenden?
Ja, ich kann und ich schon (leider kann ich im Moment nicht auf diese Stücke zugreifen). Das Problem bleibt jedoch bestehen. Auch wenn ich Material wie Karton verwende. Es ist nicht so leicht wie Papier gebogen, aber man kann es immer noch biegen.
Wie erhalten Sie die Größe, Drehung und Position des Rechtecks?
Die Funktion minAreaRect
von opencv gibt ein Objekt RotatedRect
zurück. Dieses Objekt enthält alle Daten, die ich brauche.
Hinweis
Da das Rechteck einfarbig ist, besteht keine Möglichkeit, zwischen oben und unten oder links und rechts zu unterscheiden. Dies bedeutet, dass die Rotation immer im Bereich [0, 180]
liegt, was für meine Zwecke völlig in Ordnung ist. Das Verhältnis der beiden Seiten des Rect ist immer w:h > 2:1
. Wenn das Rechteck ein Quadrat wäre, würde sich der Bereich von roation in [0, 90]
ändern, aber dies kann hier als irrelevant angesehen werden.
Wie in den Kommentaren vorgeschlagen, werde ich versuchen, Histogramm-Entzerrung durchzuführen, um Helligkeitsprobleme zu reduzieren und einen Blick auf ORB, SURF und SIFT zu werfen.
Ich werde den Fortschritt aktualisieren.
Ich weiß, dass es eine Weile her ist, seit ich die Frage gestellt habe. Ich habe kürzlich das Thema weiter verfolgt und mein Problem gelöst (allerdings nicht durch die Rechteckerkennung).
cv::equalizeHist
, cv::aruco::detectMarkers
, Es stellte sich heraus, dass die Marker-Erkennung sehr robust gegenüber Veränderungen der Beleuchtung und unterschiedlichen Betrachtungswinkeln ist, was es mir erlaubt, alle Kalibrierungsschritte zu überspringen.
Ich habe zwei Marker auf jedem Controller platziert, um die Erkennungsrobustheit noch mehr zu erhöhen. Beide Marker müssen nur einmal detektiert werden (um zu messen, wie sie korrelieren). Danach ist es ausreichend, nur einen Marker pro Controller zu finden, da der andere aus der zuvor berechneten Korrelation extrapoliert werden kann.
Hier ist ein Erkennungsergebnis in einer hellen Umgebung:
in einer dunkleren Umgebung:
und beim Ausblenden eines der Marker (der blaue Punkt zeigt die extrapolierte Markerposition an):
Die anfängliche Formerkennung, die ich implementiert habe, hat nicht gut funktioniert. Es war sehr anfällig für Änderungen der Beleuchtung. Außerdem war ein erster Kalibrierungsschritt erforderlich.
Nach dem Shape-Detection-Ansatz habe ich SIFT und ORB in Kombination mit Brute Force und Knn Matcher ausprobiert, um Features in den Frames zu extrahieren und zu lokalisieren. Es stellte sich heraus, dass monochrome Objekte nicht viele Schlüsselpunkte bieten (was für eine Überraschung). Die Performance von SIFT war trotzdem schrecklich (ca. 10 fps @ 540p). Ich zeichnete einige Linien und andere Formen auf dem Controller, was dazu führte, dass mehr Keypoints zur Verfügung standen. Dies führte jedoch nicht zu großen Verbesserungen.
Der H-Kanal im HSV-Raum ist der Farbton, und er ist nicht empfindlich gegenüber Lichtveränderungen. Roter Bereich in etwa [150.180].
Basierend auf den genannten Informationen mache ich folgende Arbeiten.
PS. Ich kann das hochgeladene Bild aufgrund des NETZWERKS nicht in der Dropbox abrufen. Also verwende ich einfach die rechte Seite deines zweiten Bildes als Eingabe.
%Vor%Nun erhalten wir das Ergebnis als (h, normiert, geöffnet):
Finde dann Konturen und filtere sie.
%Vor%Das Ergebnis ist wie folgt:
%Vor%Da sich das blaue Rechteck im Quellbild befindet, ist die Karte in zwei Seiten aufgeteilt. Aber ein sauberes Bild wird kein Problem haben.
Tags und Links c++ opencv image-processing object-detection