Cómo lograr el efecto de imagen de efecto de profundidad que trae iOS 16

Autor: fenol

0x01 Prefacio

El sistema iOS 16 nos ha traído un increíble efecto de pantalla de bloqueo de escritorio: efecto de profundidad. Puede usar una imagen ordinaria como fondo y, al mismo tiempo, puede cubrir algunos componentes del escritorio en un lugar apropiado para formar un efecto de profundidad de campo (como se muestra en la figura a continuación).

Entonces, ¿podemos lograr un efecto similar en nuestra propia aplicación? Al principio pensé que iOS 16 había agregado un nuevo control UIKit, UIVisualEffectViewque se puede implementar con unas pocas líneas de API simples como , pero al final descubrí que no existe. Si la imagen dada son varias imágenes que se han dividido en capas, entonces la implementación es simplemente emparedar el control del reloj en el medio como una galleta de emparedado. Sin embargo, en la práctica, se ha descubierto que configurar una sola imagen descargada aleatoriamente de Internet como fondo de la pantalla de bloqueo también puede lograr este efecto. Con reminiscencias del álbum del sistema iOS 16 que puede segmentar y arrastrar directamente al sujeto en la foto después de presionarlo nuevamente, creo que debe haber usado algún algoritmo de segmentación de imágenes para separar el primer plano del fondo, obteniendo así una imagen de varias capas.

0x02 Segmentación de imagen (Segmentación de imagen)

El algoritmo de segmentación de imágenes más clásico es el algoritmo watershed (Watershed), la imagen que segmenta es muy precisa y el procesamiento de bordes es muy bueno, pero requiere trazos manuales en las posiciones aproximadas del primer plano y el fondo (solo un trazo está bien ). , el último algoritmo separará automáticamente el primer plano y el fondo), lo que no se aplica a los requisitos totalmente automáticos de este documento. En los últimos años, han surgido muchos logros en el aprendizaje automático, uno de los cuales es la segmentación de imágenes totalmente automatizada. Efectivamente, después de una simple búsqueda, descubrí que Apple ha proporcionado un modelo preentrenado.

Visite el sitio web oficial de aprendizaje automático de Apple, developer.apple.com/machine-lea... para descargar el modelo entrenado DeeplabV3 . Arrastre el archivo del modelo al proyecto Xcode y podrá ver información sobre él después de seleccionarlo:

imagen

De hecho, aquí nos centramos principalmente en la entrada y la salida del modelo. Haga clic en la pestaña Predicciones y podrá ver que el modelo requiere la entrada de una imagen de 513x513, y la salida es una matriz bidimensional con un tipo de miembro de Int32 y un tamaño de 513 x 513. Cada valor representa el píxel de la imagen correspondiente Clasificación de puntos. La razón por la que los miembros aquí son Int32 en lugar de Bool simple es porque el modelo puede dividir la imagen en muchas partes diferentes, no solo en primer plano y fondo. En la práctica, encontramos que un valor de 0 puede considerarse como fondo y un valor distinto de 0 es el primer plano.

imagen

El siguiente es el resultado obtenido después de ejecutar la segmentación en una imagen de muestra:

imagen

Se divide en dos valores de 0 y 15, que son fondo y primer plano respectivamente.

0x03 práctica

El modelo ya existe, y el plan de implementación está casi listo, y el siguiente paso es la práctica específica.

Después de arrastrar el modelo al proyecto Xcode, Xcode generará automáticamente una clase para nosotros: DeepLabV3. Podemos crear directamente una instancia de él sin ninguna importación :

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

Luego, use esta instancia para crear una VNCoreMLRequestsolicitud para analizar la imagen a través del motor de aprendizaje automático y obtenga el resultado en la devolución de llamada:

    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
                // ...
            }
            
        }
    }
复制代码

Finalmente, VNImageRequestHandlercree :

    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])
            }
        }
    }
复制代码

Aviso:

  1. La devolución de llamada de la solicitud y el código que el controlador inicia la solicitud están en el mismo subproceso, esperando el resultado de forma sincrónica, por lo que es mejor enviar a la operación de subproceso aquí.
  2. La solicitud debe establecer imageCropAndScaleOption en .scallFill, de lo contrario, recortará automáticamente la parte central de forma predeterminada y obtendrá resultados inesperados.

Ingrese la siguiente imagen de muestra,

arrayValueProcese el resultado devuelto en una imagen en blanco y negro:

imagen

Se encontró que era bastante preciso. Por supuesto, si desea utilizarlo como una máscara en el código, debe tratarlo como una imagen con un fondo totalmente transparente y un primer plano opaco:

imagen

Finalmente, colocamos la imagen original en la capa inferior, otros controles en el medio y la imagen original + vista de máscara en la capa superior, formando el efecto final:

imagen

El principio real detrás de esto es la galleta sándwich:

Algunas representaciones más:

posdata 0x04

Por supuesto, este modelo no es una panacea, y todavía hay limitaciones en aplicaciones específicas.Para fotos con personas, se puede segmentar mejor, pero para fotos de paisajes como escenas grandes, es posible que no se pueda segmentar en absoluto. Puede encontrar una demostración de este artículo en Github .

Referencias

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

Este artículo fue publicado por el equipo de tecnología de NetEase Cloud Music. Se prohíbe cualquier forma de reimpresión sin autorización. Reclutamos varios puestos técnicos durante todo el año. Si va a cambiar de trabajo y le gusta la música en la nube, ¡únase a nosotros en grp.music-fe(at)corp.netease.com!

Supongo que te gusta

Origin juejin.im/post/7197608023430283319
Recomendado
Clasificación