So erzielen Sie den Tiefeneffekt-Bildeffekt von iOS 16

Autor: Phenol

0x01 Vorwort

Das iOS 16-System hat uns einen erstaunlichen Desktop-Sperrbildschirm-Effekt gebracht: Tiefeneffekt. Es kann ein gewöhnliches Bild als Hintergrund verwenden und gleichzeitig einige Desktop-Komponenten an einer geeigneten Stelle abdecken, um einen Tiefenschärfeeffekt zu erzeugen (wie in der Abbildung unten gezeigt).

Können wir also einen ähnlichen Effekt in unserer eigenen App erzielen? Zuerst dachte ich, dass iOS 16 ein neues UIKit-Steuerelement hinzugefügt hat, UIVisualEffectViewdas mit ein paar Zeilen einfacher APIs wie implementiert werden kann , aber am Ende stellte ich fest, dass es keine gibt. Wenn das gegebene Bild aus mehreren Bildern besteht, die in Schichten unterteilt wurden, besteht die Implementierung einfach darin, die Uhrsteuerung wie einen Sandwichkeks in die Mitte zu legen. In der Praxis hat sich jedoch herausgestellt, dass auch das Festlegen eines einzelnen zufällig aus dem Internet heruntergeladenen Bildes als Hintergrund für den Sperrbildschirm diesen Effekt erzielen kann. In Anlehnung an das Systemalbum von iOS 16, das das Motiv im Foto nach erneutem Drücken direkt segmentieren und ziehen kann, muss es meiner Meinung nach einen Bildsegmentierungsalgorithmus verwendet haben, um den Vordergrund vom Hintergrund zu trennen und so ein mehrschichtiges Bild zu erhalten

0x02 Bildsegmentierung (Bildsegmentierung)

Der klassischere Bildsegmentierungsalgorithmus ist der Wasserscheidenalgorithmus (Watershed). Das segmentierte Bild ist sehr genau und die Kantenverarbeitung ist sehr gut, aber es erfordert manuelle Striche an den ungefähren Positionen von Vorder- und Hintergrund (nur ein Strich ist in Ordnung ). , letzterer Algorithmus trennt automatisch Vorder- und Hintergrund), was nicht auf die vollautomatischen Anforderungen dieses Papiers zutrifft. In den letzten Jahren sind viele Errungenschaften im maschinellen Lernen entstanden, darunter die vollautomatische Bildsegmentierung. Tatsächlich habe ich nach einer einfachen Suche festgestellt, dass Apple ein vortrainiertes Modell bereitgestellt hat.

Besuchen Sie Apples offizielle Website für maschinelles Lernen developer.apple.com/machine-lea... , um das trainierte Modell DeeplabV3 herunterzuladen . Ziehen Sie die Modelldatei in das Xcode-Projekt, und Sie können einige Informationen darüber anzeigen, nachdem Sie sie ausgewählt haben:

Bild

Tatsächlich konzentrieren wir uns hier hauptsächlich auf die Ein- und Ausgabe des Modells. Klicken Sie auf die Registerkarte Vorhersagen, und Sie können sehen, dass das Modell die Eingabe eines 513 x 513-Bildes erfordert und die Ausgabe ein zweidimensionales Array mit dem Mitgliedstyp Int32 ist und eine Größe von 513 x 513. Jeder Wert repräsentiert die entsprechende Bildpixelklassifizierung von Punkten. Der Grund, warum die Mitglieder hier Int32 anstelle von einfachem Bool sind, liegt darin, dass das Modell das Bild in viele verschiedene Teile aufteilen kann, nicht nur Vorder- und Hintergrund. In der Praxis haben wir festgestellt, dass ein Wert von 0 als Hintergrund und ein anderer Wert als 0 als Vordergrund angesehen werden kann.

Bild

Das Folgende ist das Ergebnis, das nach dem Ausführen der Segmentierung auf einem Beispielbild erhalten wurde:

Bild

Es ist in zwei Werte von 0 und 15 unterteilt, die jeweils Hintergrund und Vordergrund sind.

0x03 üben

Das Modell existiert bereits, der Umsetzungsplan ist fast fertig, und der nächste Schritt ist die konkrete Praxis.

Nachdem das Modell in das Xcode-Projekt gezogen wurde, generiert Xcode automatisch eine Klasse für uns: DeepLabV3. Wir können direkt eine Instanz davon ohne Importe erstellen :

    lazy var model = try! DeepLabV3(configuration: {
        let config = MLModelConfiguration()
        config.allowLowPrecisionAccumulationOnGPU = true
        config.computeUnits = .cpuAndNeuralEngine
        return config
    }())
复制代码

Verwenden Sie dann diese Instanz, um eine VNCoreMLRequestAnfrage zum Analysieren des Bildes durch die Machine Learning Engine zu erstellen und das Ergebnis im Callback abzurufen:

    lazy var request = VNCoreMLRequest(model: try! VNCoreMLModel(for: model.model)) { [unowned self] request, error in
        if let results = request.results as? [VNCoreMLFeatureValueObservation] {
            // 最终的分割结果在 arrayValue 中
            if let feature = results.first?.featureValue, let arrayValue = feature.multiArrayValue {
                let width = arrayValue.shape[0].intValue
                let height = arrayValue.shape[1].intValue
                let stride = arrayValue.strides[0].intValue
                // ...
            }
            
        }
    }
复制代码

VNImageRequestHandlerErstellen Sie abschließend eine Anfrage an der entsprechenden Stelle :

    private func segment() {
        if let image = self.imageView.image {
            imageSize = image.size
            DispatchQueue.global().async { [unowned self] in
                self.request.imageCropAndScaleOption = .scaleFill
                let handler = VNImageRequestHandler(cgImage: image.resize(to: .init(width: 513, height: 513)).cgImage!)
                try? handler.perform([self.request])
            }
        }
    }
复制代码

Notiz:

  1. Der Rückruf der Anfrage und der Code, mit dem der Handler die Anfrage initiiert, befinden sich im selben Thread und warten synchron auf das Ergebnis, daher ist es am besten, hier an die Sub-Thread-Operation zu senden
  2. Die Anfrage muss imageCropAndScaleOption auf setzen .scallFill, andernfalls wird standardmäßig automatisch der mittlere Teil abgeschnitten, und Sie erhalten unerwartete Ergebnisse

Geben Sie das folgende Beispielbild ein,

arrayValueVerarbeiten Sie das zurückgegebene Ergebnis in ein Schwarzweißbild:

Bild

Es wurde festgestellt, dass es ziemlich genau ist. Wenn Sie es im Code als Maske verwenden möchten, sollten Sie es natürlich als Bild mit vollständig transparentem Hintergrund und undurchsichtigem Vordergrund behandeln:

Bild

Schließlich legen wir das Originalbild auf die unterste Ebene, andere Steuerelemente in die Mitte und das Originalbild + die Maskenansicht auf die oberste Ebene, um den endgültigen Effekt zu erzielen:

Bild

Das eigentliche Prinzip dahinter ist der Sandwichkeks:

Noch ein paar Renderings:

0x04 Nachschrift

Natürlich ist dieses Modell kein Allheilmittel, und in bestimmten Anwendungen gibt es noch Einschränkungen: Bei Fotos mit Personen lässt es sich besser segmentieren, bei Landschaftsfotos wie großen Szenen aber vielleicht gar nicht. Eine Demo dieses Artikels finden Sie auf Github .

Verweise

  1. developer.apple.com/documentati…
  2. www.appcoda.com.tw/vision-pers…
  3. enlight.nyc/projects/im…

Dieser Artikel wurde vom NetEase Cloud Music Technology Team veröffentlicht. Jegliche Form des Nachdrucks ohne Genehmigung ist untersagt. Wir stellen das ganze Jahr über verschiedene technische Positionen ein. Wenn Sie den Job wechseln und Cloud-Musik mögen, dann kommen Sie zu uns unter grp.music-fe(at)corp.netease.com!

Ich denke du magst

Origin juejin.im/post/7197608023430283319
Empfohlen
Rangfolge