이미지의 얼굴 식별하기

등록일시: 2017-12-12 08:00,  수정일시: 2017-12-12 08:00
조회수: 6,525
이 문서는 Cognitive Services 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.
본문에서는 알려진 인물들을 바탕으로 미리 생성해 놓은 인물 그룹을 사용해서, 알려지지 않은 얼굴을 식별하는 방법을 살펴봅니다.

본문에서는 알려진 인물들을 바탕으로 미리 생성해 놓은 인물 그룹을 사용해서, 알려지지 않은 얼굴을 식별하는 방법을 살펴봅니다. 본문의 예제는 Face API 클라이언트 라이브러리를 사용해서 C#으로 작성되었습니다.

개념

만약 본문에서 사용되는 다음의 개념들에 익숙하지 않다면, 언제든지 용어집의 정의를 참조하시기 바랍니다:

  • 얼굴 감지 (Face Detection)
  • 얼굴 식별 (Face Identify)
  • 인물 그룹 (Person Group)

준비

본문의 예제에서는 다음과 같은 기능들을 살펴봅니다:

  • 인물 그룹을 생성하는 방법 - 인물 그룹에는 알려진 사람들의 목록이 담깁니다.
  • 각 인물에 얼굴들을 배정하는 방법 - 이 얼굴들은 사람을 식별하는 기준으로 사용되므로, 포토 ID처럼 깨끗한 전면 얼굴 사진을 사용하는 것을 권장합니다. 동일한 인물의 얼굴이 담겨 있지만, 자세, 옷, 또는 헤어 스타일 등은 서로 다른 사진들의 모음을 사용하는 것이 좋습니다.

본문의 예제를 직접 수행해보려면, 여러 장의 사진을 준비해야 합니다:

  • 인물의 얼굴을 담고 있는 몇 장의 사진. 여기에서 Anna, Bill 그리고 Clare의 사진을 다운로드 받을 수 있습니다.
  • Anna, Bill 또는 Clare의 얼굴을 포함할 수도 있고 포함하지 않을 수도 있는, 신원 식별에 사용되는 일련의 테스트 사진들. 위의 링크에서 제공되는 몇 가지 예제 이미지를 사용해도 됩니다.

단계 1: API 호출 권한 부여하기

Face API를 호출할 때마다 구독 키가 필요합니다. 구독 키는 쿼리 문자열 매개 변수를 통해서 전달하거나 요청 헤더에 지정해야 합니다. 쿼리 문자열을 통해서 구독 키를 전달하는 방법은 Face - Detect API에 대한 다음의 요청 URL 사례를 참고하시기 바랍니다:

https://westus.api.cognitive.microsoft.com/face/v1.0/detect[?returnFaceId][&returnFaceLandmarks][&returnFaceAttributes]&subscription-key=<Your subscription key>

또는 HTTP 요청 헤더에 ocp-apim-subscription-key: <Your subscription key>와 같은 형태로 구독 키를 지정할 수도 있습니다. 클라이언트 라이브러리를 사용하는 경우에는 다음과 같이 FaceServiceClient 클래스의 생성자를 통해서 구독 키를 전달합니다:

faceServiceClient = new FaceServiceClient("Your subscription key");

구독 키는 Azure 관리 포털의 Marketplace 페이지에서 발급받을 수 있습니다. Cognitive Services 체험하기 페이지를 참고하시기 바랍니다.

단계 2: 인물 그룹 생성하기

이번 단계에서는 Anna, Bill 그리고 Chare, 이렇게 세 명이 포함된 "MyFriends"라는 이름의 인물 그룹을 생성합니다. 각각의 인물은 여러 개의 등록된 얼굴을 갖게 됩니다. 그리고 이렇게 등록되는 얼굴들은 이미지로부터 감지된 얼굴이어야 합니다. 모든 과정을 마치고 나면 다음 그림과 같은 인물 그룹이 생성될 것입니다:

HowToIdentify1

2.1 인물 그룹에 대한 인물 정의

인물은 식별의 기본 단위입니다. 인물에는 하나 이상의 알려진 얼굴이 등록될 수 있습니다. 인물 그룹은 인물들의 모음이며, 각 인물은 특정 인물 그룹 내부에 정의됩니다. 식별은 인물 그룹을 대상으로 수행됩니다. 따라서 작업은 먼저 인물 그룹을 생성한 다음, Anna, Bill, 그리고 Clare와 같은 인물을 생성하는 순으로 진행됩니다.

먼저, 새로운 인물 그룹을 생성해야 합니다. 이 작업은 Person Group - Create a Person Group API를 통해서 처리됩니다. 그리고 그에 대응하는 클라이언트 라이브러리 API는 FaceServiceClient 클래스의 CreatePersonGroupAsync 메서드입니다. 인물 그룹을 작성할 때 지정하는 그룹 ID는 각 구독에서 유일해야 하며, 다른 인물 그룹 관련 API를 사용해서 인물 그룹을 얻거나, 수정하거나, 또는 삭제할 때도 사용됩니다. 인물 그룹을 정의하고 나면 Person - Create a Person API를 사용해서 해당 인물 그룹에 인물을 정의할 수 있습니다. 대응하는 클라이언트 라이브러리의 메서드는 CreatePersonAsync 입니다. 마지막으로 인물이 생성되고 나면, 각각의 인물에 얼굴을 추가할 수 있습니다.

// Create an empty person group
string personGroupId = "myfriends";
await faceServiceClient.CreatePersonGroupAsync(personGroupId, "My Friends");

// Define Anna
CreatePersonResult friend1 = await faceServiceClient.CreatePersonAsync(
    // Id of the person group that the person belonged to
    personGroupId,    
    // Name of the person
    "Anna"            
);

// Define Bill and Clare in the same way

2.2 얼굴을 감지하고 올바른 인물에 등록하기

얼굴 감지 작업은 HTTP 요청 본문에 이미지 파일이 담긴 "POST" 웹 요청을 Face - Detect API에 전송하는 방식으로 수행됩니다. 클라이언트 라이브러리를 사용하는 경우에는 FaceServiceClient 클래스의 DetectAsync 메서드를 이용해서 얼굴 감지를 수행합니다.

감지된 각각의 얼굴은 Person – Add a Person Face API 호출을 통해서 원하는 특정 인물에 추가할 수 있습니다.

다음 코드는 이미지에서 얼굴을 감지하고, 이를 다시 인물에 추가하는 과정을 보여줍니다:

// Directory contains image files of Anna
const string friend1ImageDir = @"D:\Pictures\MyFriends\Anna\";

foreach (string imagePath in Directory.GetFiles(friend1ImageDir, "*.jpg"))
{
    using (Stream s = File.OpenRead(imagePath))
    {
        // Detect faces in the image and add to Anna
        await faceServiceClient.AddPersonFaceAsync(
            personGroupId, friend1.PersonId, s);
    }
}
// Do the same for Bill and Clare

이미지에 두 명 이상의 얼굴이 포함되어 있는 경우, 가장 큰 얼굴이 추가되므로 주의하시기 바랍니다. 필요한 경우, Person – Add a Person Face API의 targetFace 쿼리 문자열에 "targetFace=left,top,width,height" 형태의 문자열을 전달해서 다른 얼굴을 추가하거나, AddPersonFaceAsync 메서드의 targetFace 선택적 매개 변수를 지정해서 다른 얼굴을 추가할 수도 있습니다. 인물에 추가되는 각각의 얼굴에는 영구적인 고유한 얼굴 ID가 지정되며, 이 ID는 Person – Delete a Person Face API 및 Face – Identify API에서도 사용됩니다.

단계 3: 인물 그룹 훈련시키기

인물 그룹을 이용해서 신원을 확인하려면 먼저 인물 그룹을 훈련시켜야 합니다. 또한 인물을 추가하거나 제거한 후, 또는 등록된 얼굴이 편집된 인물이 존재하는 경우에도 다시 훈련시켜야 합니다. 훈련은 Person Group – Train Person Group API를 이용해서 수행합니다. 클라이언트 라이브러리를 사용할 경우, 간단히 TrainPersonGroupAsync 메서드를 호출하기만 하면 됩니다.

await faceServiceClient.TrainPersonGroupAsync(personGroupId);

훈련은 비동기 작업이라는 점에 주의하시기 바랍니다. TrainPersonGroupAsync 메서드가 반환된 뒤에도 훈련은 아직 완료되지 않았을 수 있습니다. 따라서 Person Group - Get Person Group Training Status API나 클라이언트 라이브러리의 GetPersonGroupTrainingStatusAsync 메서드를 이용해서 훈련 상태를 조회해야 합니다. 다음은 인물 그룹의 훈련이 끝날 때까지 대기하는 간단한 로직을 보여줍니다:

TrainingStatus trainingStatus = null;
while(true)
{
    trainingStatus = await faceServiceClient.GetPersonGroupTrainingStatusAsync(personGroupId);

    if (trainingStatus.Status != "running")
    {
        break;
    }

    await Task.Delay(1000);
}

단계 4: 정의된 인물 그룹을 대상으로 얼굴 식별하기

Face API는 식별 수행 시, 얼굴 그룹 내의 모든 얼굴을 대상으로 식별하고자 하는 얼굴과의 유사성을 계산하고, 대상 얼굴과 가장 비슷한 인물(들)을 반환합니다. 이 작업은 Face - Identify API나 클라이언트 라이브러리의 IdentifyAsync 메서드를 통해서 수행됩니다.

이전 단계에서 설명한 방법을 통해서 식별하고자 하는 대상 얼굴을 감지한 다음, 식별 API의 두 번째 인자로 식별된 얼굴 ID를 전달합니다. 한 번에 다수의 얼굴 ID를 식별할 수 있으며, 그 결과에는 모든 식별 결과가 포함됩니다. 기본적으로 식별 API는 대상 얼굴과 가장 일치하는 인물을 한 명만 반환합니다. 필요한 경우, maxNumOfCandidatesReturned 선택적 매개 변수를 전달해서 더 많은 후보를 반환하도록 지정할 수 있습니다.

다음 코드는 식별 과정을 보여줍니다:

string testImageFile = @"D:\Pictures\test_img1.jpg";

using (Stream s = File.OpenRead(testImageFile))
{
    var faces = await faceServiceClient.DetectAsync(s);
    var faceIds = faces.Select(face => face.FaceId).ToArray();

    var results = await faceServiceClient.IdentifyAsync(personGroupId, faceIds);
    foreach (var identifyResult in results)
    {
        Console.WriteLine("Result of face: {0}", identifyResult.FaceId);
        if (identifyResult.Candidates.Length == 0)
        {
            Console.WriteLine("No one identified");
        }
        else
        {
            // Get top 1 among all candidates returned
            var candidateId = identifyResult.Candidates[0].PersonId;
            var person = await faceServiceClient.GetPersonAsync(personGroupId, candidateId);
            Console.WriteLine("Identified as {0}", person.Name);
        }
    }
}

모든 단계를 완료하고 나면, 다른 얼굴들을 식별해볼 수도 있고, 얼굴을 감지하기 위해서 업로드한 이미지에 따라 Anna, Bill 또는 Clare의 얼굴이 올바르게 식별되는지 확인해볼 수도 있습니다. 다음 예제를 참고하시기 바랍니다:

HowToIdentify2

요약

본문에서는 인물 그룹을 생성하고 인물을 식별하는 과정을 살펴봤습니다. 다음은 지금까지 살펴보고 실제로 구현해본 기능들을 간단히 요약한 목록입니다: