ARKit을 활용한 생일 축하 필터 개발 도전기

2023년 5월 9일 | 기술 이야기

안녕하세요. 와디즈 앱개발팀 iOS 앱 개발자 입니다.
최근 와디즈는 ARKit을 활용한 생일 축하 필터를 개발했어요. 그 과정을 공유하고자 합니다.

기술 이야기_ARKit을 활용한 생일축하 필터 개발기

 

개발 배경

만약 여러분의 생일이 곧 다가온다면? 생일로부터 전후 3일간 와디즈 앱에서 생일 축하 필터 기능을 이용할 수 있어요.
카메라 접근 권한을 허용한 후, 화면에 진입하면 전면 카메라가 얼굴을 인식하고 고깔모자가 노출됩니다. 녹화 버튼을 누르면 와디즈의 대표 케릭터인 진국이와 지니, 조이가 나타나 함께 사진을 찍기 위한 포즈를 취해요.

이 기능의 탄생에는 생일 축하 쿠폰으로 와디즈 이용자의 펀딩 참여를 높이고자 하는 기획이 있습니다. 사용자 참여 이벤트라는 재밌는 요소를 앱에 녹이고자 했어요.

기술 이야기_ARKit을 활용한 생일축하 필터 개발기

선글라스는 실제 서비스와 무관합니다!

 

ARKit을 통한 얼굴 인식

ARKit은 WWDC17에서 공개한 AR(증강 현실) 앱을 제작하는 소프트웨어 프레임워크예요. ARKit은 iOS 기기의 카메라와 센서를 사용해 실제 세계를 기반으로 하는 가상 세계를 만드는 기술을 제공해요.
카메라를 사용해 현재 위치와 방향을 추적하고, 물체 감지, 세부 사항 추출 등의 작업을 수행할 수 있어요.

기술 이야기_ARKit을 활용한 생일축하 필터 개발기

참조 : Apple Developer Documentation

 

ARKit의 ARSCNView는 SceneKit 기반의 3D View예요. ARSCNView는 실시간으로 카메라 입력 데이터를 처리하여 가상 객체를 표시할 수 있도록 해줍니다. ARSCNView는 session이 활성화되어야 동작하며, ARSession의 설정은 ARConfiguration을 통해 설정합니다.

ARKit에서 제공되는 ARConfiguration의 종류는 아래와 같아요. configuration마다 사용자가 다른 AR 경험을 할 수 있도록 합니다.

  • ARWorldTrackingConfiguration

  • ARGeoTrackingConfiguration

  • AROrientationTrackingConfiguration

  • ARBodyTrackingConfiguration

  • ARFaceTrackingConfiguration

이 중 ARFaceTrackingConfiguration은 카메라를 통해 들어온 정보 중 얼굴을 인식하고, FaceAnchor를 통해 얼굴 정보를 제공합니다. 그러면, ARSCNViewDelegate 함수 중

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode?

를 통해서 ARKit에서 감지된 새로운 ARAnchor를 기반으로 새로운 노드를 생성할 수 있게 되죠.

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
    guard let device = MTLCreateSystemDefaultDevice() else { return nil }
    let faceGeometry = ARSCNFaceGeometry(device: device)

    let faceNode = FaceFilterNode(geometry: faceGeometry)
    let headNode = HeadNode(with: "filter_hat")
    let eyeNode = EyeNode(with: "filter_sunglasses")
    faceNode.addChildNode(headNode)
    faceNode.addChildNode(eyeNode)

    return faceNode
}

위 EyeNode와 HeadNode 는 아래처럼 SCNNode 를 상속받게 하여 정의했어요. 머리 & 눈 위치에 Filter 이미지를 적용하는 역할을 담당합니다.

class EyeNode: SCNNode, FilterNodeElementProtocol {
    init(with imageName: String, width: CGFloat = 0.2) {
        super.init()
        setup(with: imageName, width: width)
    }
    func updatePosition(for vectors: [vector_float3]) {
        let eyeIndex = 12
        if let newPosition = vectors[safe: eyeIndex] {
            self.position = SCNVector3(newPosition)
        }
    }

    //...
}

위 upatePosition 함수에서 parameter로 받는 vectors 배열은 FaceAnchor의 ARFaceGeometry 에서 제공하는 각 얼굴의 정점 요소를 담고 있는 배열로,

  • 눈의 중심

  • 입의 중심

  • 코끝

등등 1,220개 정도의 요소들을 자세하게 제공하고 있어요.

 

이렇게 새로운 노드를 생성했다면, 프레임마다 업데이트를 해줘야 하는데요. 또 다른 ARSCNViewDelegate 함수인

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor)

가 이를 핸들링 해주고 있습니다.

func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
    guard let faceAnchor = anchor as? ARFaceAnchor,
    let filterNode = node as? FilterNode else { return }

    filterNode.geometry.update(from: faceAnchor.geometry)
    let vertices = anchor.geometry.vertices
    filterNode.subNodes.forEach { $0.updatePosition(for: vertices) }
}

이를 통해서 Filter 이미지를 생성하기 위해 만든 FilterNode에 새로운 Geometry 정보를 업데이트하며, 새롭게 얻은 벡터 정보들을 통해 EyeNode, HeadNode들의 위치, 방향을 새롭게 업데이트하게 됩니다.

그럼, 아래와 같이 멋진 필터 기능이 만들어지죠. 엄청 간단하죠? 😁

기술 이야기_ARKit을 활용한 생일축하 필터 개발기

 

프로젝트를 진행하면서

프로젝트를 진행하면서 흥미로운 점도, 아쉬운 점도 있었는데요!
ARKit의 ARFaceTrackingConfiguration는 전면 카메라만을 지원하고 있어요. 후면 카메라도 가능하게 하기 위해서는 Vision Framework 등으로 프레임마다 얼굴 요소를 인식하는 기능을 구현해야 해요. 현실적으로 어려움이 있어서 아쉬웠죠.

추후 발전시키고 싶은 부분도 있는데요. 선글라스와 고깔모자가 모두 2D 요소인 것 눈치채셨나요? 3D 모델링을 하면 각도와 상관없이 조금 더 생생한 AR 경험을 줄 수 있었을 거예요. 프로젝트를 이어가 3D 요소를 추가하고 싶습니다.

제가 이번에 경험한 카메라 녹화 기능, ARKit 적용은 많은 개발자에게 흔히 있는 경험은 아니에요. 익숙하게 사용하던 프레임워크나 라이브러리 등이 아닌 배경에서 구현해 나가는 것이 초반에 많이 어려웠어요. 하지만 어떻게 하면 빠르게 적용할 수 있는지, 어떤 것들을 주의해야 하는지 나만의 그라운드 룰을 만들어 가는 것이 즐거웠습니다.
주니어 개발자로서 정말 좋은 경험을 했다 생각합니다!

궁금한 내용이 남아 있나요? 👀

앱개발팀의 조직 문화가 궁금하다면? 👉 클릭
앱개발팀은 인스타그램 공유하기 기능도 만들었어요! 👉 클릭

👇 태그를 클릭하면 같은 키워드의 글을 모아볼 수 있어요.

기술 이야기

기술 이야기

기술 조직

누구나 도전하고, 새로움을 경험할 수 있도록, 꼭 필요한 서비스를 만듭니다.