티스토리 뷰

반응형

Microsoft에서 제공하는 Cloud API를 사용해서 사진, 동영상 속의 얼굴 검출, 표정 인식, 음성인식 등을 연동해보려고 한다. Cloud API를 사용하려는 이유는 이미 지속적인 Machine Learning을 통해서 인식률 자체가 높아지고 있기 때문에 자체적으로 라리브러리를 가지고 학습시키는 경우보다 뛰어나다고 볼 수 있다.

# MS의 Cognitive Service

https://www.microsoft.com/cognitive-services

위 사이트에서 제공하는 Serivce API들은 Vision, Speech, Language, Knowledge, Search 등의 종류가 존재하는데 우선 Vision으로 제공하는 서비스들을 나열해 보면 아래와 같다.

* Computer Vision : 사진의 물체들를 감지해서 알려주는 서비스

* Content Moderator : 사진의 글자 인식 등

* Emotion : 사진의 얼굴표정을 인식해서 알려주는 서비스

* Face : 사진의 얼굴을 인식해서 알려주는 서비스

* Video : 영상 내의 움직임 등을 감지해서 알려주는 서비스로 다른 API와 달리 실시간 영상 Frame 기반으로 확인된다.

위 정도의 서비스만 가지고 현재 구현하려는 Home Automation 서비스를 구현가능하다는 판단아래 기본적으로 사진을 load하고 Cloud Service API와 연동하여 Vision 기능을 사용해보고자 한다.

# Subscription for Cloud Service API

https://www.microsoft.com/cognitive-services/en-US/subscriptions

Test를 위해서 4가지의 Service API에 가입하고 Key를 부여받았다. 우선 무료범위내로 가입하였는데, 'Show Quota'를 보니 Subscription 한 날부터 한달간 사용할 수 있는 듯 한데, 한달 후에도 사용할 수 있는지는 추가로 확인해봐야 겠다.

# 사진에서 얼굴 찾기

가장 기본적인 Test로 사진에서 얼굴 찾는 예제를 해보려고 한다. 미리 준비해 둔 사진을 로드하고, Face API를 호출해서 얼굴을 검출한 뒤, 사진에 얼굴 영역을 표시하도록 할 것이다. 

1. Nuget Package manager로 필요한 Package 설치

빈 UWP app을 생성한 뒤, Cloud에서 제공하는 Face API를 쉽게 사용하기 위해서 몇가지 필요한 Package가 있는데 아래 그림과 같다.

위에 추가로 몇개 더있지만 아래 3가지만 집중적으로 보면 된다.

- Microsft.ProjectOxford.Face : Face API Client Library to enrich your apps with Microsoft's state of-the-art cloud-based face algorithms.

- Newtosoft.Json : Json.NET is a popular high-performance JSON framework for .NET

- Win2D.uwp : An easy-to-use Windows Runtime API for immediate mode 2D graphics rendering.

쉽게 말해서 Cloud API를 사용하는 package, Cloud API가 REST API 형태의 JSON 형태이기 때문에 Newtonsoft.json이 필요하고, 사진의 Face 추출한뒤, 해당 영역을 2D로 그려주기 위한 Win2D.uwp Package 가 필요하다.

2. Package

App 내에서 Hardware 종속적인 기능들을 사용하기 위해서 설정하는 파일인 Package.appxmanifest 파일을 열어서 '웹캠'을 체크하고 저장한다.

3. MainPage.xaml 구성

UI 부분이 될 xaml 은 사진 한장을 로드해서 보여줄 것이기 때문에 Image tag를 이용해서 Asset에 include 한 사진파일을 이용한다. 나같은 경우 프로젝트의 Asset 폴더내에 20160509092907755236.jpg라는 사진을 이용했으며 Microsoft.Graphics.Canvas.UI.Xaml 라이브러리는 xaml 코드 내에 포함하여 Canvas 의 CanvasControl 사용할 것이다.

MainPage.xaml code snippet

<Page

    x:Class="CameraApp_Test.MainPage"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:local="using:CameraApp_Test"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:customCanvas="using:Microsoft.Graphics.Canvas.UI.Xaml"

    mc:Ignorable="d" RequestedTheme="Dark">


    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

        <Image Source="Assets/20160509092907755236.jpg" Stretch="None"/>

        <customCanvas:CanvasControl Draw="canvasControl_Draw" x:Name="CustomCanvas" />

    </Grid>

</Page>

using을 통해 Microsoft.Graphics.Canvas.UI.Xaml 을 include 하고 CanvasControl의 Draw를 통해 실제 cs 내에서 그려지는 코드를 삽입할 수 있다.

<필요한 Library>

 
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.UI.Xaml.Controls;
using Windows.Storage;
using Microsoft.ProjectOxford.Face;
using Microsoft.ProjectOxford.Face.Contract;
using Microsoft.Graphics.Canvas.UI.Xaml;
using Windows.UI;

<Static variable, main>

Cloud API를 Subscription 하게 되면 개인의 API Key가 생성되게 되는데 잘 기억했다가 FaceServiceClinet 객체를 생성시 key 값을 넣어서 생성해준다.

그리고 기본 지정한 이미지를 로드한다.

private readonly IFaceServiceClient faceServiceClient = new FaceServiceClient("<Your Face API Key>");
FaceRectangle[] _faceRectangles;
public MainPage()
{
    this.InitializeComponent();
    UploadAndDetectFaces("ms-appx:///Assets/StoreLogo.png");
}

<Upload 그리고 Detect Face>

20160509092907755236.jpg 라는 이미지를 로드하고 나서 이미지를 STream 데이터로 읽은뒤 Stream 데이터를 faceServiceClient.DetectAync라는 메소드를 통해서 Face API를 호출한다. REST API 로 동작하기 때문에 Request 후 Response 하여 faces.Select를 통해서 얻은 FaceRectangle에 대한 Array 값을 저장하여 Invalidate 라는 Canvas 메소드로 화면을 갱신해 준다. 

 
async void UploadAndDetectFaces(string imageFilePath)
{
   try
   {
        StorageFolder appInstalledFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
        StorageFolder assets = await appInstalledFolder.GetFolderAsync("Assets");
        var storageFile = await assets.GetFileAsync("20160509092907755236.jpg");
        var randomAccessStream = await storageFile.OpenReadAsync();
        using (Stream stream = randomAccessStream.AsStreamForRead())
       {
            //this is the fragment where face is recognized:
            var faces = await faceServiceClient.DetectAsync(stream);
            var faceRects = faces.Select(face => face.FaceRectangle);
            _faceRectangles = faceRects.ToArray();
            CustomCanvas.Invalidate();
       }
   }
   catch (Exception ex)
   {
       System.Diagnostics.Debug.WriteLine(ex.Message);
   }
}

<Detect 된 영역에 Draw 해주는 부분>

화면을 갱신해주는 메소드가 호출되면 연결되어 있는 실제 메소드가 호출되는데 작성한 코드는 아래와 같다. 미리 저장해 둔 array 값을 읽어서 Rectangle을 이미지 위에 빨간색으로 드로잉 한다.

void canvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args)
{
    if (_faceRectangles != null)
        if (_faceRectangles.Length > 0)
        {
            foreach (var faceRect in _faceRectangles)
            {
                args.DrawingSession.DrawRectangle(faceRect.Left, faceRect.Top, faceRect.Width, faceRect.Height, Colors.Red);
            }
        }
}

<실행결과>

트둥이들의 사진을 실험해보았고 사진 속에 있는 정연, 사나, 나연, 쯔위의 얼굴을 정확히 찾음을 볼 수 있다.

이 예제를 통해서 단순히 사진속의 얼굴을 찾는 API를 연동해보았지만 실제 제공하는 API는 더 다양하다. 기본적으로 Face를 Detect 하는 것 외에도 Find Similar, Group, Identify, Verify 등의 카테고리리로 나누어져 있는데, 차후 Home Automation Service 구축을 위해 Find Similar라는 기능은 이용해야 할 것 같다. 우선 오늘은 여기까지~!

반응형
댓글