Created
July 23, 2017 05:17
-
-
Save urahimono/6db84e7635f3625af6b9423f6cf62d40 to your computer and use it in GitHub Desktop.
【Unity】MicrosoftのFaceAPIを使って顔認識で遊んでみよう
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
[System.Serializable] | |
public class FaceData | |
{ | |
[SerializeField] | |
public FacePersonData[] persons = null; | |
} // class FaceData | |
[System.Serializable] | |
public class FacePersonData | |
{ | |
[SerializeField] | |
public string faceId = null; | |
[SerializeField] | |
public FaceRectangle faceRectangle = null; | |
[SerializeField] | |
public FaceLandmarks faceLandmarks = null; | |
[SerializeField] | |
public FaceAttributes faceAttributes = null; | |
} // class FacePersonData | |
[System.Serializable] | |
public class FaceRectangle | |
{ | |
[SerializeField] | |
public int top = 0; | |
[SerializeField] | |
public int left = 0; | |
[SerializeField] | |
public int width = 0; | |
[SerializeField] | |
public int height = 0; | |
} // class FaceRectangle | |
[System.Serializable] | |
public class FaceLandmarks | |
{ | |
[SerializeField] | |
public Vector2 pupilLeft = Vector2.zero; | |
[SerializeField] | |
public Vector2 pupilRight = Vector2.zero; | |
[SerializeField] | |
public Vector2 noseTip = Vector2.zero; | |
[SerializeField] | |
public Vector2 mouthLeft = Vector2.zero; | |
[SerializeField] | |
public Vector2 mouthRight = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyebrowLeftOuter = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyebrowLeftInner = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyeLeftOuter = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyeLeftTop = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyeLeftBottom = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyeLeftInner = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyebrowRightInner = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyebrowRightOuter = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyeRightInner = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyeRightTop = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyeRightBottom = Vector2.zero; | |
[SerializeField] | |
public Vector2 eyeRightOuter = Vector2.zero; | |
[SerializeField] | |
public Vector2 noseRootLeft = Vector2.zero; | |
[SerializeField] | |
public Vector2 noseRootRight = Vector2.zero; | |
[SerializeField] | |
public Vector2 noseLeftAlarTop = Vector2.zero; | |
[SerializeField] | |
public Vector2 noseRightAlarTop = Vector2.zero; | |
[SerializeField] | |
public Vector2 noseLeftAlarOutTip = Vector2.zero; | |
[SerializeField] | |
public Vector2 noseRightAlarOutTip = Vector2.zero; | |
[SerializeField] | |
public Vector2 upperLipTop = Vector2.zero; | |
[SerializeField] | |
public Vector2 upperLipBottom = Vector2.zero; | |
[SerializeField] | |
public Vector2 underLipTop = Vector2.zero; | |
[SerializeField] | |
public Vector2 underLipBottom = Vector2.zero; | |
} // class FaceLandmarks | |
[System.Serializable] | |
public class FaceAttributes | |
{ | |
[SerializeField] | |
public float age = 0.0f; | |
[SerializeField] | |
public string gender = null; | |
[SerializeField] | |
public float smile = 0.0f; | |
[SerializeField] | |
public FacialHair facialHair = null; | |
[SerializeField] | |
public HeadPose headPose = null; | |
[SerializeField] | |
public string glasses = null; | |
[SerializeField] | |
public Emotion emotion = null; | |
[SerializeField] | |
public Hair hair = null; | |
[SerializeField] | |
public Makeup makeup = null; | |
[SerializeField] | |
public Accessories[] accessories = null; | |
[SerializeField] | |
public Occlusion occlusion = null; | |
[SerializeField] | |
public Blur blur = null; | |
[SerializeField] | |
public Exposure exposure = null; | |
[SerializeField] | |
public Noise noise = null; | |
} // class FaceAttributes | |
[System.Serializable] | |
public class FacialHair | |
{ | |
[SerializeField] | |
public float moustache = 0.0f; | |
[SerializeField] | |
public float beard = 0.0f; | |
[SerializeField] | |
public float sideburns = 0.0f; | |
} // class FacialHair | |
[System.Serializable] | |
public class HeadPose | |
{ | |
[SerializeField] | |
public float pitch = 0.0f; | |
[SerializeField] | |
public float roll = 0.0f; | |
[SerializeField] | |
public float yaw = 0.0f; | |
} // class HeadPose | |
[System.Serializable] | |
public class Emotion | |
{ | |
[SerializeField] | |
public float anger = 0.0f; | |
[SerializeField] | |
public float contempt = 0.0f; | |
[SerializeField] | |
public float disgust = 0.0f; | |
[SerializeField] | |
public float fear = 0.0f; | |
[SerializeField] | |
public float happiness = 0.0f; | |
[SerializeField] | |
public float neutral = 0.0f; | |
[SerializeField] | |
public float sadness = 0.0f; | |
[SerializeField] | |
public float surprise = 0.0f; | |
} // class Emotion | |
[System.Serializable] | |
public class Hair | |
{ | |
[SerializeField] | |
public float bald = 0.0f; | |
[SerializeField] | |
public bool invisible = false; | |
[SerializeField] | |
public HairColor[] hairColor = null; | |
} // class Hair | |
[System.Serializable] | |
public class HairColor | |
{ | |
[SerializeField] | |
public string color = null; | |
[SerializeField] | |
public float confidence = 0.0f; | |
} // class HairColor | |
[System.Serializable] | |
public class Makeup | |
{ | |
[SerializeField] | |
public bool eyeMakeup = false; | |
[SerializeField] | |
public bool lipMakeup = false; | |
} // class Makeup | |
[System.Serializable] | |
public class Accessories | |
{ | |
[SerializeField] | |
public string type = null; | |
[SerializeField] | |
public float confidence = 0.0f; | |
} // class Accessories | |
[System.Serializable] | |
public class Occlusion | |
{ | |
[SerializeField] | |
public bool foreheadOccluded = false; | |
[SerializeField] | |
public bool eyeOccluded = false; | |
[SerializeField] | |
public bool mouthOccluded = false; | |
} // class Occlusion | |
[System.Serializable] | |
public class Blur | |
{ | |
[SerializeField] | |
public string blurLevel = null; | |
[SerializeField] | |
public float value = 0.0f; | |
} // class Blur | |
[System.Serializable] | |
public class Exposure | |
{ | |
[SerializeField] | |
public string exposureLevel = null; | |
[SerializeField] | |
public float value = 0.0f; | |
} // class Exposure | |
[System.Serializable] | |
public class Noise | |
{ | |
[SerializeField] | |
public string noiseLevel = null; | |
[SerializeField] | |
public float value = 0.0f; | |
} // class Noise | |
[System.Serializable] | |
public class FaceError | |
{ | |
[SerializeField] | |
public FaceErrorDetail error = null; | |
} // class FaceError | |
[System.Serializable] | |
public class FaceErrorDetail | |
{ | |
[SerializeField] | |
public string code = null; | |
[SerializeField] | |
public string message = null; | |
} // class FaceErrorDetail |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
public class TestFaceAPI : MonoBehaviour | |
{ | |
private enum ELocation | |
{ | |
WestUS, | |
EastUS2, | |
WestCentralUS, | |
WestEurope, | |
SoutheastAsia, | |
} | |
[System.Flags] | |
private enum EFaceAttributes | |
{ | |
age = 1 << 0, | |
gender = 1 << 1, | |
smile = 1 << 2, | |
facialHair = 1 << 3, | |
headPose = 1 << 4, | |
glasses = 1 << 5, | |
emotion = 1 << 6, | |
hair = 1 << 7, | |
makeup = 1 << 8, | |
accessories = 1 << 9, | |
occlusion = 1 << 10, | |
blur = 1 << 11, | |
exposure = 1 << 12, | |
noise = 1 << 13, | |
} | |
private enum EPostType | |
{ | |
Binary, | |
URL, | |
} | |
[SerializeField] | |
private string m_subscriptionKey = string.Empty; | |
[SerializeField] | |
private ELocation m_location = default( ELocation ); | |
[SerializeField] | |
private bool m_requestFaceId = true; | |
[SerializeField] | |
private bool m_requestFaceLandmarks = false; | |
[SerializeField, EnumFlags] | |
private EFaceAttributes m_requestFaceAttributes = 0; | |
[SerializeField] | |
private EPostType m_postType = default( EPostType ); | |
[SerializeField] | |
private Texture2D m_texture = null; | |
[SerializeField] | |
private string m_textureURL = null; | |
private IEnumerator Start() | |
{ | |
string url = GetFaceAPIURL(); | |
Dictionary<string, string> headers = null; | |
byte[] postData = null; | |
if( m_postType == EPostType.Binary ) | |
{ | |
headers = GetBinaryTypeHeader( m_subscriptionKey ); | |
postData = GetTextureBinary( m_texture ); | |
} | |
else | |
{ | |
headers = GetURTypeLHeader( m_subscriptionKey ); | |
postData = GetTextureURLBinary( m_textureURL ); | |
} | |
Debug.AssertFormat( postData != null && postData.Length > 0, "Postデータが不正です。" ); | |
string receivedJson = null; | |
using( WWW www = new WWW( url, postData, headers ) ) | |
{ | |
yield return www; | |
receivedJson = www.text; | |
} | |
FaceData faceData = ConvertJson( receivedJson ); | |
Debug.Log( JsonUtility.ToJson( faceData ) ); | |
} | |
private string GetFaceAPIURL() | |
{ | |
string localURL = GetLocationURL( m_location ); | |
string idField = GetFaceIdField( m_requestFaceId ); | |
string landmarksField = GetFaceLandmarksField( m_requestFaceLandmarks ); | |
string attributesField = GetFaceAttributesField( m_requestFaceAttributes ); | |
Debug.AssertFormat( !string.IsNullOrEmpty( localURL ), "不正な地域設定です。m_location={0}", m_location ); | |
return string.Format( "https://{0}.api.cognitive.microsoft.com/face/v1.0/detect{1}{2}{3}", localURL, idField, landmarksField, attributesField ); | |
} | |
private string GetLocationURL( ELocation i_location ) | |
{ | |
return i_location.ToString().ToLower(); | |
} | |
private string GetFaceIdField( bool i_flag ) | |
{ | |
return string.Format( "?returnFaceId={0}", i_flag ); | |
} | |
private string GetFaceLandmarksField( bool i_flag ) | |
{ | |
return string.Format( "&returnFaceLandmarks={0}", i_flag ); | |
} | |
private string GetFaceAttributesField( EFaceAttributes i_attributes ) | |
{ | |
string attributesStr = string.Empty; | |
foreach( EFaceAttributes attribute in System.Enum.GetValues( typeof( EFaceAttributes ) ) ) | |
{ | |
if( ( i_attributes & attribute ) != 0 ) | |
{ | |
attributesStr += string.Format( "{0},", attribute ); | |
} | |
} | |
if( string.IsNullOrEmpty( attributesStr ) ) | |
{ | |
return string.Empty; | |
} | |
// 最後の","はいらないので削除(もっといい方法があるような気がするけど……)。 | |
attributesStr = attributesStr.Remove( attributesStr.Length - 1 ); | |
return string.Format( "&returnFaceAttributes={0}", attributesStr ); | |
} | |
private Dictionary<string, string> GetBinaryTypeHeader( string i_key ) | |
{ | |
var header = new Dictionary<string, string>() | |
{ | |
{ "Content-Type", "application/octet-stream" }, | |
{ "Ocp-Apim-Subscription-Key", i_key }, | |
}; | |
return header; | |
} | |
private Dictionary<string, string> GetURTypeLHeader( string i_key ) | |
{ | |
var header = new Dictionary<string, string>() | |
{ | |
{ "Content-Type", "application/json; charset=UTF-8" }, | |
{ "Ocp-Apim-Subscription-Key", i_key }, | |
}; | |
return header; | |
} | |
private byte[] GetTextureBinary( Texture2D i_texture ) | |
{ | |
if( i_texture == null ) | |
{ | |
return null; | |
} | |
return i_texture.EncodeToPNG(); | |
} | |
private byte[] GetTextureURLBinary( string i_url ) | |
{ | |
if( string.IsNullOrEmpty( i_url ) ) | |
{ | |
return null; | |
} | |
string json = string.Format( "{{ \"url\":\"{0}\" }}", i_url ); | |
return System.Text.Encoding.UTF8.GetBytes( json ); | |
} | |
private FaceData ConvertJson( string i_json ) | |
{ | |
Debug.AssertFormat( !string.IsNullOrEmpty( i_json ), "Json情報が設定されていません。" ); | |
// Jsonデータがエラーの場合(もっといいエラーの判定があればいいんだけど……)。 | |
if( i_json.IndexOf( "error" ) > 0 ) | |
{ | |
FaceError faceError = null; | |
try | |
{ | |
faceError = JsonUtility.FromJson<FaceError>( i_json ); | |
} | |
catch( System.Exception ) | |
{ | |
faceError = new FaceError(); | |
} | |
Debug.LogWarningFormat( "顔情報の取得に失敗しているJson情報です。code={0}, message={1}", faceError.error.code, faceError.error.message ); | |
return null; | |
} | |
// 無理やりJsonUtilityで使える形に変更する。 | |
string json = string.Format( "{{\"persons\":{0}}}", i_json ); | |
FaceData faceData = null; | |
try | |
{ | |
faceData = JsonUtility.FromJson<FaceData>( json ); | |
} | |
catch( System.Exception i_exception ) | |
{ | |
Debug.LogWarningFormat( "Json情報をクラス情報へ変換することに失敗しました。exception={0}", i_exception ); | |
faceData = null; | |
} | |
return faceData; | |
} | |
} // class TestFaceAPI |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment