[WWDC] 이미지에서 신체 동작을 감지해보자. (Detect Body and Hand Pose with Vision)

dadahae·2022년 5월 12일
2

WWDC

목록 보기
1/2
post-thumbnail

WWDC2020 WWDC 스터디 1-2주차
Detect Body and Hand Pose with Vision - WWDC20 - Videos - Apple Developer
관련 공식 문서
📍Detecting Human Body Poses in Images

🏁 개요

2022년 4월 28일! 처음 WWDC 스터디가 진행되었다. 저번 USG iOS 프로그래밍 비교과 수업을 들은 학생들과 진행하게 된 스터디이다. 그 수업도 경험해보자는 식으로 가볍게 수강한 수업이었는데, iOS 개발이 재미가 있어서 열심히 하고 그래서 앱도 처음 앱스토어에 올려보고, 이렇게 WWDC 스터디에도 참여하게 되었다.

스터디의 진행 방향은 아직 불완전하다. 개발 스터디...에 대한 경험이 다들 크게 없어서 차차 진행을 하면서 피드백해 나가기로 했다. 처음엔 한가지 주제로 서로 영상을 보고 정리하고 이야기 나눌 것을 스터디 시간에 공유하려고 했는데, 그 방법으로는 얻어가는게 너무 적을 것 같다고 하여 하나의 주제를 선정하고, 그 주제를 2주간 진행하기로 했다. 2주간 애플에서 제공하는 샘플코드로 개인별 미니 프로젝트를 만들고, 블로그에 올릴 글을 작성해오기로 했다!

❗️스터디 방향

  • 2주간 하나의 주제로 스터디를 진행한다.
  • 해당 주제로 개인별 미니 프로젝트를 완성한다.
  • 해당 주제를 공부하면서 정리한 내용을 블로그에 올린다.

그래도 스터디인데, 서로에게 기록이 남아야지 않겠냐!! 는 의견에 모두 공감했다. 그니까, 스터디를 하면 스터디를 했다는 티를 팍팍 내자구. 기록하지 않으면 아무도 모르니까...

🏃🏻‍♀️가보자고

지금 4학년인 나는 졸업 프로젝트와 정보처리기사 실기를 준비중이다(...). 사실 정처기는 이번주 토요일(22/5/7)이 시험인데 걱정이 많다! 하하~ OT 및 첫번째 스터디 이후로 완전히 까먹고 있었다. 그래서 두번째 스터디 당일 관련 공부를 시작한다. 지금 아니면 언제하냐 라는 마인드로 시작한다.
++ 추가(22/05/14)
정처기는 잘 쳤고, 블로그 글도 잘 마무리했답. ^_^)

Detecting Human Body Poses in Images

이번주 주제는 ‘Vision’! 머신러닝을 이용하여 손과 몸의 포즈를 인식할 수 있다. WWDC20의 영상이고 스터디 주제로 선정되어 시청하게 되었다. 영상의 내용은 꽤나 흥미로웠는데!! Vision 프레임워크로 손와 인체의 포인트를 찍어 인식하는 기술이었다. 영상을 보고, 이해를 돕기위해 애플 공식문서의 ‘**Detecting Human Body Poses in Images’** 라는 제목의 글을 읽었다. 이미지에서 인체의 포즈를 감지하는 것에 대한 설명이었다.

0️⃣ Vision and Human Body Pose

인체의 자세(body pose)를 감지하는 기술은 Vision 프레임워크로 사용할 수 있다. 앱에 Vision 프레임워크를 사용하면 된다!

Vision의 주요 목표는 사람의 비주얼 데이터를 더 잘 인식하고 이해하도록 도와주는 도구를 제공하는 것이다. 그니까 Vision을 이용하면 사람에게 보여지는 데이터, 즉 손의 위치나 동작, 행동 등 눈에 보이는 시각 데이터를 뽑아낼 수 있다.

Vision은 iOS 14와 macOS 11부터 시작했다.

  • Vision의 인체에 19개의 점을 찍어서 인체의 자세를 감지한다.
  • Vision의 인체 자세 감지(human body pose) 기술은 Vision 자체로 사용하거나, 아니면 Core ML과 함께 사용할 수 있다! 머신러닝과 Vision을 같이 쓰면 더 다양하게 기능을 사용할 수 있다고 한다. 이것에 대한 예시로 안전 교육앱, 피트니스 앱, 사진 및 영상 편집 앱 등을 들었다. 신기하다..

1️⃣ Body Pose Request 수행하기

자, 이제 그럼 인체 자세(human body pose)를 감지하기 위한 request를 만들어보자. 먼저, Vision에서 제공해주는 클래스들을 살펴보도록 하자.

  • VNDetectHumanBodyPoseRequest : Vision은 이 클래스로 인체 감지 기능을 제공한다. 주요 인체 지점(key body point, 앞에 말한 19개의 포인트)을 감지하는 이미지 기반의 request 타입.
  • VNImageRequestHandler : 단일 이미지에 대한 하나 혹은 그 이상의 Vision 이미지 분석 요청을 처리하는 객체.
    • 이 핸들러를 인스턴스화하여 Vision request를 수행한다. 여기서는 HumanBodyPoseRequest가 되겠지...
    • 생성 시에 이미지를 지정하고, 선택적으로 completion Handler를 지정한다.
    • 그리고 perform(_:) 를 호출하여 요청을 수행한다아~~

샘플 코드는 아래와 같다!

// Get the CGImage on which to perform requests.
guard let cgImage = UIImage(named: "bodypose")?.cgImage else { return }

// Create a new image-request handler.
let requestHandler = VNImageRequestHandler(cgImage: cgImage)

// Create a new request to recognize a human body pose.
let request = VNDetectHumanBodyPoseRequest(completionHandler: bodyPoseHandler)

do {
    // Perform the body pose-detection request.
    try requestHandler.perform([request])
} catch {
    print("Unable to perform the request: \(error).")
}

VNImageRequestHandler를 사용하여 VNDetectHumanBodyPoseRequest가 CGImage에서 바디 포인트(인체 지점, body point)를 감지할 수 있게 한다.

2️⃣ 결과 처리하기

이미지에서 바디 포인트를 인식하도록 요청을 수행(perform)했다! 그럼 그 결과는 어떻게 되는 걸까?

request handler가 request(바디 포인트를 인식해줭!)을 처리하고 난 후에 request의 completion closure를 호출하여 해당 request과 오류들을 보내준다. request 객체에 결과질의하여(query) 관찰한 정보를 검색한다. 이때 결과VNHumanBodyPoseObservation객체의 배열로 반환된다.

  • 여기에서 질의하는 것(quering)은 데이터베이스에 정보를 요청하는 것이다❗️

그럼 request는 확인된 인체 자세의 고유한(unique) 정보를 리턴하고, 각 정보는 인식된 점과 정확도를 나타내는 신뢰점수(confidence score)를 포함한다.

아래 코드는 bodyPoseHandler 함수이다.

func bodyPoseHandler(request: VNRequest, error: Error?) {
    guard let observations =
            request.results as? [VNHumanBodyPoseObservation] else { 
        return 
    }
    
    // Process each observation to find the recognized body pose points.
    observations.forEach { processObservation($0) }
}

이 함수는 위의 샘플코드에서 VNDetectHumanBodyPoseRequest의 객체를 만들 때, completion handler로 사용하였다.

  • complection handler를 URLSession에서 사용해본 적은 있지만, 아직 이론적인 이해가 부족하다. 이 부분은 더 공부해야겠다.

3️⃣ 포인트 불러오기!

내가 원하는 포인트를 불러오려면... recognizedPoint(_:)함수를 호출하면 된다.

  • recognizedPoint(_:) : joint group name(관절 그룹 이름)과 연관된 인식된 포인트를 검색한다.
    • 이 함수에서 사용하는 매개변수는 특정 신체 지역의 모든 포인트를 식별하는 키! 이다.
    • 이 함수는 인식된 신체 지역(region이라고 하는데... 적당히 신체의 부위? 정도로 보면 되겠다. 몸통, 왼팔, 오른다리...)을 VNRecognizedPoint 객체의 딕셔너리 형태로 리턴한다. VNRecognizedPoint의 각각 인스턴스는 정규화된 공간에서(정규화된 공간? 이건 무슨 말인지 모르겟답) x,y 좌표와 신뢰점수를 제공한다.
    • 인식된 포인트의 신뢰점수가 0인 건 무시하자. 아예 유효하지 않은 값이다.

아래의 코드는 몸통의 모든 인식된 포인트를 검색하고 그것을 CGPoint 객체 배열로 매핑한다.

func processObservation(_ observation: VNHumanBodyPoseObservation) {
    
    // Retrieve all torso points.
    guard let recognizedPoints =
            try? observation.recognizedPoints(.torso) else { return }
    
    // Torso joint names in a clockwise ordering.
    let torsoJointNames: [VNHumanBodyPoseObservation.JointName] = [
        .neck,
        .rightShoulder,
        .rightHip,
        .root,
        .leftHip,
        .leftShoulder
    ]
    
    // Retrieve the CGPoints containing the normalized X and Y coordinates.
    let imagePoints: [CGPoint] = torsoJointNames.compactMap {
        guard let point = recognizedPoints[$0], point.confidence > 0 else { return nil }
        
        // Translate the point from normalized-coordinates to image coordinates.
        return VNImagePointForNormalizedPoint(point.location,
                                              Int(imageSize.width),
                                              Int(imageSize.height))
    }
    
    // Draw the points onscreen.
    draw(points: imagePoints)
}

위 예제는 처음에 recognizedPoint(_:)에 몸통 키를 넣어 호출하여 몸통의 인식된 포인트를 검색한다. 그런 다음, 몸통의 특정 포인트 키에 대해 반복하고 연관된 VNRecognizedPoint 객체를 검색한다. 마지막으로 포인트의 신뢰 점수가 0보다 크면 점의 좌표를 CGPoint로 추출한다 !

4️⃣ 포즈 감지의 정확도를 향상시키려면...

지금까지 Vision의 인체 동작 감지 기능을 간단하게 알아보았따! 그럼 이 기능을 향상시키기 위해서는 어떻게 해야할깝.

  • 피사체의 키(=높이)는 이상적으로 전체 이미지 높이의 1/3 이상이어야 한다.
  • 피사체의 주요 신체 영역과 포인트의 많은 부분이 이미지에 있어야 합니다.
  • 피사체가 흘러내리거나 가운같은 옷을 입으면 정확도가 떨어진다.
  • 관중이 많은 장면에서 포즈를 감지하는 것은 거의 부정확한 결과을 만들어낸다. 사람이 많은 사진에서는 검출도가 엄청 떨어진다는 뜻!!

😇 마무리 - 처음 써본 정리글

막상 써보니, 내가 먼저 이해를 하고 작성하는게 힘들었다. 사실 주제 영상은 한번보고 그것과 관련된 애플 공식문서 글을 읽었는데, 아직 100%로 이해를 못했다. Vision의 body pose 기능을 쓰려면 먼저 객체로 요청을 만들고, 그 요청을 수행하기 위해서 핸들러를 만들어준다! 그렇게 요청을 수행하면... 컴플리션 핸들러로 결과를 처리할 수 있다. 처리된 결과는 특정 자료형의 배열로 받아와진다. 그럼 그 결과값에서 원하는 포인트값을 가져오려면 객체의 특정 함수로 검색해올 수 있다~ 로 정리된다...

이게 맞나? 쓰면서 계속 생각났지만 일단 완성을 시켜보자가 목표였기에 그냥 달렸다. 그리고 솔직히 공식문서의 내용이 거의 대부분이긴 하지만, 그냥 읽는 것보다 내가 해석하고 정리를 덧붙이는게 더 도움이 된다고 판단했다.
해보니까 재밌다. 헤헤


reference

profile
iOS / Swift

2개의 댓글

comment-user-thumbnail
2022년 5월 12일

우와 너무 유익해요~!👏🏻

1개의 답글