
Teilen Sie:
Roberto is a Full Stack Engineer on the OpenTok Client SDK team. He loves learning new bits of Android, iOS, Linux, Windows, you name it! In his free time, he is very passionate about programming languages, computer graphics, and video game development for current and old platforms like ZX Spectrum and Commodore 64.
Benutzerdefinierte AR-Filter mit Vonage Video API und DeepAR erstellen
Lesedauer: 11 Minuten
Die Zukunft der Videotelefonie liegt in der künstlichen Intelligenz. Sie wird uns helfen, das (virtuelle) Eis zu brechen, uns bei der Navigation in neuen Anwendungsfällen für interaktives Video zu unterstützen, wie z. B. beim Einkaufen und bei der Fernbetreuung, und völlig neue Erfahrungen zu schaffen. Die zukünftigen Erfinder dieser Erfahrungen "sitzen" wahrscheinlich in einem virtuellen Klassenzimmer und werden von virtuellem Video geprägt wie keine Generation vor ihnen.
Als Vonage Video API Entwickler können Sie unsere Video API mit dem DeepAR SDK integrieren, um das Video-Erlebnis Ihrer Nutzer zu verbessern.
Sie können die Videoanrufe professioneller gestalten, indem Sie den Hintergrund abstrahieren, die Objekte ersetzen, unscharf machen oder verpixeln, oder indem Sie die Beleuchtung und subtile Hauttoneffekte verbessern, um das Nutzererlebnis zu verbessern.
Oder haben Sie noch mehr Spaß mit einer großen Auswahl an animierten Filtern von DeepAR.
Augmented Reality filters in action
Augmented Reality im Alltag
Die Wahrscheinlichkeit ist groß, dass Sie schon einmal an einem Video-Meeting teilgenommen haben, sei es am Arbeitsplatz, bei einem Arztbesuch oder bei einem Familientreffen.
In diesem neuen Paradigma der Video-Konferenzen gibt es viele neue Applications, die die Videokommunikation aufwerten. Sehen wir uns einige gängige Möglichkeiten an, wie Augmentierungen eingesetzt werden, um die Benutzererfahrung zu verbessern und uns dabei zu helfen, bei unseren Ferninteraktionen effektiver zu sein:
Hintergrund Abstraktion
Eine der Verbesserungen für die Videokommunikation ist die Abstraktion von allem, was sich im Hintergrund des Benutzers befindet, durch einfaches Weichzeichnen, Verpixeln oder Ersetzen des Hintergrunds. Die Vorteile umfassen:
Aktivierung des Anruferschutzes
Erleichterung der Zuschaueraktivität durch Beseitigung von Ablenkungen
Schaffung von Markenerlebnissen
Lautsprecher-Ergänzungen
Ein weiteres Beispiel, um Videoanrufe mit AR auf die nächste Stufe zu bringen, ist die Anwendung von Filtern auf die Vordergrundlautsprecher. Durch die Implementierung dieser Art von Filtern können Ihre Benutzer:
Entspannen Sie sich beim Videoanruf mit Licht-, Hautton- und Schönheitsfiltern
Freude und Unterhaltung mit lustigen Animojis
Interaktion in Echtzeit mit 3D-Objekten und sogar virtueller Gesichtsbemalung
A dog face AR filter in use
Die Flexibilität der Vonage Video API macht dies möglich, wenn sie mit AR-Partnern wie DeepAR integriert wird. In diesem Blogbeitrag zeigen wir, wie die oben genannten Anwendungsfälle mit einer Kombination der beiden APIs möglich sind.
Was ist DeepAR?
DeepAR ist eine für Mobilgeräte und HTML5 optimierte AR-Engine für Augmented Reality, Gesichtsfilter, Hintergrundsegmentierung, Make-up, Beauty-Filter und Animoji.
Die DeepAR SDK ermöglicht Entwicklern den Zugriff auf die DeepAR-Engine, verwaltet die geräteübergreifende Unterstützung und enthält ein DeepAR-Studio-Tool, das Ihnen bei der Erstellung der AR-Assets hilft.
DeepAR verwenden
Um das DeepAR SDK-Framework zu Ihrer iOS-Anwendung hinzuzufügen, müssen Sie die Zip-Datei von deren Website herunterladen, https://developer.deepar.ai/. Sobald Sie die Zip-Datei haben, müssen Sie sie entpacken und die Framework-Datei in Ihr Xcode-Projekt ziehen.

Vergessen Sie nicht, die embed des Frameworks auf "Einbetten & Signieren" zu setzen, sonst findet die Anwendung die Bibliothek möglicherweise nicht zur Laufzeit.
Sobald Sie diese Einstellung vorgenommen haben, gehen Sie zum nächsten Schritt https://developer.deepar.ai/ und ein Projekt zu erstellen, um den App-Schlüssel zu erhalten, den Sie später benötigen werden.
Hinzufügen von Lions zum aufgezeichneten Videoeingang
In diesem Blogbeitrag werden wir eine UIView erstellen, in der Sie den Inhalt Ihrer Frontkamera anzeigen und Ihr Gesicht, wenn es erkannt wird, mit einem coolen Löwen versehen wird.
Wenn Sie den gesamten Code für diesen Beitrag an einem Ort sehen möchten, können Sie ihn auf dem DeepAR GitHub.
Im Code müssen Sie mit zwei Klassen umgehen; eine ist der CameraController des DeepAR SDK. Diese Klasse ist für den Zugriff auf die Gerätekamera und das Abrufen von Bildern zuständig. Sobald das Video-Feed vorliegt, sendet es diese an die ARView-Instanz, die andere Klasse, die Sie instanziieren müssen.
ARView ist dafür verantwortlich, den Inhalt der Kamera mit den angewandten AR-Filtern anzuzeigen. ARView ist ein reguläres UIView-Kind, daher müssen Sie es zu einer beliebigen übergeordneten Ansicht innerhalb der Ansichtshierarchie Ihrer App hinzufügen.
Mit diesem Wissen könnte der Code wie folgt aussehen:
let deepARCameraController = CameraController()
let deepARView = ARView(frame: UIScreen.main.bounds)
deepARView.setLicenseKey(deepARLicense)
deepARView.delegate = self
deepARCameraController.arview = deepARView
parentView.insertSubview(deepARView, at: 0)
deepARView.initialize()
deepARCameraController?.startCamera()Im obigen Code erstellen Sie zuerst den CameraController, dann erstellen Sie die ARView-Instanz, indem Sie sie als Rahmen für den Vollbildschirm verwenden, da wir sie auf dem gesamten Bildschirm anzeigen werden.
Bitte beachten Sie, dass wir die Zuweisung self als ARView-Delegat zuweisen, also müssen Sie das ARViewDelegate-Protokoll implementieren/konform sein. Wir werden es später brauchen.
Sobald Sie beide Instanzen haben, weisen Sie die ARView-Eigenschaft der CameraController-Instanz unserer Ansicht zu und fügen sie in unsere parentView.
Das Einzige, was noch bleibt, ist die Initialisierung der Ansicht und die Aufnahme von Video von der Kamera durch den Aufruf von startCamera.
Wenn Sie Ihren Code ausführen, werden Sie feststellen, dass sich kein 🦁 über Ihrem Gesicht befindet, weil wir den Effekt noch nicht aktiviert haben.
Um dies zu tun, müssen Sie implementieren didInitializeeine Methode des ARViewDelegate, die wir aufrufen, sobald die Initialisierung des ARView abgeschlossen ist, dann können wir den Löwenfilter aktivieren.
func didInitialize() {
deepARView.switchEffect(withSlot: "effect", path: Bundle.main.path(forResource: "lion", ofType: ""))
}Damit das funktioniert, müssen Sie eine Datei namens "lion" zu Ihrem Projekt hinzufügen. Sie finden sie in dem kostenlosen Filterpaket, das Sie unter https://developer.deepar.ai/downloads. Sobald Sie es heruntergeladen haben, müssen Sie die Datei "lion" in den Stammordner des Xcode-Projekts ziehen und sicherstellen, dass sie als Ziel Ihre Anwendung hat, damit sie mit ihr gebündelt wird.
XCode
Wenn Sie die Anwendung an diesem Punkt starten, sollten Sie Ihr Gesicht mit einem coolen Löwen-Overlay sehen, das alle Ihre Bewegungen und Gesten verfolgt.
Lion
OpenTok und benutzerdefinierte Video-Treiber
Die meisten Entwickler interagieren mit der Vonage Video API über das OpenTok SDK. Eine der interessantesten Funktionen des SDK ist die Möglichkeit, einen eigenen Videotreiber zu erstellen, um jede Art von Videoinhalt an die OpenTok-Sitzung zu senden, mit der Ihr Publisher verbunden ist.
Video-Treiber lassen sich in zwei verschiedene Bereiche unterteilen:
Auf der einen Seite haben wir den Video-Capturer, der, wie der Name schon sagt, das Video von einer beliebigen Quelle aufnehmen (oder irgendwie selbst produzieren) und das SDK mit den zu sendenden Videobildern füttern muss.
Auf der anderen Seite haben wir den Video-Renderer, der, wie Sie wahrscheinlich schon erraten haben, für das Rendern der Videobilder zuständig ist, die über einen Abonnenten aus der Ferne durch eine OpenTok-Sitzung kommen.
Wenn Sie das OpenTok SDK verwendet haben, werden Sie wahrscheinlich bemerkt haben, dass Sie in einem typischen Szenario nicht mit diesen Klassen umgehen müssen. Das liegt daran, dass das OpenTok SDK mit Standard-Capturern und -Rendern ausgeliefert wird, die Videos von der Standard-Systemkamera aufnehmen und die entfernten Videobilder mit der Grafiktechnologie der jeweiligen Plattform rendern, unabhängig davon, ob es sich um Metal, OpenGL oder DirectX handelt.
Video-Treiber sind sehr leistungsfähig. Sie können einen Video-Treiber erstellen, um beliebige Videoinhalte zu senden. Sie können zum Beispiel die Ausgabe einer beliebigen Spiele-Engine aufzeichnen und diese Videoframes an das OpenTok SDK senden, um den Inhalt Ihres Spiels an jeden Teilnehmer einer OpenTok-Sitzung zu streamen. Sie können auch beliebige Rendering-Filter wie S/W oder Kantenerkennung anwenden, so dass jeder Teilnehmer anders aussieht.
Erstellen eines benutzerdefinierten OpenTok Video Capturers
Obwohl es so aussieht, als ob die Erstellung eines benutzerdefinierten Video-Capturers eine komplizierte Aufgabe ist, ist es wahrscheinlich einfacher, als Sie es erwarten können.
Sie müssen nur eine Schnittstelle implementieren, eine Klasse erweitern oder ein Protokoll anpassen, je nach Sprache und Plattform Ihrer Wahl. Wie Sie oben gesehen haben, verwenden wir in den Quellcodebeispielen für diesen Beitrag swift und iOS.
In dieser Klasse müssen Sie einige grundlegende Methoden implementieren oder außer Kraft setzen, die den Lebenszyklus des Erfassers steuern. Sie müssen folgende Methoden implementieren init, startCapture, stopCapture, isCaptureStarted Methoden sowie eine Methode zur Festlegung der Einstellungen des Capturers, die darin besteht, die Höhe, Breite, Bildrate und das Pixelformat der Videobilder anzugeben, die der Capturer senden wird.
Nachdem diese Methoden implementiert worden sind, müssen Sie den Capturer mit Bildern füttern. Je nach Plattform kann dies unterschiedlich sein, aber in der Regel müssen Sie nur eine Methode mit den Videobilddaten aufrufen.
Schauen wir uns an, wie eine erste Implementierung aussehen könnte,
class DeepARVideoCapturer: NSObject, OTVideoCapture {
fileprivate var captureStarted = false
var videoCaptureConsumer: OTVideoCaptureConsumer?
func initCapture() {
}
func releaseCapture() {
}
func start() -> Int32 {
captureStarted = true
return 0
}
func stop() -> Int32 {
captureStarted = false
return 0
}
func isCaptureStarted() -> Bool {
return captureStarted
}
func captureSettings(_ videoFormat: OTVideoFormat) -> Int32 {
return 0
}
}
Oben sehen Sie den erforderlichen Code für einen benutzerdefinierten Capturer. Wie Sie sehen können, müssen Sie das OTVideoCapture-Protokoll implementieren, das über Methoden verfügt, die aufgerufen werden, wenn der Video-Capturer initialisiert, gestartet oder gestoppt werden muss. Es ist sehr gebräuchlich, ein internes Flag zu haben, um zu wissen, wann die Aufzeichnung begonnen hat, und das ist es, was wir in dieser grundlegenden Implementierung tun. Wir werden dieses Flag in den Methoden start und stop aktualisieren.
Sie haben sicher bemerkt, dass diese Klasse von Object erbt. NSObjecterbt, da dies in Swift-Klassen, die nur von Object erben, nicht sehr üblich ist. Der Grund dafür ist, dass das OTVideoCapture-Protokoll vom NSObject-Protokoll erbt, vor allem weil die Codebasis von OpenTok SDK größtenteils aus Objective-C besteht und in dieser Sprache alle Dinge von NSObject erben.
Sobald Sie eine solche Klasse haben, müssen Sie dem Herausgeber mitteilen, dass er statt des Standard-Capturers unsere Klasse verwenden soll. Der Code hierfür sieht wie folgt aus:
let settings = OTPublisherSettings()
settings.name = UIDevice.current.name
settings.videoCapture = DeepARVideoCapturer()
otPublisher = OTPublisher(delegate: self, settings: settings)Der Capturer, den wir im obigen Codeschnipsel erstellen, sendet noch nichts, da er nur Initialisierungscode enthält. Wenn Sie versuchen, das zu verwenden, was wir jetzt haben, sollte es funktionieren, aber Sie werden nur schwarze Bilder veröffentlichen. Der nächste Schritt ist zu wissen, wie man Bilder sendet.
Wir werden diesen Teil jedoch verzögern, bis wir einige Frames zu senden haben, und diese Frames werden die Ausgabe unserer DeepAR-Ansicht sein.
Integration von DeepAR und OpenTok
Wir haben den letzten Teil des Blogbeitrags erreicht. Im ersten Teil haben wir gesehen, wie man einen einfachen Video-Capturer baut, im zweiten Teil haben wir gesehen, wie man DeepARs ARView mit einem AR-Filter eines Löwen, der das Gesicht ersetzt, verwendet. Das Einzige, was in unserem benutzerdefinierten Video-Capturer noch fehlte, war das Senden von Video-Frames, also sieht es so aus, als hätten wir alles für den letzten Schritt vorbereitet.
In diesem Schritt werden wir beide Welten miteinander verkabeln; wir müssen einige Dinge tun. Erstens müssen wir die von ARView produzierten Videobilder erhalten, und zweitens müssen wir sie mit dem von uns gebauten Video-Capturer senden.
Der erste Schritt besteht darin, ein Bild von der ARView zu erhalten. Dies kann sehr schnell geschehen, indem der ARView-Delegat oder -Listener eingestellt wird. Der Delegat oder die Klasse, die die Listener-Schnittstelle implementiert, erhält einen Aufruf seiner Methode, wenn ein Bild verfügbar ist. Sobald dies geschieht, müssen wir dieses Bild an die OpenTok-Welt senden.
Wenn Sie sich erinnern, haben wir bereits den Delegaten von ARView gesetzt, und in seiner didInitialize Methode haben wir den Löwenfilter aktiviert. Jetzt müssen wir ARView mitteilen, dass wir seine Videobilder abrufen wollen. Dies geschieht mit dem unten stehenden Code:
func didInitialize() {
deepARView.switchEffect(withSlot: "effect", path: Bundle.main.path(forResource: "lion", ofType: ""))
deepARView.startFrameOutput(withOutputWidth: 640, outputHeight: 0, subframe: CGRect(x: 0, y: 0, width: 1, height: 1))
}Die erste Zeile ist das, was wir im ersten Teil des Blogeintrags haben, und mit der zweiten Zeile fordern wir ARView auf, eine andere Delegatenmethode mit dem Inhalt der AR View aufzurufen.
Danach müssen wir die Methode frameAvailable Methode implementieren, die jedes Mal aufgerufen wird, wenn ein Videobild fertig ist. In dieser Methode werden wir den Inhalt an den OpenTok-Capturer senden.
func frameAvailable(_ sampleBuffer: CMSampleBuffer!) {
autoreleasepool {
guard let pb = CMSampleBufferGetImageBuffer(sampleBuffer) else {
print("Invalid Image buffer")
return
}
deepARCapturer.pushFrame(pb)
}
}Sie haben vielleicht die pushFrame Methode in der letzten Zeile bemerkt haben. Mit dieser Methode überbrücken wir die DeepAR-Ansicht und den OpenTok Video-Capturer, wenn Sie sich erinnern, war deepARCapturer der Name für den benutzerdefinierten Video-Capturer, den wir verwendet haben.
Dies ist wahrscheinlich der komplizierteste Teil des Blogposts. Wir haben es mit CoreImage und CoreVideo iOS Frameworks zu tun, um die RGB-Informationen des Frames zu erhalten.
Damit alles funktioniert, müssen wir den pushFrame im DeepARVideoCapturer implementieren, und das wird so aussehen:
func pushFrame(_ pb: CVPixelBuffer) {
// 1
if otFrame == nil {
let otFormat = OTVideoFormat()
otFormat.pixelFormat = .ARGB
otFormat.imageWidth = UInt32(CVPixelBufferGetWidth(pb))
otFormat.imageHeight = UInt32(CVPixelBufferGetHeight(pb))
otFormat.bytesPerRow = [CVPixelBufferGetBytesPerRow(pb)]
otFrame = OTVideoFrame(format: otFormat)
}
guard let frame = otFrame else {
print("Error creating video frame")
return
}
// 2
CVPixelBufferLockBaseAddress(pb, .readOnly)
if let frameData = CVPixelBufferGetBaseAddress(pb) {
frame.orientation = .up
frame.clearPlanes()
frame.planes?.addPointer(frameData)
// 3
videoCaptureConsumer?.consumeFrame(frame)
}
CVPixelBufferUnlockBaseAddress(pb, .readOnly)
}Gehen wir Schritt für Schritt vor, um diese Methode zu verstehen. Wie Sie sehen können, haben wir sie in drei Abschnitte unterteilt.
In Abschnitt 1 (oben mit //1 gekennzeichnet) erstellen wir eine neue Instanz von OTVideoFrame. Diese OTVideoFrame Klasse dient als Container für die Videobildinformationen, die wir später verwenden werden, wenn wir das Bild an das OpenTok SDK übergeben. Typischerweise enthält ein Video-Frame seine Formatinformationen (RGB, YUV, etc.), die Abmessungen, die Anzahl der Bytes, die eine Zeile im Video-Frame wiegt, und natürlich die Video-Frame-Informationen.
Sie fragen sich vielleicht, wozu wir die Byte-Größe der Zeilen benötigen. Videobildformate sind kompliziert zu erklären, und es gibt verschiedene Formate, aber in der Regel ist es hilfreich zu wissen, wie groß der Informationspuffer des Videobildes ist. Sie können die Anzahl der Bytes pro Zeile mit der Bildhöhe multiplizieren, und schon haben Sie das Ergebnis. Manchmal wird die Größe der Zeile nicht durch Multiplikation der Größe eines Pixels mit der Breite des Bildes berechnet, da manchmal zusätzliche leere Pixel als Füllung hinzugefügt werden.
Wenn dieser letzte Absatz für Sie verwirrend ist, machen Sie sich keine Sorgen, Sie wissen nicht, was Sie dort eingeben sollen, da die CoreVideo-Funktionen es für Sie zurückgeben werden.
Wie Sie sehen können, werden wir den "Container" in jedem Frame wiederverwenden, wobei zu berücksichtigen ist, dass diese Funktion etwa 30 Mal pro Sekunde aufgerufen wird.
Nachdem wir eine Instanz von OTVideoFrame erstellt und mit den Informationen gefüllt haben, die in allen Video-Frames gleich sind, können wir zu Abschnitt 2 (// 2) übergehen.
In diesem Abschnitt sperren wir zunächst den Inhalt des Video-Frames, um zu verhindern, dass ein anderer Thread ihn ändern oder löschen kann, während wir darauf zugreifen, indem wir CVPixelBufferLockBaseAddressDanach erhalten wir den Zeiger auf die Frame-Informationen durch den Aufruf von CVPixelBufferGetBaseAddress, und schließlich fügen wir diese Informationen zu unserer OTVideoFrame-Instanz hinzu.
Wie wir bereits erwähnt haben, gibt es verschiedene Arten von Video-Bildformaten. Hier werden wir ARGB verwenden, das normalerweise als Pixelbildformat bezeichnet wird. Das bedeutet, dass der Puffer aus einer Folge von Pixelinformationen besteht, die mit vier Werten kodiert sind, einem für den Alphakanal und anderen für R, G und B.
Es gibt auch andere Formate wie YUV422, das als planares Bildformat bezeichnet wird, weil das Bild in verschiedene Ebenen unterteilt ist.
Wir erläutern dies, um den frame.planes?.addPointer() Aufruf zu verstehen, da wir ARGB verwenden und es eine Ebene hat, so füllen wir unsere OTVideoFrame-Instanz mit Bilddaten.
Wenn wir schließlich eine vollständige OTVideoFrame-Instanz mit Videobildinformationen und -inhalten haben, müssen wir sie nur noch an das OpenTok SDK senden, damit sie über das Netzwerk an die übrigen Sitzungsteilnehmer gesendet werden kann. Und das machen Sie in Abschnitt 3 (// 3) mit videoCaptureConsumer?.consumeFrame(frame) Aufruf.
videoCaptureConsumer ein Mitglied des OTVideoCapture-Protokolls ist und dieses Mitglied gesetzt wird, wenn die OTVideoCapturer durch das OpenTok SDK initialisiert wird, müssen Sie diese Methode immer dann aufrufen, wenn Sie ein Videobild an die Sitzung senden wollen.
Nach all diesen Schritten haben Sie alles vorbereitet, um einen Publisher zu erstellen, der die Inhalte von DeepAR magic an eine OpenTok-Sitzung sendet und jeden mit Ihrem löwenhaften Auftritt beeindruckt.
Gerade erst begonnen
Das Vonage Video API-Team investiert in AR-Produktfunktionen und Partnerschaften, um sicherzustellen, dass unsere Kunden bei der Entwicklung und Verbesserung interaktiver Videoerlebnisse über die beste Technologie und das beste Know-how verfügen.
Mit dem Ausbau unserer Video API hat Vonage eine steigende Nachfrage nach den von unseren Partnern angebotenen Dienstleistungen verzeichnet. Wir sind dankbar für die Zusammenarbeit mit fantastischen Technologie-, Anwendungs- und Integrationsunternehmen auf der ganzen Welt. Mit Vonage können Sie die Vorteile des gesamten Spektrums unserer Kommunikations-APIs nutzen und ein größeres Stück vom Kuchen abhaben.
Das könnte Ihnen auch gefallen:
Tutorial: Verwenden Sie einen Greenscreen in Javascript mit Vonage Video
Einen Partner finden: Kommunikations-APIs Partner
Teilen Sie:
Roberto is a Full Stack Engineer on the OpenTok Client SDK team. He loves learning new bits of Android, iOS, Linux, Windows, you name it! In his free time, he is very passionate about programming languages, computer graphics, and video game development for current and old platforms like ZX Spectrum and Commodore 64.