In meinem Code erhalte ich Frames von einer Kamera mit einem Zeiger auf ein nicht verwaltetes Objekt, mache einige Berechnungen darauf und mache es dann in einem Picturebox-Steuerelement sichtbar.
Bevor ich in dieser Anwendung mit allen Details weiter gehe, möchte ich sicher sein, dass der Basiscode für diesen Prozess gut ist.
Insbesondere möchte ich:
- halten Sie die Ausführungszeit minimal und vermeiden Sie unnötige Operationen, wie z
Kopieren von mehr Bildern als nötig. Ich möchte nur essentiell bleiben
Operationen
- zu verstehen, ob eine Verzögerung des Berechnungsprozesses für jeden Frame nachteilige Auswirkungen auf die Art und Weise hat, in der Bilder gezeigt werden (d. h. wenn sie nicht gedruckt wird, was ich erwarte) oder ein Bild übersprungen wird
- Verhindern Sie schwerwiegendere Fehler, beispielsweise durch Speicher- oder Thread-Management oder durch Bildanzeige.
Zu diesem Zweck habe ich ein paar experimentelle Codezeilen eingerichtet (siehe unten), aber ich kann die Ergebnisse dessen, was ich gefunden habe, nicht erklären. Wenn Sie die ausführbaren Dateien von OpenCv haben, können Sie es selbst ausprobieren.
Ergebnisse [Dual Core 2 Duo T6600 2,2 GHz]:
A . puffercopy = false; copyBitmap = false; refresh = false;
Dies ist die einfachere Konfiguration. Jeder Rahmen wird der Reihe nach abgerufen, Operationen werden durchgeführt (in der Realität basieren sie auf demselben Rahmen, hier nur Berechnungen), dann wird das Ergebnis der Berechnungen über dem Bild gedruckt und schließlich wird es auf einer Bildbox angezeigt br>
OpenCv Dokumentation sagt:
OpenCV 1.x Funktionen cvRetrieveFrame und cv.RetrieveFrame Rückbild gespeichert in der Videoaufnahmestruktur. Es ist nicht erlaubt Ändern oder veröffentlichen Sie das Bild! Sie können den Rahmen mit kopieren cvCloneImage () und dann machen Sie was Sie wollen mit der Kopie.
Aber das hindert uns nicht daran, Experimente zu machen.
Wenn die Berechnung nicht intensiv ist (niedrige Anzahl von Iterationen, N), ist alles in Ordnung und die Tatsache, dass wir den Bildpuffer manipulieren, der vom Unmanaged Frame Retriever stammt, stellt hier kein Problem dar.
Der Grund ist, dass sie wahrscheinlich raten, den Puffer unberührt zu belassen, falls die Leute ihre Struktur (nicht ihre Werte) verändern oder Operationen asynchron ausführen würden, ohne es zu merken. Jetzt rufen wir Frames ab und ändern ihren Inhalt der Reihe nach.
Wenn N erhöht wird (N = 1000000 oder mehr), wenn die Anzahl der Bilder pro Sekunde nicht hoch ist, zum Beispiel mit künstlichem Licht und niedriger Belichtung, scheint alles in Ordnung zu sein, aber nach einer Weile ist das Video verzögert und die Grafik ist darauf eingeprägt blinken. Bei einer höheren Bildrate erscheint das Blinken von Anfang an, auch wenn das Video noch flüssig ist.
Liegt das daran, dass der Mechanismus zum Anzeigen von Bildern auf dem Steuerelement (oder Aktualisieren oder was auch immer) irgendwie asynchron ist und wenn die Bildbox ihren Datenpuffer abruft, wird sie in der Zwischenzeit von der Kamera modifiziert, wobei die Grafik gelöscht wird
Oder gibt es einen anderen Grund?
Warum würde das Bild auf diese Weise verzögert werden, d. H. Ich würde erwarten, dass die Verzögerung aufgrund von Berechnungen nur die von der Kamera empfangenen Rahmen überspringt, wenn die Berechnung noch nicht erfolgt ist, und de facto nur die Bildrate verringert; oder alternativ, dass alle Rahmen empfangen werden und die Verzögerung aufgrund von Berechnungen das System dazu bringt, Bilder zu verarbeiten, die Minuten zuvor erhalten wurden, weil die Warteschlange von zu verarbeitenden Bildern mit der Zeit ansteigt
Stattdessen scheint das beobachtete Verhalten hybrid zwischen den beiden zu sein: Es gibt eine Verzögerung von ein paar Sekunden, aber diese scheint sich nicht viel zu erhöhen, während der Erfassungsprozess weitergeht.
B . Pufferkopie = Wahr; copyBitmap = false; refresh = false;
Hier mache ich eine tiefe Kopie des Puffers in einen zweiten Puffer, nach dem Rat der OpenCv-Dokumentation.
Nichts verändert sich. Der zweite Puffer ändert seine Adresse im Speicher während des Laufs nicht.
C . puffercopy = false; copyBitmap = wahr; refresh = false;
Jetzt wird die (tiefe) Kopie der Bitmap jedesmal einem neuen Speicherplatz zugeordnet
Der Blink-Effekt ist weg, aber der Rückstand bleibt nach einer gewissen Zeit bestehen.
D . puffercopy = false; copyBitmap = false; refresh = true;
Wie vorher.
Bitte helfen Sie mir, diese Ergebnisse zu erklären!
Wenn ich so ehrlich bin, ist es ein wenig mühsam, alle Details Ihrer Fragen zu verstehen, aber lassen Sie mich ein paar Punkte machen, die Ihnen helfen, Ihre Ergebnisse zu analysieren.
Im Fall A sagen Sie, dass Sie Berechnungen direkt im Puffer durchführen. Die Dokumentation besagt, dass Sie dies nicht tun sollten. Wenn Sie dies tun, können Sie mit undefinierten Ergebnissen rechnen. OpenCV geht davon aus, dass Sie es nicht anfassen, also könnte es Dinge tun, die plötzlich diesen Teil des Speichers löschen, eine andere App verarbeiten lassen, usw. Es könnte so aussehen, als ob es funktioniert, aber Sie können es nie sicher wissen, also nicht tu es * schlägt dein Handgelenk * Insbesondere wenn deine Verarbeitung viel Zeit in Anspruch nimmt, überschreibt die Kamera möglicherweise den Puffer, während du gerade dabei bist, ihn zu verarbeiten.
Sie sollten den Puffer kopieren, bevor Sie etwas tun. Dies wird Ihnen ein Stück Erinnerung geben, das Sie mit Ihrem Wunsch tun können. Sie können ein Bitmap erstellen, das auf diesen Speicher verweist, und den Speicher manuell freigeben, wenn Sie ihn nicht mehr benötigen.
Wenn Ihre Verarbeitungsrate (pro Sekunde verarbeitete Bilder) geringer ist als die Anzahl der Bilder, die pro Sekunde von der Kamera aufgenommen werden, müssen Sie damit rechnen, dass einige Bilder verworfen werden. Wenn Sie eine Live-Ansicht der verarbeiteten Bilder anzeigen möchten, wird es verzögert und es gibt keinen einfachen Weg darum herum. Wenn es entscheidend ist, dass Ihre Anwendung ein flüssiges Video verarbeitet (z. B. wenn Sie ein Objekt verfolgen), sollten Sie das Video auf Festplatte speichern, damit Sie nicht in Echtzeit arbeiten müssen. Sie können Multithreading auch so betrachten, dass mehrere Frames gleichzeitig verarbeitet werden, aber die Live-Ansicht würde eine Latenz haben.
Gibt es übrigens einen besonderen Grund, warum Sie EmguCV nicht verwenden? Es hat Abstraktionen für die Kamera und ein System, das ein Ereignis auslöst, wenn die Kamera ein neues Bild aufgenommen hat. Auf diese Weise müssen Sie cvQueryFrame
nicht kontinuierlich für einen Hintergrundthread aufrufen.
Ich denke, dass Sie immer noch ein Problem mit Ihrer UnmanageCopy-Methode haben, indem Sie das Bild nur beim ersten Aufruf klonen und anschließend kopieren. Ich glaube, dass Sie eine cvCloneImage (f) jede Zeit machen müssen, da die Kopie nur eine seichte Kopie ausführt, keine tiefe Kopie, wie Sie zu denken scheinen.
Tags und Links c# opencv camera bitmap picturebox