Skip to content

Instantly share code, notes, and snippets.

@urahimono
Created July 23, 2017 05:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save urahimono/6db84e7635f3625af6b9423f6cf62d40 to your computer and use it in GitHub Desktop.
Save urahimono/6db84e7635f3625af6b9423f6cf62d40 to your computer and use it in GitHub Desktop.
【Unity】MicrosoftのFaceAPIを使って顔認識で遊んでみよう
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
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