HoloLens(1세대) 및 Azure 304: 얼굴 인식


참고

Mixed Reality 아카데미 자습서는 HoloLens(1세대) 및 Mixed Reality 몰입형 헤드셋을 염두에 두고 설계되었습니다. 따라서 이러한 디바이스 개발에 대한 지침을 계속 찾고 있는 개발자를 위해 이러한 자습서를 그대로 두는 것이 중요합니다. 이러한 자습서는 HoloLens 2에 사용되는 최신 도구 집합 또는 상호 작용으로 업데이트되지 않습니다. 대신 지원되는 디바이스에서 계속 작동하도록 유지 관리됩니다. HoloLens 2 위해 개발하는 방법을 보여 줄 새로운 자습서 시리즈가 미래에 게시될 예정입니다. 이 알림은 해당 자습서가 게시될 때 해당 자습서에 대한 링크로 업데이트됩니다.


이 과정을 완료한 결과

이 과정에서는 Microsoft Face API를 사용하여 Azure Cognitive Services를 사용하여 혼합 현실 애플리케이션에 얼굴 인식 기능을 추가하는 방법을 알아봅니다.

Azure Face API 는 개발자에게 클라우드에서 가장 진보된 얼굴 알고리즘을 제공하는 Microsoft 서비스입니다. Face API에는 특성이 있는 얼굴 감지와 얼굴 인식이라는 두 가지 기본 함수가 있습니다. 이를 통해 개발자는 단순히 얼굴에 대한 그룹 집합을 설정한 다음, 나중에 서비스에 쿼리 이미지를 보내 얼굴이 속한 사람을 결정할 수 있습니다. 자세한 내용은 Azure 얼굴 인식 페이지를 참조하세요.

이 과정을 완료하면 다음을 수행할 수 있는 혼합 현실 HoloLens 애플리케이션이 있습니다.

  1. 탭 제스처를 사용하여 온보드 HoloLens 카메라를 사용하여 이미지 캡처를 시작합니다.
  2. 캡처된 이미지를 Azure Face API 서비스로 보냅니다.
  3. Face API 알고리즘의 결과를 받습니다.
  4. 간단한 사용자 인터페이스를 사용하여 일치하는 사람의 이름을 표시합니다.

그러면 Face API Service에서 Unity 기반 혼합 현실 애플리케이션으로 결과를 가져오는 방법을 설명합니다.

애플리케이션에서 결과를 디자인과 통합하는 방법은 사용자에게 달려 있습니다. 이 과정은 Unity 프로젝트와 Azure 서비스를 통합하는 방법을 교육하기 위해 고안되었습니다. 혼합 현실 애플리케이션을 향상시키기 위해 이 과정에서 얻은 지식을 사용하는 것이 여러분의 임무입니다.

디바이스 지원

과정 HoloLens 몰입형 헤드셋
MR 및 Azure 304: 얼굴 인식 ✔️ ✔️

참고

이 과정은 주로 HoloLens에 중점을 두지만, 이 과정에서 배운 내용을 VR(몰입형) 헤드셋에 Windows Mixed Reality 적용할 수도 있습니다. 몰입형(VR) 헤드셋에는 액세스할 수 있는 카메라가 없으므로 PC에 연결된 외부 카메라가 필요합니다. 과정을 진행하면서 몰입형(VR) 헤드셋을 지원하기 위해 사용해야 할 수 있는 변경 사항에 대한 메모를 볼 수 있습니다.

사전 요구 사항

참고

이 자습서는 Unity 및 C#에 대한 기본 경험이 있는 개발자를 위해 설계되었습니다. 또한 이 문서의 필수 구성 요소 및 서면 지침은 작성 당시 테스트 및 확인된 내용(2018년 5월)을 나타냅니다. 이 과정의 정보가 아래에 나열된 것보다 최신 소프트웨어에서 찾을 수 있는 내용과 완벽하게 일치한다고 가정해서는 안 되지만 도구 설치 문서에 나열된 대로 최신 소프트웨어를 자유롭게 사용할 수 있습니다.

이 과정에서는 다음 하드웨어 및 소프트웨어를 사용하는 것이 좋습니다.

시작하기 전에

  1. 이 프로젝트를 빌드하는 데 문제가 발생하지 않도록 이 자습서에서 언급한 프로젝트를 루트 또는 루트에 가까운 폴더에 만드는 것이 좋습니다(긴 폴더 경로는 빌드 시 문제를 일으킬 수 있음).
  2. HoloLens를 설정하고 테스트합니다. HoloLens 설정을 지원해야 하는 경우 HoloLens 설정 문서를 참조하세요.
  3. 새 HoloLens 앱 개발을 시작할 때 보정 및 센서 튜닝을 수행하는 것이 좋습니다(때로는 각 사용자에 대해 이러한 작업을 수행하는 데 도움이 될 수 있음).

보정에 대한 도움말은 HoloLens 보정 문서에 대한 이 링크를 따르세요.

센서 튜닝에 대한 도움말은 HoloLens 센서 튜닝 문서에 대한 링크를 따르세요.

1장 - Azure Portal

Azure에서 Face API 서비스를 사용하려면 애플리케이션에서 사용할 수 있도록 서비스의 instance 구성해야 합니다.

  1. 먼저 Azure Portal에 로그인합니다.

    참고

    Azure 계정이 아직 없는 경우 계정을 만들어야 합니다. 강의실 또는 랩 상황에서 이 자습서를 따르는 경우 강사 또는 감독자 중 한 명에게 새 계정 설정에 대한 도움을 요청하세요.

  2. 로그인한 후 왼쪽 위 모서리에서 새로 만들기를 클릭하고 Face API를 검색한 후 Enter 키를 누릅니 .

    얼굴 API 검색

    참고

    New라는 단어가 최신 포털에서 리소스 만들기로 대체되었을 수 있습니다.

  3. 새 페이지에서 Face API 서비스에 대한 설명을 제공합니다. 이 프롬프트의 왼쪽 아래에서 만들기 단추를 선택하여 이 서비스와의 연결을 만듭니다.

    face API 정보

  4. 만들기를 클릭한 후에는 다음을 수행합니다.

    1. 이 서비스 instance 원하는 이름을 삽입합니다.

    2. 구독을 선택합니다.

    3. Face API 서비스를 처음 만드는 경우 F0이라는 무료 계층을 사용할 수 있어야 하므로 적절한 가격 책정 계층을 선택합니다.

    4. 리소스 그룹을 선택하거나 새 그룹을 만듭니다. 리소스 그룹은 Azure 자산 컬렉션에 대한 액세스를 모니터링, 제어, 프로비전 및 관리하는 방법을 제공합니다. 단일 프로젝트(예: 이러한 랩)와 연결된 모든 Azure 서비스를 공통 리소스 그룹 아래에 유지하는 것이 좋습니다.

      Azure 리소스 그룹에 대해 자세히 알아보려면 리소스 그룹 문서를 방문하세요.

    5. 나중에 사용하는 UWP 앱 인 Person Maker는 위치에 '미국 서부'를 사용해야 합니다.

    6. 또한 이 서비스에 적용된 사용 약관을 이해했음을 확인해야 합니다.

    7. 만들기를 선택합니다.*

      얼굴 API 서비스 만들기

  5. 만들기*를 클릭하면 서비스가 생성될 때까지 기다려야 합니다. 이 작업은 1분 정도 걸릴 수 있습니다.

  6. 서비스 instance 만들어지면 포털에 알림이 표시됩니다.

    서비스 만들기 알림

  7. 알림을 클릭하여 새 서비스 instance 탐색합니다.

    리소스 알림으로 이동

  8. 준비가 되면 알림에서 리소스로 이동 단추를 클릭하여 새 서비스 instance 탐색합니다.

    액세스 얼굴 API 키

  9. 이 자습서 내에서 애플리케이션은 서비스의 구독 '키'를 사용하여 수행되는 서비스를 호출해야 합니다. Face API 서비스의 빠른 시작 페이지에서 첫 번째 지점은 키 잡기에 대한 숫자 1입니다.

  10. 서비스 페이지에서 파란색 하이퍼링크(빠른 시작 페이지에 있는 경우) 또는 서비스 탐색 메뉴의 링크(왼쪽, '키' 아이콘으로 표시됨)를 선택하여 키를 표시합니다.

    참고

    나중에 필요하므로 키 중 하나를 기록하고 보호합니다.

2장 - 'Person Maker' UWP 애플리케이션 사용

Person Maker라는 미리 빌드된 UWP 애플리케이션을 다운로드해야 합니다. 이 앱은 이 과정의 최종 제품이 아니며, 이후 프로젝트에서 사용할 Azure 항목을 만드는 데 도움이 되는 도구일 뿐입니다.

Person Maker 를 사용하면 사용자 및 사용자 그룹과 연결된 Azure 항목을 만들 수 있습니다. 애플리케이션은 사용자가 추가한 사람의 얼굴을 인식하기 위해 필요한 모든 정보를 나중에 FaceAPI에서 사용할 수 있는 형식으로 배치합니다.

[중요] Person Maker 는 몇 가지 기본 제한을 사용하여 무료 구독 계층의 분당 서비스 호출 수를 초과하지 않도록 합니다. 위쪽의 녹색 텍스트는 빨간색으로 변경되고 제한이 발생하면 '활성'으로 업데이트됩니다. 이 경우 애플리케이션을 기다리기만 하면 됩니다(다음에 얼굴 서비스에 계속 액세스할 수 있을 때까지 기다렸다가 다시 사용할 수 있을 때 'IN-ACTIVE'로 업데이트됨).

이 애플리케이션은 Face API를 최대한 활용할 수 있는 Microsoft.ProjectOxford.Face 라이브러리를 사용합니다. 이 라이브러리는 NuGet 패키지로 무료로 사용할 수 있습니다. 이와 유사한 API에 대한 자세한 내용은 API 참조 문서를 참조하세요.

참고

이는 필요한 단계일 뿐이며, 이러한 작업을 수행하는 방법에 대한 지침은 문서 아래쪽에 있습니다. Person Maker 앱을 사용하면 다음을 수행할 수 있습니다.

  • 연결할 여러 사람으로 구성된 그룹인 사람 그룹을 만듭니다. Azure 계정을 사용하여 여러 개인 그룹을 호스트할 수 있습니다.

  • Person 그룹의 구성원인 Person을 만듭니다. 각 사용자에게는 여러 얼굴 이미지가 연결되어 있습니다.

  • Azure Face API Service가 해당 얼굴로 사람을 인식할 수 있도록 인물에 얼굴이미지를 할당합니다.

  • Azure Face API Service학습합니다.

사용자를 인식하도록 이 앱을 학습하려면 개인 그룹에 추가하려는 각 사람의 10장의 클로즈업 사진이 필요합니다. Windows 10 캠 앱은 이러한 작업을 수행하는 데 도움이 될 수 있습니다. 이미지 파일 크기가 4MB 이하이고 1KB 이하인 경우 각 사진이 명확해야 합니다(흐리거나, 모호하거나, 제목에서 너무 멀리 떨어져 있지 않음). 사진의 크기는 jpg 또는 png 파일 형식이어야 합니다.

참고

이 자습서를 따르는 경우 HoloLens를 켜 놓을 때처럼 자신의 얼굴을 학습에 사용하지 마십시오. 동료 또는 동료 학생의 얼굴을 사용합니다.

실행 중인 사람 메이커:

  1. PersonMaker 폴더를 열고 PersonMaker 솔루션을 두 번 클릭하여 Visual Studio에서 엽니다.

  2. PersonMaker 솔루션이 열리면 다음을 확인합니다.

    1. 솔루션 구성디버그로 설정됩니다.

    2. 솔루션 플랫폼x86으로 설정됩니다.

    3. 대상 플랫폼로컬 컴퓨터입니다.

    4. NuGet 패키지를 복원해야 할 수도 있습니다(솔루션을 마우스 오른쪽 단추로 클릭하고 NuGet 패키지 복원을 선택).

  3. 로컬 컴퓨터를 클릭하면 애플리케이션이 시작됩니다. 더 작은 화면에서는 모든 콘텐츠가 표시되지 않을 수 있지만 아래로 스크롤하여 볼 수 있습니다.

    person maker 사용자 인터페이스

  4. Azure 내 Face API 서비스에서 Azure 인증 키를 삽입합니다.

  5. 삽입:

    1. 개인 그룹에 할당할 ID입니다. ID는 공백이 없는 소문자여야 합니다. 이 ID는 나중에 Unity 프로젝트에서 필요하므로 기록해 둡니다.
    2. 개인 그룹에 할당할 이름입니다(공백이 있을 수 있음).
  6. 사용자 그룹 만들기 단추를 누릅니다. 확인 메시지가 단추 아래에 표시됩니다.

참고

'액세스 거부' 오류가 발생하면 Azure 서비스에 대해 설정한 위치를 검사. 위에서 설명한 대로 이 앱은 '미국 서부'를 위해 설계되었습니다.

중요

알려진 그룹 가져오기 단추를 클릭할 수도 있습니다. 이는 이미 사람 그룹을 만들고 새 그룹을 만드는 대신 사용하려는 경우에 해당합니다. 알려진 그룹을 사용하여 사람 그룹 만들기를 클릭하면 그룹도 가져옵니다.

  1. 만들려는 사람의이름을 삽입합니다.

    1. 사용자 만들기 단추를 클릭합니다.

    2. 확인 메시지가 단추 아래에 표시됩니다.

    3. 이전에 만든 사람을 삭제하려면 텍스트 상자에 이름을 쓰고 사람 삭제를 누릅니다.

  2. 그룹에 추가하려는 사람의 사진 10개(10장)의 위치를 알고 있는지 확인합니다.

  3. 폴더 만들기 및 열기를 눌러 사용자와 연결된 폴더에 대한 Windows Explorer 엽니다. 폴더에 10개(10개) 이미지를 추가합니다. JPG 또는 PNG 파일 형식이어야 합니다.

  4. Azure에 제출을 클릭합니다. 카운터에 제출 상태가 표시되고 완료될 때 메시지가 표시됩니다.

  5. 카운터가 완료되고 확인 메시지가 표시되면 학습 을 클릭하여 서비스를 학습시킵니다.

프로세스가 완료되면 Unity로 이동할 준비가 된 것입니다.

3장 - Unity 프로젝트 설정

다음은 혼합 현실로 개발하기 위한 일반적인 설정이며, 따라서 다른 프로젝트에 적합한 템플릿입니다.

  1. Unity를 열고 새로 만들기를 클릭합니다.

    새 Unity 프로젝트를 시작합니다.

  2. 이제 Unity 프로젝트 이름을 제공해야 합니다. MR_FaceRecognition 삽입합니다. 프로젝트 형식이 3D로 설정되어 있는지 확인합니다. 위치를 적절한 위치로 설정합니다(루트 디렉터리에 더 가까울수록 좋습니다). 그런 다음 프로젝트 만들기를 클릭합니다.

    새 Unity 프로젝트에 대한 세부 정보를 제공합니다.

  3. Unity가 열려 있는 경우 기본 스크립트 편집 기가 Visual Studio로 설정되어 있는지 확인하는 것이 좋습니다. 기본 설정 편집 > 으로 이동한 다음 새 창에서 외부 도구로 이동합니다. 외부 스크립트 편집기를 Visual Studio 2017로 변경합니다. 기본 설정 창을 닫습니다.

    스크립트 편집기 기본 설정을 업데이트합니다.

  4. 다음으로, 파일 > 빌드 설정으로 이동하여 플랫폼 전환 단추를 클릭하여 플랫폼을 유니버설 Windows 플랫폼전환합니다.

    빌드 설정 창에서 플랫폼을 UWP로 전환합니다.

  5. 파일 > 빌드 설정으로 이동하여 다음을 확인합니다.

    1. 대상 디바이스HoloLens로 설정됩니다.

      몰입형 헤드셋의 경우 대상 디바이스모든 디바이스로 설정합니다.

    2. 빌드 유형D3D로 설정됨

    3. SDK최신 설치됨으로 설정됨

    4. Visual Studio 버전설치된 최신 버전으로 설정됨

    5. 빌드 및 실행로컬 컴퓨터로 설정됩니다.

    6. 장면을 저장하고 빌드에 추가합니다.

      1. 열린 장면 추가를 선택하여 이 작업을 수행합니다. 저장 창이 나타납니다.

        열린 장면 추가 단추를 클릭합니다.

      2. 새 폴더 단추를 선택하여 새 폴더를 만들고 이름을 Scenes로 지정합니다.

        새 스크립트 폴더 만들기

      3. 새로 만든 Scenes 폴더를 연 다음 파일 이름: 텍스트 필드에 FaceRecScene을 입력한 다음 저장을 누릅니다.

        새 장면에 이름을 지정합니다.

    7. 빌드 설정의 나머지 설정은 현재 기본값으로 남아 있어야 합니다.

  6. 빌드 설정 창에서 플레이어 설정 단추를 클릭하면 Inspector가 있는 공간에서 관련 패널이 열립니다.

    플레이어 설정을 엽니다.

  7. 이 패널에서 몇 가지 설정을 확인해야 합니다.

    1. 기타 설정 탭에서 다음을 수행합니다.

      1. 스크립팅런타임 버전은실험적 (.NET 4.6 등가)이어야 합니다. 이렇게 변경하면 편집기를 다시 시작해야 합니다.

      2. 백 엔드 스크립팅.NET이어야 합니다.

      3. API 호환성 수준은.NET 4.6이어야 합니다.

        다른 설정을 업데이트합니다.

    2. 게시 설정 탭의 기능에서 다음을 검사.

      • InternetClient

      • 웹캠

        게시 설정을 업데이트합니다.

    3. 패널 아래쪽의 XR 설정(게시 설정 아래에 있음)에서 Virtual Reality Supported를 체크하고 Windows Mixed Reality SDK가 추가되었는지 확인합니다.

      X R 설정을 업데이트합니다.

  8. 빌드 설정으로 돌아가면 Unity C# 프로젝트가 더 이상 회색으로 표시되지 않습니다. 이 옆에 있는 확인란을 선택합니다.

  9. 빌드 설정 창을 닫습니다.

  10. 장면 및 프로젝트를 저장합니다(파일 > 저장 장면/파일 > 저장 프로젝트).

챕터 4 - 기본 카메라 설정

중요

이 과정의 Unity 설정 구성 요소를 건너뛰고 코드를 계속 진행하려면 이 .unitypackage를 자유롭게 다운로드하고 사용자 지정 패키지로 프로젝트로 가져올 수 있습니다. 이 패키지에는 5장에서 다루는 Newtonsoft DLL 가져오기도 포함되어 있습니다. 이 항목을 가져오면 6장에서 계속할 수 있습니다.

  1. 계층 패널에서 기본 카메라를 선택합니다.

  2. 선택하면 검사기 패널에서 주 카메라의 모든 구성 요소를 볼 수 있습니다.

    1. Camera 개체의 이름은 주 카메라여야 합니다(맞춤법 유의하세요!)

    2. 주 카메라 태그MainCamera 로 설정해야 합니다(맞춤법 유의하세요!)

    3. 변환 위치0, 0, 0으로 설정되어 있는지 확인합니다.

    4. 플래그 지우기를 단색으로 설정

    5. 카메라 구성 요소의 배경 색을 검은색, 알파 0으로 설정(16진수 코드: #00000000)

      카메라 구성 요소 설정

5장 - Newtonsoft.Json 라이브러리 가져오기

중요

마지막 챕터에서 '.unitypackage'를 가져온 경우 이 챕터를 건너뛸 수 있습니다.

수신되어 Bot Service 전송된 개체를 역직렬화하고 직렬화하려면 Newtonsoft.Json 라이브러리를 다운로드해야 합니다. 이 Unity 패키지 파일에서 올바른 Unity 폴더 구조로 이미 구성된 호환되는 버전을 찾을 수 있습니다.

라이브러리를 가져오려면 다음을 수행합니다.

  1. Unity 패키지를 다운로드합니다.

  2. 자산, 패키지 가져오기, 사용자 지정 패키지를 클릭합니다.

    Newtonsoft.Json 가져오기

  3. 다운로드한 Unity 패키지를 찾아 열기를 클릭합니다.

  4. 패키지의 모든 구성 요소가 선택되어 있는지 확인하고 가져오기를 클릭합니다.

    Newtonsoft.Json 자산 가져오기

6장 - FaceAnalysis 클래스 만들기

FaceAnalysis 클래스의 목적은 Azure Face Recognition Service와 통신하는 데 필요한 메서드를 호스트하는 것입니다.

  • 서비스에 캡처 이미지를 보낸 후 캡처 이미지를 분석하고 내부의 얼굴을 식별하고 알려진 사람에 속하는지 확인합니다.
  • 알려진 사람이 발견되면 이 클래스는 해당 이름을 장면에 UI 텍스트로 표시합니다.

FaceAnalysis 클래스를 만들려면 다음을 수행합니다.

  1. 프로젝트 패널에 있는 자산 폴더를 마우스 오른쪽 단추로 클릭한 다음폴더만들기>를 클릭합니다. 스크립트 폴더 를 호출합니다.

    FaceAnalysis 클래스를 만듭니다.

  2. 방금 만든 폴더를 두 번 클릭하여 엽니다.

  3. 폴더 내부를 마우스 오른쪽 단추로 클릭한 다음C# 스크립트만들기>를 클릭합니다. 스크립트 FaceAnalysis를 호출합니다.

  4. FaceAnalysis 스크립트를 두 번 클릭하여 Visual Studio 2017에서 엽니다.

  5. FaceAnalysis 클래스 위에 다음 네임스페이스를 입력합니다.

        using Newtonsoft.Json;
        using System.Collections;
        using System.Collections.Generic;
        using System.IO;
        using System.Text;
        using UnityEngine;
        using UnityEngine.Networking;
    
  6. 이제 역직렬화에 사용되는 모든 개체를 추가해야 합니다. 이러한 개체는 FaceAnalysis 스크립트 외부에 추가해야 합니다(아래쪽 중괄호 아래).

        /// <summary>
        /// The Person Group object
        /// </summary>
        public class Group_RootObject
        {
            public string personGroupId { get; set; }
            public string name { get; set; }
            public object userData { get; set; }
        }
    
        /// <summary>
        /// The Person Face object
        /// </summary>
        public class Face_RootObject
        {
            public string faceId { get; set; }
        }
    
        /// <summary>
        /// Collection of faces that needs to be identified
        /// </summary>
        public class FacesToIdentify_RootObject
        {
            public string personGroupId { get; set; }
            public List<string> faceIds { get; set; }
            public int maxNumOfCandidatesReturned { get; set; }
            public double confidenceThreshold { get; set; }
        }
    
        /// <summary>
        /// Collection of Candidates for the face
        /// </summary>
        public class Candidate_RootObject
        {
            public string faceId { get; set; }
            public List<Candidate> candidates { get; set; }
        }
    
        public class Candidate
        {
            public string personId { get; set; }
            public double confidence { get; set; }
        }
    
        /// <summary>
        /// Name and Id of the identified Person
        /// </summary>
        public class IdentifiedPerson_RootObject
        {
            public string personId { get; set; }
            public string name { get; set; }
        }
    
  7. Start()Update() 메서드는 사용되지 않으므로 지금 삭제합니다.

  8. FaceAnalysis 클래스 내에 다음 변수를 추가합니다.

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static FaceAnalysis Instance;
    
        /// <summary>
        /// The analysis result text
        /// </summary>
        private TextMesh labelText;
    
        /// <summary>
        /// Bytes of the image captured with camera
        /// </summary>
        internal byte[] imageBytes;
    
        /// <summary>
        /// Path of the image captured with camera
        /// </summary>
        internal string imagePath;
    
        /// <summary>
        /// Base endpoint of Face Recognition Service
        /// </summary>
        const string baseEndpoint = "https://westus.api.cognitive.microsoft.com/face/v1.0/";
    
        /// <summary>
        /// Auth key of Face Recognition Service
        /// </summary>
        private const string key = "- Insert your key here -";
    
        /// <summary>
        /// Id (name) of the created person group 
        /// </summary>
        private const string personGroupId = "- Insert your group Id here -";
    

    참고

    personGroupId를 서비스 키 및 이전에 만든 그룹의 ID로 바꿉니다.

  9. 클래스를 초기화하고 ImageCapture 클래스를 Main Camera에 추가하고 Label 만들기 메서드를 호출하는 Awake() 메서드를 추가합니다.

        /// <summary>
        /// Initialises this class
        /// </summary>
        private void Awake()
        {
            // Allows this instance to behave like a singleton
            Instance = this;
    
            // Add the ImageCapture Class to this Game Object
            gameObject.AddComponent<ImageCapture>();
    
            // Create the text label in the scene
            CreateLabel();
        }
    
  10. 분석 결과를 표시하는 Label 개체를 만드는 CreateLabel() 메서드를 추가합니다.

        /// <summary>
        /// Spawns cursor for the Main Camera
        /// </summary>
        private void CreateLabel()
        {
            // Create a sphere as new cursor
            GameObject newLabel = new GameObject();
    
            // Attach the label to the Main Camera
            newLabel.transform.parent = gameObject.transform;
    
            // Resize and position the new cursor
            newLabel.transform.localScale = new Vector3(0.4f, 0.4f, 0.4f);
            newLabel.transform.position = new Vector3(0f, 3f, 60f);
    
            // Creating the text of the Label
            labelText = newLabel.AddComponent<TextMesh>();
            labelText.anchor = TextAnchor.MiddleCenter;
            labelText.alignment = TextAlignment.Center;
            labelText.tabSize = 4;
            labelText.fontSize = 50;
            labelText.text = ".";       
        }
    
  11. DetectFacesFromImage()GetImageAsByteArray() 메서드를 추가합니다. 전자는 얼굴 인식 서비스에 제출된 이미지에서 가능한 얼굴을 감지하도록 요청하고, 후자는 캡처된 이미지를 바이트 배열로 변환해야 합니다.

        /// <summary>
        /// Detect faces from a submitted image
        /// </summary>
        internal IEnumerator DetectFacesFromImage()
        {
            WWWForm webForm = new WWWForm();
            string detectFacesEndpoint = $"{baseEndpoint}detect";
    
            // Change the image into a bytes array
            imageBytes = GetImageAsByteArray(imagePath);
    
            using (UnityWebRequest www = 
                UnityWebRequest.Post(detectFacesEndpoint, webForm))
            {
                www.SetRequestHeader("Ocp-Apim-Subscription-Key", key);
                www.SetRequestHeader("Content-Type", "application/octet-stream");
                www.uploadHandler.contentType = "application/octet-stream";
                www.uploadHandler = new UploadHandlerRaw(imageBytes);
                www.downloadHandler = new DownloadHandlerBuffer();
    
                yield return www.SendWebRequest();
                string jsonResponse = www.downloadHandler.text;
                Face_RootObject[] face_RootObject = 
                    JsonConvert.DeserializeObject<Face_RootObject[]>(jsonResponse);
    
                List<string> facesIdList = new List<string>();
                // Create a list with the face Ids of faces detected in image
                foreach (Face_RootObject faceRO in face_RootObject)
                {
                    facesIdList.Add(faceRO.faceId);
                    Debug.Log($"Detected face - Id: {faceRO.faceId}");
                }
    
                StartCoroutine(IdentifyFaces(facesIdList));
            }
        }
    
        /// <summary>
        /// Returns the contents of the specified file as a byte array.
        /// </summary>
        static byte[] GetImageAsByteArray(string imageFilePath)
        {
            FileStream fileStream = new FileStream(imageFilePath, FileMode.Open, FileAccess.Read);
            BinaryReader binaryReader = new BinaryReader(fileStream);
            return binaryReader.ReadBytes((int)fileStream.Length);
        }
    
  12. 제출된 이미지에서 이전에 감지된 알려진 얼굴을 식별하도록 얼굴 인식 서비스를 요청하는 IdentifyFaces() 메서드를 추가합니다. 요청은 식별된 사람의 ID를 반환하지만 이름은 반환하지 않습니다.

        /// <summary>
        /// Identify the faces found in the image within the person group
        /// </summary>
        internal IEnumerator IdentifyFaces(List<string> listOfFacesIdToIdentify)
        {
            // Create the object hosting the faces to identify
            FacesToIdentify_RootObject facesToIdentify = new FacesToIdentify_RootObject();
            facesToIdentify.faceIds = new List<string>();
            facesToIdentify.personGroupId = personGroupId;
            foreach (string facesId in listOfFacesIdToIdentify)
            {
                facesToIdentify.faceIds.Add(facesId);
            }
            facesToIdentify.maxNumOfCandidatesReturned = 1;
            facesToIdentify.confidenceThreshold = 0.5;
    
            // Serialize to Json format
            string facesToIdentifyJson = JsonConvert.SerializeObject(facesToIdentify);
            // Change the object into a bytes array
            byte[] facesData = Encoding.UTF8.GetBytes(facesToIdentifyJson);
    
            WWWForm webForm = new WWWForm();
            string detectFacesEndpoint = $"{baseEndpoint}identify";
    
            using (UnityWebRequest www = UnityWebRequest.Post(detectFacesEndpoint, webForm))
            {
                www.SetRequestHeader("Ocp-Apim-Subscription-Key", key);
                www.SetRequestHeader("Content-Type", "application/json");
                www.uploadHandler.contentType = "application/json";
                www.uploadHandler = new UploadHandlerRaw(facesData);
                www.downloadHandler = new DownloadHandlerBuffer();
    
                yield return www.SendWebRequest();
                string jsonResponse = www.downloadHandler.text;
                Debug.Log($"Get Person - jsonResponse: {jsonResponse}");
                Candidate_RootObject [] candidate_RootObject = JsonConvert.DeserializeObject<Candidate_RootObject[]>(jsonResponse);
    
                // For each face to identify that ahs been submitted, display its candidate
                foreach (Candidate_RootObject candidateRO in candidate_RootObject)
                {
                    StartCoroutine(GetPerson(candidateRO.candidates[0].personId));
    
                    // Delay the next "GetPerson" call, so all faces candidate are displayed properly
                    yield return new WaitForSeconds(3);
                }           
            }
        }
    
  13. GetPerson() 메서드를 추가합니다. 그런 다음, 이 메서드는 사용자 ID를 제공하여 얼굴 인식 서비스에 식별된 사람의 이름을 반환하도록 요청합니다.

        /// <summary>
        /// Provided a personId, retrieve the person name associated with it
        /// </summary>
        internal IEnumerator GetPerson(string personId)
        {
            string getGroupEndpoint = $"{baseEndpoint}persongroups/{personGroupId}/persons/{personId}?";
            WWWForm webForm = new WWWForm();
    
            using (UnityWebRequest www = UnityWebRequest.Get(getGroupEndpoint))
            {
                www.SetRequestHeader("Ocp-Apim-Subscription-Key", key);
                www.downloadHandler = new DownloadHandlerBuffer();
                yield return www.SendWebRequest();
                string jsonResponse = www.downloadHandler.text;
    
                Debug.Log($"Get Person - jsonResponse: {jsonResponse}");
                IdentifiedPerson_RootObject identifiedPerson_RootObject = JsonConvert.DeserializeObject<IdentifiedPerson_RootObject>(jsonResponse);
    
                // Display the name of the person in the UI
                labelText.text = identifiedPerson_RootObject.name;
            }
        }
    
  14. Unity 편집기로 돌아가기 전에 변경 내용을 저장 해야 합니다.

  15. Unity 편집기에서 FaceAnalysis 스크립트를 프로젝트 패널의 스크립트 폴더에서 계층 구조 패널의 Main Camera 개체로 끌어옵니다. 새 스크립트 구성 요소가 주 카메라에 추가됩니다.

주 카메라에 FaceAnalysis 배치

7장 - ImageCapture 클래스 만들기

ImageCapture 클래스의 목적은 Azure Face Recognition Service와 통신하는 데 필요한 메서드를 호스트하여 캡처할 이미지를 분석하고, 그 안에 있는 얼굴을 식별하고, 알려진 사람에게 속하는지 확인하는 것입니다. 알려진 사람이 발견되면 이 클래스는 해당 이름을 장면에 UI 텍스트로 표시합니다.

ImageCapture 클래스를 만들려면 다음을 수행합니다.

  1. 이전에 만든 Scripts 폴더 내부를 마우스 오른쪽 단추로 클릭한 다음 만들기, C# 스크립트를 클릭합니다. ImageCapture 스크립트를 호출합니다.

  2. ImageCapture 스크립트를 두 번 클릭하여 Visual Studio 2017에서 엽니다.

  3. ImageCapture 클래스 위에 다음 네임스페이스를 입력합니다.

        using System.IO;
        using System.Linq;
        using UnityEngine;
        using UnityEngine.XR.WSA.Input;
        using UnityEngine.XR.WSA.WebCam;
    
  4. ImageCapture 클래스 내에 다음 변수를 추가합니다.

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static ImageCapture instance;
    
        /// <summary>
        /// Keeps track of tapCounts to name the captured images 
        /// </summary>
        private int tapsCount;
    
        /// <summary>
        /// PhotoCapture object used to capture images on HoloLens 
        /// </summary>
        private PhotoCapture photoCaptureObject = null;
    
        /// <summary>
        /// HoloLens class to capture user gestures
        /// </summary>
        private GestureRecognizer recognizer;
    
  5. 클래스를 초기화하고 HoloLens가 사용자의 제스처를 캡처하도록 허용하는 데 필요한 Awake()Start() 메서드를 추가합니다.

        /// <summary>
        /// Initialises this class
        /// </summary>
        private void Awake()
        {
            instance = this;
        }
    
        /// <summary>
        /// Called right after Awake
        /// </summary>
        void Start()
        {
            // Initialises user gestures capture 
            recognizer = new GestureRecognizer();
            recognizer.SetRecognizableGestures(GestureSettings.Tap);
            recognizer.Tapped += TapHandler;
            recognizer.StartCapturingGestures();
        }
    
  6. 사용자가 제스처를 수행할 때 호출되는 TapHandler()를 추가합니다.

        /// <summary>
        /// Respond to Tap Input.
        /// </summary>
        private void TapHandler(TappedEventArgs obj)
        {
            tapsCount++;
            ExecuteImageCaptureAndAnalysis();
        }
    
  7. 이미지 캡처 프로세스를 시작하는 ExecuteImageCaptureAndAnalysis() 메서드를 추가합니다.

        /// <summary>
        /// Begin process of Image Capturing and send To Azure Computer Vision service.
        /// </summary>
        private void ExecuteImageCaptureAndAnalysis()
        {
            Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending
                ((res) => res.width * res.height).First();
            Texture2D targetTexture = new Texture2D(cameraResolution.width, cameraResolution.height);
    
            PhotoCapture.CreateAsync(false, delegate (PhotoCapture captureObject)
            {
                photoCaptureObject = captureObject;
    
                CameraParameters c = new CameraParameters();
                c.hologramOpacity = 0.0f;
                c.cameraResolutionWidth = targetTexture.width;
                c.cameraResolutionHeight = targetTexture.height;
                c.pixelFormat = CapturePixelFormat.BGRA32;
    
                captureObject.StartPhotoModeAsync(c, delegate (PhotoCapture.PhotoCaptureResult result)
                {
                    string filename = string.Format(@"CapturedImage{0}.jpg", tapsCount);
                    string filePath = Path.Combine(Application.persistentDataPath, filename);
    
                    // Set the image path on the FaceAnalysis class
                    FaceAnalysis.Instance.imagePath = filePath;
    
                    photoCaptureObject.TakePhotoAsync
                    (filePath, PhotoCaptureFileOutputFormat.JPG, OnCapturedPhotoToDisk);
                });
            });
        }
    
  8. 사진 캡처 프로세스가 완료되었을 때 호출되는 처리기를 추가합니다.

        /// <summary>
        /// Called right after the photo capture process has concluded
        /// </summary>
        void OnCapturedPhotoToDisk(PhotoCapture.PhotoCaptureResult result)
        {
            photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
        }
    
        /// <summary>
        /// Register the full execution of the Photo Capture. If successful, it will begin the Image Analysis process.
        /// </summary>
        void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
        {
            photoCaptureObject.Dispose();
            photoCaptureObject = null;
    
            // Request image caputer analysis
            StartCoroutine(FaceAnalysis.Instance.DetectFacesFromImage());
        }
    
  9. Unity 편집기로 돌아가기 전에 변경 내용을 저장 해야 합니다.

8장 - 솔루션 빌드

애플리케이션에 대한 철저한 테스트를 수행하려면 HoloLens에 테스트용으로 로드해야 합니다.

이렇게 하기 전에 다음을 확인합니다.

  • 챕터 3에 언급된 모든 설정이 올바르게 설정됩니다.
  • 스크립트 FaceAnalysis는 Main Camera 개체에 연결됩니다.
  • 인증 키그룹 ID는 모두 FaceAnalysis 스크립트 내에서 설정되었습니다.

이 점은 솔루션을 빌드할 준비가 된 것입니다. 솔루션이 빌드되면 애플리케이션을 배포할 준비가 됩니다.

빌드 프로세스를 시작하려면 다음을 수행합니다.

  1. 파일, 저장을 클릭하여 현재 장면을 저장합니다.

  2. 파일, 빌드 설정으로 이동하여 열린 장면 추가를 클릭합니다.

  3. Unity C# 프로젝트를 선택해야 합니다.

    Visual Studio 솔루션 배포

  4. 빌드를 누릅니다. 이렇게 하면 Unity에서 파일 탐색기 창을 시작하고, 여기서 앱을 빌드할 폴더를 선택해야 합니다. 이제 Unity 프로젝트 내에서 해당 폴더를 만들고 앱이라고 합니다. 그런 다음 앱 폴더를 선택한 상태에서 폴더 선택을 누릅니다.

  5. Unity는 App 폴더로 프로젝트 빌드를 시작합니다.

  6. Unity 빌드가 완료되면(다소 시간이 걸릴 수 있음) 빌드 위치에 파일 탐색기 창이 열립니다.

    Visual Studio에서 솔루션 배포

  7. App 폴더를 연 다음 새 프로젝트 솔루션(위와 같이 MR_FaceRecognition.sln)을 엽니다.

9장 - 애플리케이션 배포

HoloLens에 배포하려면 다음을 수행합니다.

  1. HoloLens의 IP 주소(원격 배포의 경우)가 필요하며 HoloLens가 개발자 모드에 있는지 확인해야 합니다. 가상 하드 디스크 파일에 대한 중요 정보를 제공하려면

    1. HoloLens를 착용하는 동안 설정을 엽니다.
    2. 네트워크 & 인터넷 > Wi-Fi > 고급 옵션으로 이동합니다.
    3. IPv4 주소를 기록해 둡니다.
    4. 다음으로 설정으로 다시 이동한 다음 개발자용 & 보안 > 업데이트로 이동합니다.
    5. 개발자 모드를 설정합니다.
  2. 새 Unity 빌드( App 폴더)로 이동하여 Visual Studio를 사용하여 솔루션 파일을 엽니다.

  3. 솔루션 구성에서 디버그를 선택합니다.

  4. 솔루션 플랫폼에서 x86, 원격 머신을 선택합니다.

    솔루션 구성 변경

  5. 빌드 메뉴로 이동하여 솔루션 배포를 클릭하여 HoloLens에 애플리케이션을 테스트용으로 로드합니다.

  6. 이제 시작 준비가 된 HoloLens에 설치된 앱 목록에 앱이 표시됩니다.

참고

몰입형 헤드셋에 배포하려면 솔루션 플랫폼을로컬 머신으로 설정하고 구성을디버그로 설정하고 x86플랫폼으로 설정합니다. 그런 다음 빌드 메뉴를 사용하여 로컬 머신에 배포하고 솔루션 배포를 선택합니다.

10장 - 애플리케이션 사용

  1. HoloLens를 착용하고 앱을 시작합니다.

  2. Face API에 등록한 사람을 확인합니다. 확인할 사항은 다음과 같습니다.

    • 사람의 얼굴은 너무 멀지 않고 명확하게 볼 수 있습니다.
    • 환경 조명이 너무 어둡지 않음
  3. 탭 제스처를 사용하여 사람의 사진을 캡처합니다.

  4. 앱이 분석 요청을 보내고 응답을 받을 때까지 기다립니다.

  5. 사용자가 성공적으로 인식되면 해당 사용자의 이름이 UI 텍스트로 표시됩니다.

  6. 몇 초마다 탭 제스처를 사용하여 캡처 프로세스를 반복할 수 있습니다.

완료된 Azure Face API 애플리케이션

축하합니다. Azure Face Recognition 서비스를 활용하여 이미지 내에서 얼굴을 감지하고 알려진 얼굴을 식별하는 혼합 현실 앱을 빌드했습니다.

이 과정을 완료한 결과

보너스 연습

연습 1

Azure Face API는 단일 이미지에서 최대 64개 얼굴을 감지할 수 있을 만큼 강력합니다. 다른 많은 사람들 사이에서 두세 개의 얼굴을 인식할 수 있도록 애플리케이션을 확장합니다.

연습 2

Azure Face API는 모든 종류의 특성 정보를 다시 제공할 수도 있습니다. 이를 애플리케이션에 통합합니다. Emotion API와 결합하면 더욱 흥미로울 수 있습니다.