update 1.0.6
This commit is contained in:
Родитель
77b1905165
Коммит
c71b4a68f5
|
@ -0,0 +1,192 @@
|
|||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FaceMaskExample
|
||||
{
|
||||
[CustomEditor(typeof(FaceMaskData))]
|
||||
public class FaceMaskDataEditor : Editor
|
||||
{
|
||||
SerializedProperty image;
|
||||
SerializedProperty isDynamicMode;
|
||||
SerializedProperty enableColorCorrection;
|
||||
SerializedProperty faceRect;
|
||||
SerializedProperty landmarkPoints;
|
||||
|
||||
bool isDrag = false;
|
||||
int currentPointID = -1;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
image = serializedObject.FindProperty("_image");
|
||||
isDynamicMode = serializedObject.FindProperty("isDynamicMode");
|
||||
enableColorCorrection = serializedObject.FindProperty("enableColorCorrection");
|
||||
faceRect = serializedObject.FindProperty("_faceRect");
|
||||
landmarkPoints = serializedObject.FindProperty("_landmarkPoints");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
Texture2D tex = image.objectReferenceValue as Texture2D;
|
||||
|
||||
// Draw image.
|
||||
if (tex != null)
|
||||
{
|
||||
GUILayout.Box(GUIContent.none, GUILayout.Width(tex.width), GUILayout.Height(tex.height));
|
||||
Rect imageRect = GUILayoutUtility.GetLastRect ();
|
||||
GUI.DrawTexture (imageRect, tex);
|
||||
|
||||
if (!isDynamicMode.boolValue) {
|
||||
// Draw face rect.
|
||||
DrawFaceRect (imageRect, faceRect.rectValue, Color.red);
|
||||
|
||||
// Draw landmark points.
|
||||
DrawFaceLandmark (imageRect, landmarkPoints, Color.green, Color.blue);
|
||||
|
||||
// Update mouse cursor.
|
||||
for (int i = 0; i < landmarkPoints.arraySize; i++) {
|
||||
Vector2 pt = landmarkPoints.GetArrayElementAtIndex (i).vector2Value;
|
||||
pt.x += imageRect.x;
|
||||
pt.y += imageRect.y;
|
||||
Rect r = new Rect (pt.x - 4, pt.y - 4, 8, 8);
|
||||
EditorGUIUtility.AddCursorRect (r, MouseCursor.MoveArrow);
|
||||
}
|
||||
|
||||
// Mouse event.
|
||||
if (Event.current.type == EventType.MouseDown) {
|
||||
Rect mousePosRect = new Rect (Event.current.mousePosition.x - 4, Event.current.mousePosition.y - 4, 8, 8);
|
||||
int id = GetPointID (imageRect, landmarkPoints, mousePosRect);
|
||||
if (id >= 0) {
|
||||
isDrag = true;
|
||||
currentPointID = id;
|
||||
}
|
||||
|
||||
Repaint ();
|
||||
}
|
||||
|
||||
if (Event.current.type == EventType.MouseDrag) {
|
||||
if (isDrag && currentPointID >= 0) {
|
||||
Vector2 newPt = new Vector2 (Event.current.mousePosition.x - imageRect.x, Event.current.mousePosition.y - imageRect.y);
|
||||
newPt.x = Mathf.Clamp (newPt.x, 0, tex.width);
|
||||
newPt.y = Mathf.Clamp (newPt.y, 0, tex.height);
|
||||
landmarkPoints.GetArrayElementAtIndex (currentPointID).vector2Value = newPt;
|
||||
|
||||
if (!imageRect.Contains (Event.current.mousePosition)) {
|
||||
isDrag = false;
|
||||
currentPointID = -1;
|
||||
}
|
||||
}
|
||||
|
||||
Repaint ();
|
||||
}
|
||||
|
||||
if (Event.current.type == EventType.MouseUp) {
|
||||
if (isDrag && currentPointID >= 0) {
|
||||
Vector2 newPt = new Vector2 (Event.current.mousePosition.x - imageRect.x, Event.current.mousePosition.y - imageRect.y);
|
||||
newPt.x = Mathf.Clamp (newPt.x, 0, tex.width);
|
||||
newPt.y = Mathf.Clamp (newPt.y, 0, tex.height);
|
||||
landmarkPoints.GetArrayElementAtIndex (currentPointID).vector2Value = newPt;
|
||||
}
|
||||
isDrag = false;
|
||||
currentPointID = -1;
|
||||
|
||||
Repaint ();
|
||||
}
|
||||
|
||||
if (currentPointID > -1 && currentPointID < landmarkPoints.arraySize) {
|
||||
Vector2 pt = landmarkPoints.GetArrayElementAtIndex (currentPointID).vector2Value;
|
||||
pt.x += imageRect.x;
|
||||
pt.y += imageRect.y;
|
||||
Handles.color = Color.yellow;
|
||||
Handles.DrawSolidDisc (pt, Vector3.forward, 3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display input field.
|
||||
EditorGUILayout.PropertyField(image);
|
||||
EditorGUILayout.PropertyField(isDynamicMode);
|
||||
EditorGUILayout.PropertyField(enableColorCorrection);
|
||||
EditorGUILayout.PropertyField(faceRect);
|
||||
EditorGUILayout.PropertyField(landmarkPoints, true);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void DrawFaceRect (Rect imageRect, Rect faceRect, Color color)
|
||||
{
|
||||
faceRect.x += imageRect.x; faceRect.y += imageRect.y;
|
||||
Handles.color = color;
|
||||
Handles.DrawSolidRectangleWithOutline(faceRect, new Color(0, 0, 0, 0), Color.white);
|
||||
}
|
||||
|
||||
private void DrawFaceLandmark (Rect imageRect, SerializedProperty landmarkPoints, Color lineColor, Color pointColor)
|
||||
{
|
||||
if (landmarkPoints.isArray && landmarkPoints.arraySize == 68) {
|
||||
|
||||
Handles.color = lineColor;
|
||||
|
||||
for (int i = 1; i <= 16; ++i)
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(i).vector2Value, landmarkPoints.GetArrayElementAtIndex(i-1).vector2Value);
|
||||
|
||||
for (int i = 28; i <= 30; ++i)
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(i).vector2Value, landmarkPoints.GetArrayElementAtIndex(i-1).vector2Value);
|
||||
|
||||
for (int i = 18; i <= 21; ++i)
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(i).vector2Value, landmarkPoints.GetArrayElementAtIndex(i-1).vector2Value);
|
||||
for (int i = 23; i <= 26; ++i)
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(i).vector2Value, landmarkPoints.GetArrayElementAtIndex(i-1).vector2Value);
|
||||
for (int i = 31; i <= 35; ++i)
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(i).vector2Value, landmarkPoints.GetArrayElementAtIndex(i-1).vector2Value);
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(30).vector2Value, landmarkPoints.GetArrayElementAtIndex(35).vector2Value);
|
||||
|
||||
for (int i = 37; i <= 41; ++i)
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(i).vector2Value, landmarkPoints.GetArrayElementAtIndex(i-1).vector2Value);
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(36).vector2Value, landmarkPoints.GetArrayElementAtIndex(41).vector2Value);
|
||||
|
||||
for (int i = 43; i <= 47; ++i)
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(i).vector2Value, landmarkPoints.GetArrayElementAtIndex(i-1).vector2Value);
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(42).vector2Value, landmarkPoints.GetArrayElementAtIndex(47).vector2Value);
|
||||
|
||||
for (int i = 49; i <= 59; ++i)
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(i).vector2Value, landmarkPoints.GetArrayElementAtIndex(i-1).vector2Value);
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(48).vector2Value, landmarkPoints.GetArrayElementAtIndex(59).vector2Value);
|
||||
|
||||
for (int i = 61; i <= 67; ++i)
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(i).vector2Value, landmarkPoints.GetArrayElementAtIndex(i-1).vector2Value);
|
||||
DrawLine(imageRect, landmarkPoints.GetArrayElementAtIndex(60).vector2Value, landmarkPoints.GetArrayElementAtIndex(67).vector2Value);
|
||||
|
||||
// Draw Points.
|
||||
Handles.color = pointColor;
|
||||
for (int i = 0; i < landmarkPoints.arraySize; i++) {
|
||||
Vector2 pt = landmarkPoints.GetArrayElementAtIndex(i).vector2Value;
|
||||
pt.x += imageRect.x; pt.y += imageRect.y;
|
||||
Handles.DrawSolidDisc(pt, Vector3.forward, 2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawLine (Rect imageRect, Vector2 pt1, Vector2 pt2)
|
||||
{
|
||||
pt1.x += imageRect.x; pt1.y += imageRect.y;
|
||||
pt2.x += imageRect.x; pt2.y += imageRect.y;
|
||||
Handles.DrawLine (pt1, pt2);
|
||||
}
|
||||
|
||||
private int GetPointID (Rect imageRect, SerializedProperty landmarkPoints, Rect rect)
|
||||
{
|
||||
if (landmarkPoints.isArray && landmarkPoints.arraySize == 68) {
|
||||
for (int i = 0; i < landmarkPoints.arraySize; i++) {
|
||||
Vector2 pt = landmarkPoints.GetArrayElementAtIndex(i).vector2Value;
|
||||
pt.x += imageRect.x; pt.y += imageRect.y;
|
||||
if (rect.Contains(pt))
|
||||
return i;
|
||||
}
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7c80dd142a6fcc744a2f10f3a3aa4d49
|
||||
timeCreated: 1483125206
|
||||
guid: 8a88c11434a86fc40aaa5fcbcb8a0e17
|
||||
timeCreated: 1525011094
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
|
@ -342,7 +342,7 @@ namespace FaceMaskExample
|
|||
}
|
||||
|
||||
TextureImporter importer = TextureImporter.GetAtPath (alphaMaskTexturePath) as TextureImporter;
|
||||
importer.textureType = TextureImporterType.Advanced;
|
||||
importer.textureType = TextureImporterType.Default;
|
||||
importer.mipmapEnabled = false;
|
||||
importer.wrapMode = TextureWrapMode.Clamp;
|
||||
importer.maxTextureSize = 1024;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEngine.UI;
|
||||
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
using UnityEngine.SceneManagement;
|
||||
|
@ -12,10 +13,48 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
public class FaceMaskExample : MonoBehaviour
|
||||
{
|
||||
public Text exampleTitle;
|
||||
public Text versionInfo;
|
||||
public ScrollRect scrollRect;
|
||||
static float verticalNormalizedPosition = 1f;
|
||||
|
||||
// Use this for initialization
|
||||
void Start ()
|
||||
{
|
||||
exampleTitle.text = "FaceMask Example " + Application.version;
|
||||
|
||||
versionInfo.text = OpenCVForUnity.Core.NATIVE_LIBRARY_NAME + " " + OpenCVForUnity.Utils.getVersion () + " (" + OpenCVForUnity.Core.VERSION + ")";
|
||||
versionInfo.text += " / " + "dlibfacelandmarkdetector" + " " + DlibFaceLandmarkDetector.Utils.getVersion ();
|
||||
versionInfo.text += " / UnityEditor " + Application.unityVersion;
|
||||
versionInfo.text += " / ";
|
||||
|
||||
#if UNITY_EDITOR
|
||||
versionInfo.text += "Editor";
|
||||
#elif UNITY_STANDALONE_WIN
|
||||
versionInfo.text += "Windows";
|
||||
#elif UNITY_STANDALONE_OSX
|
||||
versionInfo.text += "Mac OSX";
|
||||
#elif UNITY_STANDALONE_LINUX
|
||||
versionInfo.text += "Linux";
|
||||
#elif UNITY_ANDROID
|
||||
versionInfo.text += "Android";
|
||||
#elif UNITY_IOS
|
||||
versionInfo.text += "iOS";
|
||||
#elif UNITY_WSA
|
||||
versionInfo.text += "WSA";
|
||||
#elif UNITY_WEBGL
|
||||
versionInfo.text += "WebGL";
|
||||
#endif
|
||||
versionInfo.text += " ";
|
||||
#if ENABLE_MONO
|
||||
versionInfo.text += "Mono";
|
||||
#elif ENABLE_IL2CPP
|
||||
versionInfo.text += "IL2CPP";
|
||||
#elif ENABLE_DOTNET
|
||||
versionInfo.text += ".NET";
|
||||
#endif
|
||||
|
||||
scrollRect.verticalNormalizedPosition = verticalNormalizedPosition;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
|
@ -24,6 +63,12 @@ namespace FaceMaskExample
|
|||
|
||||
}
|
||||
|
||||
public void OnScrollRectValueChanged ()
|
||||
{
|
||||
verticalNormalizedPosition = scrollRect.verticalNormalizedPosition;
|
||||
}
|
||||
|
||||
|
||||
public void OnShowLicenseButtonClick ()
|
||||
{
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
|
|
|
@ -116,6 +116,9 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: facc282ddcd086e46a52c5e4dee1cb0e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
exampleTitle: {fileID: 1369632056}
|
||||
versionInfo: {fileID: 942732235}
|
||||
scrollRect: {fileID: 976017885}
|
||||
--- !u!81 &96283526
|
||||
AudioListener:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -390,6 +393,7 @@ GameObject:
|
|||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 224: {fileID: 537841981}
|
||||
- 114: {fileID: 537841982}
|
||||
m_Layer: 5
|
||||
m_Name: SceneList
|
||||
m_TagString: Untagged
|
||||
|
@ -411,13 +415,31 @@ RectTransform:
|
|||
m_Children:
|
||||
- {fileID: 976017881}
|
||||
- {fileID: 235587656}
|
||||
m_Father: {fileID: 1488394138}
|
||||
m_RootOrder: 0
|
||||
m_Father: {fileID: 1661287683}
|
||||
m_RootOrder: 2
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: -10}
|
||||
m_SizeDelta: {x: -20, y: -20}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 1}
|
||||
--- !u!114 &537841982
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 537841980}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 1679637790, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: -1
|
||||
m_FlexibleWidth: -1
|
||||
m_FlexibleHeight: 1
|
||||
--- !u!1 &542799650
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -451,7 +473,7 @@ RectTransform:
|
|||
m_Children:
|
||||
- {fileID: 1149847639}
|
||||
m_Father: {fileID: 1339781662}
|
||||
m_RootOrder: 2
|
||||
m_RootOrder: 3
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
|
@ -641,6 +663,58 @@ CanvasRenderer:
|
|||
type: 2}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 629095086}
|
||||
--- !u!1 &683672275
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 224: {fileID: 683672276}
|
||||
- 114: {fileID: 683672277}
|
||||
m_Layer: 0
|
||||
m_Name: Spacer
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &683672276
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 683672275}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1339781662}
|
||||
m_RootOrder: 1
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &683672277
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 683672275}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 1679637790, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: 5
|
||||
m_FlexibleWidth: -1
|
||||
m_FlexibleHeight: -1
|
||||
--- !u!1 &707767032
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -676,6 +750,80 @@ RectTransform:
|
|||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: -20, y: -20}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!1 &942732233
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 224: {fileID: 942732234}
|
||||
- 222: {fileID: 942732236}
|
||||
- 114: {fileID: 942732235}
|
||||
m_Layer: 5
|
||||
m_Name: VersionInfo
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &942732234
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 942732233}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1.1062992, y: 1.1062992, z: 1}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1661287683}
|
||||
m_RootOrder: 1
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &942732235
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 942732233}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
|
||||
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 14
|
||||
m_FontStyle: 0
|
||||
m_BestFit: 0
|
||||
m_MinSize: 1
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text:
|
||||
--- !u!222 &942732236
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 942732233}
|
||||
--- !u!1 &976017880
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -1350,6 +1498,7 @@ RectTransform:
|
|||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children:
|
||||
- {fileID: 1088752999}
|
||||
- {fileID: 683672276}
|
||||
- {fileID: 1775689014}
|
||||
- {fileID: 542799651}
|
||||
- {fileID: 1718137805}
|
||||
|
@ -1396,6 +1545,80 @@ MonoBehaviour:
|
|||
m_EditorClassIdentifier:
|
||||
m_HorizontalFit: 0
|
||||
m_VerticalFit: 2
|
||||
--- !u!1 &1369632055
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 224: {fileID: 1369632058}
|
||||
- 222: {fileID: 1369632057}
|
||||
- 114: {fileID: 1369632056}
|
||||
m_Layer: 5
|
||||
m_Name: ExampleTitle
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1369632056
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 1369632055}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
|
||||
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_FontData:
|
||||
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_FontSize: 22
|
||||
m_FontStyle: 1
|
||||
m_BestFit: 0
|
||||
m_MinSize: 2
|
||||
m_MaxSize: 40
|
||||
m_Alignment: 4
|
||||
m_AlignByGeometry: 0
|
||||
m_RichText: 1
|
||||
m_HorizontalOverflow: 0
|
||||
m_VerticalOverflow: 0
|
||||
m_LineSpacing: 1
|
||||
m_Text: FaceMask Example
|
||||
--- !u!222 &1369632057
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 1369632055}
|
||||
--- !u!224 &1369632058
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 1369632055}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1.1062992, y: 1.1062992, z: 1}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1661287683}
|
||||
m_RootOrder: 0
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!1 &1488394137
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -1426,7 +1649,7 @@ RectTransform:
|
|||
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children:
|
||||
- {fileID: 537841981}
|
||||
- {fileID: 1661287683}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
|
@ -1493,6 +1716,63 @@ Canvas:
|
|||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
m_TargetDisplay: 0
|
||||
--- !u!1 &1661287682
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 224: {fileID: 1661287683}
|
||||
- 114: {fileID: 1661287684}
|
||||
m_Layer: 5
|
||||
m_Name: Panel
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1661287683
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 1661287682}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children:
|
||||
- {fileID: 1369632058}
|
||||
- {fileID: 942732234}
|
||||
- {fileID: 537841981}
|
||||
m_Father: {fileID: 1488394138}
|
||||
m_RootOrder: 0
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: -20, y: -20}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1661287684
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 1661287682}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 1297475563, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Padding:
|
||||
m_Left: 0
|
||||
m_Right: 0
|
||||
m_Top: 0
|
||||
m_Bottom: 0
|
||||
m_ChildAlignment: 0
|
||||
m_Spacing: 10
|
||||
m_ChildForceExpandWidth: 1
|
||||
m_ChildForceExpandHeight: 0
|
||||
--- !u!1 &1718137804
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -1526,7 +1806,7 @@ RectTransform:
|
|||
m_Children:
|
||||
- {fileID: 1097508684}
|
||||
m_Father: {fileID: 1339781662}
|
||||
m_RootOrder: 3
|
||||
m_RootOrder: 4
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
|
@ -1672,7 +1952,7 @@ RectTransform:
|
|||
m_Children:
|
||||
- {fileID: 1266655927}
|
||||
m_Father: {fileID: 1339781662}
|
||||
m_RootOrder: 1
|
||||
m_RootOrder: 2
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
|
@ -1818,7 +2098,7 @@ RectTransform:
|
|||
m_Children:
|
||||
- {fileID: 629095087}
|
||||
m_Father: {fileID: 1339781662}
|
||||
m_RootOrder: 4
|
||||
m_RootOrder: 5
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
|
|
|
@ -15,8 +15,8 @@ Mesh:
|
|||
firstVertex: 0
|
||||
vertexCount: 68
|
||||
localAABB:
|
||||
m_Center: {x: .001953125, y: -.16015625, z: 0}
|
||||
m_Extent: {x: .2734375, y: .287109375, z: 0}
|
||||
m_Center: {x: 0.001953125, y: -0.16015625, z: 0}
|
||||
m_Extent: {x: 0.2734375, y: 0.28710938, z: 0}
|
||||
m_Shapes:
|
||||
vertices: []
|
||||
shapes: []
|
||||
|
@ -122,8 +122,8 @@ Mesh:
|
|||
m_BitSize: 0
|
||||
m_UVInfo: 0
|
||||
m_LocalAABB:
|
||||
m_Center: {x: .001953125, y: -.16015625, z: 0}
|
||||
m_Extent: {x: .2734375, y: .287109375, z: 0}
|
||||
m_Center: {x: 0.001953125, y: -0.16015625, z: 0}
|
||||
m_Extent: {x: 0.2734375, y: 0.28710938, z: 0}
|
||||
m_MeshUsageFlags: 0
|
||||
m_BakedConvexCollisionMesh:
|
||||
m_BakedTriangleCollisionMesh:
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 67f7db10ac869ee479d4495c3d7af34d
|
||||
timeCreated: 1501330981
|
||||
timeCreated: 1527248034
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 4300000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
Двоичные данные
Assets/FaceMaskExample/FaceMaskPrefab/FaceMaskAlphaMask.png
Двоичные данные
Assets/FaceMaskExample/FaceMaskPrefab/FaceMaskAlphaMask.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 21 KiB После Ширина: | Высота: | Размер: 21 KiB |
|
@ -1,15 +1,15 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 470faf94133e4a741bb9abe37e1dfb1f
|
||||
timeCreated: 1501330981
|
||||
timeCreated: 1527248034
|
||||
licenseType: Free
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
serializedVersion: 4
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
|
@ -17,14 +17,12 @@ TextureImporter:
|
|||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 13
|
||||
maxTextureSize: 1024
|
||||
|
@ -35,20 +33,35 @@ TextureImporter:
|
|||
wrapMode: 1
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 0
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 0
|
||||
textureShape: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
platformSettings:
|
||||
- buildTarget: DefaultTexturePlatform
|
||||
maxTextureSize: 1024
|
||||
textureFormat: -1
|
||||
textureCompression: 0
|
||||
compressionQuality: 50
|
||||
crunchedCompression: 0
|
||||
allowsAlphaSplitting: 0
|
||||
overridden: 0
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
|
|
|
@ -2,39 +2,36 @@
|
|||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 5
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: FaceMaskMaterial
|
||||
m_Shader: {fileID: 4800000, guid: 007b092c44f554a4698c59144e1a2b7f, type: 3}
|
||||
m_ShaderKeywords:
|
||||
m_LightmapFlags: 5
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_SavedProperties:
|
||||
serializedVersion: 2
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
data:
|
||||
first:
|
||||
name: _MainTex
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _MaskTex
|
||||
second:
|
||||
m_Texture: {fileID: 2800000, guid: 470faf94133e4a741bb9abe37e1dfb1f, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _LUTTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MaskTex:
|
||||
m_Texture: {fileID: 2800000, guid: 470faf94133e4a741bb9abe37e1dfb1f, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
data:
|
||||
first:
|
||||
name: _Fade
|
||||
second: 0
|
||||
- _ColorCorrection: 0
|
||||
- _Fade: 0
|
||||
m_Colors:
|
||||
data:
|
||||
first:
|
||||
name: _Color
|
||||
second: {r: .5, g: .5, b: .5, a: .5}
|
||||
- _Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.5}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c59ad3a6597e0af4f9c488d7b05cc590
|
||||
timeCreated: 1501330981
|
||||
guid: 61fa2fcb482ca224e991e0be29d75304
|
||||
timeCreated: 1527248034
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
|
@ -1,90 +1,5 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &182672
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 494784}
|
||||
- 33: {fileID: 3348782}
|
||||
- 64: {fileID: 6490466}
|
||||
- 23: {fileID: 2328594}
|
||||
- 114: {fileID: 11403932}
|
||||
m_Layer: 0
|
||||
m_Name: FaceMaskTrackedMesh
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &494784
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 182672}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
--- !u!23 &2328594
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 182672}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: c59ad3a6597e0af4f9c488d7b05cc590, type: 2}
|
||||
m_SubsetIndices:
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_UseLightProbes: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_PreserveUVs: 0
|
||||
m_ImportantGI: 0
|
||||
m_AutoUVMaxDistance: .5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!33 &3348782
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 182672}
|
||||
m_Mesh: {fileID: 4300000, guid: 67f7db10ac869ee479d4495c3d7af34d, type: 2}
|
||||
--- !u!64 &6490466
|
||||
MeshCollider:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 182672}
|
||||
m_Material: {fileID: 0}
|
||||
m_IsTrigger: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_Convex: 0
|
||||
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!114 &11403932
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 182672}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: c47754ddde934e14c95f9de06ad6413d, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
|
@ -94,5 +9,101 @@ Prefab:
|
|||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 182672}
|
||||
m_RootGameObject: {fileID: 1138294731141240}
|
||||
m_IsPrefabParent: 1
|
||||
--- !u!1 &1138294731141240
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 5
|
||||
m_Component:
|
||||
- component: {fileID: 4506640658691720}
|
||||
- component: {fileID: 33613210590286308}
|
||||
- component: {fileID: 64714649276791744}
|
||||
- component: {fileID: 23122890318565152}
|
||||
- component: {fileID: 114248784669247606}
|
||||
m_Layer: 0
|
||||
m_Name: FaceMaskTrackedMesh
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4506640658691720
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1138294731141240}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!23 &23122890318565152
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1138294731141240}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 61fa2fcb482ca224e991e0be29d75304, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!33 &33613210590286308
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1138294731141240}
|
||||
m_Mesh: {fileID: 4300000, guid: 67f7db10ac869ee479d4495c3d7af34d, type: 2}
|
||||
--- !u!64 &64714649276791744
|
||||
MeshCollider:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1138294731141240}
|
||||
m_Material: {fileID: 0}
|
||||
m_IsTrigger: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_Convex: 0
|
||||
m_InflateMesh: 0
|
||||
m_SkinWidth: 0.01
|
||||
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
|
||||
--- !u!114 &114248784669247606
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 1138294731141240}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: c47754ddde934e14c95f9de06ad6413d, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
|
|
|
@ -5,6 +5,9 @@ Properties
|
|||
_MaskTex ("Mask", 2D) = "white" {}
|
||||
_Color ("Color", Color) = (0.5, 0.5, 0.5, 0.5)
|
||||
_Fade ("Fade", Range(0,1)) = 0
|
||||
|
||||
_ColorCorrection ("ColorCorrection", Range(0,1)) = 0
|
||||
_LUTTex ("LUTTex", 2D) = "black" {}
|
||||
}
|
||||
|
||||
SubShader
|
||||
|
@ -34,6 +37,9 @@ Properties
|
|||
float4 _Color;
|
||||
float _Fade;
|
||||
|
||||
float _ColorCorrection;
|
||||
sampler2D _LUTTex;
|
||||
|
||||
struct appdata_t
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
|
@ -50,21 +56,36 @@ Properties
|
|||
|
||||
float4 _MainTex_ST;
|
||||
float4 _MaskTex_ST;
|
||||
float4 _LUTTex_ST;
|
||||
|
||||
v2f vert (appdata_t v)
|
||||
{
|
||||
v2f o;
|
||||
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
|
||||
o.pos = UnityObjectToClipPos(v.vertex);
|
||||
o.uv1 = TRANSFORM_TEX(v.texcoord, _MainTex);
|
||||
o.uv2 = TRANSFORM_TEX(v.texcoord1, _MaskTex);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
half4 frag (v2f i) : COLOR
|
||||
{
|
||||
half4 base = tex2D(_MainTex, i.uv1) * (_Color * 2.0f);
|
||||
half4 base = tex2D(_MainTex, i.uv1);
|
||||
half4 mask = tex2D (_MaskTex, i.uv2);
|
||||
|
||||
if (_ColorCorrection > 0)
|
||||
{
|
||||
float w = base.w;
|
||||
float3 lut_base;
|
||||
|
||||
lut_base.r = tex2D(_LUTTex, float2(base.r, 0)).r;
|
||||
lut_base.g = tex2D(_LUTTex, float2(base.g, 0)).g;
|
||||
lut_base.b = tex2D(_LUTTex, float2(base.b, 0)).b;
|
||||
|
||||
base = half4(lerp(base.rgb, lut_base.rgb, _ColorCorrection), w);
|
||||
}
|
||||
|
||||
base = base * (_Color * 2.0f);
|
||||
|
||||
base.w = base.w * mask.x * mask.x * mask.x * (1 - _Fade);
|
||||
return base;
|
||||
}
|
||||
|
|
Двоичные данные
Assets/FaceMaskExample/ReadMe.pdf
Двоичные данные
Assets/FaceMaskExample/ReadMe.pdf
Двоичный файл не отображается.
|
@ -8,9 +8,9 @@ namespace OpenCVForUnity.RectangleTrack
|
|||
/// <summary>
|
||||
/// Rectangle tracker.
|
||||
/// Referring to https://github.com/Itseez/opencv/blob/master/modules/objdetect/src/detection_based_tracker.cpp.
|
||||
/// v 1.0.1
|
||||
/// v 1.0.2
|
||||
/// </summary>
|
||||
public class RectangleTracker : IDisposable
|
||||
public class RectangleTracker
|
||||
{
|
||||
public List<TrackedObject> trackedObjects
|
||||
{
|
||||
|
|
|
@ -1,237 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FaceMaskExample
|
||||
{
|
||||
public static class ExampleDataSet
|
||||
{
|
||||
public static int index
|
||||
{
|
||||
get { return _index; }
|
||||
}
|
||||
static int _index = 0;
|
||||
|
||||
public static int length
|
||||
{
|
||||
get { return filenames.Length; }
|
||||
}
|
||||
|
||||
static string[] filenames = new string[5]{
|
||||
"face_mask1",
|
||||
"face_mask2",
|
||||
"face_mask3",
|
||||
"face_mask4",
|
||||
"face_mask5"
|
||||
};
|
||||
|
||||
static Rect[] faceRcts = new Rect[5]{
|
||||
new Rect(),
|
||||
new Rect(),
|
||||
new Rect(),
|
||||
//panda
|
||||
new Rect(17, 64, 261, 205),
|
||||
//anime
|
||||
new Rect(56, 85, 190, 196)
|
||||
};
|
||||
|
||||
static List<Vector2>[] landmarkPoints = new List<Vector2>[5]{
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
//panda
|
||||
new List<Vector2>(){
|
||||
new Vector2(31, 136),
|
||||
new Vector2(23, 169),
|
||||
new Vector2(26, 195),
|
||||
new Vector2(35, 216),
|
||||
new Vector2(53, 236),
|
||||
new Vector2(71, 251),
|
||||
new Vector2(96, 257),
|
||||
new Vector2(132, 259),
|
||||
new Vector2(143, 263),
|
||||
//9
|
||||
new Vector2(165, 258),
|
||||
new Vector2(198, 255),
|
||||
new Vector2(222, 242),
|
||||
new Vector2(235, 231),
|
||||
new Vector2(248, 215),
|
||||
new Vector2(260, 195),
|
||||
new Vector2(272, 171),
|
||||
new Vector2(264, 135),
|
||||
//17
|
||||
new Vector2(45, 115),
|
||||
new Vector2(70, 94),
|
||||
new Vector2(97, 89),
|
||||
new Vector2(116, 90),
|
||||
new Vector2(135, 105),
|
||||
new Vector2(157, 104),
|
||||
new Vector2(176, 90),
|
||||
new Vector2(198, 86),
|
||||
new Vector2(223, 90),
|
||||
new Vector2(248, 110),
|
||||
//27
|
||||
new Vector2(148, 134),
|
||||
new Vector2(147, 152),
|
||||
new Vector2(145, 174),
|
||||
new Vector2(144, 192),
|
||||
new Vector2(117, 205),
|
||||
new Vector2(128, 213),
|
||||
new Vector2(143, 216),
|
||||
new Vector2(160, 216),
|
||||
new Vector2(174, 206),
|
||||
//36
|
||||
new Vector2(96, 138),
|
||||
new Vector2(101, 131),
|
||||
new Vector2(111, 132),
|
||||
new Vector2(114, 140),
|
||||
new Vector2(109, 146),
|
||||
new Vector2(100, 146),
|
||||
new Vector2(180, 138),
|
||||
new Vector2(186, 130),
|
||||
new Vector2(195, 131),
|
||||
new Vector2(199, 137),
|
||||
new Vector2(195, 143),
|
||||
new Vector2(185, 143),
|
||||
//48
|
||||
new Vector2(109, 235),
|
||||
new Vector2(118, 231),
|
||||
new Vector2(129, 228),
|
||||
new Vector2(143, 225),
|
||||
new Vector2(156, 227),
|
||||
new Vector2(174, 232),
|
||||
new Vector2(181, 234),
|
||||
new Vector2(173, 241),
|
||||
new Vector2(156, 245),
|
||||
new Vector2(143, 245),
|
||||
new Vector2(130, 244),
|
||||
new Vector2(117, 239),
|
||||
new Vector2(114, 235),
|
||||
new Vector2(130, 232),
|
||||
new Vector2(142, 232),
|
||||
new Vector2(157, 233),
|
||||
new Vector2(175, 236),
|
||||
new Vector2(155, 237),
|
||||
new Vector2(143, 238),
|
||||
new Vector2(130, 237)
|
||||
},
|
||||
//anime
|
||||
new List<Vector2>(){
|
||||
new Vector2(62, 179),
|
||||
new Vector2(72, 209),
|
||||
new Vector2(75, 223),
|
||||
new Vector2(81, 236),
|
||||
new Vector2(90, 244),
|
||||
new Vector2(101, 251),
|
||||
new Vector2(116, 258),
|
||||
new Vector2(129, 262),
|
||||
new Vector2(142, 268),
|
||||
new Vector2(160, 265),
|
||||
new Vector2(184, 260),
|
||||
new Vector2(202, 253),
|
||||
new Vector2(210, 247),
|
||||
new Vector2(217, 239),
|
||||
new Vector2(222, 229),
|
||||
new Vector2(225, 222),
|
||||
new Vector2(243, 191),
|
||||
//17
|
||||
new Vector2(68, 136),
|
||||
new Vector2(86, 128),
|
||||
new Vector2(104, 126),
|
||||
new Vector2(122, 131),
|
||||
new Vector2(134, 141),
|
||||
new Vector2(177, 143),
|
||||
new Vector2(191, 135),
|
||||
new Vector2(209, 132),
|
||||
new Vector2(227, 136),
|
||||
new Vector2(239, 143),
|
||||
//27
|
||||
new Vector2(153, 163),
|
||||
new Vector2(150, 190),
|
||||
new Vector2(149, 201),
|
||||
new Vector2(148, 212),
|
||||
new Vector2(138, 217),
|
||||
new Vector2(141, 219),
|
||||
new Vector2(149, 221),
|
||||
new Vector2(152, 220),
|
||||
new Vector2(155, 217),
|
||||
//36
|
||||
new Vector2(70, 182),
|
||||
new Vector2(85, 165),
|
||||
new Vector2(114, 168),
|
||||
new Vector2(122, 192),
|
||||
new Vector2(113, 211),
|
||||
new Vector2(82, 209),
|
||||
new Vector2(177, 196),
|
||||
new Vector2(189, 174),
|
||||
new Vector2(220, 175),
|
||||
new Vector2(234, 192),
|
||||
new Vector2(215, 220),
|
||||
new Vector2(184, 217),
|
||||
//48
|
||||
new Vector2(132, 249),
|
||||
new Vector2(134, 249),
|
||||
new Vector2(139, 250),
|
||||
new Vector2(144, 251),
|
||||
new Vector2(148, 251),
|
||||
new Vector2(153, 250),
|
||||
new Vector2(155, 251),
|
||||
new Vector2(154, 253),
|
||||
new Vector2(149, 257),
|
||||
new Vector2(144, 257),
|
||||
new Vector2(138, 256),
|
||||
new Vector2(133, 252),
|
||||
new Vector2(133, 250),
|
||||
new Vector2(139, 252),
|
||||
new Vector2(144, 254),
|
||||
new Vector2(148, 253),
|
||||
new Vector2(153, 251),
|
||||
new Vector2(148, 254),
|
||||
new Vector2(144, 254),
|
||||
new Vector2(139, 253),
|
||||
}
|
||||
};
|
||||
|
||||
public static ExampleMaskData GetData(){
|
||||
return new ExampleMaskData(filenames[_index], faceRcts[_index], landmarkPoints[_index]);
|
||||
}
|
||||
|
||||
public static ExampleMaskData GetData(int index){
|
||||
return new ExampleMaskData(filenames[index], faceRcts[index], landmarkPoints[index]);
|
||||
}
|
||||
|
||||
public static void Next(){
|
||||
_index++;
|
||||
if(_index == filenames.Length)
|
||||
_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public class ExampleMaskData
|
||||
{
|
||||
public string fileName
|
||||
{
|
||||
get { return this._filename; }
|
||||
}
|
||||
string _filename;
|
||||
|
||||
public Rect faceRect
|
||||
{
|
||||
get { return this._faceRect; }
|
||||
}
|
||||
Rect _faceRect;
|
||||
|
||||
public List<Vector2> landmarkPoints
|
||||
{
|
||||
get { return this._landmarkPoints; }
|
||||
}
|
||||
List<Vector2> _landmarkPoints;
|
||||
|
||||
public ExampleMaskData(string filename, Rect faceRect, List<Vector2> landmarkPoints){
|
||||
this._filename = filename;
|
||||
this._faceRect = faceRect;
|
||||
this._landmarkPoints = landmarkPoints;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 172e02f113885e441808191b26575189
|
||||
guid: cc4c7b2d203ad794d8cd529f3b2e0d66
|
||||
folderAsset: yes
|
||||
timeCreated: 1483198025
|
||||
timeCreated: 1526396773
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
|
@ -0,0 +1,165 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using OpenCVForUnity;
|
||||
using System;
|
||||
|
||||
namespace FaceMaskExample
|
||||
{
|
||||
public class FaceMaskColorCorrector
|
||||
{
|
||||
Mat src_mask;
|
||||
Mat dst_mask;
|
||||
Dictionary<int, Texture2D> LUTTexDict;
|
||||
|
||||
Point[] src_facialContourPoints;
|
||||
Point[] dst_facialContourPoints;
|
||||
|
||||
public FaceMaskColorCorrector ()
|
||||
{
|
||||
LUTTexDict = new Dictionary<int, Texture2D> ();
|
||||
|
||||
src_facialContourPoints = new Point[9];
|
||||
for (int i = 0; i < src_facialContourPoints.Length; i++) {
|
||||
src_facialContourPoints [i] = new Point ();
|
||||
}
|
||||
|
||||
dst_facialContourPoints = new Point[9];
|
||||
for (int i = 0; i < dst_facialContourPoints.Length; i++) {
|
||||
dst_facialContourPoints [i] = new Point ();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void CreateLUTTex (int id)
|
||||
{
|
||||
if (!LUTTexDict.ContainsKey (id))
|
||||
LUTTexDict.Add (id, new Texture2D (256, 1, TextureFormat.RGB24, false));
|
||||
}
|
||||
|
||||
public virtual Texture2D UpdateLUTTex (int id, Mat src, Mat dst, List<Vector2> src_landmarkPoints, List<Vector2> dst_landmarkPoints)
|
||||
{
|
||||
if (src_mask != null && (src.width () != src_mask.width () || src.height () != src_mask.height ())) {
|
||||
src_mask.Dispose ();
|
||||
src_mask = null;
|
||||
}
|
||||
src_mask = src_mask ?? new Mat (src.rows(), src.cols(), CvType.CV_8UC1, Scalar.all(0));
|
||||
|
||||
if (dst_mask != null && (dst.width () != dst_mask.width () || dst.height () != dst_mask.height ())) {
|
||||
dst_mask.Dispose ();
|
||||
dst_mask = null;
|
||||
}
|
||||
dst_mask = dst_mask ?? new Mat (dst.rows(), dst.cols(), CvType.CV_8UC1, Scalar.all(0));
|
||||
|
||||
// Get facial contour points.
|
||||
GetFacialContourPoints (src_landmarkPoints, src_facialContourPoints);
|
||||
GetFacialContourPoints (dst_landmarkPoints, dst_facialContourPoints);
|
||||
|
||||
// Get facial contour rect.
|
||||
OpenCVForUnity.Rect src_facialContourRect = Imgproc.boundingRect(new MatOfPoint(src_facialContourPoints));
|
||||
OpenCVForUnity.Rect dst_facialContourRect = Imgproc.boundingRect(new MatOfPoint(dst_facialContourPoints));
|
||||
src_facialContourRect = src_facialContourRect.intersect (new OpenCVForUnity.Rect(0, 0, src.width(), src.height()));
|
||||
dst_facialContourRect = dst_facialContourRect.intersect (new OpenCVForUnity.Rect(0, 0, dst.width(), dst.height()));
|
||||
|
||||
Mat src_ROI = new Mat (src, src_facialContourRect);
|
||||
Mat dst_ROI = new Mat (dst, dst_facialContourRect);
|
||||
Mat src_mask_ROI = new Mat (src_mask, src_facialContourRect);
|
||||
Mat dst_mask_ROI = new Mat (dst_mask, dst_facialContourRect);
|
||||
|
||||
GetPointsInFrame (src_mask_ROI, src_facialContourPoints, src_facialContourPoints);
|
||||
GetPointsInFrame (dst_mask_ROI, dst_facialContourPoints, dst_facialContourPoints);
|
||||
|
||||
src_mask_ROI.setTo (new Scalar(0));
|
||||
dst_mask_ROI.setTo (new Scalar(0));
|
||||
Imgproc.fillConvexPoly(src_mask_ROI, new MatOfPoint(src_facialContourPoints), new Scalar(255));
|
||||
Imgproc.fillConvexPoly(dst_mask_ROI, new MatOfPoint(dst_facialContourPoints), new Scalar(255));
|
||||
|
||||
Texture2D LUTTex;
|
||||
if (LUTTexDict.ContainsKey (id)) {
|
||||
LUTTex = LUTTexDict[id];
|
||||
} else {
|
||||
LUTTex = new Texture2D (256, 1, TextureFormat.RGB24, false);
|
||||
LUTTexDict.Add (id ,LUTTex);
|
||||
}
|
||||
|
||||
FaceMaskShaderUtils.CalculateLUT (src_ROI, dst_ROI, src_mask_ROI, dst_mask_ROI, LUTTex);
|
||||
|
||||
return LUTTex;
|
||||
}
|
||||
|
||||
public virtual void DeleteLUTTex (int id)
|
||||
{
|
||||
if (LUTTexDict.ContainsKey (id)) {
|
||||
Texture2D.Destroy(LUTTexDict [id]);
|
||||
LUTTexDict.Remove (id);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Texture2D GetLUTTex (int id)
|
||||
{
|
||||
if (LUTTexDict.ContainsKey (id)) {
|
||||
return LUTTexDict [id];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual void GetFacialContourPoints(List<Vector2> landmark_points, Point[] dst_points)
|
||||
{
|
||||
if (landmark_points.Count < 9)
|
||||
throw new ArgumentException("Invalid landmark_points.");
|
||||
|
||||
if (dst_points.Length != 9)
|
||||
throw new ArgumentException("Invalid points.");
|
||||
|
||||
dst_points[0].x = landmark_points[0].x; dst_points[0].y = landmark_points[0].y;
|
||||
dst_points[1].x = landmark_points[3].x; dst_points[1].y = landmark_points[3].y;
|
||||
dst_points[2].x = landmark_points[5].x; dst_points[2].y = landmark_points[5].y;
|
||||
dst_points[3].x = landmark_points[8].x; dst_points[3].y = landmark_points[8].y;
|
||||
dst_points[4].x = landmark_points[11].x; dst_points[4].y = landmark_points[11].y;
|
||||
dst_points[5].x = landmark_points[13].x; dst_points[5].y = landmark_points[13].y;
|
||||
dst_points[6].x = landmark_points[16].x; dst_points[6].y = landmark_points[16].y;
|
||||
float nose_length_x = landmark_points[27].x - landmark_points[30].x;
|
||||
float nose_length_y = landmark_points[27].y - landmark_points[30].y;
|
||||
dst_points [7].x = landmark_points [26].x + nose_length_x; dst_points [7].y = landmark_points [26].y + nose_length_y;
|
||||
dst_points [8].x = landmark_points [17].x + nose_length_x; dst_points [8].y = landmark_points [17].y + nose_length_y;
|
||||
}
|
||||
|
||||
protected virtual void GetPointsInFrame(Mat frame, Point[] points, Point[] dst_points)
|
||||
{
|
||||
if (points.Length != dst_points.Length)
|
||||
throw new ArgumentException("points.Length != dst_points.Length");
|
||||
|
||||
Size wholesize = new Size();
|
||||
Point ofs = new Point();
|
||||
frame.locateROI(wholesize, ofs);
|
||||
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
dst_points [i].x = points [i].x - ofs.x;
|
||||
dst_points [i].y = points [i].y - ofs.y;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Reset ()
|
||||
{
|
||||
foreach (var key in LUTTexDict.Keys) {
|
||||
Texture2D.Destroy(LUTTexDict [key]);
|
||||
}
|
||||
LUTTexDict.Clear ();
|
||||
}
|
||||
|
||||
public virtual void Dispose ()
|
||||
{
|
||||
if (src_mask != null) {
|
||||
src_mask.Dispose ();
|
||||
src_mask = null;
|
||||
}
|
||||
|
||||
if (dst_mask != null) {
|
||||
dst_mask.Dispose ();
|
||||
dst_mask = null;
|
||||
}
|
||||
|
||||
Reset ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 115e52ebcf96f3042a999f130ad1312a
|
||||
timeCreated: 1526371347
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,216 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using OpenCVForUnity;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace FaceMaskExample
|
||||
{
|
||||
public class FaceMaskShaderUtils
|
||||
{
|
||||
// Match histograms of 'src' to that of 'dst', according to both masks.
|
||||
public static void CalculateLUT (Mat src, Mat dst, Mat src_mask, Mat dst_mask, Texture2D LUTTex)
|
||||
{
|
||||
if (src.channels() < 3)
|
||||
throw new ArgumentException ("src.channels() < 3");
|
||||
|
||||
if (dst.channels() < 3)
|
||||
throw new ArgumentException ("dst.channels() < 3");
|
||||
|
||||
if (src_mask.channels() != 1)
|
||||
throw new ArgumentException ("src_mask.channels() != 1");
|
||||
|
||||
if (dst_mask.channels() != 1)
|
||||
throw new ArgumentException ("dst_mask.channels() != 1");
|
||||
|
||||
if (src_mask != null && src.total() != src_mask.total())
|
||||
throw new ArgumentException ("src.total() != src_mask.total()");
|
||||
|
||||
if (dst_mask != null && dst.total() != dst_mask.total())
|
||||
throw new ArgumentException ("dst.total() != dst_mask.total()");
|
||||
|
||||
if (LUTTex.width != 256 || LUTTex.height != 1 || LUTTex.format != TextureFormat.RGB24)
|
||||
throw new ArgumentException ("Invalid LUTTex.");
|
||||
|
||||
byte[] LUT = new byte[3 * 256];
|
||||
double[][] src_hist = new double[3][]; for(int i=0; i<src_hist.Length; i++ ){ src_hist[i] = new double[256];}
|
||||
double[][] dst_hist = new double[3][]; for(int i=0; i<dst_hist.Length; i++ ){ dst_hist[i] = new double[256];}
|
||||
double[][] src_cdf = new double[3][]; for(int i=0; i<src_cdf.Length; i++ ){ src_cdf[i] = new double[256];}
|
||||
double[][] dst_cdf = new double[3][]; for(int i=0; i<dst_cdf.Length; i++ ){ dst_cdf[i] = new double[256];}
|
||||
|
||||
double[] src_histMax = new double[3];
|
||||
double[] dst_histMax = new double[3];
|
||||
|
||||
byte[] src_mask_byte = null;
|
||||
byte[] dst_mask_byte = null;
|
||||
if (src_mask != null) {
|
||||
src_mask_byte = new byte[src_mask.total() * src_mask.channels()];
|
||||
Utils.copyFromMat<byte>(src_mask, src_mask_byte);
|
||||
}
|
||||
if (dst_mask != null) {
|
||||
dst_mask_byte = new byte[dst_mask.total () * dst_mask.channels ()];
|
||||
Utils.copyFromMat<byte> (dst_mask, dst_mask_byte);
|
||||
}
|
||||
|
||||
byte[] src_byte = new byte[src.total() * src.channels()];
|
||||
Utils.copyFromMat<byte>(src, src_byte);
|
||||
byte[] dst_byte = new byte[dst.total() * dst.channels()];
|
||||
Utils.copyFromMat<byte>(dst, dst_byte);
|
||||
|
||||
int pixel_i = 0;
|
||||
int channels = src.channels();
|
||||
int total = (int)src.total();
|
||||
if (src_mask_byte != null) {
|
||||
for (int i = 0; i < total; i++) {
|
||||
if (src_mask_byte [i] != 0) {
|
||||
byte c = src_byte [pixel_i];
|
||||
src_hist [0] [c]++;
|
||||
if (src_hist [0] [c] > src_histMax [0])
|
||||
src_histMax [0] = src_hist [0] [c];
|
||||
|
||||
c = src_byte [pixel_i + 1];
|
||||
src_hist [1] [c]++;
|
||||
if (src_hist [1] [c] > src_histMax [1])
|
||||
src_histMax [1] = src_hist [1] [c];
|
||||
|
||||
c = src_byte [pixel_i + 2];
|
||||
src_hist [2] [c]++;
|
||||
if (src_hist [2] [c] > src_histMax [2])
|
||||
src_histMax [2] = src_hist [2] [c];
|
||||
}
|
||||
|
||||
// Advance to next pixel
|
||||
pixel_i += channels;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < total; i++) {
|
||||
byte c = src_byte [pixel_i];
|
||||
src_hist [0] [c]++;
|
||||
if (src_hist [0] [c] > src_histMax [0])
|
||||
src_histMax [0] = src_hist [0] [c];
|
||||
|
||||
c = src_byte [pixel_i + 1];
|
||||
src_hist [1] [c]++;
|
||||
if (src_hist [1] [c] > src_histMax [1])
|
||||
src_histMax [1] = src_hist [1] [c];
|
||||
|
||||
c = src_byte [pixel_i + 2];
|
||||
src_hist [2] [c]++;
|
||||
if (src_hist [2] [c] > src_histMax [2])
|
||||
src_histMax [2] = src_hist [2] [c];
|
||||
|
||||
// Advance to next pixel
|
||||
pixel_i += channels;
|
||||
}
|
||||
}
|
||||
|
||||
pixel_i = 0;
|
||||
channels = dst.channels ();
|
||||
total = (int)dst.total ();
|
||||
if (dst_mask_byte != null) {
|
||||
for (int i = 0; i < total; i++) {
|
||||
if (dst_mask_byte [i] != 0) {
|
||||
byte c = dst_byte [pixel_i];
|
||||
dst_hist [0] [c]++;
|
||||
if (dst_hist [0] [c] > dst_histMax [0])
|
||||
dst_histMax [0] = dst_hist [0] [c];
|
||||
|
||||
c = dst_byte [pixel_i + 1];
|
||||
dst_hist [1] [c]++;
|
||||
if (dst_hist [1] [c] > dst_histMax [1])
|
||||
dst_histMax [1] = dst_hist [1] [c];
|
||||
|
||||
c = dst_byte [pixel_i + 2];
|
||||
dst_hist [2] [c]++;
|
||||
if (dst_hist [2] [c] > dst_histMax [2])
|
||||
dst_histMax [2] = dst_hist [2] [c];
|
||||
}
|
||||
// Advance to next pixel
|
||||
pixel_i += channels;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < total; i++) {
|
||||
byte c = dst_byte [pixel_i];
|
||||
dst_hist [0] [c]++;
|
||||
if (dst_hist [0] [c] > dst_histMax [0])
|
||||
dst_histMax [0] = dst_hist [0] [c];
|
||||
|
||||
c = dst_byte [pixel_i + 1];
|
||||
dst_hist [1] [c]++;
|
||||
if (dst_hist [1] [c] > dst_histMax [1])
|
||||
dst_histMax [1] = dst_hist [1] [c];
|
||||
|
||||
c = dst_byte [pixel_i + 2];
|
||||
dst_hist [2] [c]++;
|
||||
if (dst_hist [2] [c] > dst_histMax [2])
|
||||
dst_histMax [2] = dst_hist [2] [c];
|
||||
|
||||
// Advance to next pixel
|
||||
pixel_i += channels;
|
||||
}
|
||||
}
|
||||
|
||||
//normalize hist
|
||||
for (int i = 0; i < 256; i++) {
|
||||
src_hist [0][i] /= src_histMax[0];
|
||||
src_hist [1][i] /= src_histMax[1];
|
||||
src_hist [2][i] /= src_histMax[2];
|
||||
|
||||
dst_hist [0][i] /= dst_histMax[0];
|
||||
dst_hist [1][i] /= dst_histMax[1];
|
||||
dst_hist [2][i] /= dst_histMax[2];
|
||||
}
|
||||
|
||||
// Calc cumulative distribution function (CDF)
|
||||
src_cdf[0][0] = src_hist[0][0];
|
||||
src_cdf[1][0] = src_hist[1][0];
|
||||
src_cdf[2][0] = src_hist[2][0];
|
||||
dst_cdf[0][0] = dst_hist[0][0];
|
||||
dst_cdf[1][0] = dst_hist[1][0];
|
||||
dst_cdf[2][0] = dst_hist[2][0];
|
||||
for (int i = 1; i < 256; i++)
|
||||
{
|
||||
src_cdf[0][i] = src_cdf[0][i - 1] + src_hist[0][i];
|
||||
src_cdf[1][i] = src_cdf[1][i - 1] + src_hist[1][i];
|
||||
src_cdf[2][i] = src_cdf[2][i - 1] + src_hist[2][i];
|
||||
|
||||
dst_cdf[0][i] = dst_cdf[0][i - 1] + dst_hist[0][i];
|
||||
dst_cdf[1][i] = dst_cdf[1][i - 1] + dst_hist[1][i];
|
||||
dst_cdf[2][i] = dst_cdf[2][i - 1] + dst_hist[2][i];
|
||||
}
|
||||
|
||||
// Normalize CDF
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
src_cdf[0][i] /= src_cdf[0][255];
|
||||
src_cdf[1][i] /= src_cdf[1][255];
|
||||
src_cdf[2][i] /= src_cdf[2][255];
|
||||
|
||||
dst_cdf[0][i] /= dst_cdf[0][255];
|
||||
dst_cdf[1][i] /= dst_cdf[1][255];
|
||||
dst_cdf[2][i] /= dst_cdf[2][255];
|
||||
}
|
||||
|
||||
// Create lookup table
|
||||
const double HISTMATCH_EPSILON = 0.000001f;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int last = 0;
|
||||
for (int j = 0; j < 256; j++) {
|
||||
double F1j = src_cdf [i][j];
|
||||
|
||||
for (int k = last; k < 256; k++) {
|
||||
double F2k = dst_cdf [i][k];
|
||||
if (Math.Abs (F2k - F1j) < HISTMATCH_EPSILON || F2k > F1j) {
|
||||
LUT [(j * 3) + i] = (byte)k;
|
||||
last = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LUTTex.LoadRawTextureData (LUT);
|
||||
LUTTex.Apply (false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f6e8292e06d610744bc4121e6b2d5674
|
||||
timeCreated: 1526354798
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c2ac2406cdfdcba47b1d7f050bcd8e99
|
||||
folderAsset: yes
|
||||
timeCreated: 1525000564
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,112 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class FaceMaskData : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
private Texture2D _image;
|
||||
public Texture2D image
|
||||
{
|
||||
get { return this._image; }
|
||||
set { this._image = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if to use dynamically detected points.
|
||||
/// </summary>
|
||||
[TooltipAttribute ("Determines if to use dynamically detected points.")]
|
||||
public bool isDynamicMode = true;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if to enable color correction.
|
||||
/// </summary>
|
||||
[TooltipAttribute ("Determines if to enable color correction.")]
|
||||
public bool enableColorCorrection = true;
|
||||
|
||||
[SerializeField]
|
||||
private Rect _faceRect = new Rect(78, 95, 151, 150);
|
||||
public Rect faceRect
|
||||
{
|
||||
get { return this._faceRect; }
|
||||
set { this._faceRect = value; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private List<Vector2> _landmarkPoints = new List<Vector2> ()
|
||||
{
|
||||
new Vector2(84, 148),
|
||||
new Vector2(84, 167),
|
||||
new Vector2(86, 187),
|
||||
new Vector2(89, 206),
|
||||
new Vector2(96, 224),
|
||||
new Vector2(106, 240),
|
||||
new Vector2(119, 253),
|
||||
new Vector2(134, 264),
|
||||
new Vector2(151, 266),
|
||||
new Vector2(168, 264),
|
||||
new Vector2(184, 254),
|
||||
new Vector2(197, 241),
|
||||
new Vector2(207, 226),
|
||||
new Vector2(214, 209),
|
||||
new Vector2(218, 190),
|
||||
new Vector2(221, 170),
|
||||
new Vector2(221, 150),
|
||||
new Vector2(100, 125),
|
||||
new Vector2(108, 117),
|
||||
new Vector2(119, 114),
|
||||
new Vector2(130, 116),
|
||||
new Vector2(141, 120),
|
||||
new Vector2(164, 120),
|
||||
new Vector2(176, 116),
|
||||
new Vector2(187, 115),
|
||||
new Vector2(199, 118),
|
||||
new Vector2(206, 126),
|
||||
new Vector2(153, 133),
|
||||
new Vector2(153, 144),
|
||||
new Vector2(154, 156),
|
||||
new Vector2(154, 168),
|
||||
new Vector2(142, 181),
|
||||
new Vector2(148, 182),
|
||||
new Vector2(154, 184),
|
||||
new Vector2(160, 182),
|
||||
new Vector2(165, 181),
|
||||
new Vector2(113, 134),
|
||||
new Vector2(120, 127),
|
||||
new Vector2(129, 127),
|
||||
new Vector2(136, 136),
|
||||
new Vector2(128, 137),
|
||||
new Vector2(119, 137),
|
||||
new Vector2(170, 137),
|
||||
new Vector2(177, 128),
|
||||
new Vector2(187, 128),
|
||||
new Vector2(193, 136),
|
||||
new Vector2(188, 139),
|
||||
new Vector2(178, 138),
|
||||
new Vector2(127, 215),
|
||||
new Vector2(135, 204),
|
||||
new Vector2(145, 199),
|
||||
new Vector2(154, 201),
|
||||
new Vector2(163, 199),
|
||||
new Vector2(173, 205),
|
||||
new Vector2(178, 218),
|
||||
new Vector2(173, 225),
|
||||
new Vector2(163, 229),
|
||||
new Vector2(154, 230),
|
||||
new Vector2(144, 228),
|
||||
new Vector2(134, 224),
|
||||
new Vector2(131, 215),
|
||||
new Vector2(145, 206),
|
||||
new Vector2(154, 207),
|
||||
new Vector2(163, 207),
|
||||
new Vector2(175, 217),
|
||||
new Vector2(163, 219),
|
||||
new Vector2(154, 220),
|
||||
new Vector2(144, 218)
|
||||
};
|
||||
public List<Vector2> landmarkPoints
|
||||
{
|
||||
get { return this._landmarkPoints; }
|
||||
set { this._landmarkPoints = value; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0cea3acc41ae7e1498ab5b898cf0043c
|
||||
timeCreated: 1525001700
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b4a6d591d8cbd6428a328610864ce7d
|
||||
folderAsset: yes
|
||||
timeCreated: 1525003155
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,131 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &152650
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 406216}
|
||||
- 114: {fileID: 11454898}
|
||||
m_Layer: 0
|
||||
m_Name: Anime
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &406216
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 152650}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
--- !u!114 &11454898
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 152650}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cea3acc41ae7e1498ab5b898cf0043c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_image: {fileID: 2800000, guid: b1d066fd26876b04c9d7f88c65d0a68a, type: 3}
|
||||
isDynamicMode: 0
|
||||
enableColorCorrection: 0
|
||||
_faceRect:
|
||||
serializedVersion: 2
|
||||
x: 56
|
||||
y: 85
|
||||
width: 190
|
||||
height: 196
|
||||
_landmarkPoints:
|
||||
- {x: 62, y: 179}
|
||||
- {x: 72, y: 209}
|
||||
- {x: 75, y: 223}
|
||||
- {x: 81, y: 236}
|
||||
- {x: 90, y: 244}
|
||||
- {x: 101, y: 251}
|
||||
- {x: 116, y: 258}
|
||||
- {x: 129, y: 262}
|
||||
- {x: 142, y: 268}
|
||||
- {x: 160, y: 265}
|
||||
- {x: 184, y: 260}
|
||||
- {x: 202, y: 253}
|
||||
- {x: 210, y: 247}
|
||||
- {x: 217, y: 239}
|
||||
- {x: 222, y: 229}
|
||||
- {x: 225, y: 222}
|
||||
- {x: 243, y: 191}
|
||||
- {x: 68, y: 136}
|
||||
- {x: 86, y: 128}
|
||||
- {x: 104, y: 126}
|
||||
- {x: 122, y: 131}
|
||||
- {x: 134, y: 141}
|
||||
- {x: 177, y: 143}
|
||||
- {x: 191, y: 135}
|
||||
- {x: 209, y: 132}
|
||||
- {x: 227, y: 136}
|
||||
- {x: 239, y: 143}
|
||||
- {x: 153, y: 163}
|
||||
- {x: 150, y: 190}
|
||||
- {x: 149, y: 201}
|
||||
- {x: 148, y: 212}
|
||||
- {x: 138, y: 217}
|
||||
- {x: 141, y: 219}
|
||||
- {x: 149, y: 221}
|
||||
- {x: 152, y: 220}
|
||||
- {x: 155, y: 217}
|
||||
- {x: 70, y: 182}
|
||||
- {x: 85, y: 165}
|
||||
- {x: 114, y: 168}
|
||||
- {x: 122, y: 192}
|
||||
- {x: 113, y: 211}
|
||||
- {x: 82, y: 209}
|
||||
- {x: 177, y: 196}
|
||||
- {x: 189, y: 174}
|
||||
- {x: 220, y: 175}
|
||||
- {x: 234, y: 192}
|
||||
- {x: 215, y: 220}
|
||||
- {x: 184, y: 217}
|
||||
- {x: 132, y: 249}
|
||||
- {x: 134, y: 249}
|
||||
- {x: 139, y: 250}
|
||||
- {x: 144, y: 251}
|
||||
- {x: 148, y: 251}
|
||||
- {x: 153, y: 250}
|
||||
- {x: 155, y: 251}
|
||||
- {x: 154, y: 253}
|
||||
- {x: 149, y: 257}
|
||||
- {x: 144, y: 257}
|
||||
- {x: 138, y: 256}
|
||||
- {x: 133, y: 252}
|
||||
- {x: 133, y: 250}
|
||||
- {x: 139, y: 252}
|
||||
- {x: 144, y: 254}
|
||||
- {x: 148, y: 253}
|
||||
- {x: 153, y: 251}
|
||||
- {x: 148, y: 254}
|
||||
- {x: 144, y: 254}
|
||||
- {x: 139, y: 253}
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 152650}
|
||||
m_IsPrefabParent: 1
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 87cd6c3c5699198498930c4fc18182ba
|
||||
timeCreated: 1525055205
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,130 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &145198
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 458588}
|
||||
- 114: {fileID: 11428486}
|
||||
m_Layer: 0
|
||||
m_Name: Men1
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &458588
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 145198}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
--- !u!114 &11428486
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 145198}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cea3acc41ae7e1498ab5b898cf0043c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_image: {fileID: 2800000, guid: 15fcadce448f349488a1b74f026ce010, type: 3}
|
||||
isDynamicMode: 0
|
||||
_faceRect:
|
||||
serializedVersion: 2
|
||||
x: 78
|
||||
y: 95
|
||||
width: 151
|
||||
height: 150
|
||||
_landmarkPoints:
|
||||
- {x: 84, y: 148}
|
||||
- {x: 84, y: 167}
|
||||
- {x: 86, y: 187}
|
||||
- {x: 89, y: 206}
|
||||
- {x: 96, y: 224}
|
||||
- {x: 106, y: 240}
|
||||
- {x: 119, y: 253}
|
||||
- {x: 134, y: 264}
|
||||
- {x: 151, y: 266}
|
||||
- {x: 168, y: 264}
|
||||
- {x: 184, y: 254}
|
||||
- {x: 197, y: 241}
|
||||
- {x: 207, y: 226}
|
||||
- {x: 214, y: 209}
|
||||
- {x: 218, y: 190}
|
||||
- {x: 221, y: 170}
|
||||
- {x: 221, y: 150}
|
||||
- {x: 103, y: 113}
|
||||
- {x: 109, y: 106}
|
||||
- {x: 117, y: 103}
|
||||
- {x: 130, y: 105}
|
||||
- {x: 140, y: 113}
|
||||
- {x: 167, y: 114}
|
||||
- {x: 175, y: 107}
|
||||
- {x: 188, y: 103}
|
||||
- {x: 200, y: 108}
|
||||
- {x: 207, y: 116}
|
||||
- {x: 153, y: 133}
|
||||
- {x: 153, y: 144}
|
||||
- {x: 153, y: 156}
|
||||
- {x: 155, y: 166}
|
||||
- {x: 140, y: 178}
|
||||
- {x: 147, y: 181}
|
||||
- {x: 156, y: 180}
|
||||
- {x: 164, y: 180}
|
||||
- {x: 171, y: 178}
|
||||
- {x: 113, y: 134}
|
||||
- {x: 120, y: 127}
|
||||
- {x: 129, y: 127}
|
||||
- {x: 136, y: 134}
|
||||
- {x: 128, y: 137}
|
||||
- {x: 119, y: 137}
|
||||
- {x: 169, y: 134}
|
||||
- {x: 177, y: 126}
|
||||
- {x: 188, y: 126}
|
||||
- {x: 194, y: 134}
|
||||
- {x: 188, y: 139}
|
||||
- {x: 178, y: 138}
|
||||
- {x: 124, y: 217}
|
||||
- {x: 131, y: 203}
|
||||
- {x: 143, y: 198}
|
||||
- {x: 155, y: 195}
|
||||
- {x: 171, y: 198}
|
||||
- {x: 179, y: 205}
|
||||
- {x: 184, y: 218}
|
||||
- {x: 179, y: 226}
|
||||
- {x: 167, y: 230}
|
||||
- {x: 154, y: 230}
|
||||
- {x: 139, y: 229}
|
||||
- {x: 127, y: 226}
|
||||
- {x: 128, y: 215}
|
||||
- {x: 136, y: 204}
|
||||
- {x: 154, y: 201}
|
||||
- {x: 172, y: 204}
|
||||
- {x: 179, y: 216}
|
||||
- {x: 173, y: 222}
|
||||
- {x: 156, y: 224}
|
||||
- {x: 136, y: 222}
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 145198}
|
||||
m_IsPrefabParent: 1
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5cbfc79db1c11e641bdf1ff74dd73c1e
|
||||
timeCreated: 1525053911
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,130 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &171702
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 445690}
|
||||
- 114: {fileID: 11482412}
|
||||
m_Layer: 0
|
||||
m_Name: Men2
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &445690
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 171702}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
--- !u!114 &11482412
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 171702}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cea3acc41ae7e1498ab5b898cf0043c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_image: {fileID: 2800000, guid: 7777667c554b97c4cbe1120b7dcea0a4, type: 3}
|
||||
isDynamicMode: 0
|
||||
_faceRect:
|
||||
serializedVersion: 2
|
||||
x: 62
|
||||
y: 112
|
||||
width: 150
|
||||
height: 150
|
||||
_landmarkPoints:
|
||||
- {x: 72, y: 146}
|
||||
- {x: 74, y: 167}
|
||||
- {x: 79, y: 187}
|
||||
- {x: 84, y: 207}
|
||||
- {x: 93, y: 225}
|
||||
- {x: 105, y: 240}
|
||||
- {x: 119, y: 251}
|
||||
- {x: 134, y: 259}
|
||||
- {x: 150, y: 259}
|
||||
- {x: 167, y: 254}
|
||||
- {x: 180, y: 244}
|
||||
- {x: 192, y: 228}
|
||||
- {x: 201, y: 211}
|
||||
- {x: 207, y: 192}
|
||||
- {x: 209, y: 171}
|
||||
- {x: 210, y: 149}
|
||||
- {x: 207, y: 129}
|
||||
- {x: 79, y: 138}
|
||||
- {x: 86, y: 129}
|
||||
- {x: 97, y: 125}
|
||||
- {x: 109, y: 126}
|
||||
- {x: 122, y: 130}
|
||||
- {x: 143, y: 128}
|
||||
- {x: 154, y: 121}
|
||||
- {x: 168, y: 116}
|
||||
- {x: 185, y: 117}
|
||||
- {x: 194, y: 123}
|
||||
- {x: 134, y: 140}
|
||||
- {x: 135, y: 155}
|
||||
- {x: 136, y: 169}
|
||||
- {x: 137, y: 184}
|
||||
- {x: 125, y: 192}
|
||||
- {x: 132, y: 195}
|
||||
- {x: 140, y: 197}
|
||||
- {x: 148, y: 193}
|
||||
- {x: 154, y: 189}
|
||||
- {x: 94, y: 145}
|
||||
- {x: 100, y: 139}
|
||||
- {x: 111, y: 138}
|
||||
- {x: 119, y: 145}
|
||||
- {x: 110, y: 148}
|
||||
- {x: 101, y: 149}
|
||||
- {x: 154, y: 140}
|
||||
- {x: 160, y: 132}
|
||||
- {x: 171, y: 130}
|
||||
- {x: 179, y: 134}
|
||||
- {x: 173, y: 140}
|
||||
- {x: 163, y: 141}
|
||||
- {x: 117, y: 219}
|
||||
- {x: 125, y: 215}
|
||||
- {x: 135, y: 212}
|
||||
- {x: 144, y: 211}
|
||||
- {x: 152, y: 210}
|
||||
- {x: 161, y: 210}
|
||||
- {x: 169, y: 213}
|
||||
- {x: 166, y: 220}
|
||||
- {x: 159, y: 227}
|
||||
- {x: 148, y: 232}
|
||||
- {x: 137, y: 230}
|
||||
- {x: 126, y: 228}
|
||||
- {x: 124, y: 219}
|
||||
- {x: 131, y: 222}
|
||||
- {x: 143, y: 225}
|
||||
- {x: 152, y: 221}
|
||||
- {x: 167, y: 215}
|
||||
- {x: 152, y: 213}
|
||||
- {x: 142, y: 215}
|
||||
- {x: 129, y: 216}
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 171702}
|
||||
m_IsPrefabParent: 1
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 559ab07359e66dd49b294369acce470b
|
||||
timeCreated: 1525053811
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,131 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &166552
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 478316}
|
||||
- 114: {fileID: 11443002}
|
||||
m_Layer: 0
|
||||
m_Name: Panda
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &478316
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 166552}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
--- !u!114 &11443002
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 166552}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cea3acc41ae7e1498ab5b898cf0043c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_image: {fileID: 2800000, guid: 4fd4dcb14f9983446b7b67f68114e9ba, type: 3}
|
||||
isDynamicMode: 0
|
||||
enableColorCorrection: 0
|
||||
_faceRect:
|
||||
serializedVersion: 2
|
||||
x: 17
|
||||
y: 64
|
||||
width: 261
|
||||
height: 205
|
||||
_landmarkPoints:
|
||||
- {x: 31, y: 136}
|
||||
- {x: 23, y: 169}
|
||||
- {x: 26, y: 195}
|
||||
- {x: 35, y: 216}
|
||||
- {x: 53, y: 236}
|
||||
- {x: 71, y: 251}
|
||||
- {x: 96, y: 257}
|
||||
- {x: 132, y: 259}
|
||||
- {x: 143, y: 263}
|
||||
- {x: 165, y: 258}
|
||||
- {x: 198, y: 255}
|
||||
- {x: 222, y: 242}
|
||||
- {x: 235, y: 231}
|
||||
- {x: 248, y: 215}
|
||||
- {x: 260, y: 195}
|
||||
- {x: 272, y: 171}
|
||||
- {x: 264, y: 135}
|
||||
- {x: 45, y: 115}
|
||||
- {x: 70, y: 94}
|
||||
- {x: 97, y: 89}
|
||||
- {x: 116, y: 90}
|
||||
- {x: 135, y: 105}
|
||||
- {x: 157, y: 104}
|
||||
- {x: 176, y: 90}
|
||||
- {x: 198, y: 86}
|
||||
- {x: 223, y: 90}
|
||||
- {x: 248, y: 110}
|
||||
- {x: 148, y: 134}
|
||||
- {x: 147, y: 152}
|
||||
- {x: 145, y: 174}
|
||||
- {x: 144, y: 192}
|
||||
- {x: 117, y: 205}
|
||||
- {x: 128, y: 213}
|
||||
- {x: 143, y: 216}
|
||||
- {x: 160, y: 216}
|
||||
- {x: 174, y: 206}
|
||||
- {x: 96, y: 138}
|
||||
- {x: 101, y: 131}
|
||||
- {x: 111, y: 132}
|
||||
- {x: 114, y: 140}
|
||||
- {x: 109, y: 146}
|
||||
- {x: 100, y: 146}
|
||||
- {x: 180, y: 138}
|
||||
- {x: 186, y: 130}
|
||||
- {x: 195, y: 131}
|
||||
- {x: 199, y: 137}
|
||||
- {x: 195, y: 143}
|
||||
- {x: 185, y: 143}
|
||||
- {x: 109, y: 235}
|
||||
- {x: 118, y: 231}
|
||||
- {x: 129, y: 228}
|
||||
- {x: 143, y: 225}
|
||||
- {x: 156, y: 227}
|
||||
- {x: 174, y: 232}
|
||||
- {x: 181, y: 234}
|
||||
- {x: 173, y: 241}
|
||||
- {x: 156, y: 245}
|
||||
- {x: 143, y: 245}
|
||||
- {x: 130, y: 244}
|
||||
- {x: 117, y: 239}
|
||||
- {x: 114, y: 235}
|
||||
- {x: 130, y: 232}
|
||||
- {x: 142, y: 232}
|
||||
- {x: 157, y: 233}
|
||||
- {x: 175, y: 236}
|
||||
- {x: 155, y: 237}
|
||||
- {x: 143, y: 238}
|
||||
- {x: 130, y: 237}
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 166552}
|
||||
m_IsPrefabParent: 1
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 56cec6161f5a7cf44a2014b7f955f26d
|
||||
timeCreated: 1525055192
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,130 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &106612
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 403126}
|
||||
- 114: {fileID: 11496078}
|
||||
m_Layer: 0
|
||||
m_Name: Women01
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &403126
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 106612}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
--- !u!114 &11496078
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 106612}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cea3acc41ae7e1498ab5b898cf0043c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_image: {fileID: 2800000, guid: 48eaa7a1d574ef647af0a2e1834f7250, type: 3}
|
||||
isDynamicMode: 0
|
||||
_faceRect:
|
||||
serializedVersion: 2
|
||||
x: 42
|
||||
y: 137
|
||||
width: 216
|
||||
height: 216
|
||||
_landmarkPoints:
|
||||
- {x: 46, y: 195}
|
||||
- {x: 54, y: 223}
|
||||
- {x: 66, y: 250}
|
||||
- {x: 78, y: 275}
|
||||
- {x: 93, y: 296}
|
||||
- {x: 115, y: 312}
|
||||
- {x: 139, y: 325}
|
||||
- {x: 164, y: 334}
|
||||
- {x: 188, y: 332}
|
||||
- {x: 206, y: 321}
|
||||
- {x: 218, y: 301}
|
||||
- {x: 227, y: 279}
|
||||
- {x: 236, y: 257}
|
||||
- {x: 241, y: 232}
|
||||
- {x: 242, y: 207}
|
||||
- {x: 240, y: 181}
|
||||
- {x: 237, y: 156}
|
||||
- {x: 69, y: 184}
|
||||
- {x: 80, y: 176}
|
||||
- {x: 98, y: 174}
|
||||
- {x: 116, y: 177}
|
||||
- {x: 134, y: 182}
|
||||
- {x: 172, y: 174}
|
||||
- {x: 185, y: 163}
|
||||
- {x: 199, y: 154}
|
||||
- {x: 215, y: 147}
|
||||
- {x: 227, y: 151}
|
||||
- {x: 159, y: 195}
|
||||
- {x: 164, y: 214}
|
||||
- {x: 169, y: 232}
|
||||
- {x: 174, y: 251}
|
||||
- {x: 154, y: 259}
|
||||
- {x: 165, y: 261}
|
||||
- {x: 176, y: 262}
|
||||
- {x: 184, y: 256}
|
||||
- {x: 190, y: 248}
|
||||
- {x: 92, y: 205}
|
||||
- {x: 103, y: 197}
|
||||
- {x: 117, y: 195}
|
||||
- {x: 130, y: 204}
|
||||
- {x: 118, y: 208}
|
||||
- {x: 103, y: 210}
|
||||
- {x: 180, y: 191}
|
||||
- {x: 189, y: 177}
|
||||
- {x: 202, y: 172}
|
||||
- {x: 214, y: 176}
|
||||
- {x: 207, y: 185}
|
||||
- {x: 195, y: 189}
|
||||
- {x: 131, y: 281}
|
||||
- {x: 149, y: 276}
|
||||
- {x: 165, y: 272}
|
||||
- {x: 176, y: 272}
|
||||
- {x: 187, y: 267}
|
||||
- {x: 199, y: 262}
|
||||
- {x: 212, y: 259}
|
||||
- {x: 204, y: 280}
|
||||
- {x: 194, y: 293}
|
||||
- {x: 183, y: 298}
|
||||
- {x: 171, y: 300}
|
||||
- {x: 152, y: 296}
|
||||
- {x: 139, y: 282}
|
||||
- {x: 167, y: 277}
|
||||
- {x: 178, y: 276}
|
||||
- {x: 189, y: 272}
|
||||
- {x: 206, y: 263}
|
||||
- {x: 190, y: 279}
|
||||
- {x: 179, y: 283}
|
||||
- {x: 168, y: 286}
|
||||
--- !u!1001 &100100000
|
||||
Prefab:
|
||||
m_ObjectHideFlags: 1
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 106612}
|
||||
m_IsPrefabParent: 1
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7bce755f0fbe79948b5ce92abdd4db30
|
||||
timeCreated: 1525053872
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 21181885807ea634fb644f9e2b6c0f90
|
||||
folderAsset: yes
|
||||
timeCreated: 1524908864
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,105 @@
|
|||
using OpenCVForUnity;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
namespace FaceMaskExample
|
||||
{
|
||||
/// <summary>
|
||||
/// Low Pass Points Filter.
|
||||
/// v 1.0.1
|
||||
/// </summary>
|
||||
public class LowPassPointsFilter : PointsFilterBase
|
||||
{
|
||||
public double diffLawPass = 2;
|
||||
|
||||
bool flag = false;
|
||||
|
||||
List<Vector2> lastPoints;
|
||||
|
||||
public LowPassPointsFilter (int numberOfElements) : base (numberOfElements)
|
||||
{
|
||||
lastPoints = new List<Vector2> ();
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
lastPoints.Add (new Vector2 ());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes points by filter.
|
||||
/// </summary>
|
||||
/// <param name="img">Image mat.</param>
|
||||
/// <param name="srcPoints">Input points.</param>
|
||||
/// <param name="dstPoints">Output points.</param>
|
||||
/// <param name="drawDebugPoints">if true, draws debug points.</param>
|
||||
/// <returns>Output points.</returns>
|
||||
public override List<Vector2> Process (Mat img, List<Vector2> srcPoints, List<Vector2> dstPoints = null, bool drawDebugPoints = false)
|
||||
{
|
||||
if (srcPoints != null && srcPoints.Count != numberOfElements) {
|
||||
throw new ArgumentException ("The number of elements is different.");
|
||||
}
|
||||
|
||||
if (srcPoints != null) {
|
||||
|
||||
if (dstPoints == null) {
|
||||
dstPoints = new List<Vector2> ();
|
||||
}
|
||||
if (dstPoints != null && dstPoints.Count != numberOfElements) {
|
||||
dstPoints.Clear ();
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
dstPoints.Add (new Vector2 ());
|
||||
}
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
double diff = Math.Sqrt (Math.Pow (srcPoints [i].x - lastPoints [i].x, 2.0) + Math.Pow (srcPoints [i].y - lastPoints [i].y, 2.0));
|
||||
if (diff > diffLawPass) {
|
||||
lastPoints [i] = srcPoints [i];
|
||||
if (drawDebugPoints)
|
||||
Imgproc.circle (img, new Point (srcPoints [i].x, srcPoints [i].y), 1, new Scalar (0, 255, 0, 255), -1);
|
||||
} else {
|
||||
if (drawDebugPoints)
|
||||
Imgproc.circle (img, new Point (lastPoints [i].x, lastPoints [i].y), 1, new Scalar (255, 0, 0, 255), -1);
|
||||
}
|
||||
dstPoints [i] = lastPoints [i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
lastPoints [i] = srcPoints [i];
|
||||
dstPoints [i] = srcPoints [i];
|
||||
}
|
||||
if (drawDebugPoints) {
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
Imgproc.circle (img, new Point (srcPoints [i].x, srcPoints [i].y), 1, new Scalar (0, 0, 255, 255), -1);
|
||||
}
|
||||
}
|
||||
flag = true;
|
||||
}
|
||||
return dstPoints;
|
||||
} else {
|
||||
return dstPoints == null ? srcPoints : dstPoints;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets filter.
|
||||
/// </summary>
|
||||
public override void Reset ()
|
||||
{
|
||||
flag = false;
|
||||
for (int i = 0; i < lastPoints.Count; i++) {
|
||||
lastPoints[i] = new Vector2 ();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To release the resources for the initialized method.
|
||||
/// </summary>
|
||||
public override void Dispose ()
|
||||
{
|
||||
if (lastPoints != null)
|
||||
lastPoints.Clear ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 24f3540b93dd3b74c907ab1a9fbf4010
|
||||
timeCreated: 1524908864
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,226 @@
|
|||
using OpenCVForUnity;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
namespace FaceMaskExample
|
||||
{
|
||||
/// <summary>
|
||||
/// Optical Flow Points Filter.
|
||||
/// v 1.0.2
|
||||
/// </summary>
|
||||
public class OFPointsFilter : PointsFilterBase
|
||||
{
|
||||
public double diffCheckSensitivity = 1;
|
||||
|
||||
bool flag = false;
|
||||
double diffDlib = 1;
|
||||
MatOfPoint prevTrackPtsMat;
|
||||
|
||||
// Optical Flow
|
||||
Mat prevgray, gray;
|
||||
List<Point> prevTrackPts;
|
||||
List<Point> nextTrackPts;
|
||||
MatOfPoint2f mOP2fPrevTrackPts;
|
||||
MatOfPoint2f mOP2fNextTrackPts;
|
||||
MatOfByte status;
|
||||
MatOfFloat err;
|
||||
|
||||
public OFPointsFilter (int numberOfElements) : base (numberOfElements)
|
||||
{
|
||||
diffDlib = diffDlib * (double)numberOfElements / 68.0;
|
||||
prevTrackPtsMat = new MatOfPoint ();
|
||||
|
||||
// Initialize Optical Flow
|
||||
InitializeOpticalFlow ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes points by filter.
|
||||
/// </summary>
|
||||
/// <param name="img">Image mat.</param>
|
||||
/// <param name="srcPoints">Input points.</param>
|
||||
/// <param name="dstPoints">Output points.</param>
|
||||
/// <param name="drawDebugPoints">if true, draws debug points.</param>
|
||||
/// <returns>Output points.</returns>
|
||||
public override List<Vector2> Process (Mat img, List<Vector2> srcPoints, List<Vector2> dstPoints = null, bool drawDebugPoints = false)
|
||||
{
|
||||
if (srcPoints != null && srcPoints.Count != numberOfElements) {
|
||||
throw new ArgumentException ("The number of elements is different.");
|
||||
}
|
||||
|
||||
if (srcPoints == null) {
|
||||
return dstPoints == null ? srcPoints : dstPoints;
|
||||
}
|
||||
|
||||
if (!flag) {
|
||||
if (img.channels () == 4) {
|
||||
Imgproc.cvtColor (img, prevgray, Imgproc.COLOR_RGBA2GRAY);
|
||||
} else if (img.channels () == 3) {
|
||||
Imgproc.cvtColor (img, prevgray, Imgproc.COLOR_RGB2GRAY);
|
||||
} else {
|
||||
if (prevgray.total () == 0) {
|
||||
prevgray = img.clone ();
|
||||
} else {
|
||||
img.copyTo (prevgray);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
prevTrackPts[i] = new Point (srcPoints [i].x, srcPoints [i].y);
|
||||
}
|
||||
|
||||
flag = true;
|
||||
}
|
||||
|
||||
if (srcPoints != null) {
|
||||
|
||||
if (dstPoints == null) {
|
||||
dstPoints = new List<Vector2> ();
|
||||
}
|
||||
if (dstPoints != null && dstPoints.Count != numberOfElements) {
|
||||
dstPoints.Clear ();
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
dstPoints.Add (new Vector2 ());
|
||||
}
|
||||
}
|
||||
|
||||
if (img.channels () == 4) {
|
||||
Imgproc.cvtColor (img, gray, Imgproc.COLOR_RGBA2GRAY);
|
||||
} else if (img.channels () == 3) {
|
||||
Imgproc.cvtColor (img, gray, Imgproc.COLOR_RGB2GRAY);
|
||||
} else {
|
||||
if (gray.total () == 0) {
|
||||
gray = img.clone ();
|
||||
} else {
|
||||
img.copyTo (gray);
|
||||
}
|
||||
}
|
||||
|
||||
if (prevgray.total () > 0) {
|
||||
mOP2fPrevTrackPts.fromList (prevTrackPts);
|
||||
mOP2fNextTrackPts.fromList (nextTrackPts);
|
||||
Video.calcOpticalFlowPyrLK (prevgray, gray, mOP2fPrevTrackPts, mOP2fNextTrackPts, status, err);
|
||||
prevTrackPts = mOP2fPrevTrackPts.toList ();
|
||||
nextTrackPts = mOP2fNextTrackPts.toList ();
|
||||
|
||||
// clac diffDlib
|
||||
prevTrackPtsMat.fromList (prevTrackPts);
|
||||
OpenCVForUnity.Rect rect = Imgproc.boundingRect (prevTrackPtsMat);
|
||||
double diffDlib = this.diffDlib * rect.area () / 40000.0 * diffCheckSensitivity;
|
||||
|
||||
// if the face is moving so fast, use dlib to detect the face
|
||||
double diff = calDistanceDiff (prevTrackPts, nextTrackPts);
|
||||
if (drawDebugPoints)
|
||||
Debug.Log ("variance:" + diff);
|
||||
if (diff > diffDlib) {
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
nextTrackPts [i].x = srcPoints [i].x;
|
||||
nextTrackPts [i].y = srcPoints [i].y;
|
||||
|
||||
dstPoints [i] = srcPoints [i];
|
||||
}
|
||||
|
||||
if (drawDebugPoints) {
|
||||
Debug.Log ("DLIB");
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
Imgproc.circle (img, new Point (srcPoints [i].x, srcPoints [i].y), 2, new Scalar (255, 0, 0, 255), -1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// In this case, use Optical Flow
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
dstPoints [i] = new Vector2 ((float)nextTrackPts [i].x, (float)nextTrackPts [i].y);
|
||||
}
|
||||
|
||||
if (drawDebugPoints) {
|
||||
Debug.Log ("Optical Flow");
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
Imgproc.circle (img, nextTrackPts [i], 2, new Scalar (0, 0, 255, 255), -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Swap (ref prevTrackPts, ref nextTrackPts);
|
||||
Swap (ref prevgray, ref gray);
|
||||
}
|
||||
return dstPoints;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets filter.
|
||||
/// </summary>
|
||||
public override void Reset ()
|
||||
{
|
||||
flag = false;
|
||||
|
||||
// Reset Optical Flow
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
prevTrackPts[i].x = 0.0;
|
||||
prevTrackPts[i].y = 0.0;
|
||||
}
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
nextTrackPts[i].x = 0.0;
|
||||
nextTrackPts[i].y = 0.0;
|
||||
}
|
||||
|
||||
if (prevgray != null) {
|
||||
prevgray.Dispose ();
|
||||
prevgray = new Mat();
|
||||
}
|
||||
if (gray != null) {
|
||||
gray.Dispose ();
|
||||
gray = new Mat();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To release the resources for the initialized method.
|
||||
/// </summary>
|
||||
public override void Dispose ()
|
||||
{
|
||||
DisposeOpticalFlow ();
|
||||
|
||||
if (prevTrackPtsMat != null)
|
||||
prevTrackPtsMat.Dispose ();
|
||||
}
|
||||
|
||||
protected virtual void InitializeOpticalFlow ()
|
||||
{
|
||||
prevTrackPts = new List<Point> ();
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
prevTrackPts.Add (new Point (0, 0));
|
||||
}
|
||||
nextTrackPts = new List<Point> ();
|
||||
for (int i = 0; i < numberOfElements; i++) {
|
||||
nextTrackPts.Add (new Point (0, 0));
|
||||
}
|
||||
prevgray = new Mat ();
|
||||
gray = new Mat ();
|
||||
mOP2fPrevTrackPts = new MatOfPoint2f ();
|
||||
mOP2fNextTrackPts = new MatOfPoint2f ();
|
||||
status = new MatOfByte ();
|
||||
err = new MatOfFloat ();
|
||||
}
|
||||
|
||||
protected virtual void DisposeOpticalFlow ()
|
||||
{
|
||||
if (prevTrackPts != null)
|
||||
prevTrackPts.Clear ();
|
||||
if (nextTrackPts != null)
|
||||
nextTrackPts.Clear ();
|
||||
if (prevgray != null)
|
||||
prevgray.Dispose ();
|
||||
if (gray != null)
|
||||
gray.Dispose ();
|
||||
if (mOP2fPrevTrackPts != null)
|
||||
mOP2fPrevTrackPts.Dispose ();
|
||||
if (mOP2fNextTrackPts != null)
|
||||
mOP2fNextTrackPts.Dispose ();
|
||||
if (status != null)
|
||||
status.Dispose ();
|
||||
if (err != null)
|
||||
err.Dispose ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0d06a0c2df0f8374fad9aec01903ddad
|
||||
timeCreated: 1524908864
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,69 @@
|
|||
using OpenCVForUnity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FaceMaskExample
|
||||
{
|
||||
/// <summary>
|
||||
/// Points Filter Base.
|
||||
/// v 1.0.0
|
||||
/// </summary>
|
||||
public abstract class PointsFilterBase
|
||||
{
|
||||
protected int numberOfElements;
|
||||
|
||||
public PointsFilterBase (int numberOfElements)
|
||||
{
|
||||
this.numberOfElements = numberOfElements;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes points by filter.
|
||||
/// </summary>
|
||||
/// <param name="img">Image mat.</param>
|
||||
/// <param name="srcPoints">Input points.</param>
|
||||
/// <param name="dstPoints">Output points.</param>
|
||||
/// <param name="drawDebugPoints">if true, draws debug points.</param>
|
||||
/// <returns>Output points.</returns>
|
||||
public abstract List<Vector2> Process (Mat img, List<Vector2> srcPoints, List<Vector2> dstPoints = null, bool drawDebugPoints = false);
|
||||
|
||||
/// <summary>
|
||||
/// Resets filter.
|
||||
/// </summary>
|
||||
public abstract void Reset ();
|
||||
|
||||
/// <summary>
|
||||
/// To release the resources for the initialized method.
|
||||
/// </summary>
|
||||
public abstract void Dispose ();
|
||||
|
||||
// This function is to calculate the variance
|
||||
protected virtual double calDistanceDiff (List<Point> curPoints, List<Point> lastPoints)
|
||||
{
|
||||
double variance = 0.0;
|
||||
double sum = 0.0;
|
||||
List<double> diffs = new List<double> ();
|
||||
if (curPoints.Count == lastPoints.Count) {
|
||||
for (int i = 0; i < curPoints.Count; i++) {
|
||||
double diff = Math.Sqrt (Math.Pow (curPoints [i].x - lastPoints [i].x, 2.0) + Math.Pow (curPoints [i].y - lastPoints [i].y, 2.0));
|
||||
sum += diff;
|
||||
diffs.Add (diff);
|
||||
}
|
||||
double mean = sum / diffs.Count;
|
||||
for (int i = 0; i < curPoints.Count; i++) {
|
||||
variance += Math.Pow (diffs [i] - mean, 2);
|
||||
}
|
||||
return variance / diffs.Count;
|
||||
}
|
||||
return variance;
|
||||
}
|
||||
|
||||
protected virtual void Swap<T> (ref T a, ref T b)
|
||||
{
|
||||
var t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 293161dac92d6dc428ad94076f333159
|
||||
timeCreated: 1524908864
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -33,9 +33,13 @@ namespace FaceMaskExample
|
|||
|
||||
public Material material
|
||||
{
|
||||
get { return _material; }
|
||||
get { return _meshRenderer.material; }
|
||||
}
|
||||
|
||||
public Material sharedMaterial
|
||||
{
|
||||
get { return _meshRenderer.sharedMaterial; }
|
||||
}
|
||||
protected Material _material;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
|
@ -46,7 +50,6 @@ namespace FaceMaskExample
|
|||
if (_meshRenderer.material == null)
|
||||
throw new Exception("material does not exist.");
|
||||
|
||||
_material = _meshRenderer.material;
|
||||
_meshRenderer.sortingOrder = 32767;
|
||||
}
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FaceMaskExample
|
||||
{
|
||||
public class FpsMonitor : MonoBehaviour
|
||||
{
|
||||
int tick = 0;
|
||||
float elapsed = 0;
|
||||
float fps = 0;
|
||||
|
||||
public enum Alignment
|
||||
{
|
||||
LeftTop,
|
||||
RightTop,
|
||||
LeftBottom,
|
||||
RightBottom,
|
||||
}
|
||||
|
||||
public Alignment alignment = Alignment.RightTop;
|
||||
|
||||
const float GUI_WIDTH = 75f;
|
||||
const float GUI_HEIGHT = 30f;
|
||||
const float MARGIN_X = 10f;
|
||||
const float MARGIN_Y = 10f;
|
||||
const float INNER_X = 8f;
|
||||
const float INNER_Y = 5f;
|
||||
const float GUI_CONSOLE_HEIGHT = 50f;
|
||||
|
||||
public Vector2 offset = new Vector2(MARGIN_X, MARGIN_Y);
|
||||
public bool boxVisible = true;
|
||||
public float boxWidth = GUI_WIDTH;
|
||||
public float boxHeight = GUI_HEIGHT;
|
||||
public Vector2 padding = new Vector2(INNER_X, INNER_Y);
|
||||
public float consoleHeight = GUI_CONSOLE_HEIGHT;
|
||||
|
||||
GUIStyle console_labelStyle;
|
||||
|
||||
float x, y;
|
||||
Rect outer;
|
||||
Rect inner;
|
||||
|
||||
float console_x, console_y;
|
||||
Rect console_outer;
|
||||
Rect console_inner;
|
||||
|
||||
int oldScrWidth;
|
||||
int oldScrHeight;
|
||||
|
||||
Dictionary<string, string> outputDict = new Dictionary<string, string> ();
|
||||
public string consoleText;
|
||||
|
||||
// Use this for initialization
|
||||
void Start () {
|
||||
console_labelStyle = new GUIStyle ();
|
||||
console_labelStyle.fontSize = 32;
|
||||
console_labelStyle.fontStyle = FontStyle.Normal;
|
||||
console_labelStyle.wordWrap = true;
|
||||
console_labelStyle.normal.textColor = Color.white;
|
||||
|
||||
oldScrWidth = Screen.width;
|
||||
oldScrHeight = Screen.height;
|
||||
LocateGUI();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update () {
|
||||
tick++;
|
||||
elapsed += Time.deltaTime;
|
||||
if (elapsed >= 1f) {
|
||||
fps = tick / elapsed;
|
||||
tick = 0;
|
||||
elapsed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI () {
|
||||
if (oldScrWidth != Screen.width || oldScrHeight != Screen.height) {
|
||||
LocateGUI();
|
||||
}
|
||||
oldScrWidth = Screen.width;
|
||||
oldScrHeight = Screen.height;
|
||||
|
||||
if (boxVisible) {
|
||||
GUI.Box(outer, "");
|
||||
}
|
||||
|
||||
GUILayout.BeginArea(inner);
|
||||
{
|
||||
GUILayout.BeginVertical();
|
||||
GUILayout.Label("fps : " + fps.ToString("F1"));
|
||||
foreach (KeyValuePair<string, string> pair in outputDict) {
|
||||
GUILayout.Label(pair.Key + " : " + pair.Value);
|
||||
}
|
||||
GUILayout.EndVertical();
|
||||
}
|
||||
GUILayout.EndArea ();
|
||||
|
||||
if (!string.IsNullOrEmpty(consoleText)) {
|
||||
if (boxVisible) {
|
||||
GUI.Box (console_outer, "");
|
||||
}
|
||||
|
||||
GUILayout.BeginArea (console_inner);
|
||||
{
|
||||
GUILayout.BeginVertical ();
|
||||
GUILayout.Label (consoleText, console_labelStyle);
|
||||
GUILayout.EndVertical ();
|
||||
}
|
||||
GUILayout.EndArea ();
|
||||
}
|
||||
}
|
||||
|
||||
public void Add (string key, string value) {
|
||||
if (outputDict.ContainsKey (key)) {
|
||||
outputDict [key] = value;
|
||||
} else {
|
||||
outputDict.Add (key, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove (string key) {
|
||||
outputDict.Remove (key);
|
||||
}
|
||||
|
||||
public void Clear () {
|
||||
outputDict.Clear ();
|
||||
}
|
||||
|
||||
public void LocateGUI() {
|
||||
x = GetAlignedX(alignment, boxWidth);
|
||||
y = GetAlignedY(alignment, boxHeight);
|
||||
outer = new Rect(x, y, boxWidth, boxHeight);
|
||||
inner = new Rect(x + padding.x, y + padding.y, boxWidth, boxHeight);
|
||||
|
||||
console_x = GetAlignedX(Alignment.LeftBottom, Screen.width);
|
||||
console_y = GetAlignedY(Alignment.LeftBottom, consoleHeight);
|
||||
console_outer = new Rect(console_x, console_y, Screen.width - offset.x*2, consoleHeight);
|
||||
console_inner = new Rect(console_x + padding.x, console_y + padding.y, Screen.width - offset.x*2 - padding.x, consoleHeight);
|
||||
}
|
||||
|
||||
float GetAlignedX(Alignment anchor, float w) {
|
||||
switch (anchor) {
|
||||
default:
|
||||
case Alignment.LeftTop:
|
||||
case Alignment.LeftBottom:
|
||||
return offset.x;
|
||||
|
||||
case Alignment.RightTop:
|
||||
case Alignment.RightBottom:
|
||||
return Screen.width - w - offset.x;
|
||||
}
|
||||
}
|
||||
|
||||
float GetAlignedY(Alignment anchor, float h) {
|
||||
switch (anchor) {
|
||||
default:
|
||||
case Alignment.LeftTop:
|
||||
case Alignment.RightTop:
|
||||
return offset.y;
|
||||
|
||||
case Alignment.LeftBottom:
|
||||
case Alignment.RightBottom:
|
||||
return Screen.height - h - offset.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cd57f7322151d1e48a147066c213efaf
|
||||
timeCreated: 1524882968
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -14,7 +14,7 @@ namespace FaceMaskExample
|
|||
public static class OpenCVForUnityUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the image.
|
||||
/// Sets a image.
|
||||
/// </summary>
|
||||
/// <param name="faceLandmarkDetector">Face landmark detector.</param>
|
||||
/// <param name="imgMat">Image mat.</param>
|
||||
|
@ -27,7 +27,7 @@ namespace FaceMaskExample
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the face rect.
|
||||
/// Draws a face rect.
|
||||
/// </summary>
|
||||
/// <param name="imgMat">Image mat.</param>
|
||||
/// <param name="rect">Rect.</param>
|
||||
|
@ -39,23 +39,55 @@ namespace FaceMaskExample
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the face landmark.
|
||||
/// Draws a face rect.
|
||||
/// </summary>
|
||||
/// <param name="imgMat">Image mat.</param>
|
||||
/// <param name="rect">RectDetection.</param>
|
||||
/// <param name="color">Color.</param>
|
||||
/// <param name="thickness">Thickness.</param>
|
||||
public static void DrawFaceRect (Mat imgMat, DlibFaceLandmarkDetector.FaceLandmarkDetector.RectDetection rect, Scalar color, int thickness)
|
||||
{
|
||||
UnityEngine.Rect _rect = rect.rect;
|
||||
Imgproc.putText (imgMat, "detection_confidence : " + rect.detection_confidence, new Point (_rect.xMin, _rect.yMin - 20), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
Imgproc.putText (imgMat, "weight_index : " + rect.weight_index, new Point (_rect.xMin, _rect.yMin - 5), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
Imgproc.rectangle (imgMat, new Point (_rect.xMin, _rect.yMin), new Point (_rect.xMax, _rect.yMax), color, thickness);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a face rect.
|
||||
/// </summary>
|
||||
/// <param name="imgMat">Image mat.</param>
|
||||
/// <param name="rect">Detected object's data. [left, top, width, height, detection_confidence, weight_index]</param>
|
||||
/// <param name="color">Color.</param>
|
||||
/// <param name="thickness">Thickness.</param>
|
||||
public static void DrawFaceRect (Mat imgMat, double[] rect, Scalar color, int thickness)
|
||||
{
|
||||
if (rect.Length > 4)
|
||||
Imgproc.putText (imgMat, "detection_confidence : " + rect[4], new Point (rect[0], rect[1] - 20), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
if (rect.Length > 5)
|
||||
Imgproc.putText (imgMat, "weight_index : " + rect[5], new Point (rect[0], rect[1] - 5), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
Imgproc.rectangle (imgMat, new Point (rect[0], rect[1]), new Point (rect[0] + rect[2], rect[1] + rect[3]), color, thickness);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a face landmark.
|
||||
/// This method supports 68 landmark points.
|
||||
/// </summary>
|
||||
/// <param name="imgMat">Image mat.</param>
|
||||
/// <param name="points">Points.</param>
|
||||
/// <param name="color">Color.</param>
|
||||
/// <param name="thickness">Thickness.</param>
|
||||
public static void DrawFaceLandmark (Mat imgMat, List<Vector2> points, Scalar color, int thickness)
|
||||
/// <param name="drawIndexNumbers">Determines if draw index numbers.</param>
|
||||
public static void DrawFaceLandmark (Mat imgMat, List<Vector2> points, Scalar color, int thickness, bool drawIndexNumbers = false)
|
||||
{
|
||||
// //Draw the index number of facelandmark points.
|
||||
// for (int i = 0; i < points.Count; i++) {
|
||||
//
|
||||
// Imgproc.putText (imgMat, "" + i, new Point (points [i].x, points [i].y), Core.FONT_HERSHEY_SIMPLEX, 0.4, new Scalar (0, 0, 255, 255), 1, Core.LINE_AA, false);
|
||||
//
|
||||
// }
|
||||
if (points.Count == 5) {
|
||||
|
||||
if (points.Count == 68) {
|
||||
Imgproc.line (imgMat, new Point (points [0].x, points [0].y), new Point (points [1].x, points [1].y), color, thickness);
|
||||
Imgproc.line (imgMat, new Point (points [1].x, points [1].y), new Point (points [4].x, points [4].y), color, thickness);
|
||||
Imgproc.line (imgMat, new Point (points [4].x, points [4].y), new Point (points [3].x, points [3].y), color, thickness);
|
||||
Imgproc.line (imgMat, new Point (points [3].x, points [3].y), new Point (points [2].x, points [2].y), color, thickness);
|
||||
|
||||
} else if (points.Count == 68) {
|
||||
|
||||
for (int i = 1; i <= 16; ++i)
|
||||
Imgproc.line (imgMat, new Point (points [i].x, points [i].y), new Point (points [i - 1].x, points [i - 1].y), color, thickness);
|
||||
|
@ -91,6 +123,238 @@ namespace FaceMaskExample
|
|||
Imgproc.circle (imgMat, new Point (points [i].x, points [i].y), 2, color, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the index number of facelandmark points.
|
||||
if (drawIndexNumbers) {
|
||||
for (int i = 0; i < points.Count; ++i)
|
||||
Imgproc.putText (imgMat, i.ToString (), new Point (points [i].x, points [i].y), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a face landmark.
|
||||
/// This method supports 68 landmark points.
|
||||
/// </summary>
|
||||
/// <param name="imgMat">Image mat.</param>
|
||||
/// <param name="points">Points.</param>
|
||||
/// <param name="color">Color.</param>
|
||||
/// <param name="thickness">Thickness.</param>
|
||||
/// <param name="drawIndexNumbers">Determines if draw index numbers.</param>
|
||||
public static void DrawFaceLandmark (Mat imgMat, List<Point> points, Scalar color, int thickness, bool drawIndexNumbers = false)
|
||||
{
|
||||
if (points.Count == 5) {
|
||||
|
||||
Imgproc.line (imgMat, points [0], points [1], color, thickness);
|
||||
Imgproc.line (imgMat, points [1], points [4], color, thickness);
|
||||
Imgproc.line (imgMat, points [4], points [3], color, thickness);
|
||||
Imgproc.line (imgMat, points [3], points [2], color, thickness);
|
||||
|
||||
} else if (points.Count == 68) {
|
||||
|
||||
for (int i = 1; i <= 16; ++i)
|
||||
Imgproc.line (imgMat, points [i], points [i - 1], color, thickness);
|
||||
|
||||
for (int i = 28; i <= 30; ++i)
|
||||
Imgproc.line (imgMat, points [i], points [i - 1], color, thickness);
|
||||
|
||||
for (int i = 18; i <= 21; ++i)
|
||||
Imgproc.line (imgMat, points [i], points [i - 1], color, thickness);
|
||||
for (int i = 23; i <= 26; ++i)
|
||||
Imgproc.line (imgMat, points [i], points [i - 1], color, thickness);
|
||||
for (int i = 31; i <= 35; ++i)
|
||||
Imgproc.line (imgMat, points [i], points [i - 1], color, thickness);
|
||||
Imgproc.line (imgMat, points [30], points [35], color, thickness);
|
||||
|
||||
for (int i = 37; i <= 41; ++i)
|
||||
Imgproc.line (imgMat, points [i], points [i - 1], color, thickness);
|
||||
Imgproc.line (imgMat, points [36], points [41], color, thickness);
|
||||
|
||||
for (int i = 43; i <= 47; ++i)
|
||||
Imgproc.line (imgMat, points [i], points [i - 1], color, thickness);
|
||||
Imgproc.line (imgMat, points [42], points [47], color, thickness);
|
||||
|
||||
for (int i = 49; i <= 59; ++i)
|
||||
Imgproc.line (imgMat, points [i], points [i - 1], color, thickness);
|
||||
Imgproc.line (imgMat, points [48], points [59], color, thickness);
|
||||
|
||||
for (int i = 61; i <= 67; ++i)
|
||||
Imgproc.line (imgMat, points [i], points [i - 1], color, thickness);
|
||||
Imgproc.line (imgMat, points [60], points [67], color, thickness);
|
||||
} else {
|
||||
for (int i = 0; i < points.Count; i++) {
|
||||
Imgproc.circle (imgMat, points [i], 2, color, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the index number of facelandmark points.
|
||||
if (drawIndexNumbers) {
|
||||
for (int i = 0; i < points.Count; ++i)
|
||||
Imgproc.putText (imgMat, i.ToString (), points [i], Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a face landmark.
|
||||
/// This method supports 68 landmark points.
|
||||
/// </summary>
|
||||
/// <param name="imgMat">Image mat.</param>
|
||||
/// <param name="points">Detected object landmark data.[x_0, y_0, x_1, y_1, ...]</param>
|
||||
/// <param name="color">Color.</param>
|
||||
/// <param name="thickness">Thickness.</param>
|
||||
/// <param name="drawIndexNumbers">Determines if draw index numbers.</param>
|
||||
public static void DrawFaceLandmark (Mat imgMat, double[] points, Scalar color, int thickness, bool drawIndexNumbers = false)
|
||||
{
|
||||
List<Vector2> _points = new List<Vector2> ();
|
||||
for (int i = 0; i < points.Length; i = i + 2) {
|
||||
_points.Add (new Vector2 ((float)points [i], (float)points [i + 1]));
|
||||
}
|
||||
DrawFaceLandmark (imgMat, _points, color, thickness, drawIndexNumbers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert vector2 list to point list.
|
||||
/// </summary>
|
||||
/// <param name="vecs">List of vector2.</param>
|
||||
/// <param name="pts">List of point.</param>
|
||||
/// <returns>List of point.</returns>
|
||||
public static List<Point> ConvertVector2ListToPointList (List<Vector2> vecs, List<Point> pts = null)
|
||||
{
|
||||
if (pts == null) {
|
||||
pts = new List<Point> ();
|
||||
}
|
||||
|
||||
if (pts.Count != vecs.Count) {
|
||||
pts.Clear ();
|
||||
for (int i = 0; i < vecs.Count; i++) {
|
||||
pts.Add (new Point ());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < vecs.Count; ++i) {
|
||||
pts [i].x = vecs [i].x;
|
||||
pts [i].y = vecs [i].y;
|
||||
}
|
||||
|
||||
return pts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert vector2 list to array.
|
||||
/// </summary>
|
||||
/// <param name="vecs">List of vector2.</param>
|
||||
/// <param name="arr">Array of double.</param>
|
||||
/// <returns>Array of double.</returns>
|
||||
public static double[] ConvertVector2ListToArray (List<Vector2> vecs, double[] arr = null)
|
||||
{
|
||||
if (arr == null || (arr != null && arr.Length != vecs.Count * 2)) {
|
||||
arr = new double[vecs.Count * 2];
|
||||
}
|
||||
|
||||
for (int i = 0; i < vecs.Count; ++i) {
|
||||
arr [i * 2] = vecs [i].x;
|
||||
arr [i * 2 + 1] = vecs [i].y;
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert point list to vector2 list.
|
||||
/// </summary>
|
||||
/// <param name="pts">List of point.</param>
|
||||
/// <param name="vecs">List of vector2.</param>
|
||||
/// <returns>List of vector2.</returns>
|
||||
public static List<Vector2> ConvertPointListToVector2List (List<Point> pts, List<Vector2> vecs = null)
|
||||
{
|
||||
if (vecs == null) {
|
||||
vecs = new List<Vector2> ();
|
||||
}
|
||||
|
||||
if (vecs.Count != pts.Count) {
|
||||
vecs.Clear ();
|
||||
for (int i = 0; i < pts.Count; i++) {
|
||||
vecs.Add (new Vector2 ());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < pts.Count; ++i) {
|
||||
vecs.Add (new Vector2((float)pts[i].x, (float)pts[i].y));
|
||||
}
|
||||
|
||||
return vecs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert point list to array.
|
||||
/// </summary>
|
||||
/// <param name="pts">List of point.</param>
|
||||
/// <param name="arr">Array of double.</param>
|
||||
/// <returns>Array of double.</returns>
|
||||
public static double[] ConvertPointListToArray (List<Point> pts, double[] arr = null)
|
||||
{
|
||||
if (arr == null || (arr != null && arr.Length != pts.Count * 2)) {
|
||||
arr = new double[pts.Count * 2];
|
||||
}
|
||||
|
||||
for (int i = 0; i < pts.Count; ++i) {
|
||||
arr [i * 2] = pts [i].x;
|
||||
arr [i * 2 + 1] = pts [i].y;
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert array to vector2 list.
|
||||
/// </summary>
|
||||
/// <param name="arr">Array of double.</param>
|
||||
/// <param name="vecs">List of vector2.</param>
|
||||
/// <returns>List of vector2.</returns>
|
||||
public static List<Vector2> ConvertArrayToVector2List (double[] arr, List<Vector2> vecs = null)
|
||||
{
|
||||
if (vecs == null) {
|
||||
vecs = new List<Vector2> ();
|
||||
}
|
||||
|
||||
if (vecs.Count != arr.Length / 2) {
|
||||
vecs.Clear ();
|
||||
for (int i = 0; i < arr.Length / 2; i++) {
|
||||
vecs.Add (new Vector2 ());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < vecs.Count; ++i) {
|
||||
vecs [i] = new Vector2((float)arr [i * 2], (float)arr [i * 2 + 1]);
|
||||
}
|
||||
|
||||
return vecs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert array to point list.
|
||||
/// </summary>
|
||||
/// <param name="arr">Array of double.</param>
|
||||
/// <param name="pts">List of point.</param>
|
||||
/// <returns>List of point.</returns>
|
||||
public static List<Point> ConvertArrayToPointList (double[] arr, List<Point> pts = null)
|
||||
{
|
||||
if (pts == null) {
|
||||
pts = new List<Point> ();
|
||||
}
|
||||
|
||||
if (pts.Count != arr.Length / 2) {
|
||||
pts.Clear ();
|
||||
for (int i = 0; i < arr.Length / 2; i++) {
|
||||
pts.Add (new Point ());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < pts.Count; ++i) {
|
||||
pts [i].x = arr [i * 2];
|
||||
pts [i].y = arr [i * 2 + 1];
|
||||
}
|
||||
|
||||
return pts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,67 +3,138 @@ using System;
|
|||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace FaceMaskExample
|
||||
{
|
||||
/// <summary>
|
||||
/// Webcam texture to mat helper.
|
||||
/// v 1.0.4
|
||||
/// WebcamTexture to mat helper.
|
||||
/// v 1.0.8
|
||||
/// </summary>
|
||||
public class WebCamTextureToMatHelper : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Set the name of the device to use.
|
||||
/// Set the name of the camera device to use. (or device index number)
|
||||
/// </summary>
|
||||
[SerializeField, TooltipAttribute ("Set the name of the device to use.")]
|
||||
public string requestedDeviceName = null;
|
||||
[SerializeField, FormerlySerializedAs("requestedDeviceName"), TooltipAttribute ("Set the name of the device to use. (or device index number)")]
|
||||
protected string _requestedDeviceName = null;
|
||||
public virtual string requestedDeviceName {
|
||||
get { return _requestedDeviceName; }
|
||||
set {
|
||||
_requestedDeviceName = value;
|
||||
if (hasInitDone) {
|
||||
Initialize ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the width of WebCamTexture.
|
||||
/// Set the width of camera.
|
||||
/// </summary>
|
||||
[SerializeField, TooltipAttribute ("Set the width of WebCamTexture.")]
|
||||
public int requestedWidth = 640;
|
||||
[SerializeField, FormerlySerializedAs("requestedWidth"), TooltipAttribute ("Set the width of camera.")]
|
||||
protected int _requestedWidth = 640;
|
||||
public virtual int requestedWidth {
|
||||
get { return _requestedWidth; }
|
||||
set {
|
||||
_requestedWidth = (int)Mathf.Clamp(value, 0f, float.MaxValue);
|
||||
if (hasInitDone) {
|
||||
Initialize ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the height of WebCamTexture.
|
||||
/// Set the height of camera.
|
||||
/// </summary>
|
||||
[SerializeField, TooltipAttribute ("Set the height of WebCamTexture.")]
|
||||
public int requestedHeight = 480;
|
||||
[SerializeField, FormerlySerializedAs("requestedHeight"), TooltipAttribute ("Set the height of camera.")]
|
||||
protected int _requestedHeight = 480;
|
||||
public virtual int requestedHeight {
|
||||
get { return _requestedHeight; }
|
||||
set {
|
||||
_requestedHeight = (int)Mathf.Clamp(value, 0f, float.MaxValue);
|
||||
if (hasInitDone) {
|
||||
Initialize ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set whether to use the front facing camera.
|
||||
/// </summary>
|
||||
[SerializeField, TooltipAttribute ("Set whether to use the front facing camera.")]
|
||||
public bool requestedIsFrontFacing = false;
|
||||
[SerializeField, FormerlySerializedAs("requestedIsFrontFacing"), TooltipAttribute ("Set whether to use the front facing camera.")]
|
||||
protected bool _requestedIsFrontFacing = false;
|
||||
public virtual bool requestedIsFrontFacing {
|
||||
get { return _requestedIsFrontFacing; }
|
||||
set {
|
||||
_requestedIsFrontFacing = value;
|
||||
if (hasInitDone) {
|
||||
Initialize (_requestedIsFrontFacing, requestedFPS, rotate90Degree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set FPS of WebCamTexture.
|
||||
/// Set the frame rate of camera.
|
||||
/// </summary>
|
||||
[SerializeField, TooltipAttribute ("Set FPS of WebCamTexture.")]
|
||||
public int requestedFPS = 30;
|
||||
[SerializeField, FormerlySerializedAs("requestedFPS"), TooltipAttribute ("Set the frame rate of camera.")]
|
||||
protected float _requestedFPS = 30f;
|
||||
public virtual float requestedFPS {
|
||||
get { return _requestedFPS; }
|
||||
set {
|
||||
_requestedFPS = Mathf.Clamp(value, -1f, float.MaxValue);
|
||||
if (hasInitDone) {
|
||||
bool isPlaying = IsPlaying ();
|
||||
Stop ();
|
||||
webCamTexture.requestedFPS = _requestedFPS;
|
||||
if (isPlaying) Play ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether to rotate WebCamTexture 90 degrees.
|
||||
/// Sets whether to rotate camera frame 90 degrees. (clockwise)
|
||||
/// </summary>
|
||||
[SerializeField, TooltipAttribute ("Sets whether to rotate WebCamTexture 90 degrees.")]
|
||||
public bool requestedRotate90Degree = false;
|
||||
[SerializeField, FormerlySerializedAs("rotate90Degree"), TooltipAttribute ("Sets whether to rotate camera frame 90 degrees. (clockwise)")]
|
||||
protected bool _rotate90Degree = false;
|
||||
public virtual bool rotate90Degree {
|
||||
get { return _rotate90Degree; }
|
||||
set {
|
||||
_rotate90Degree = value;
|
||||
if (hasInitDone) {
|
||||
Initialize ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if flips vertically.
|
||||
/// </summary>
|
||||
[SerializeField, TooltipAttribute ("Determines if flips vertically.")]
|
||||
public bool flipVertical = false;
|
||||
[SerializeField, FormerlySerializedAs("flipVertical"), TooltipAttribute ("Determines if flips vertically.")]
|
||||
protected bool _flipVertical = false;
|
||||
public virtual bool flipVertical {
|
||||
get { return _flipVertical; }
|
||||
set { _flipVertical = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if flips horizontal.
|
||||
/// </summary>
|
||||
[SerializeField, TooltipAttribute ("Determines if flips horizontal.")]
|
||||
public bool flipHorizontal = false;
|
||||
|
||||
[SerializeField, FormerlySerializedAs("flipHorizontal"), TooltipAttribute ("Determines if flips horizontal.")]
|
||||
protected bool _flipHorizontal = false;
|
||||
public virtual bool flipHorizontal {
|
||||
get { return _flipHorizontal; }
|
||||
set { _flipHorizontal = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The timeout frame count.
|
||||
/// The number of frames before the initialization process times out.
|
||||
/// </summary>
|
||||
public int timeoutFrameCount = 300;
|
||||
[SerializeField, FormerlySerializedAs("timeoutFrameCount"), TooltipAttribute ("The number of frames before the initialization process times out.")]
|
||||
protected int _timeoutFrameCount = 300;
|
||||
public virtual int timeoutFrameCount {
|
||||
get { return _timeoutFrameCount; }
|
||||
set { _timeoutFrameCount = (int)Mathf.Clamp(value, 0f, float.MaxValue); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UnityEvent that is triggered when this instance is initialized.
|
||||
|
@ -81,24 +152,24 @@ namespace FaceMaskExample
|
|||
public ErrorUnityEvent onErrorOccurred;
|
||||
|
||||
/// <summary>
|
||||
/// The webcam texture.
|
||||
/// The active WebcamTexture.
|
||||
/// </summary>
|
||||
protected WebCamTexture webCamTexture;
|
||||
|
||||
/// <summary>
|
||||
/// The webcam device.
|
||||
/// The active WebcamDevice.
|
||||
/// </summary>
|
||||
protected WebCamDevice webCamDevice;
|
||||
|
||||
/// <summary>
|
||||
/// The rgba mat.
|
||||
/// The frame mat.
|
||||
/// </summary>
|
||||
protected Mat rgbaMat;
|
||||
protected Mat frameMat;
|
||||
|
||||
/// <summary>
|
||||
/// The rotated rgba mat
|
||||
/// The rotated frame mat
|
||||
/// </summary>
|
||||
protected Mat rotatedRgbaMat;
|
||||
protected Mat rotatedFrameMat;
|
||||
|
||||
/// <summary>
|
||||
/// The buffer colors.
|
||||
|
@ -116,15 +187,32 @@ namespace FaceMaskExample
|
|||
protected bool hasInitDone = false;
|
||||
|
||||
/// <summary>
|
||||
/// Orientation of the screen.
|
||||
/// The initialization coroutine.
|
||||
/// </summary>
|
||||
protected IEnumerator initCoroutine;
|
||||
|
||||
/// <summary>
|
||||
/// The orientation of the screen.
|
||||
/// </summary>
|
||||
protected ScreenOrientation screenOrientation;
|
||||
|
||||
/// <summary>
|
||||
/// The width of the screen.
|
||||
/// </summary>
|
||||
protected int screenWidth;
|
||||
|
||||
/// <summary>
|
||||
/// The height of the screen.
|
||||
/// </summary>
|
||||
protected int screenHeight;
|
||||
|
||||
|
||||
[System.Serializable]
|
||||
public enum ErrorCode :int
|
||||
{
|
||||
CAMERA_DEVICE_NOT_EXIST = 0,
|
||||
TIMEOUT = 1,
|
||||
UNKNOWN = 0,
|
||||
CAMERA_DEVICE_NOT_EXIST = 1,
|
||||
TIMEOUT = 2,
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
|
@ -133,12 +221,58 @@ namespace FaceMaskExample
|
|||
|
||||
}
|
||||
|
||||
protected virtual void OnValidate()
|
||||
{
|
||||
_requestedWidth = (int)Mathf.Clamp(_requestedWidth, 0f, float.MaxValue);
|
||||
_requestedHeight = (int)Mathf.Clamp(_requestedHeight, 0f, float.MaxValue);
|
||||
_requestedFPS = Mathf.Clamp(_requestedFPS, -1f, float.MaxValue);
|
||||
_timeoutFrameCount = (int)Mathf.Clamp(_timeoutFrameCount, 0f, float.MaxValue);
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
protected virtual void Update ()
|
||||
{
|
||||
if (hasInitDone) {
|
||||
if (screenOrientation != Screen.orientation) {
|
||||
StartCoroutine (_Initialize ());
|
||||
// Catch the orientation change of the screen and correct the mat image to the correct direction.
|
||||
if (screenOrientation != Screen.orientation && (screenWidth != Screen.width || screenHeight != Screen.height)) {
|
||||
|
||||
if (onDisposed != null)
|
||||
onDisposed.Invoke ();
|
||||
|
||||
if (frameMat != null) {
|
||||
frameMat.Dispose ();
|
||||
frameMat = null;
|
||||
}
|
||||
if (rotatedFrameMat != null) {
|
||||
rotatedFrameMat.Dispose ();
|
||||
rotatedFrameMat = null;
|
||||
}
|
||||
|
||||
frameMat = new Mat (webCamTexture.height, webCamTexture.width, CvType.CV_8UC4);
|
||||
screenOrientation = Screen.orientation;
|
||||
screenWidth = Screen.width;
|
||||
screenHeight = Screen.height;
|
||||
|
||||
bool isRotatedFrame = false;
|
||||
#if !UNITY_EDITOR && !(UNITY_STANDALONE || UNITY_WEBGL)
|
||||
if (screenOrientation == ScreenOrientation.Portrait || screenOrientation == ScreenOrientation.PortraitUpsideDown) {
|
||||
if (!rotate90Degree)
|
||||
isRotatedFrame = true;
|
||||
} else if (rotate90Degree) {
|
||||
isRotatedFrame = true;
|
||||
}
|
||||
#else
|
||||
if (rotate90Degree)
|
||||
isRotatedFrame = true;
|
||||
#endif
|
||||
if (isRotatedFrame)
|
||||
rotatedFrameMat = new Mat (webCamTexture.width, webCamTexture.height, CvType.CV_8UC4);
|
||||
|
||||
if (onInitialized != null)
|
||||
onInitialized.Invoke ();
|
||||
} else {
|
||||
screenWidth = Screen.width;
|
||||
screenHeight = Screen.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +291,10 @@ namespace FaceMaskExample
|
|||
public virtual void Initialize ()
|
||||
{
|
||||
if (isInitWaiting)
|
||||
return;
|
||||
{
|
||||
CancelInitCoroutine ();
|
||||
ReleaseResources ();
|
||||
}
|
||||
|
||||
if (onInitialized == null)
|
||||
onInitialized = new UnityEvent ();
|
||||
|
@ -166,7 +303,63 @@ namespace FaceMaskExample
|
|||
if (onErrorOccurred == null)
|
||||
onErrorOccurred = new ErrorUnityEvent ();
|
||||
|
||||
StartCoroutine (_Initialize ());
|
||||
initCoroutine = _Initialize ();
|
||||
StartCoroutine (initCoroutine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this instance.
|
||||
/// </summary>
|
||||
/// <param name="requestedWidth">Requested width.</param>
|
||||
/// <param name="requestedHeight">Requested height.</param>
|
||||
public virtual void Initialize (int requestedWidth, int requestedHeight)
|
||||
{
|
||||
if (isInitWaiting)
|
||||
{
|
||||
CancelInitCoroutine ();
|
||||
ReleaseResources ();
|
||||
}
|
||||
|
||||
this._requestedWidth = requestedWidth;
|
||||
this._requestedHeight = requestedHeight;
|
||||
if (onInitialized == null)
|
||||
onInitialized = new UnityEvent ();
|
||||
if (onDisposed == null)
|
||||
onDisposed = new UnityEvent ();
|
||||
if (onErrorOccurred == null)
|
||||
onErrorOccurred = new ErrorUnityEvent ();
|
||||
|
||||
initCoroutine = _Initialize ();
|
||||
StartCoroutine (initCoroutine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this instance.
|
||||
/// </summary>
|
||||
/// <param name="requestedIsFrontFacing">If set to <c>true</c> requested to using the front camera.</param>
|
||||
/// <param name="requestedFPS">Requested FPS.</param>
|
||||
/// <param name="rotate90Degree">If set to <c>true</c> requested to rotate camera frame 90 degrees. (clockwise)</param>
|
||||
public virtual void Initialize (bool requestedIsFrontFacing, float requestedFPS = 30f, bool rotate90Degree = false)
|
||||
{
|
||||
if (isInitWaiting)
|
||||
{
|
||||
CancelInitCoroutine ();
|
||||
ReleaseResources ();
|
||||
}
|
||||
|
||||
_requestedDeviceName = null;
|
||||
this._requestedIsFrontFacing = requestedIsFrontFacing;
|
||||
this._requestedFPS = requestedFPS;
|
||||
this._rotate90Degree = rotate90Degree;
|
||||
if (onInitialized == null)
|
||||
onInitialized = new UnityEvent ();
|
||||
if (onDisposed == null)
|
||||
onDisposed = new UnityEvent ();
|
||||
if (onErrorOccurred == null)
|
||||
onErrorOccurred = new ErrorUnityEvent ();
|
||||
|
||||
initCoroutine = _Initialize ();
|
||||
StartCoroutine (initCoroutine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -177,16 +370,21 @@ namespace FaceMaskExample
|
|||
/// <param name="requestedHeight">Requested height.</param>
|
||||
/// <param name="requestedIsFrontFacing">If set to <c>true</c> requested to using the front camera.</param>
|
||||
/// <param name="requestedFPS">Requested FPS.</param>
|
||||
public virtual void Initialize (string deviceName, int requestedWidth, int requestedHeight, bool requestedIsFrontFacing = false, int requestedFPS = 30)
|
||||
/// <param name="rotate90Degree">If set to <c>true</c> requested to rotate camera frame 90 degrees. (clockwise)</param>
|
||||
public virtual void Initialize (string deviceName, int requestedWidth, int requestedHeight, bool requestedIsFrontFacing = false, float requestedFPS = 30f, bool rotate90Degree = false)
|
||||
{
|
||||
if (isInitWaiting)
|
||||
return;
|
||||
{
|
||||
CancelInitCoroutine ();
|
||||
ReleaseResources ();
|
||||
}
|
||||
|
||||
this.requestedDeviceName = deviceName;
|
||||
this.requestedWidth = requestedWidth;
|
||||
this.requestedHeight = requestedHeight;
|
||||
this.requestedIsFrontFacing = requestedIsFrontFacing;
|
||||
this.requestedFPS = requestedFPS;
|
||||
this._requestedDeviceName = deviceName;
|
||||
this._requestedWidth = requestedWidth;
|
||||
this._requestedHeight = requestedHeight;
|
||||
this._requestedIsFrontFacing = requestedIsFrontFacing;
|
||||
this._requestedFPS = requestedFPS;
|
||||
this._rotate90Degree = rotate90Degree;
|
||||
if (onInitialized == null)
|
||||
onInitialized = new UnityEvent ();
|
||||
if (onDisposed == null)
|
||||
|
@ -194,7 +392,8 @@ namespace FaceMaskExample
|
|||
if (onErrorOccurred == null)
|
||||
onErrorOccurred = new ErrorUnityEvent ();
|
||||
|
||||
StartCoroutine (_Initialize ());
|
||||
initCoroutine = _Initialize ();
|
||||
StartCoroutine (initCoroutine);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -203,20 +402,54 @@ namespace FaceMaskExample
|
|||
protected virtual IEnumerator _Initialize ()
|
||||
{
|
||||
if (hasInitDone)
|
||||
_Dispose ();
|
||||
{
|
||||
ReleaseResources ();
|
||||
|
||||
if (onDisposed != null)
|
||||
onDisposed.Invoke ();
|
||||
}
|
||||
|
||||
isInitWaiting = true;
|
||||
|
||||
// Creates the camera
|
||||
if (!String.IsNullOrEmpty (requestedDeviceName)) {
|
||||
webCamTexture = new WebCamTexture (requestedDeviceName, requestedWidth, requestedHeight, requestedFPS);
|
||||
} else {
|
||||
int requestedDeviceIndex = -1;
|
||||
if (Int32.TryParse (requestedDeviceName, out requestedDeviceIndex)) {
|
||||
if (requestedDeviceIndex >= 0 && requestedDeviceIndex < WebCamTexture.devices.Length) {
|
||||
webCamDevice = WebCamTexture.devices [requestedDeviceIndex];
|
||||
if (requestedFPS < 0) {
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestedWidth, requestedHeight);
|
||||
} else {
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestedWidth, requestedHeight, (int)requestedFPS);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int cameraIndex = 0; cameraIndex < WebCamTexture.devices.Length; cameraIndex++) {
|
||||
if (WebCamTexture.devices [cameraIndex].name == requestedDeviceName) {
|
||||
webCamDevice = WebCamTexture.devices [cameraIndex];
|
||||
if (requestedFPS < 0) {
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestedWidth, requestedHeight);
|
||||
} else {
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestedWidth, requestedHeight, (int)requestedFPS);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (webCamTexture == null)
|
||||
Debug.Log ("Cannot find camera device " + requestedDeviceName + ".");
|
||||
}
|
||||
|
||||
if (webCamTexture == null) {
|
||||
// Checks how many and which cameras are available on the device
|
||||
for (int cameraIndex = 0; cameraIndex < WebCamTexture.devices.Length; cameraIndex++) {
|
||||
for (int cameraIndex = 0; cameraIndex < WebCamTexture.devices.Length; cameraIndex++) {
|
||||
if (WebCamTexture.devices [cameraIndex].isFrontFacing == requestedIsFrontFacing) {
|
||||
|
||||
webCamDevice = WebCamTexture.devices [cameraIndex];
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestedWidth, requestedHeight, requestedFPS);
|
||||
|
||||
if (requestedFPS < 0) {
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestedWidth, requestedHeight);
|
||||
} else {
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestedWidth, requestedHeight, (int)requestedFPS);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +458,11 @@ namespace FaceMaskExample
|
|||
if (webCamTexture == null) {
|
||||
if (WebCamTexture.devices.Length > 0) {
|
||||
webCamDevice = WebCamTexture.devices [0];
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestedWidth, requestedHeight, requestedFPS);
|
||||
if (requestedFPS < 0) {
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestedWidth, requestedHeight);
|
||||
} else {
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestedWidth, requestedHeight, (int)requestedFPS);
|
||||
}
|
||||
} else {
|
||||
isInitWaiting = false;
|
||||
|
||||
|
@ -265,30 +502,37 @@ namespace FaceMaskExample
|
|||
}
|
||||
if (isTimeout) break;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Debug.Log ("name " + webCamTexture.name + " width " + webCamTexture.width + " height " + webCamTexture.height + " fps " + webCamTexture.requestedFPS);
|
||||
Debug.Log ("videoRotationAngle " + webCamTexture.videoRotationAngle + " videoVerticallyMirrored " + webCamTexture.videoVerticallyMirrored + " isFrongFacing " + webCamDevice.isFrontFacing);
|
||||
Debug.Log ("WebCamTextureToMatHelper:: " + "devicename:" + webCamTexture.deviceName + " name:" + webCamTexture.name + " width:" + webCamTexture.width + " height:" + webCamTexture.height + " fps:" + webCamTexture.requestedFPS
|
||||
+ " videoRotationAngle:" + webCamTexture.videoRotationAngle + " videoVerticallyMirrored:" + webCamTexture.videoVerticallyMirrored + " isFrongFacing:" + webCamDevice.isFrontFacing);
|
||||
|
||||
if (colors == null || colors.Length != webCamTexture.width * webCamTexture.height)
|
||||
colors = new Color32[webCamTexture.width * webCamTexture.height];
|
||||
|
||||
rgbaMat = new Mat (webCamTexture.height, webCamTexture.width, CvType.CV_8UC4);
|
||||
frameMat = new Mat (webCamTexture.height, webCamTexture.width, CvType.CV_8UC4);
|
||||
screenOrientation = Screen.orientation;
|
||||
screenWidth = Screen.width;
|
||||
screenHeight = Screen.height;
|
||||
|
||||
bool isRotatedFrame = false;
|
||||
#if !UNITY_EDITOR && !(UNITY_STANDALONE || UNITY_WEBGL)
|
||||
if (screenOrientation == ScreenOrientation.Portrait || screenOrientation == ScreenOrientation.PortraitUpsideDown) {
|
||||
rotatedRgbaMat = new Mat (webCamTexture.width, webCamTexture.height, CvType.CV_8UC4);
|
||||
if (!rotate90Degree)
|
||||
isRotatedFrame = true;
|
||||
} else if (rotate90Degree) {
|
||||
isRotatedFrame = true;
|
||||
}
|
||||
#else
|
||||
if (rotate90Degree)
|
||||
isRotatedFrame = true;
|
||||
#endif
|
||||
|
||||
if (requestedRotate90Degree) {
|
||||
if (rotatedRgbaMat == null)
|
||||
rotatedRgbaMat = new Mat (webCamTexture.width, webCamTexture.height, CvType.CV_8UC4);
|
||||
}
|
||||
if (isRotatedFrame)
|
||||
rotatedFrameMat = new Mat (webCamTexture.width, webCamTexture.height, CvType.CV_8UC4);
|
||||
|
||||
isInitWaiting = false;
|
||||
hasInitDone = true;
|
||||
initCoroutine = null;
|
||||
|
||||
if (onInitialized != null)
|
||||
onInitialized.Invoke ();
|
||||
|
@ -296,7 +540,7 @@ namespace FaceMaskExample
|
|||
break;
|
||||
} else {
|
||||
initFrameCount++;
|
||||
yield return 0;
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,6 +548,7 @@ namespace FaceMaskExample
|
|||
webCamTexture.Stop ();
|
||||
webCamTexture = null;
|
||||
isInitWaiting = false;
|
||||
initCoroutine = null;
|
||||
|
||||
if (onErrorOccurred != null)
|
||||
onErrorOccurred.Invoke (ErrorCode.TIMEOUT);
|
||||
|
@ -320,7 +565,7 @@ namespace FaceMaskExample
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the webcam texture.
|
||||
/// Starts the camera.
|
||||
/// </summary>
|
||||
public virtual void Play ()
|
||||
{
|
||||
|
@ -329,7 +574,7 @@ namespace FaceMaskExample
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pauses the webcam texture
|
||||
/// Pauses the active camera.
|
||||
/// </summary>
|
||||
public virtual void Pause ()
|
||||
{
|
||||
|
@ -338,7 +583,7 @@ namespace FaceMaskExample
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the webcam texture.
|
||||
/// Stops the active camera.
|
||||
/// </summary>
|
||||
public virtual void Stop ()
|
||||
{
|
||||
|
@ -347,34 +592,99 @@ namespace FaceMaskExample
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the webcam texture is currently playing.
|
||||
/// Indicates whether the active camera is currently playing.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if the webcam texture is playing, <c>false</c> otherwise.</returns>
|
||||
/// <returns><c>true</c>, if the active camera is playing, <c>false</c> otherwise.</returns>
|
||||
public virtual bool IsPlaying ()
|
||||
{
|
||||
if (!hasInitDone)
|
||||
return false;
|
||||
return webCamTexture.isPlaying;
|
||||
return hasInitDone ? webCamTexture.isPlaying : false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the webcam texture.
|
||||
/// Indicates whether the active camera device is currently front facng.
|
||||
/// </summary>
|
||||
/// <returns>The webcam texture.</returns>
|
||||
/// <returns><c>true</c>, if the active camera device is front facng, <c>false</c> otherwise.</returns>
|
||||
public virtual bool IsFrontFacing ()
|
||||
{
|
||||
return hasInitDone ? webCamDevice.isFrontFacing : false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the active camera device name.
|
||||
/// </summary>
|
||||
/// <returns>The active camera device name.</returns>
|
||||
public virtual string GetDeviceName ()
|
||||
{
|
||||
return hasInitDone ? webCamTexture.deviceName : "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the active camera width.
|
||||
/// </summary>
|
||||
/// <returns>The active camera width.</returns>
|
||||
public virtual int GetWidth ()
|
||||
{
|
||||
if (!hasInitDone)
|
||||
return -1;
|
||||
return (rotatedFrameMat != null) ? frameMat.height () : frameMat.width ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the active camera height.
|
||||
/// </summary>
|
||||
/// <returns>The active camera height.</returns>
|
||||
public virtual int GetHeight ()
|
||||
{
|
||||
if (!hasInitDone)
|
||||
return -1;
|
||||
return (rotatedFrameMat != null) ? frameMat.width () : frameMat.height ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the active camera framerate.
|
||||
/// </summary>
|
||||
/// <returns>The active camera framerate.</returns>
|
||||
public virtual float GetFPS ()
|
||||
{
|
||||
return hasInitDone ? webCamTexture.requestedFPS : -1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the active WebcamTexture.
|
||||
/// </summary>
|
||||
/// <returns>The active WebcamTexture.</returns>
|
||||
public virtual WebCamTexture GetWebCamTexture ()
|
||||
{
|
||||
return (hasInitDone) ? webCamTexture : null;
|
||||
return hasInitDone ? webCamTexture : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the webcam device.
|
||||
/// Returns the active WebcamDevice.
|
||||
/// </summary>
|
||||
/// <returns>The webcam device.</returns>
|
||||
/// <returns>The active WebcamDevice.</returns>
|
||||
public virtual WebCamDevice GetWebCamDevice ()
|
||||
{
|
||||
return webCamDevice;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the camera to world matrix.
|
||||
/// </summary>
|
||||
/// <returns>The camera to world matrix.</returns>
|
||||
public virtual Matrix4x4 GetCameraToWorldMatrix ()
|
||||
{
|
||||
return Camera.main.cameraToWorldMatrix;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the projection matrix matrix.
|
||||
/// </summary>
|
||||
/// <returns>The projection matrix.</returns>
|
||||
public virtual Matrix4x4 GetProjectionMatrix ()
|
||||
{
|
||||
return Camera.main.projectionMatrix;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the video buffer of the frame has been updated.
|
||||
/// </summary>
|
||||
|
@ -397,40 +707,62 @@ namespace FaceMaskExample
|
|||
|
||||
/// <summary>
|
||||
/// Gets the mat of the current frame.
|
||||
/// The Mat object's type is 'CV_8UC4' (RGBA).
|
||||
/// </summary>
|
||||
/// <returns>The mat.</returns>
|
||||
/// <returns>The mat of the current frame.</returns>
|
||||
public virtual Mat GetMat ()
|
||||
{
|
||||
if (!hasInitDone || !webCamTexture.isPlaying) {
|
||||
if (rotatedRgbaMat != null) {
|
||||
return rotatedRgbaMat;
|
||||
return (rotatedFrameMat != null) ? rotatedFrameMat : frameMat;
|
||||
}
|
||||
|
||||
Utils.webCamTextureToMat (webCamTexture, frameMat, colors);
|
||||
|
||||
#if !UNITY_EDITOR && !(UNITY_STANDALONE || UNITY_WEBGL)
|
||||
if (rotatedFrameMat != null) {
|
||||
if (screenOrientation == ScreenOrientation.Portrait || screenOrientation == ScreenOrientation.PortraitUpsideDown) {
|
||||
// (Orientation is Portrait, rotate90Degree is false)
|
||||
if (webCamDevice.isFrontFacing){
|
||||
FlipMat (frameMat, !flipHorizontal, !flipVertical);
|
||||
}else{
|
||||
FlipMat (frameMat, flipHorizontal, flipVertical);
|
||||
}
|
||||
} else {
|
||||
return rgbaMat;
|
||||
// (Orientation is Landscape, rotate90Degrees=true)
|
||||
FlipMat (frameMat, flipVertical, flipHorizontal);
|
||||
}
|
||||
}
|
||||
|
||||
Utils.webCamTextureToMat (webCamTexture, rgbaMat, colors);
|
||||
|
||||
if (rotatedRgbaMat != null) {
|
||||
|
||||
Core.rotate (rgbaMat, rotatedRgbaMat, Core.ROTATE_90_CLOCKWISE);
|
||||
|
||||
FlipMat (rotatedRgbaMat);
|
||||
|
||||
return rotatedRgbaMat;
|
||||
Core.rotate (frameMat, rotatedFrameMat, Core.ROTATE_90_CLOCKWISE);
|
||||
return rotatedFrameMat;
|
||||
} else {
|
||||
|
||||
FlipMat (rgbaMat);
|
||||
|
||||
return rgbaMat;
|
||||
if (screenOrientation == ScreenOrientation.Portrait || screenOrientation == ScreenOrientation.PortraitUpsideDown) {
|
||||
// (Orientation is Portrait, rotate90Degree is ture)
|
||||
if (webCamDevice.isFrontFacing){
|
||||
FlipMat (frameMat, flipHorizontal, flipVertical);
|
||||
}else{
|
||||
FlipMat (frameMat, !flipHorizontal, !flipVertical);
|
||||
}
|
||||
} else {
|
||||
// (Orientation is Landscape, rotate90Degree is false)
|
||||
FlipMat (frameMat, flipVertical, flipHorizontal);
|
||||
}
|
||||
return frameMat;
|
||||
}
|
||||
#else
|
||||
FlipMat (frameMat, flipVertical, flipHorizontal);
|
||||
if (rotatedFrameMat != null) {
|
||||
Core.rotate (frameMat, rotatedFrameMat, Core.ROTATE_90_CLOCKWISE);
|
||||
return rotatedFrameMat;
|
||||
} else {
|
||||
return frameMat;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flips the mat.
|
||||
/// </summary>
|
||||
/// <param name="mat">Mat.</param>
|
||||
protected virtual void FlipMat (Mat mat)
|
||||
protected virtual void FlipMat (Mat mat, bool flipVertical, bool flipHorizontal)
|
||||
{
|
||||
int flipCode = int.MinValue;
|
||||
|
||||
|
@ -492,28 +824,38 @@ namespace FaceMaskExample
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// To release the resources for the initialized method.
|
||||
/// Cancel Init Coroutine.
|
||||
/// </summary>
|
||||
protected virtual void _Dispose ()
|
||||
protected virtual void CancelInitCoroutine ()
|
||||
{
|
||||
if (initCoroutine != null) {
|
||||
StopCoroutine (initCoroutine);
|
||||
((IDisposable)initCoroutine).Dispose ();
|
||||
initCoroutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To release the resources.
|
||||
/// </summary>
|
||||
protected virtual void ReleaseResources ()
|
||||
{
|
||||
isInitWaiting = false;
|
||||
hasInitDone = false;
|
||||
|
||||
if (webCamTexture != null) {
|
||||
webCamTexture.Stop ();
|
||||
WebCamTexture.Destroy (webCamTexture);
|
||||
webCamTexture = null;
|
||||
}
|
||||
if (rgbaMat != null) {
|
||||
rgbaMat.Dispose ();
|
||||
rgbaMat = null;
|
||||
if (frameMat != null) {
|
||||
frameMat.Dispose ();
|
||||
frameMat = null;
|
||||
}
|
||||
if (rotatedRgbaMat != null) {
|
||||
rotatedRgbaMat.Dispose ();
|
||||
rotatedRgbaMat = null;
|
||||
if (rotatedFrameMat != null) {
|
||||
rotatedFrameMat.Dispose ();
|
||||
rotatedFrameMat = null;
|
||||
}
|
||||
|
||||
if (onDisposed != null)
|
||||
onDisposed.Invoke ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -525,11 +867,21 @@ namespace FaceMaskExample
|
|||
/// the garbage collector can reclaim the memory that the <see cref="WebCamTextureToMatHelper"/> was occupying.</remarks>
|
||||
public virtual void Dispose ()
|
||||
{
|
||||
if (hasInitDone)
|
||||
_Dispose ();
|
||||
|
||||
if (colors != null)
|
||||
colors = null;
|
||||
|
||||
if (isInitWaiting)
|
||||
{
|
||||
CancelInitCoroutine ();
|
||||
ReleaseResources ();
|
||||
}
|
||||
else if (hasInitDone)
|
||||
{
|
||||
ReleaseResources ();
|
||||
|
||||
if (onDisposed != null)
|
||||
onDisposed.Invoke ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,16 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
public Toggle useDlibFaceDetecterToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if enables color correction.
|
||||
/// </summary>
|
||||
public bool enableColorCorrection = true;
|
||||
|
||||
/// <summary>
|
||||
/// The enable color correction toggle.
|
||||
/// </summary>
|
||||
public Toggle enableColorCorrectionToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if filters non frontal faces.
|
||||
/// </summary>
|
||||
|
@ -65,11 +75,6 @@ namespace FaceMaskExample
|
|||
/// The toggle for switching debug face points display state.
|
||||
/// </summary>
|
||||
public Toggle displayDebugFacePointsToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The upload image button.
|
||||
/// </summary>
|
||||
public Button uploadImageButton;
|
||||
|
||||
/// <summary>
|
||||
/// The image texture.
|
||||
|
@ -80,12 +85,17 @@ namespace FaceMaskExample
|
|||
/// The cascade.
|
||||
/// </summary>
|
||||
CascadeClassifier cascade;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The face landmark detector.
|
||||
/// </summary>
|
||||
FaceLandmarkDetector faceLandmarkDetector;
|
||||
|
||||
/// <summary>
|
||||
/// The face mask color corrector.
|
||||
/// </summary>
|
||||
FaceMaskColorCorrector faceMaskColorCorrector;
|
||||
|
||||
/// <summary>
|
||||
/// The mesh overlay.
|
||||
/// </summary>
|
||||
|
@ -137,7 +147,6 @@ namespace FaceMaskExample
|
|||
coroutines.Clear ();
|
||||
|
||||
Run ();
|
||||
uploadImageButton.interactable = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -147,6 +156,7 @@ namespace FaceMaskExample
|
|||
|
||||
displayFaceRectsToggle.isOn = displayFaceRects;
|
||||
useDlibFaceDetecterToggle.isOn = useDlibFaceDetecter;
|
||||
enableColorCorrectionToggle.isOn = enableColorCorrection;
|
||||
filterNonFrontalFacesToggle.isOn = filterNonFrontalFaces;
|
||||
displayDebugFacePointsToggle.isOn = displayDebugFacePoints;
|
||||
|
||||
|
@ -181,9 +191,9 @@ namespace FaceMaskExample
|
|||
if (faceLandmarkDetector == null)
|
||||
faceLandmarkDetector = new FaceLandmarkDetector (sp_human_face_68_dat_filepath);
|
||||
|
||||
faceMaskColorCorrector = faceMaskColorCorrector ?? new FaceMaskColorCorrector ();
|
||||
FrontalFaceChecker frontalFaceChecker = new FrontalFaceChecker (width, height);
|
||||
|
||||
|
||||
// detect faces.
|
||||
List<OpenCVForUnity.Rect> detectResult = new List<OpenCVForUnity.Rect> ();
|
||||
if (useDlibFaceDetecter) {
|
||||
|
@ -217,7 +227,7 @@ namespace FaceMaskExample
|
|||
}
|
||||
|
||||
gray.Dispose ();
|
||||
}
|
||||
}
|
||||
|
||||
// detect face landmark points.
|
||||
OpenCVForUnityUtils.SetImage (faceLandmarkDetector, rgbaMat);
|
||||
|
@ -267,11 +277,20 @@ namespace FaceMaskExample
|
|||
}
|
||||
meshOverlay.UpdateObject (i, vertices, null, uv);
|
||||
|
||||
if (enableColorCorrection) {
|
||||
faceMaskColorCorrector.CreateLUTTex (i);
|
||||
Texture2D LUTTex = faceMaskColorCorrector.UpdateLUTTex (i, rgbaMat, rgbaMat, landmarkPoints [face_nums [0]], landmarkPoints [face_nums [i]]);
|
||||
tm.sharedMaterial.SetTexture ("_LUTTex", LUTTex);
|
||||
tm.sharedMaterial.SetFloat ("_ColorCorrection", 1f);
|
||||
} else {
|
||||
tm.sharedMaterial.SetFloat ("_ColorCorrection", 0f);
|
||||
}
|
||||
|
||||
// filter non frontal faces.
|
||||
if (filterNonFrontalFaces && frontalFaceChecker.GetFrontalFaceRate (landmarkPoints [i]) < frontalFaceRateLowerLimit) {
|
||||
tm.material.SetFloat ("_Fade", 1f);
|
||||
tm.sharedMaterial.SetFloat ("_Fade", 1f);
|
||||
} else {
|
||||
tm.material.SetFloat ("_Fade", 0.3f);
|
||||
tm.sharedMaterial.SetFloat ("_Fade", 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,6 +329,9 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
void OnDestroy ()
|
||||
{
|
||||
if (faceMaskColorCorrector != null)
|
||||
faceMaskColorCorrector.Dispose ();
|
||||
|
||||
if (faceLandmarkDetector != null)
|
||||
faceLandmarkDetector.Dispose ();
|
||||
|
||||
|
@ -360,6 +382,21 @@ namespace FaceMaskExample
|
|||
Run ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the enable color correction toggle value changed event.
|
||||
/// </summary>
|
||||
public void OnEnableColorCorrectionToggleValueChanged ()
|
||||
{
|
||||
if (enableColorCorrectionToggle.isOn) {
|
||||
enableColorCorrection = true;
|
||||
} else {
|
||||
enableColorCorrection = false;
|
||||
}
|
||||
|
||||
if (imgTexture != null)
|
||||
Run ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the filter non frontal faces toggle value changed event.
|
||||
/// </summary>
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -20,6 +20,15 @@ namespace FaceMaskExample
|
|||
[RequireComponent (typeof(TrackedMeshOverlay))]
|
||||
public class VideoCaptureFaceMaskExample : MonoBehaviour
|
||||
{
|
||||
[HeaderAttribute ("FaceMaskData")]
|
||||
|
||||
/// <summary>
|
||||
/// The face mask data list.
|
||||
/// </summary>
|
||||
public List<FaceMaskData> faceMaskDatas;
|
||||
|
||||
[HeaderAttribute ("Option")]
|
||||
|
||||
/// <summary>
|
||||
/// Determines if use dlib face detector.
|
||||
/// </summary>
|
||||
|
@ -30,6 +39,26 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
public Toggle useDlibFaceDetecterToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if enables noise filter.
|
||||
/// </summary>
|
||||
public bool enableNoiseFilter = true;
|
||||
|
||||
/// <summary>
|
||||
/// The enable noise filter toggle.
|
||||
/// </summary>
|
||||
public Toggle enableNoiseFilterToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if enables color correction.
|
||||
/// </summary>
|
||||
public bool enableColorCorrection = true;
|
||||
|
||||
/// <summary>
|
||||
/// The enable color correction toggle.
|
||||
/// </summary>
|
||||
public Toggle enableColorCorrectionToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if filters non frontal faces.
|
||||
/// </summary>
|
||||
|
@ -66,11 +95,6 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
public Toggle displayDebugFacePointsToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The upload face mask button.
|
||||
/// </summary>
|
||||
public Button uploadFaceMaskButton;
|
||||
|
||||
/// <summary>
|
||||
/// The width of the frame.
|
||||
/// </summary>
|
||||
|
@ -105,17 +129,32 @@ namespace FaceMaskExample
|
|||
/// The cascade.
|
||||
/// </summary>
|
||||
CascadeClassifier cascade;
|
||||
|
||||
/// <summary>
|
||||
/// The face landmark detector.
|
||||
/// </summary>
|
||||
FaceLandmarkDetector faceLandmarkDetector;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The detection based tracker.
|
||||
/// </summary>
|
||||
RectangleTracker rectangleTracker;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The face landmark detector.
|
||||
/// </summary>
|
||||
FaceLandmarkDetector faceLandmarkDetector;
|
||||
|
||||
/// <summary>
|
||||
/// The mean points filter dictionary.
|
||||
/// </summary>
|
||||
Dictionary<int, LowPassPointsFilter> lowPassFilterDict;
|
||||
|
||||
/// <summary>
|
||||
/// The optical flow points filter dictionary.
|
||||
/// </summary>
|
||||
Dictionary<int, OFPointsFilter> opticalFlowFilterDict;
|
||||
|
||||
/// <summary>
|
||||
/// The face mask color corrector.
|
||||
/// </summary>
|
||||
FaceMaskColorCorrector faceMaskColorCorrector;
|
||||
|
||||
/// <summary>
|
||||
/// The frontal face checker.
|
||||
/// </summary>
|
||||
|
@ -130,6 +169,16 @@ namespace FaceMaskExample
|
|||
/// The Shader.PropertyToID for "_Fade".
|
||||
/// </summary>
|
||||
int shader_FadeID;
|
||||
|
||||
/// <summary>
|
||||
/// The Shader.PropertyToID for "_ColorCorrection".
|
||||
/// </summary>
|
||||
int shader_ColorCorrectionID;
|
||||
|
||||
/// <summary>
|
||||
/// The Shader.PropertyToID for "_LUTTex".
|
||||
/// </summary>
|
||||
int shader_LUTTexID;
|
||||
|
||||
/// <summary>
|
||||
/// The face mask texture.
|
||||
|
@ -140,6 +189,11 @@ namespace FaceMaskExample
|
|||
/// The face mask mat.
|
||||
/// </summary>
|
||||
Mat faceMaskMat;
|
||||
|
||||
/// <summary>
|
||||
/// The index number of face mask data.
|
||||
/// </summary>
|
||||
int faceMaskDataIndex = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The detected face rect in mask mat.
|
||||
|
@ -211,7 +265,6 @@ namespace FaceMaskExample
|
|||
coroutines.Clear ();
|
||||
|
||||
Run ();
|
||||
uploadFaceMaskButton.interactable = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -220,6 +273,8 @@ namespace FaceMaskExample
|
|||
meshOverlay = this.GetComponent<TrackedMeshOverlay> ();
|
||||
|
||||
shader_FadeID = Shader.PropertyToID("_Fade");
|
||||
shader_ColorCorrectionID = Shader.PropertyToID("_ColorCorrection");
|
||||
shader_LUTTexID = Shader.PropertyToID("_LUTTex");
|
||||
|
||||
rectangleTracker = new RectangleTracker ();
|
||||
|
||||
|
@ -227,6 +282,10 @@ namespace FaceMaskExample
|
|||
|
||||
faceLandmarkDetector = new FaceLandmarkDetector (sp_human_face_68_dat_filepath);
|
||||
|
||||
lowPassFilterDict = new Dictionary<int, LowPassPointsFilter> ();
|
||||
opticalFlowFilterDict = new Dictionary<int, OFPointsFilter> ();
|
||||
|
||||
faceMaskColorCorrector = new FaceMaskColorCorrector ();
|
||||
|
||||
rgbMat = new Mat ();
|
||||
|
||||
|
@ -250,7 +309,7 @@ namespace FaceMaskExample
|
|||
Debug.Log ("CAP_PROP_FRAME_HEIGHT: " + capture.get (Videoio.CAP_PROP_FRAME_HEIGHT));
|
||||
|
||||
|
||||
texture = new Texture2D ((int)(frameWidth), (int)(frameHeight), TextureFormat.RGBA32, false);
|
||||
texture = new Texture2D ((int)(frameWidth), (int)(frameHeight), TextureFormat.RGB24, false);
|
||||
gameObject.transform.localScale = new Vector3 ((float)frameWidth, (float)frameHeight, 1);
|
||||
float widthScale = (float)Screen.width / (float)frameWidth;
|
||||
float heightScale = (float)Screen.height / (float)frameHeight;
|
||||
|
@ -273,6 +332,8 @@ namespace FaceMaskExample
|
|||
|
||||
displayFaceRectsToggle.isOn = displayFaceRects;
|
||||
useDlibFaceDetecterToggle.isOn = useDlibFaceDetecter;
|
||||
enableNoiseFilterToggle.isOn = enableNoiseFilter;
|
||||
enableColorCorrectionToggle.isOn = enableColorCorrection;
|
||||
filterNonFrontalFacesToggle.isOn = filterNonFrontalFaces;
|
||||
displayDebugFacePointsToggle.isOn = displayDebugFacePoints;
|
||||
|
||||
|
@ -320,36 +381,70 @@ namespace FaceMaskExample
|
|||
r.y += (int)(r.height * 0.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// face traking.
|
||||
// face tracking.
|
||||
rectangleTracker.UpdateTrackedObjects (detectResult);
|
||||
List<TrackedRect> trackedRects = new List<TrackedRect> ();
|
||||
rectangleTracker.GetObjects (trackedRects, true);
|
||||
|
||||
|
||||
// create noise filter.
|
||||
foreach (var openCVRect in trackedRects) {
|
||||
if (openCVRect.state == TrackedState.NEW) {
|
||||
if (!lowPassFilterDict.ContainsKey(openCVRect.id))
|
||||
lowPassFilterDict.Add (openCVRect.id, new LowPassPointsFilter((int)faceLandmarkDetector.GetShapePredictorNumParts()));
|
||||
if (!opticalFlowFilterDict.ContainsKey(openCVRect.id))
|
||||
opticalFlowFilterDict.Add (openCVRect.id, new OFPointsFilter((int)faceLandmarkDetector.GetShapePredictorNumParts()));
|
||||
}else if (openCVRect.state == TrackedState.DELETED){
|
||||
if (lowPassFilterDict.ContainsKey (openCVRect.id)) {
|
||||
lowPassFilterDict [openCVRect.id].Dispose ();
|
||||
lowPassFilterDict.Remove (openCVRect.id);
|
||||
}
|
||||
if (opticalFlowFilterDict.ContainsKey (openCVRect.id)) {
|
||||
opticalFlowFilterDict [openCVRect.id].Dispose ();
|
||||
opticalFlowFilterDict.Remove (openCVRect.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create LUT texture.
|
||||
foreach (var openCVRect in trackedRects) {
|
||||
if (openCVRect.state == TrackedState.NEW) {
|
||||
faceMaskColorCorrector.CreateLUTTex (openCVRect.id);
|
||||
}else if (openCVRect.state == TrackedState.DELETED) {
|
||||
faceMaskColorCorrector.DeleteLUTTex (openCVRect.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// detect face landmark points.
|
||||
OpenCVForUnityUtils.SetImage (faceLandmarkDetector, rgbMat);
|
||||
List<List<Vector2>> landmarkPoints = new List<List<Vector2>> ();
|
||||
for (int i = 0; i < trackedRects.Count; i++) {
|
||||
TrackedRect tr = trackedRects [i];
|
||||
UnityEngine.Rect rect = new UnityEngine.Rect (tr.x, tr.y, tr.width, tr.height);
|
||||
|
||||
|
||||
List<Vector2> points = faceLandmarkDetector.DetectLandmark (rect);
|
||||
|
||||
// apply noise filter.
|
||||
if (enableNoiseFilter) {
|
||||
if (tr.state > TrackedState.NEW && tr.state < TrackedState.DELETED) {
|
||||
opticalFlowFilterDict [tr.id].Process (rgbMat, points, points);
|
||||
lowPassFilterDict [tr.id].Process (rgbMat, points, points);
|
||||
}
|
||||
}
|
||||
|
||||
landmarkPoints.Add (points);
|
||||
}
|
||||
|
||||
// face masking.
|
||||
if (faceMaskTexture != null && landmarkPoints.Count >= 1) {
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
|
||||
float imageWidth = meshOverlay.width;
|
||||
float imageHeight = meshOverlay.height;
|
||||
if (faceMaskTexture != null && landmarkPoints.Count >= 1) { // Apply face masking between detected faces and a face mask image.
|
||||
|
||||
float maskImageWidth = faceMaskTexture.width;
|
||||
float maskImageHeight = faceMaskTexture.height;
|
||||
|
||||
TrackedRect tr;
|
||||
TrackedMesh tm;
|
||||
|
||||
for (int i = 0; i < trackedRects.Count; i++) {
|
||||
tr = trackedRects [i];
|
||||
|
||||
|
@ -357,50 +452,22 @@ namespace FaceMaskExample
|
|||
meshOverlay.CreateObject (tr.id, faceMaskTexture);
|
||||
}
|
||||
if (tr.state < TrackedState.DELETED) {
|
||||
tm = meshOverlay.GetObjectById (tr.id);
|
||||
|
||||
Vector3[] vertices = tm.meshFilter.mesh.vertices;
|
||||
if (vertices.Length == landmarkPoints [i].Count) {
|
||||
for (int j = 0; j < vertices.Length; j++) {
|
||||
vertices [j].x = landmarkPoints [i] [j].x / imageWidth - 0.5f;
|
||||
vertices [j].y = 0.5f - landmarkPoints [i] [j].y / imageHeight;
|
||||
}
|
||||
}
|
||||
Vector2[] uv = tm.meshFilter.mesh.uv;
|
||||
if (uv.Length == faceLandmarkPointsInMask.Count) {
|
||||
for (int jj = 0; jj < uv.Length; jj++) {
|
||||
uv [jj].x = faceLandmarkPointsInMask [jj].x / maskImageWidth;
|
||||
uv [jj].y = (maskImageHeight - faceLandmarkPointsInMask [jj].y) / maskImageHeight;
|
||||
}
|
||||
}
|
||||
meshOverlay.UpdateObject (tr.id, vertices, null, uv);
|
||||
MaskFace (meshOverlay, tr, landmarkPoints [i], faceLandmarkPointsInMask, maskImageWidth, maskImageHeight);
|
||||
|
||||
if (tr.numFramesNotDetected > 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
}else if (tr.numFramesNotDetected > 0 && tr.numFramesNotDetected <= 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f + (0.7f/4f) * tr.numFramesNotDetected);
|
||||
} else {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f);
|
||||
if (enableColorCorrection) {
|
||||
CorrectFaceMaskColor (tr.id, faceMaskMat, rgbMat, faceLandmarkPointsInMask, landmarkPoints [i]);
|
||||
}
|
||||
|
||||
// filter non frontal faces.
|
||||
if (filterNonFrontalFaces && frontalFaceChecker.GetFrontalFaceRate (landmarkPoints [i]) < frontalFaceRateLowerLimit) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
}
|
||||
|
||||
} else if (tr.state == TrackedState.DELETED) {
|
||||
meshOverlay.DeleteObject (tr.id);
|
||||
}
|
||||
}
|
||||
} else if (landmarkPoints.Count >= 1) {
|
||||
|
||||
float imageWidth = meshOverlay.width;
|
||||
float imageHeight = meshOverlay.height;
|
||||
} else if (landmarkPoints.Count >= 1) { // Apply face masking between detected faces.
|
||||
|
||||
float maskImageWidth = texture.width;
|
||||
float maskImageHeight = texture.height;
|
||||
|
||||
TrackedRect tr;
|
||||
TrackedMesh tm;
|
||||
|
||||
for (int i = 0; i < trackedRects.Count; i++) {
|
||||
tr = trackedRects [i];
|
||||
|
||||
|
@ -408,37 +475,11 @@ namespace FaceMaskExample
|
|||
meshOverlay.CreateObject (tr.id, texture);
|
||||
}
|
||||
if (tr.state < TrackedState.DELETED) {
|
||||
tm = meshOverlay.GetObjectById (tr.id);
|
||||
|
||||
Vector3[] vertices = tm.meshFilter.mesh.vertices;
|
||||
if (vertices.Length == landmarkPoints [i].Count) {
|
||||
for (int j = 0; j < vertices.Length; j++) {
|
||||
vertices [j].x = landmarkPoints[i][j].x / imageWidth - 0.5f;
|
||||
vertices [j].y = 0.5f - landmarkPoints[i][j].y / imageHeight;
|
||||
}
|
||||
}
|
||||
Vector2[] uv = tm.meshFilter.mesh.uv;
|
||||
if (uv.Length == landmarkPoints [0].Count) {
|
||||
for (int jj = 0; jj < uv.Length; jj++) {
|
||||
uv [jj].x = landmarkPoints[0][jj].x / maskImageWidth;
|
||||
uv [jj].y = (maskImageHeight - landmarkPoints[0][jj].y) / maskImageHeight;
|
||||
}
|
||||
}
|
||||
meshOverlay.UpdateObject (tr.id, vertices, null, uv);
|
||||
|
||||
if (tr.numFramesNotDetected > 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
}else if (tr.numFramesNotDetected > 0 && tr.numFramesNotDetected <= 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f + (0.7f/4f) * tr.numFramesNotDetected);
|
||||
} else {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f);
|
||||
}
|
||||
MaskFace (meshOverlay, tr, landmarkPoints [i], landmarkPoints [0], maskImageWidth, maskImageHeight);
|
||||
|
||||
// filter non frontal faces.
|
||||
if (filterNonFrontalFaces && frontalFaceChecker.GetFrontalFaceRate (landmarkPoints [i]) < frontalFaceRateLowerLimit) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
if (enableColorCorrection) {
|
||||
CorrectFaceMaskColor (tr.id, rgbMat, rgbMat, landmarkPoints [0], landmarkPoints [i]);
|
||||
}
|
||||
|
||||
} else if (tr.state == TrackedState.DELETED) {
|
||||
meshOverlay.DeleteObject (tr.id);
|
||||
}
|
||||
|
@ -489,14 +530,73 @@ namespace FaceMaskExample
|
|||
trans.put (1, 2, ty);
|
||||
|
||||
Imgproc.warpAffine (faceMaskMat, rgbMat, trans, rgbMat.size (), Imgproc.INTER_LINEAR, Core.BORDER_TRANSPARENT, new Scalar (0));
|
||||
|
||||
if (displayFaceRects || displayDebugFacePointsToggle)
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
}
|
||||
|
||||
Imgproc.putText (rgbMat, "W:" + rgbMat.width () + " H:" + rgbMat.height () + " SO:" + Screen.orientation, new Point (5, rgbMat.rows () - 10), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
// Imgproc.putText (rgbMat, "W:" + rgbMat.width () + " H:" + rgbMat.height () + " SO:" + Screen.orientation, new Point (5, rgbMat.rows () - 10), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
|
||||
OpenCVForUnity.Utils.matToTexture2D (rgbMat, texture);
|
||||
OpenCVForUnity.Utils.fastMatToTexture2D (rgbMat, texture);
|
||||
}
|
||||
}
|
||||
|
||||
private void MaskFace (TrackedMeshOverlay meshOverlay, TrackedRect tr, List<Vector2> landmarkPoints, List<Vector2> landmarkPointsInMaskImage, float maskImageWidth = 0, float maskImageHeight = 0)
|
||||
{
|
||||
float imageWidth = meshOverlay.width;
|
||||
float imageHeight = meshOverlay.height;
|
||||
|
||||
if (maskImageWidth == 0)
|
||||
maskImageWidth = imageWidth;
|
||||
|
||||
if (maskImageHeight == 0)
|
||||
maskImageHeight = imageHeight;
|
||||
|
||||
TrackedMesh tm = meshOverlay.GetObjectById (tr.id);
|
||||
|
||||
Vector3[] vertices = tm.meshFilter.mesh.vertices;
|
||||
if (vertices.Length == landmarkPoints.Count) {
|
||||
for (int j = 0; j < vertices.Length; j++) {
|
||||
vertices [j].x = landmarkPoints[j].x / imageWidth - 0.5f;
|
||||
vertices [j].y = 0.5f - landmarkPoints[j].y / imageHeight;
|
||||
}
|
||||
}
|
||||
Vector2[] uv = tm.meshFilter.mesh.uv;
|
||||
if (uv.Length == landmarkPointsInMaskImage.Count) {
|
||||
for (int jj = 0; jj < uv.Length; jj++) {
|
||||
uv [jj].x = landmarkPointsInMaskImage[jj].x / maskImageWidth;
|
||||
uv [jj].y = (maskImageHeight - landmarkPointsInMaskImage[jj].y) / maskImageHeight;
|
||||
}
|
||||
}
|
||||
meshOverlay.UpdateObject (tr.id, vertices, null, uv);
|
||||
|
||||
if (tr.numFramesNotDetected > 3) {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 1f);
|
||||
}else if (tr.numFramesNotDetected > 0 && tr.numFramesNotDetected <= 3) {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 0.3f + (0.7f/4f) * tr.numFramesNotDetected);
|
||||
} else {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 0.3f);
|
||||
}
|
||||
|
||||
if (enableColorCorrection) {
|
||||
tm.sharedMaterial.SetFloat (shader_ColorCorrectionID, 1f);
|
||||
} else {
|
||||
tm.sharedMaterial.SetFloat (shader_ColorCorrectionID, 0f);
|
||||
}
|
||||
|
||||
// filter non frontal faces.
|
||||
if (filterNonFrontalFaces && frontalFaceChecker.GetFrontalFaceRate (landmarkPoints) < frontalFaceRateLowerLimit) {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
private void CorrectFaceMaskColor (int id, Mat src, Mat dst, List<Vector2> src_landmarkPoints, List<Vector2> dst_landmarkPoints)
|
||||
{
|
||||
Texture2D LUTTex = faceMaskColorCorrector.UpdateLUTTex(id, src, dst, src_landmarkPoints, dst_landmarkPoints);
|
||||
TrackedMesh tm = meshOverlay.GetObjectById (id);
|
||||
tm.sharedMaterial.SetTexture (shader_LUTTexID, LUTTex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the disable event.
|
||||
/// </summary>
|
||||
|
@ -515,6 +615,18 @@ namespace FaceMaskExample
|
|||
if (faceLandmarkDetector != null)
|
||||
faceLandmarkDetector.Dispose ();
|
||||
|
||||
foreach (var key in lowPassFilterDict.Keys) {
|
||||
lowPassFilterDict [key].Dispose ();
|
||||
}
|
||||
lowPassFilterDict.Clear ();
|
||||
foreach (var key in opticalFlowFilterDict.Keys) {
|
||||
opticalFlowFilterDict [key].Dispose ();
|
||||
}
|
||||
opticalFlowFilterDict.Clear ();
|
||||
|
||||
if (faceMaskColorCorrector != null)
|
||||
faceMaskColorCorrector.Dispose ();
|
||||
|
||||
if (frontalFaceChecker != null)
|
||||
frontalFaceChecker.Dispose ();
|
||||
|
||||
|
@ -550,6 +662,36 @@ namespace FaceMaskExample
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the enable noise filter toggle value changed event.
|
||||
/// </summary>
|
||||
public void OnEnableNoiseFilterToggleValueChanged ()
|
||||
{
|
||||
if (enableNoiseFilterToggle.isOn) {
|
||||
enableNoiseFilter = true;
|
||||
foreach (var key in lowPassFilterDict.Keys) {
|
||||
lowPassFilterDict [key].Reset ();
|
||||
}
|
||||
foreach (var key in opticalFlowFilterDict.Keys) {
|
||||
opticalFlowFilterDict [key].Reset ();
|
||||
}
|
||||
} else {
|
||||
enableNoiseFilter = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the enable color correction toggle value changed event.
|
||||
/// </summary>
|
||||
public void OnEnableColorCorrectionToggleValueChanged ()
|
||||
{
|
||||
if (enableColorCorrectionToggle.isOn) {
|
||||
enableColorCorrection = true;
|
||||
} else {
|
||||
enableColorCorrection = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the filter non frontal faces toggle value changed event.
|
||||
/// </summary>
|
||||
|
@ -592,28 +734,68 @@ namespace FaceMaskExample
|
|||
public void OnChangeFaceMaskButtonClick ()
|
||||
{
|
||||
RemoveFaceMask ();
|
||||
|
||||
ExampleMaskData maskData = ExampleDataSet.GetData();
|
||||
|
||||
faceMaskTexture = Resources.Load (maskData.fileName) as Texture2D;
|
||||
|
||||
if (faceMaskDatas.Count == 0)
|
||||
return;
|
||||
|
||||
FaceMaskData maskData = faceMaskDatas[faceMaskDataIndex];
|
||||
faceMaskDataIndex = (faceMaskDataIndex < faceMaskDatas.Count - 1) ? faceMaskDataIndex + 1 : 0;
|
||||
|
||||
if (maskData == null) {
|
||||
Debug.LogError ("maskData == null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (maskData.image == null) {
|
||||
Debug.LogError ("image == null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (maskData.landmarkPoints.Count != 68) {
|
||||
Debug.LogError ("landmarkPoints.Count != 68");
|
||||
return;
|
||||
}
|
||||
|
||||
faceMaskTexture = maskData.image;
|
||||
faceMaskMat = new Mat (faceMaskTexture.height, faceMaskTexture.width, CvType.CV_8UC3);
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
Debug.Log ("faceMaskMat ToString " + faceMaskMat.ToString ());
|
||||
|
||||
if(maskData.landmarkPoints != null){
|
||||
faceRectInMask = maskData.faceRect;
|
||||
faceLandmarkPointsInMask = maskData.landmarkPoints;
|
||||
}else{
|
||||
if(maskData.isDynamicMode){
|
||||
faceRectInMask = DetectFace (faceMaskMat);
|
||||
faceLandmarkPointsInMask = DetectFaceLandmarkPoints (faceMaskMat, faceRectInMask);
|
||||
|
||||
maskData.faceRect = faceRectInMask;
|
||||
maskData.landmarkPoints = faceLandmarkPointsInMask;
|
||||
}else{
|
||||
faceRectInMask = maskData.faceRect;
|
||||
faceLandmarkPointsInMask = maskData.landmarkPoints;
|
||||
}
|
||||
|
||||
ExampleDataSet.Next();
|
||||
|
||||
|
||||
if (faceRectInMask.width == 0 && faceRectInMask.height == 0){
|
||||
RemoveFaceMask ();
|
||||
Debug.Log ("A face could not be detected from the input image.");
|
||||
Debug.LogError ("A face could not be detected from the input image.");
|
||||
}
|
||||
|
||||
enableColorCorrectionToggle.isOn = maskData.enableColorCorrection;
|
||||
|
||||
/*
|
||||
DumpFaceRect (faceRectInMask);
|
||||
DumpLandMarkPoints (faceLandmarkPointsInMask);
|
||||
*/
|
||||
|
||||
/*
|
||||
if (maskData.name == "Panda") {
|
||||
UnityEngine.Rect faceRect;
|
||||
List<Vector2> landmarkPoints;
|
||||
CreatePandaMaskData (out faceRect, out landmarkPoints);
|
||||
SetFaceMaskData (maskData, faceRect, landmarkPoints);
|
||||
}else if (maskData.name == "Anime") {
|
||||
UnityEngine.Rect faceRect;
|
||||
List<Vector2> landmarkPoints;
|
||||
CreateAnimeMaskData (out faceRect, out landmarkPoints);
|
||||
SetFaceMaskData (maskData, faceRect, landmarkPoints);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -625,12 +807,13 @@ namespace FaceMaskExample
|
|||
}
|
||||
|
||||
private void RemoveFaceMask ()
|
||||
{
|
||||
{
|
||||
faceMaskTexture = null;
|
||||
if (faceMaskMat != null) {
|
||||
faceMaskMat.Dispose ();
|
||||
faceMaskMat = null;
|
||||
}
|
||||
|
||||
rectangleTracker.Reset ();
|
||||
meshOverlay.Reset ();
|
||||
}
|
||||
|
@ -672,5 +855,195 @@ namespace FaceMaskExample
|
|||
|
||||
return points;
|
||||
}
|
||||
|
||||
/*
|
||||
private void DumpFaceRect (UnityEngine.Rect faceRect)
|
||||
{
|
||||
Debug.Log ("== DumpFaceRect ==");
|
||||
Debug.Log ("new Rect(" + faceRect.x + ", " + faceRect.y + ", " + faceRect.width + ", " + faceRect.height + ");");
|
||||
Debug.Log ("==================");
|
||||
}
|
||||
|
||||
private void DumpLandMarkPoints (List<Vector2> landmarkPoints)
|
||||
{
|
||||
Debug.Log ("== DumpLandMarkPoints ==");
|
||||
string str = "";
|
||||
for (int i = 0; i < landmarkPoints.Count; i++) {
|
||||
str = str + "new Vector2(" + landmarkPoints[i].x + ", " + landmarkPoints[i].y + ")";
|
||||
if (i < landmarkPoints.Count - 1) {
|
||||
str = str + "," + "\n";
|
||||
}
|
||||
}
|
||||
Debug.Log (str);
|
||||
Debug.Log ("==================");
|
||||
}
|
||||
|
||||
private void SetFaceMaskData (FaceMaskData data, UnityEngine.Rect faceRect, List<Vector2> landmarkPoints)
|
||||
{
|
||||
data.faceRect = faceRect;
|
||||
data.landmarkPoints = landmarkPoints;
|
||||
}
|
||||
|
||||
private void CreatePandaMaskData (out UnityEngine.Rect faceRect, out List<Vector2> landmarkPoints)
|
||||
{
|
||||
faceRect = new UnityEngine.Rect (17, 64, 261, 205);
|
||||
|
||||
landmarkPoints = new List<Vector2> () {
|
||||
new Vector2 (31, 136),
|
||||
new Vector2 (23, 169),
|
||||
new Vector2 (26, 195),
|
||||
new Vector2 (35, 216),
|
||||
new Vector2 (53, 236),
|
||||
new Vector2 (71, 251),
|
||||
new Vector2 (96, 257),
|
||||
new Vector2 (132, 259),
|
||||
new Vector2 (143, 263),
|
||||
//9
|
||||
new Vector2 (165, 258),
|
||||
new Vector2 (198, 255),
|
||||
new Vector2 (222, 242),
|
||||
new Vector2 (235, 231),
|
||||
new Vector2 (248, 215),
|
||||
new Vector2 (260, 195),
|
||||
new Vector2 (272, 171),
|
||||
new Vector2 (264, 135),
|
||||
//17
|
||||
new Vector2 (45, 115),
|
||||
new Vector2 (70, 94),
|
||||
new Vector2 (97, 89),
|
||||
new Vector2 (116, 90),
|
||||
new Vector2 (135, 105),
|
||||
new Vector2 (157, 104),
|
||||
new Vector2 (176, 90),
|
||||
new Vector2 (198, 86),
|
||||
new Vector2 (223, 90),
|
||||
new Vector2 (248, 110),
|
||||
//27
|
||||
new Vector2 (148, 134),
|
||||
new Vector2 (147, 152),
|
||||
new Vector2 (145, 174),
|
||||
new Vector2 (144, 192),
|
||||
new Vector2 (117, 205),
|
||||
new Vector2 (128, 213),
|
||||
new Vector2 (143, 216),
|
||||
new Vector2 (160, 216),
|
||||
new Vector2 (174, 206),
|
||||
//36
|
||||
new Vector2 (96, 138),
|
||||
new Vector2 (101, 131),
|
||||
new Vector2 (111, 132),
|
||||
new Vector2 (114, 140),
|
||||
new Vector2 (109, 146),
|
||||
new Vector2 (100, 146),
|
||||
new Vector2 (180, 138),
|
||||
new Vector2 (186, 130),
|
||||
new Vector2 (195, 131),
|
||||
new Vector2 (199, 137),
|
||||
new Vector2 (195, 143),
|
||||
new Vector2 (185, 143),
|
||||
//48
|
||||
new Vector2 (109, 235),
|
||||
new Vector2 (118, 231),
|
||||
new Vector2 (129, 228),
|
||||
new Vector2 (143, 225),
|
||||
new Vector2 (156, 227),
|
||||
new Vector2 (174, 232),
|
||||
new Vector2 (181, 234),
|
||||
new Vector2 (173, 241),
|
||||
new Vector2 (156, 245),
|
||||
new Vector2 (143, 245),
|
||||
new Vector2 (130, 244),
|
||||
new Vector2 (117, 239),
|
||||
new Vector2 (114, 235),
|
||||
new Vector2 (130, 232),
|
||||
new Vector2 (142, 232),
|
||||
new Vector2 (157, 233),
|
||||
new Vector2 (175, 236),
|
||||
new Vector2 (155, 237),
|
||||
new Vector2 (143, 238),
|
||||
new Vector2 (130, 237)
|
||||
};
|
||||
}
|
||||
|
||||
private void CreateAnimeMaskData (out UnityEngine.Rect faceRect, out List<Vector2> landmarkPoints)
|
||||
{
|
||||
faceRect = new UnityEngine.Rect (56, 85, 190, 196);
|
||||
|
||||
landmarkPoints = new List<Vector2> () {
|
||||
new Vector2(62, 179),
|
||||
new Vector2(72, 209),
|
||||
new Vector2(75, 223),
|
||||
new Vector2(81, 236),
|
||||
new Vector2(90, 244),
|
||||
new Vector2(101, 251),
|
||||
new Vector2(116, 258),
|
||||
new Vector2(129, 262),
|
||||
new Vector2(142, 268),
|
||||
new Vector2(160, 265),
|
||||
new Vector2(184, 260),
|
||||
new Vector2(202, 253),
|
||||
new Vector2(210, 247),
|
||||
new Vector2(217, 239),
|
||||
new Vector2(222, 229),
|
||||
new Vector2(225, 222),
|
||||
new Vector2(243, 191),
|
||||
//17
|
||||
new Vector2(68, 136),
|
||||
new Vector2(86, 128),
|
||||
new Vector2(104, 126),
|
||||
new Vector2(122, 131),
|
||||
new Vector2(134, 141),
|
||||
new Vector2(177, 143),
|
||||
new Vector2(191, 135),
|
||||
new Vector2(209, 132),
|
||||
new Vector2(227, 136),
|
||||
new Vector2(239, 143),
|
||||
//27
|
||||
new Vector2(153, 163),
|
||||
new Vector2(150, 190),
|
||||
new Vector2(149, 201),
|
||||
new Vector2(148, 212),
|
||||
new Vector2(138, 217),
|
||||
new Vector2(141, 219),
|
||||
new Vector2(149, 221),
|
||||
new Vector2(152, 220),
|
||||
new Vector2(155, 217),
|
||||
//36
|
||||
new Vector2(70, 182),
|
||||
new Vector2(85, 165),
|
||||
new Vector2(114, 168),
|
||||
new Vector2(122, 192),
|
||||
new Vector2(113, 211),
|
||||
new Vector2(82, 209),
|
||||
new Vector2(177, 196),
|
||||
new Vector2(189, 174),
|
||||
new Vector2(220, 175),
|
||||
new Vector2(234, 192),
|
||||
new Vector2(215, 220),
|
||||
new Vector2(184, 217),
|
||||
//48
|
||||
new Vector2(132, 249),
|
||||
new Vector2(134, 249),
|
||||
new Vector2(139, 250),
|
||||
new Vector2(144, 251),
|
||||
new Vector2(148, 251),
|
||||
new Vector2(153, 250),
|
||||
new Vector2(155, 251),
|
||||
new Vector2(154, 253),
|
||||
new Vector2(149, 257),
|
||||
new Vector2(144, 257),
|
||||
new Vector2(138, 256),
|
||||
new Vector2(133, 252),
|
||||
new Vector2(133, 250),
|
||||
new Vector2(139, 252),
|
||||
new Vector2(144, 254),
|
||||
new Vector2(148, 253),
|
||||
new Vector2(153, 251),
|
||||
new Vector2(148, 254),
|
||||
new Vector2(144, 254),
|
||||
new Vector2(139, 253)
|
||||
};
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -39,6 +39,15 @@ namespace FaceMaskExample
|
|||
|
||||
[Space(15)]
|
||||
|
||||
[HeaderAttribute ("FaceMaskData")]
|
||||
|
||||
/// <summary>
|
||||
/// The face mask data list.
|
||||
/// </summary>
|
||||
public List<FaceMaskData> faceMaskDatas;
|
||||
|
||||
[HeaderAttribute ("Option")]
|
||||
|
||||
/// <summary>
|
||||
/// Determines if use dlib face detector.
|
||||
/// </summary>
|
||||
|
@ -49,6 +58,26 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
public Toggle useDlibFaceDetecterToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if enables noise filter.
|
||||
/// </summary>
|
||||
public bool enableNoiseFilter = true;
|
||||
|
||||
/// <summary>
|
||||
/// The enable noise filter toggle.
|
||||
/// </summary>
|
||||
public Toggle enableNoiseFilterToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if enables color correction.
|
||||
/// </summary>
|
||||
public bool enableColorCorrection = true;
|
||||
|
||||
/// <summary>
|
||||
/// The enable color correction toggle.
|
||||
/// </summary>
|
||||
public Toggle enableColorCorrectionToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if filters non frontal faces.
|
||||
/// </summary>
|
||||
|
@ -84,16 +113,6 @@ namespace FaceMaskExample
|
|||
/// The toggle for switching debug face points display state.
|
||||
/// </summary>
|
||||
public Toggle displayDebugFacePointsToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The upload face mask button.
|
||||
/// </summary>
|
||||
public Button uploadFaceMaskButton;
|
||||
|
||||
/// <summary>
|
||||
/// The colors.
|
||||
/// </summary>
|
||||
Color32[] colors;
|
||||
|
||||
/// <summary>
|
||||
/// The gray mat.
|
||||
|
@ -109,7 +128,12 @@ namespace FaceMaskExample
|
|||
/// The cascade.
|
||||
/// </summary>
|
||||
CascadeClassifier cascade;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The detection based tracker.
|
||||
/// </summary>
|
||||
RectangleTracker rectangleTracker;
|
||||
|
||||
/// <summary>
|
||||
/// The web cam texture to mat helper.
|
||||
/// </summary>
|
||||
|
@ -119,11 +143,21 @@ namespace FaceMaskExample
|
|||
/// The face landmark detector.
|
||||
/// </summary>
|
||||
FaceLandmarkDetector faceLandmarkDetector;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The detection based tracker.
|
||||
/// The mean points filter dictionary.
|
||||
/// </summary>
|
||||
RectangleTracker rectangleTracker;
|
||||
Dictionary<int, LowPassPointsFilter> lowPassFilterDict;
|
||||
|
||||
/// <summary>
|
||||
/// The optical flow points filter dictionary.
|
||||
/// </summary>
|
||||
Dictionary<int, OFPointsFilter> opticalFlowFilterDict;
|
||||
|
||||
/// <summary>
|
||||
/// The face mask color corrector.
|
||||
/// </summary>
|
||||
FaceMaskColorCorrector faceMaskColorCorrector;
|
||||
|
||||
/// <summary>
|
||||
/// The frontal face checker.
|
||||
|
@ -139,6 +173,16 @@ namespace FaceMaskExample
|
|||
/// The Shader.PropertyToID for "_Fade".
|
||||
/// </summary>
|
||||
int shader_FadeID;
|
||||
|
||||
/// <summary>
|
||||
/// The Shader.PropertyToID for "_ColorCorrection".
|
||||
/// </summary>
|
||||
int shader_ColorCorrectionID;
|
||||
|
||||
/// <summary>
|
||||
/// The Shader.PropertyToID for "_LUTTex".
|
||||
/// </summary>
|
||||
int shader_LUTTexID;
|
||||
|
||||
/// <summary>
|
||||
/// The face mask texture.
|
||||
|
@ -150,6 +194,11 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
Mat faceMaskMat;
|
||||
|
||||
/// <summary>
|
||||
/// The index number of face mask data.
|
||||
/// </summary>
|
||||
int faceMaskDataIndex = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The detected face rect in mask mat.
|
||||
/// </summary>
|
||||
|
@ -170,6 +219,15 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
string sp_human_face_68_dat_filepath;
|
||||
|
||||
/// <summary>
|
||||
/// The FPS monitor.
|
||||
/// </summary>
|
||||
FpsMonitor fpsMonitor;
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
float rearCameraRequestedFPS;
|
||||
#endif
|
||||
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
Stack<IEnumerator> coroutines = new Stack<IEnumerator> ();
|
||||
#endif
|
||||
|
@ -177,6 +235,8 @@ namespace FaceMaskExample
|
|||
// Use this for initialization
|
||||
void Start ()
|
||||
{
|
||||
fpsMonitor = GetComponent<FpsMonitor> ();
|
||||
|
||||
webCamTextureToMatHelper = gameObject.GetComponent<WebCamTextureToMatHelper> ();
|
||||
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
|
@ -208,7 +268,6 @@ namespace FaceMaskExample
|
|||
coroutines.Clear ();
|
||||
|
||||
Run ();
|
||||
uploadFaceMaskButton.interactable = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -234,15 +293,37 @@ namespace FaceMaskExample
|
|||
|
||||
|
||||
shader_FadeID = Shader.PropertyToID("_Fade");
|
||||
shader_ColorCorrectionID = Shader.PropertyToID("_ColorCorrection");
|
||||
shader_LUTTexID = Shader.PropertyToID("_LUTTex");
|
||||
|
||||
rectangleTracker = new RectangleTracker ();
|
||||
|
||||
faceLandmarkDetector = new FaceLandmarkDetector (sp_human_face_68_dat_filepath);
|
||||
|
||||
lowPassFilterDict = new Dictionary<int, LowPassPointsFilter> ();
|
||||
opticalFlowFilterDict = new Dictionary<int, OFPointsFilter> ();
|
||||
|
||||
faceMaskColorCorrector = new FaceMaskColorCorrector ();
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
// Set the requestedFPS parameter to avoid the problem of the WebCamTexture image becoming low light on some Android devices. (Pixel, pixel 2)
|
||||
// https://forum.unity.com/threads/android-webcamtexture-in-low-light-only-some-models.520656/
|
||||
// https://forum.unity.com/threads/released-opencv-for-unity.277080/page-33#post-3445178
|
||||
rearCameraRequestedFPS = webCamTextureToMatHelper.requestedFPS;
|
||||
if (webCamTextureToMatHelper.requestedIsFrontFacing) {
|
||||
webCamTextureToMatHelper.requestedFPS = 15;
|
||||
webCamTextureToMatHelper.Initialize ();
|
||||
} else {
|
||||
webCamTextureToMatHelper.Initialize ();
|
||||
}
|
||||
#else
|
||||
webCamTextureToMatHelper.Initialize ();
|
||||
#endif
|
||||
|
||||
displayFaceRectsToggle.isOn = displayFaceRects;
|
||||
useDlibFaceDetecterToggle.isOn = useDlibFaceDetecter;
|
||||
enableNoiseFilterToggle.isOn = enableNoiseFilter;
|
||||
enableColorCorrectionToggle.isOn = enableColorCorrection;
|
||||
filterNonFrontalFacesToggle.isOn = filterNonFrontalFaces;
|
||||
displayDebugFacePointsToggle.isOn = displayDebugFacePoints;
|
||||
}
|
||||
|
@ -256,13 +337,19 @@ namespace FaceMaskExample
|
|||
|
||||
Mat webCamTextureMat = webCamTextureToMatHelper.GetMat ();
|
||||
|
||||
colors = new Color32[webCamTextureMat.cols () * webCamTextureMat.rows ()];
|
||||
texture = new Texture2D (webCamTextureMat.cols (), webCamTextureMat.rows (), TextureFormat.RGBA32, false);
|
||||
|
||||
|
||||
gameObject.transform.localScale = new Vector3 (webCamTextureMat.cols (), webCamTextureMat.rows (), 1);
|
||||
Debug.Log ("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation);
|
||||
|
||||
if (fpsMonitor != null){
|
||||
fpsMonitor.Add ("width", webCamTextureMat.width ().ToString());
|
||||
fpsMonitor.Add ("height", webCamTextureMat.height ().ToString());
|
||||
fpsMonitor.Add ("orientation", Screen.orientation.ToString());
|
||||
}
|
||||
|
||||
|
||||
float width = gameObject.transform.localScale.x;
|
||||
float height = gameObject.transform.localScale.y;
|
||||
|
||||
|
@ -298,9 +385,25 @@ namespace FaceMaskExample
|
|||
|
||||
grayMat.Dispose ();
|
||||
|
||||
if (texture != null) {
|
||||
Texture2D.Destroy(texture);
|
||||
texture = null;
|
||||
}
|
||||
|
||||
rectangleTracker.Reset ();
|
||||
meshOverlay.Reset ();
|
||||
|
||||
foreach (var key in lowPassFilterDict.Keys) {
|
||||
lowPassFilterDict [key].Dispose ();
|
||||
}
|
||||
lowPassFilterDict.Clear ();
|
||||
foreach (var key in opticalFlowFilterDict.Keys) {
|
||||
opticalFlowFilterDict [key].Dispose ();
|
||||
}
|
||||
opticalFlowFilterDict.Clear ();
|
||||
|
||||
faceMaskColorCorrector.Reset ();
|
||||
|
||||
frontalFaceChecker.Dispose ();
|
||||
}
|
||||
|
||||
|
@ -345,13 +448,41 @@ namespace FaceMaskExample
|
|||
foreach (OpenCVForUnity.Rect r in detectResult) {
|
||||
r.y += (int)(r.height * 0.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// face traking.
|
||||
// face tracking.
|
||||
rectangleTracker.UpdateTrackedObjects (detectResult);
|
||||
List<TrackedRect> trackedRects = new List<TrackedRect> ();
|
||||
rectangleTracker.GetObjects (trackedRects, true);
|
||||
|
||||
|
||||
// create noise filter.
|
||||
foreach (var openCVRect in trackedRects) {
|
||||
if (openCVRect.state == TrackedState.NEW) {
|
||||
if (!lowPassFilterDict.ContainsKey(openCVRect.id))
|
||||
lowPassFilterDict.Add (openCVRect.id, new LowPassPointsFilter((int)faceLandmarkDetector.GetShapePredictorNumParts()));
|
||||
if (!opticalFlowFilterDict.ContainsKey(openCVRect.id))
|
||||
opticalFlowFilterDict.Add (openCVRect.id, new OFPointsFilter((int)faceLandmarkDetector.GetShapePredictorNumParts()));
|
||||
}else if (openCVRect.state == TrackedState.DELETED){
|
||||
if (lowPassFilterDict.ContainsKey (openCVRect.id)) {
|
||||
lowPassFilterDict [openCVRect.id].Dispose ();
|
||||
lowPassFilterDict.Remove (openCVRect.id);
|
||||
}
|
||||
if (opticalFlowFilterDict.ContainsKey (openCVRect.id)) {
|
||||
opticalFlowFilterDict [openCVRect.id].Dispose ();
|
||||
opticalFlowFilterDict.Remove (openCVRect.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create LUT texture.
|
||||
foreach (var openCVRect in trackedRects) {
|
||||
if (openCVRect.state == TrackedState.NEW) {
|
||||
faceMaskColorCorrector.CreateLUTTex (openCVRect.id);
|
||||
}else if (openCVRect.state == TrackedState.DELETED) {
|
||||
faceMaskColorCorrector.DeleteLUTTex (openCVRect.id);
|
||||
}
|
||||
}
|
||||
|
||||
// detect face landmark points.
|
||||
OpenCVForUnityUtils.SetImage (faceLandmarkDetector, rgbaMat);
|
||||
List<List<Vector2>> landmarkPoints = new List<List<Vector2>> ();
|
||||
|
@ -361,6 +492,14 @@ namespace FaceMaskExample
|
|||
|
||||
List<Vector2> points = faceLandmarkDetector.DetectLandmark (rect);
|
||||
|
||||
// apply noise filter.
|
||||
if (enableNoiseFilter) {
|
||||
if (tr.state > TrackedState.NEW && tr.state < TrackedState.DELETED) {
|
||||
opticalFlowFilterDict [tr.id].Process (rgbaMat, points, points);
|
||||
lowPassFilterDict [tr.id].Process (rgbaMat, points, points);
|
||||
}
|
||||
}
|
||||
|
||||
if (extendForehead){
|
||||
AddForeheadPoints(points);
|
||||
}
|
||||
|
@ -369,16 +508,13 @@ namespace FaceMaskExample
|
|||
}
|
||||
|
||||
// face masking.
|
||||
if (faceMaskTexture != null && landmarkPoints.Count >= 1) {
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
if (faceMaskTexture != null && landmarkPoints.Count >= 1) { // Apply face masking between detected faces and a face mask image.
|
||||
|
||||
float imageWidth = meshOverlay.width;
|
||||
float imageHeight = meshOverlay.height;
|
||||
float maskImageWidth = faceMaskTexture.width;
|
||||
float maskImageHeight = faceMaskTexture.height;
|
||||
|
||||
TrackedRect tr;
|
||||
TrackedMesh tm;
|
||||
|
||||
for (int i = 0; i < trackedRects.Count; i++) {
|
||||
tr = trackedRects [i];
|
||||
|
||||
|
@ -386,50 +522,22 @@ namespace FaceMaskExample
|
|||
meshOverlay.CreateObject (tr.id, faceMaskTexture);
|
||||
}
|
||||
if (tr.state < TrackedState.DELETED) {
|
||||
tm = meshOverlay.GetObjectById (tr.id);
|
||||
MaskFace (meshOverlay, tr, landmarkPoints [i], faceLandmarkPointsInMask, maskImageWidth, maskImageHeight);
|
||||
|
||||
Vector3[] vertices = tm.meshFilter.mesh.vertices;
|
||||
if (vertices.Length == landmarkPoints [i].Count) {
|
||||
for (int j = 0; j < vertices.Length; j++) {
|
||||
vertices [j].x = landmarkPoints [i] [j].x / imageWidth - 0.5f;
|
||||
vertices [j].y = 0.5f - landmarkPoints [i] [j].y / imageHeight;
|
||||
}
|
||||
if (enableColorCorrection) {
|
||||
CorrectFaceMaskColor (tr.id, faceMaskMat, rgbaMat, faceLandmarkPointsInMask, landmarkPoints [i]);
|
||||
}
|
||||
Vector2[] uv = tm.meshFilter.mesh.uv;
|
||||
if (uv.Length == faceLandmarkPointsInMask.Count) {
|
||||
for (int jj = 0; jj < uv.Length; jj++) {
|
||||
uv [jj].x = faceLandmarkPointsInMask [jj].x / maskImageWidth;
|
||||
uv [jj].y = (maskImageHeight - faceLandmarkPointsInMask [jj].y) / maskImageHeight;
|
||||
}
|
||||
}
|
||||
meshOverlay.UpdateObject (tr.id, vertices, null, uv);
|
||||
|
||||
if (tr.numFramesNotDetected > 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
}else if (tr.numFramesNotDetected > 0 && tr.numFramesNotDetected <= 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f + (0.7f/4f) * tr.numFramesNotDetected);
|
||||
} else {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f);
|
||||
}
|
||||
|
||||
// filter non frontal faces.
|
||||
if (filterNonFrontalFaces && frontalFaceChecker.GetFrontalFaceRate (landmarkPoints [i]) < frontalFaceRateLowerLimit) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
}
|
||||
|
||||
} else if (tr.state == TrackedState.DELETED) {
|
||||
meshOverlay.DeleteObject (tr.id);
|
||||
}
|
||||
}
|
||||
} else if (landmarkPoints.Count >= 1) {
|
||||
} else if (landmarkPoints.Count >= 1) { // Apply face masking between detected faces.
|
||||
|
||||
float imageWidth = meshOverlay.width;
|
||||
float imageHeight = meshOverlay.height;
|
||||
float maskImageWidth = texture.width;
|
||||
float maskImageHeight = texture.height;
|
||||
|
||||
TrackedRect tr;
|
||||
TrackedMesh tm;
|
||||
|
||||
for (int i = 0; i < trackedRects.Count; i++) {
|
||||
tr = trackedRects [i];
|
||||
|
||||
|
@ -437,37 +545,11 @@ namespace FaceMaskExample
|
|||
meshOverlay.CreateObject (tr.id, texture);
|
||||
}
|
||||
if (tr.state < TrackedState.DELETED) {
|
||||
tm = meshOverlay.GetObjectById (tr.id);
|
||||
|
||||
Vector3[] vertices = tm.meshFilter.mesh.vertices;
|
||||
if (vertices.Length == landmarkPoints [i].Count) {
|
||||
for (int j = 0; j < vertices.Length; j++) {
|
||||
vertices [j].x = landmarkPoints[i][j].x / imageWidth - 0.5f;
|
||||
vertices [j].y = 0.5f - landmarkPoints[i][j].y / imageHeight;
|
||||
}
|
||||
}
|
||||
Vector2[] uv = tm.meshFilter.mesh.uv;
|
||||
if (uv.Length == landmarkPoints [0].Count) {
|
||||
for (int jj = 0; jj < uv.Length; jj++) {
|
||||
uv [jj].x = landmarkPoints[0][jj].x / maskImageWidth;
|
||||
uv [jj].y = (maskImageHeight - landmarkPoints[0][jj].y) / maskImageHeight;
|
||||
}
|
||||
}
|
||||
meshOverlay.UpdateObject (tr.id, vertices, null, uv);
|
||||
MaskFace (meshOverlay, tr, landmarkPoints [i], landmarkPoints [0], maskImageWidth, maskImageHeight);
|
||||
|
||||
if (tr.numFramesNotDetected > 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
}else if (tr.numFramesNotDetected > 0 && tr.numFramesNotDetected <= 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f + (0.7f/4f) * tr.numFramesNotDetected);
|
||||
} else {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f);
|
||||
if (enableColorCorrection) {
|
||||
CorrectFaceMaskColor (tr.id, rgbaMat, rgbaMat, landmarkPoints [0], landmarkPoints [i]);
|
||||
}
|
||||
|
||||
// filter nonsfrontal faces.
|
||||
if (filterNonFrontalFaces && frontalFaceChecker.GetFrontalFaceRate (landmarkPoints [i]) < frontalFaceRateLowerLimit) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
}
|
||||
|
||||
} else if (tr.state == TrackedState.DELETED) {
|
||||
meshOverlay.DeleteObject (tr.id);
|
||||
}
|
||||
|
@ -519,14 +601,73 @@ namespace FaceMaskExample
|
|||
trans.put (1, 2, ty);
|
||||
|
||||
Imgproc.warpAffine (faceMaskMat, rgbaMat, trans, rgbaMat.size (), Imgproc.INTER_LINEAR, Core.BORDER_TRANSPARENT, new Scalar (0));
|
||||
|
||||
if (displayFaceRects || displayDebugFacePointsToggle)
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
}
|
||||
|
||||
Imgproc.putText (rgbaMat, "W:" + rgbaMat.width () + " H:" + rgbaMat.height () + " SO:" + Screen.orientation, new Point (5, rgbaMat.rows () - 10), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
// Imgproc.putText (rgbaMat, "W:" + rgbaMat.width () + " H:" + rgbaMat.height () + " SO:" + Screen.orientation, new Point (5, rgbaMat.rows () - 10), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
|
||||
OpenCVForUnity.Utils.matToTexture2D (rgbaMat, texture, colors);
|
||||
OpenCVForUnity.Utils.fastMatToTexture2D (rgbaMat, texture);
|
||||
}
|
||||
}
|
||||
|
||||
private void MaskFace (TrackedMeshOverlay meshOverlay, TrackedRect tr, List<Vector2> landmarkPoints, List<Vector2> landmarkPointsInMaskImage, float maskImageWidth = 0, float maskImageHeight = 0)
|
||||
{
|
||||
float imageWidth = meshOverlay.width;
|
||||
float imageHeight = meshOverlay.height;
|
||||
|
||||
if (maskImageWidth == 0)
|
||||
maskImageWidth = imageWidth;
|
||||
|
||||
if (maskImageHeight == 0)
|
||||
maskImageHeight = imageHeight;
|
||||
|
||||
TrackedMesh tm = meshOverlay.GetObjectById (tr.id);
|
||||
|
||||
Vector3[] vertices = tm.meshFilter.mesh.vertices;
|
||||
if (vertices.Length == landmarkPoints.Count) {
|
||||
for (int j = 0; j < vertices.Length; j++) {
|
||||
vertices [j].x = landmarkPoints[j].x / imageWidth - 0.5f;
|
||||
vertices [j].y = 0.5f - landmarkPoints[j].y / imageHeight;
|
||||
}
|
||||
}
|
||||
Vector2[] uv = tm.meshFilter.mesh.uv;
|
||||
if (uv.Length == landmarkPointsInMaskImage.Count) {
|
||||
for (int jj = 0; jj < uv.Length; jj++) {
|
||||
uv [jj].x = landmarkPointsInMaskImage[jj].x / maskImageWidth;
|
||||
uv [jj].y = (maskImageHeight - landmarkPointsInMaskImage[jj].y) / maskImageHeight;
|
||||
}
|
||||
}
|
||||
meshOverlay.UpdateObject (tr.id, vertices, null, uv);
|
||||
|
||||
if (tr.numFramesNotDetected > 3) {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 1f);
|
||||
}else if (tr.numFramesNotDetected > 0 && tr.numFramesNotDetected <= 3) {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 0.3f + (0.7f/4f) * tr.numFramesNotDetected);
|
||||
} else {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 0.3f);
|
||||
}
|
||||
|
||||
if (enableColorCorrection) {
|
||||
tm.sharedMaterial.SetFloat (shader_ColorCorrectionID, 1f);
|
||||
} else {
|
||||
tm.sharedMaterial.SetFloat (shader_ColorCorrectionID, 0f);
|
||||
}
|
||||
|
||||
// filter non frontal faces.
|
||||
if (filterNonFrontalFaces && frontalFaceChecker.GetFrontalFaceRate (landmarkPoints) < frontalFaceRateLowerLimit) {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
private void CorrectFaceMaskColor (int id, Mat src, Mat dst, List<Vector2> src_landmarkPoints, List<Vector2> dst_landmarkPoints)
|
||||
{
|
||||
Texture2D LUTTex = faceMaskColorCorrector.UpdateLUTTex(id, src, dst, src_landmarkPoints, dst_landmarkPoints);
|
||||
TrackedMesh tm = meshOverlay.GetObjectById (id);
|
||||
tm.sharedMaterial.SetTexture (shader_LUTTexID, LUTTex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the destroy event.
|
||||
/// </summary>
|
||||
|
@ -543,6 +684,18 @@ namespace FaceMaskExample
|
|||
if (faceLandmarkDetector != null)
|
||||
faceLandmarkDetector.Dispose ();
|
||||
|
||||
foreach (var key in lowPassFilterDict.Keys) {
|
||||
lowPassFilterDict [key].Dispose ();
|
||||
}
|
||||
lowPassFilterDict.Clear ();
|
||||
foreach (var key in opticalFlowFilterDict.Keys) {
|
||||
opticalFlowFilterDict [key].Dispose ();
|
||||
}
|
||||
opticalFlowFilterDict.Clear ();
|
||||
|
||||
if (faceMaskColorCorrector != null)
|
||||
faceMaskColorCorrector.Dispose ();
|
||||
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
foreach (var coroutine in coroutines) {
|
||||
StopCoroutine (coroutine);
|
||||
|
@ -584,7 +737,16 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
public void OnChangeCameraButtonClick ()
|
||||
{
|
||||
webCamTextureToMatHelper.Initialize (null, webCamTextureToMatHelper.requestedWidth, webCamTextureToMatHelper.requestedHeight, !webCamTextureToMatHelper.requestedIsFrontFacing);
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
if (!webCamTextureToMatHelper.IsFrontFacing ()) {
|
||||
rearCameraRequestedFPS = webCamTextureToMatHelper.requestedFPS;
|
||||
webCamTextureToMatHelper.Initialize (!webCamTextureToMatHelper.IsFrontFacing (), 15, webCamTextureToMatHelper.rotate90Degree);
|
||||
} else {
|
||||
webCamTextureToMatHelper.Initialize (!webCamTextureToMatHelper.IsFrontFacing (), rearCameraRequestedFPS, webCamTextureToMatHelper.rotate90Degree);
|
||||
}
|
||||
#else
|
||||
webCamTextureToMatHelper.requestedIsFrontFacing = !webCamTextureToMatHelper.IsFrontFacing ();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -599,6 +761,36 @@ namespace FaceMaskExample
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the enable noise filter toggle value changed event.
|
||||
/// </summary>
|
||||
public void OnEnableNoiseFilterToggleValueChanged ()
|
||||
{
|
||||
if (enableNoiseFilterToggle.isOn) {
|
||||
enableNoiseFilter = true;
|
||||
foreach (var key in lowPassFilterDict.Keys) {
|
||||
lowPassFilterDict [key].Reset ();
|
||||
}
|
||||
foreach (var key in opticalFlowFilterDict.Keys) {
|
||||
opticalFlowFilterDict [key].Reset ();
|
||||
}
|
||||
} else {
|
||||
enableNoiseFilter = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the enable color correction toggle value changed event.
|
||||
/// </summary>
|
||||
public void OnEnableColorCorrectionToggleValueChanged ()
|
||||
{
|
||||
if (enableColorCorrectionToggle.isOn) {
|
||||
enableColorCorrection = true;
|
||||
} else {
|
||||
enableColorCorrection = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the filter non frontal faces toggle value changed event.
|
||||
/// </summary>
|
||||
|
@ -642,31 +834,54 @@ namespace FaceMaskExample
|
|||
{
|
||||
RemoveFaceMask ();
|
||||
|
||||
ExampleMaskData maskData = ExampleDataSet.GetData();
|
||||
if (faceMaskDatas.Count == 0)
|
||||
return;
|
||||
|
||||
faceMaskTexture = Resources.Load (maskData.fileName) as Texture2D;
|
||||
FaceMaskData maskData = faceMaskDatas[faceMaskDataIndex];
|
||||
faceMaskDataIndex = (faceMaskDataIndex < faceMaskDatas.Count - 1) ? faceMaskDataIndex + 1 : 0;
|
||||
|
||||
if (maskData == null) {
|
||||
Debug.LogError ("maskData == null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (maskData.image == null) {
|
||||
Debug.LogError ("image == null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (maskData.landmarkPoints.Count != 68) {
|
||||
Debug.LogError ("landmarkPoints.Count != 68");
|
||||
return;
|
||||
}
|
||||
|
||||
faceMaskTexture = maskData.image;
|
||||
faceMaskMat = new Mat (faceMaskTexture.height, faceMaskTexture.width, CvType.CV_8UC4);
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
Debug.Log ("faceMaskMat ToString " + faceMaskMat.ToString ());
|
||||
|
||||
if(maskData.landmarkPoints != null){
|
||||
faceRectInMask = maskData.faceRect;
|
||||
faceLandmarkPointsInMask = new List<Vector2>(maskData.landmarkPoints);
|
||||
}else{
|
||||
if(maskData.isDynamicMode){
|
||||
faceRectInMask = DetectFace (faceMaskMat);
|
||||
faceLandmarkPointsInMask = DetectFaceLandmarkPoints (faceMaskMat, faceRectInMask);
|
||||
|
||||
maskData.faceRect = faceRectInMask;
|
||||
maskData.landmarkPoints = faceLandmarkPointsInMask;
|
||||
}else{
|
||||
faceRectInMask = maskData.faceRect;
|
||||
faceLandmarkPointsInMask = maskData.landmarkPoints;
|
||||
}
|
||||
|
||||
if (extendForehead) {
|
||||
AddForeheadPoints(faceLandmarkPointsInMask);
|
||||
List<Vector2> newLandmarkPointsInMask = new List<Vector2> (faceLandmarkPointsInMask);
|
||||
AddForeheadPoints(newLandmarkPointsInMask);
|
||||
faceLandmarkPointsInMask = newLandmarkPointsInMask;
|
||||
}
|
||||
|
||||
ExampleDataSet.Next();
|
||||
|
||||
if (faceRectInMask.width == 0 && faceRectInMask.height == 0){
|
||||
RemoveFaceMask ();
|
||||
Debug.Log ("A face could not be detected from the input image.");
|
||||
Debug.LogError ("A face could not be detected from the input image.");
|
||||
}
|
||||
|
||||
enableColorCorrectionToggle.isOn = maskData.enableColorCorrection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -725,6 +940,7 @@ namespace FaceMaskExample
|
|||
faceMaskMat.Dispose ();
|
||||
faceMaskMat = null;
|
||||
}
|
||||
|
||||
rectangleTracker.Reset ();
|
||||
meshOverlay.Reset ();
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -20,6 +20,15 @@ namespace FaceMaskExample
|
|||
[RequireComponent (typeof(WebCamTextureToMatHelper), typeof(TrackedMeshOverlay))]
|
||||
public class WebCamTextureFaceMaskExample : MonoBehaviour
|
||||
{
|
||||
[HeaderAttribute ("FaceMaskData")]
|
||||
|
||||
/// <summary>
|
||||
/// The face mask data list.
|
||||
/// </summary>
|
||||
public List<FaceMaskData> faceMaskDatas;
|
||||
|
||||
[HeaderAttribute ("Option")]
|
||||
|
||||
/// <summary>
|
||||
/// Determines if use dlib face detector.
|
||||
/// </summary>
|
||||
|
@ -30,6 +39,26 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
public Toggle useDlibFaceDetecterToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if enables noise filter.
|
||||
/// </summary>
|
||||
public bool enableNoiseFilter = true;
|
||||
|
||||
/// <summary>
|
||||
/// The enable noise filter toggle.
|
||||
/// </summary>
|
||||
public Toggle enableNoiseFilterToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if enables color correction.
|
||||
/// </summary>
|
||||
public bool enableColorCorrection = true;
|
||||
|
||||
/// <summary>
|
||||
/// The enable color correction toggle.
|
||||
/// </summary>
|
||||
public Toggle enableColorCorrectionToggle;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if filters non frontal faces.
|
||||
/// </summary>
|
||||
|
@ -65,16 +94,6 @@ namespace FaceMaskExample
|
|||
/// The toggle for switching debug face points display state.
|
||||
/// </summary>
|
||||
public Toggle displayDebugFacePointsToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The upload face mask button.
|
||||
/// </summary>
|
||||
public Button uploadFaceMaskButton;
|
||||
|
||||
/// <summary>
|
||||
/// The colors.
|
||||
/// </summary>
|
||||
Color32[] colors;
|
||||
|
||||
/// <summary>
|
||||
/// The gray mat.
|
||||
|
@ -90,7 +109,12 @@ namespace FaceMaskExample
|
|||
/// The cascade.
|
||||
/// </summary>
|
||||
CascadeClassifier cascade;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The detection based tracker.
|
||||
/// </summary>
|
||||
RectangleTracker rectangleTracker;
|
||||
|
||||
/// <summary>
|
||||
/// The web cam texture to mat helper.
|
||||
/// </summary>
|
||||
|
@ -100,11 +124,21 @@ namespace FaceMaskExample
|
|||
/// The face landmark detector.
|
||||
/// </summary>
|
||||
FaceLandmarkDetector faceLandmarkDetector;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The detection based tracker.
|
||||
/// The mean points filter dictionary.
|
||||
/// </summary>
|
||||
RectangleTracker rectangleTracker;
|
||||
Dictionary<int, LowPassPointsFilter> lowPassFilterDict;
|
||||
|
||||
/// <summary>
|
||||
/// The optical flow points filter dictionary.
|
||||
/// </summary>
|
||||
Dictionary<int, OFPointsFilter> opticalFlowFilterDict;
|
||||
|
||||
/// <summary>
|
||||
/// The face mask color corrector.
|
||||
/// </summary>
|
||||
FaceMaskColorCorrector faceMaskColorCorrector;
|
||||
|
||||
/// <summary>
|
||||
/// The frontal face checker.
|
||||
|
@ -120,7 +154,17 @@ namespace FaceMaskExample
|
|||
/// The Shader.PropertyToID for "_Fade".
|
||||
/// </summary>
|
||||
int shader_FadeID;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The Shader.PropertyToID for "_ColorCorrection".
|
||||
/// </summary>
|
||||
int shader_ColorCorrectionID;
|
||||
|
||||
/// <summary>
|
||||
/// The Shader.PropertyToID for "_LUTTex".
|
||||
/// </summary>
|
||||
int shader_LUTTexID;
|
||||
|
||||
/// <summary>
|
||||
/// The face mask texture.
|
||||
/// </summary>
|
||||
|
@ -131,6 +175,11 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
Mat faceMaskMat;
|
||||
|
||||
/// <summary>
|
||||
/// The index number of face mask data.
|
||||
/// </summary>
|
||||
int faceMaskDataIndex = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The detected face rect in mask mat.
|
||||
/// </summary>
|
||||
|
@ -151,6 +200,15 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
string sp_human_face_68_dat_filepath;
|
||||
|
||||
/// <summary>
|
||||
/// The FPS monitor.
|
||||
/// </summary>
|
||||
FpsMonitor fpsMonitor;
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
float rearCameraRequestedFPS;
|
||||
#endif
|
||||
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
Stack<IEnumerator> coroutines = new Stack<IEnumerator> ();
|
||||
#endif
|
||||
|
@ -158,6 +216,8 @@ namespace FaceMaskExample
|
|||
// Use this for initialization
|
||||
void Start ()
|
||||
{
|
||||
fpsMonitor = GetComponent<FpsMonitor> ();
|
||||
|
||||
webCamTextureToMatHelper = gameObject.GetComponent<WebCamTextureToMatHelper> ();
|
||||
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
|
@ -189,7 +249,6 @@ namespace FaceMaskExample
|
|||
coroutines.Clear ();
|
||||
|
||||
Run ();
|
||||
uploadFaceMaskButton.interactable = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -198,15 +257,37 @@ namespace FaceMaskExample
|
|||
meshOverlay = this.GetComponent<TrackedMeshOverlay> ();
|
||||
|
||||
shader_FadeID = Shader.PropertyToID("_Fade");
|
||||
shader_ColorCorrectionID = Shader.PropertyToID("_ColorCorrection");
|
||||
shader_LUTTexID = Shader.PropertyToID("_LUTTex");
|
||||
|
||||
rectangleTracker = new RectangleTracker ();
|
||||
|
||||
faceLandmarkDetector = new FaceLandmarkDetector (sp_human_face_68_dat_filepath);
|
||||
|
||||
lowPassFilterDict = new Dictionary<int, LowPassPointsFilter> ();
|
||||
opticalFlowFilterDict = new Dictionary<int, OFPointsFilter> ();
|
||||
|
||||
faceMaskColorCorrector = new FaceMaskColorCorrector ();
|
||||
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
// Set the requestedFPS parameter to avoid the problem of the WebCamTexture image becoming low light on some Android devices. (Pixel, pixel 2)
|
||||
// https://forum.unity.com/threads/android-webcamtexture-in-low-light-only-some-models.520656/
|
||||
// https://forum.unity.com/threads/released-opencv-for-unity.277080/page-33#post-3445178
|
||||
rearCameraRequestedFPS = webCamTextureToMatHelper.requestedFPS;
|
||||
if (webCamTextureToMatHelper.requestedIsFrontFacing) {
|
||||
webCamTextureToMatHelper.requestedFPS = 15;
|
||||
webCamTextureToMatHelper.Initialize ();
|
||||
} else {
|
||||
webCamTextureToMatHelper.Initialize ();
|
||||
}
|
||||
#else
|
||||
webCamTextureToMatHelper.Initialize ();
|
||||
#endif
|
||||
|
||||
displayFaceRectsToggle.isOn = displayFaceRects;
|
||||
useDlibFaceDetecterToggle.isOn = useDlibFaceDetecter;
|
||||
enableNoiseFilterToggle.isOn = enableNoiseFilter;
|
||||
enableColorCorrectionToggle.isOn = enableColorCorrection;
|
||||
filterNonFrontalFacesToggle.isOn = filterNonFrontalFaces;
|
||||
displayDebugFacePointsToggle.isOn = displayDebugFacePoints;
|
||||
}
|
||||
|
@ -220,13 +301,19 @@ namespace FaceMaskExample
|
|||
|
||||
Mat webCamTextureMat = webCamTextureToMatHelper.GetMat ();
|
||||
|
||||
colors = new Color32[webCamTextureMat.cols () * webCamTextureMat.rows ()];
|
||||
texture = new Texture2D (webCamTextureMat.cols (), webCamTextureMat.rows (), TextureFormat.RGBA32, false);
|
||||
|
||||
|
||||
gameObject.transform.localScale = new Vector3 (webCamTextureMat.cols (), webCamTextureMat.rows (), 1);
|
||||
Debug.Log ("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation);
|
||||
|
||||
if (fpsMonitor != null){
|
||||
fpsMonitor.Add ("width", webCamTextureMat.width ().ToString());
|
||||
fpsMonitor.Add ("height", webCamTextureMat.height ().ToString());
|
||||
fpsMonitor.Add ("orientation", Screen.orientation.ToString());
|
||||
}
|
||||
|
||||
|
||||
float width = gameObject.transform.localScale.x;
|
||||
float height = gameObject.transform.localScale.y;
|
||||
|
||||
|
@ -262,9 +349,25 @@ namespace FaceMaskExample
|
|||
|
||||
grayMat.Dispose ();
|
||||
|
||||
if (texture != null) {
|
||||
Texture2D.Destroy(texture);
|
||||
texture = null;
|
||||
}
|
||||
|
||||
rectangleTracker.Reset ();
|
||||
meshOverlay.Reset ();
|
||||
|
||||
foreach (var key in lowPassFilterDict.Keys) {
|
||||
lowPassFilterDict [key].Dispose ();
|
||||
}
|
||||
lowPassFilterDict.Clear ();
|
||||
foreach (var key in opticalFlowFilterDict.Keys) {
|
||||
opticalFlowFilterDict [key].Dispose ();
|
||||
}
|
||||
opticalFlowFilterDict.Clear ();
|
||||
|
||||
faceMaskColorCorrector.Reset ();
|
||||
|
||||
frontalFaceChecker.Dispose ();
|
||||
}
|
||||
|
||||
|
@ -312,11 +415,40 @@ namespace FaceMaskExample
|
|||
}
|
||||
}
|
||||
|
||||
// face traking.
|
||||
|
||||
// face tracking.
|
||||
rectangleTracker.UpdateTrackedObjects (detectResult);
|
||||
List<TrackedRect> trackedRects = new List<TrackedRect> ();
|
||||
rectangleTracker.GetObjects (trackedRects, true);
|
||||
|
||||
|
||||
// create noise filter.
|
||||
foreach (var openCVRect in trackedRects) {
|
||||
if (openCVRect.state == TrackedState.NEW) {
|
||||
if (!lowPassFilterDict.ContainsKey(openCVRect.id))
|
||||
lowPassFilterDict.Add (openCVRect.id, new LowPassPointsFilter((int)faceLandmarkDetector.GetShapePredictorNumParts()));
|
||||
if (!opticalFlowFilterDict.ContainsKey(openCVRect.id))
|
||||
opticalFlowFilterDict.Add (openCVRect.id, new OFPointsFilter((int)faceLandmarkDetector.GetShapePredictorNumParts()));
|
||||
}else if (openCVRect.state == TrackedState.DELETED){
|
||||
if (lowPassFilterDict.ContainsKey (openCVRect.id)) {
|
||||
lowPassFilterDict [openCVRect.id].Dispose ();
|
||||
lowPassFilterDict.Remove (openCVRect.id);
|
||||
}
|
||||
if (opticalFlowFilterDict.ContainsKey (openCVRect.id)) {
|
||||
opticalFlowFilterDict [openCVRect.id].Dispose ();
|
||||
opticalFlowFilterDict.Remove (openCVRect.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create LUT texture.
|
||||
foreach (var openCVRect in trackedRects) {
|
||||
if (openCVRect.state == TrackedState.NEW) {
|
||||
faceMaskColorCorrector.CreateLUTTex (openCVRect.id);
|
||||
}else if (openCVRect.state == TrackedState.DELETED) {
|
||||
faceMaskColorCorrector.DeleteLUTTex (openCVRect.id);
|
||||
}
|
||||
}
|
||||
|
||||
// detect face landmark points.
|
||||
OpenCVForUnityUtils.SetImage (faceLandmarkDetector, rgbaMat);
|
||||
List<List<Vector2>> landmarkPoints = new List<List<Vector2>> ();
|
||||
|
@ -325,20 +457,26 @@ namespace FaceMaskExample
|
|||
UnityEngine.Rect rect = new UnityEngine.Rect (tr.x, tr.y, tr.width, tr.height);
|
||||
|
||||
List<Vector2> points = faceLandmarkDetector.DetectLandmark (rect);
|
||||
|
||||
// apply noise filter.
|
||||
if (enableNoiseFilter) {
|
||||
if (tr.state > TrackedState.NEW && tr.state < TrackedState.DELETED) {
|
||||
opticalFlowFilterDict [tr.id].Process (rgbaMat, points, points);
|
||||
lowPassFilterDict [tr.id].Process (rgbaMat, points, points);
|
||||
}
|
||||
}
|
||||
|
||||
landmarkPoints.Add (points);
|
||||
}
|
||||
|
||||
// face masking.
|
||||
if (faceMaskTexture != null && landmarkPoints.Count >= 1) {
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
if (faceMaskTexture != null && landmarkPoints.Count >= 1) { // Apply face masking between detected faces and a face mask image.
|
||||
|
||||
float imageWidth = meshOverlay.width;
|
||||
float imageHeight = meshOverlay.height;
|
||||
float maskImageWidth = faceMaskTexture.width;
|
||||
float maskImageHeight = faceMaskTexture.height;
|
||||
|
||||
TrackedRect tr;
|
||||
TrackedMesh tm;
|
||||
|
||||
for (int i = 0; i < trackedRects.Count; i++) {
|
||||
tr = trackedRects [i];
|
||||
|
||||
|
@ -346,50 +484,22 @@ namespace FaceMaskExample
|
|||
meshOverlay.CreateObject (tr.id, faceMaskTexture);
|
||||
}
|
||||
if (tr.state < TrackedState.DELETED) {
|
||||
tm = meshOverlay.GetObjectById (tr.id);
|
||||
MaskFace (meshOverlay, tr, landmarkPoints [i], faceLandmarkPointsInMask, maskImageWidth, maskImageHeight);
|
||||
|
||||
Vector3[] vertices = tm.meshFilter.mesh.vertices;
|
||||
if (vertices.Length == landmarkPoints [i].Count) {
|
||||
for (int j = 0; j < vertices.Length; j++) {
|
||||
vertices [j].x = landmarkPoints [i] [j].x / imageWidth - 0.5f;
|
||||
vertices [j].y = 0.5f - landmarkPoints [i] [j].y / imageHeight;
|
||||
}
|
||||
if (enableColorCorrection) {
|
||||
CorrectFaceMaskColor (tr.id, faceMaskMat, rgbaMat, faceLandmarkPointsInMask, landmarkPoints [i]);
|
||||
}
|
||||
Vector2[] uv = tm.meshFilter.mesh.uv;
|
||||
if (uv.Length == faceLandmarkPointsInMask.Count) {
|
||||
for (int jj = 0; jj < uv.Length; jj++) {
|
||||
uv [jj].x = faceLandmarkPointsInMask [jj].x / maskImageWidth;
|
||||
uv [jj].y = (maskImageHeight - faceLandmarkPointsInMask [jj].y) / maskImageHeight;
|
||||
}
|
||||
}
|
||||
meshOverlay.UpdateObject (tr.id, vertices, null, uv);
|
||||
|
||||
if (tr.numFramesNotDetected > 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
}else if (tr.numFramesNotDetected > 0 && tr.numFramesNotDetected <= 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f + (0.7f/4f) * tr.numFramesNotDetected);
|
||||
} else {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f);
|
||||
}
|
||||
|
||||
// filter non frontal faces.
|
||||
if (filterNonFrontalFaces && frontalFaceChecker.GetFrontalFaceRate (landmarkPoints [i]) < frontalFaceRateLowerLimit) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
}
|
||||
|
||||
} else if (tr.state == TrackedState.DELETED) {
|
||||
meshOverlay.DeleteObject (tr.id);
|
||||
}
|
||||
}
|
||||
} else if (landmarkPoints.Count >= 1) {
|
||||
|
||||
float imageWidth = meshOverlay.width;
|
||||
float imageHeight = meshOverlay.height;
|
||||
} else if (landmarkPoints.Count >= 1) { // Apply face masking between detected faces.
|
||||
|
||||
float maskImageWidth = texture.width;
|
||||
float maskImageHeight = texture.height;
|
||||
|
||||
TrackedRect tr;
|
||||
TrackedMesh tm;
|
||||
|
||||
for (int i = 0; i < trackedRects.Count; i++) {
|
||||
tr = trackedRects [i];
|
||||
|
||||
|
@ -397,37 +507,11 @@ namespace FaceMaskExample
|
|||
meshOverlay.CreateObject (tr.id, texture);
|
||||
}
|
||||
if (tr.state < TrackedState.DELETED) {
|
||||
tm = meshOverlay.GetObjectById (tr.id);
|
||||
|
||||
Vector3[] vertices = tm.meshFilter.mesh.vertices;
|
||||
if (vertices.Length == landmarkPoints [i].Count) {
|
||||
for (int j = 0; j < vertices.Length; j++) {
|
||||
vertices [j].x = landmarkPoints[i][j].x / imageWidth - 0.5f;
|
||||
vertices [j].y = 0.5f - landmarkPoints[i][j].y / imageHeight;
|
||||
}
|
||||
}
|
||||
Vector2[] uv = tm.meshFilter.mesh.uv;
|
||||
if (uv.Length == landmarkPoints [0].Count) {
|
||||
for (int jj = 0; jj < uv.Length; jj++) {
|
||||
uv [jj].x = landmarkPoints[0][jj].x / maskImageWidth;
|
||||
uv [jj].y = (maskImageHeight - landmarkPoints[0][jj].y) / maskImageHeight;
|
||||
}
|
||||
}
|
||||
meshOverlay.UpdateObject (tr.id, vertices, null, uv);
|
||||
MaskFace (meshOverlay, tr, landmarkPoints [i], landmarkPoints [0], maskImageWidth, maskImageHeight);
|
||||
|
||||
if (tr.numFramesNotDetected > 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
}else if (tr.numFramesNotDetected > 0 && tr.numFramesNotDetected <= 3) {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f + (0.7f/4f) * tr.numFramesNotDetected);
|
||||
} else {
|
||||
tm.material.SetFloat (shader_FadeID, 0.3f);
|
||||
if (enableColorCorrection) {
|
||||
CorrectFaceMaskColor (tr.id, rgbaMat, rgbaMat, landmarkPoints [0], landmarkPoints [i]);
|
||||
}
|
||||
|
||||
// filter nonsfrontal faces.
|
||||
if (filterNonFrontalFaces && frontalFaceChecker.GetFrontalFaceRate (landmarkPoints [i]) < frontalFaceRateLowerLimit) {
|
||||
tm.material.SetFloat (shader_FadeID, 1f);
|
||||
}
|
||||
|
||||
} else if (tr.state == TrackedState.DELETED) {
|
||||
meshOverlay.DeleteObject (tr.id);
|
||||
}
|
||||
|
@ -479,14 +563,73 @@ namespace FaceMaskExample
|
|||
trans.put (1, 2, ty);
|
||||
|
||||
Imgproc.warpAffine (faceMaskMat, rgbaMat, trans, rgbaMat.size (), Imgproc.INTER_LINEAR, Core.BORDER_TRANSPARENT, new Scalar (0));
|
||||
|
||||
if (displayFaceRects || displayDebugFacePointsToggle)
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
}
|
||||
|
||||
Imgproc.putText (rgbaMat, "W:" + rgbaMat.width () + " H:" + rgbaMat.height () + " SO:" + Screen.orientation, new Point (5, rgbaMat.rows () - 10), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
// Imgproc.putText (rgbaMat, "W:" + rgbaMat.width () + " H:" + rgbaMat.height () + " SO:" + Screen.orientation, new Point (5, rgbaMat.rows () - 10), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
|
||||
|
||||
OpenCVForUnity.Utils.matToTexture2D (rgbaMat, texture, colors);
|
||||
OpenCVForUnity.Utils.fastMatToTexture2D (rgbaMat, texture);
|
||||
}
|
||||
}
|
||||
|
||||
private void MaskFace (TrackedMeshOverlay meshOverlay, TrackedRect tr, List<Vector2> landmarkPoints, List<Vector2> landmarkPointsInMaskImage, float maskImageWidth = 0, float maskImageHeight = 0)
|
||||
{
|
||||
float imageWidth = meshOverlay.width;
|
||||
float imageHeight = meshOverlay.height;
|
||||
|
||||
if (maskImageWidth == 0)
|
||||
maskImageWidth = imageWidth;
|
||||
|
||||
if (maskImageHeight == 0)
|
||||
maskImageHeight = imageHeight;
|
||||
|
||||
TrackedMesh tm = meshOverlay.GetObjectById (tr.id);
|
||||
|
||||
Vector3[] vertices = tm.meshFilter.mesh.vertices;
|
||||
if (vertices.Length == landmarkPoints.Count) {
|
||||
for (int j = 0; j < vertices.Length; j++) {
|
||||
vertices [j].x = landmarkPoints[j].x / imageWidth - 0.5f;
|
||||
vertices [j].y = 0.5f - landmarkPoints[j].y / imageHeight;
|
||||
}
|
||||
}
|
||||
Vector2[] uv = tm.meshFilter.mesh.uv;
|
||||
if (uv.Length == landmarkPointsInMaskImage.Count) {
|
||||
for (int jj = 0; jj < uv.Length; jj++) {
|
||||
uv [jj].x = landmarkPointsInMaskImage[jj].x / maskImageWidth;
|
||||
uv [jj].y = (maskImageHeight - landmarkPointsInMaskImage[jj].y) / maskImageHeight;
|
||||
}
|
||||
}
|
||||
meshOverlay.UpdateObject (tr.id, vertices, null, uv);
|
||||
|
||||
if (tr.numFramesNotDetected > 3) {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 1f);
|
||||
}else if (tr.numFramesNotDetected > 0 && tr.numFramesNotDetected <= 3) {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 0.3f + (0.7f/4f) * tr.numFramesNotDetected);
|
||||
} else {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 0.3f);
|
||||
}
|
||||
|
||||
if (enableColorCorrection) {
|
||||
tm.sharedMaterial.SetFloat (shader_ColorCorrectionID, 1f);
|
||||
} else {
|
||||
tm.sharedMaterial.SetFloat (shader_ColorCorrectionID, 0f);
|
||||
}
|
||||
|
||||
// filter non frontal faces.
|
||||
if (filterNonFrontalFaces && frontalFaceChecker.GetFrontalFaceRate (landmarkPoints) < frontalFaceRateLowerLimit) {
|
||||
tm.sharedMaterial.SetFloat (shader_FadeID, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
private void CorrectFaceMaskColor (int id, Mat src, Mat dst, List<Vector2> src_landmarkPoints, List<Vector2> dst_landmarkPoints)
|
||||
{
|
||||
Texture2D LUTTex = faceMaskColorCorrector.UpdateLUTTex(id, src, dst, src_landmarkPoints, dst_landmarkPoints);
|
||||
TrackedMesh tm = meshOverlay.GetObjectById (id);
|
||||
tm.sharedMaterial.SetTexture (shader_LUTTexID, LUTTex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the destroy event.
|
||||
/// </summary>
|
||||
|
@ -503,6 +646,18 @@ namespace FaceMaskExample
|
|||
if (faceLandmarkDetector != null)
|
||||
faceLandmarkDetector.Dispose ();
|
||||
|
||||
foreach (var key in lowPassFilterDict.Keys) {
|
||||
lowPassFilterDict [key].Dispose ();
|
||||
}
|
||||
lowPassFilterDict.Clear ();
|
||||
foreach (var key in opticalFlowFilterDict.Keys) {
|
||||
opticalFlowFilterDict [key].Dispose ();
|
||||
}
|
||||
opticalFlowFilterDict.Clear ();
|
||||
|
||||
if (faceMaskColorCorrector != null)
|
||||
faceMaskColorCorrector.Dispose ();
|
||||
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
foreach (var coroutine in coroutines) {
|
||||
StopCoroutine (coroutine);
|
||||
|
@ -544,7 +699,16 @@ namespace FaceMaskExample
|
|||
/// </summary>
|
||||
public void OnChangeCameraButtonClick ()
|
||||
{
|
||||
webCamTextureToMatHelper.Initialize (null, webCamTextureToMatHelper.requestedWidth, webCamTextureToMatHelper.requestedHeight, !webCamTextureToMatHelper.requestedIsFrontFacing);
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
if (!webCamTextureToMatHelper.IsFrontFacing ()) {
|
||||
rearCameraRequestedFPS = webCamTextureToMatHelper.requestedFPS;
|
||||
webCamTextureToMatHelper.Initialize (!webCamTextureToMatHelper.IsFrontFacing (), 15, webCamTextureToMatHelper.rotate90Degree);
|
||||
} else {
|
||||
webCamTextureToMatHelper.Initialize (!webCamTextureToMatHelper.IsFrontFacing (), rearCameraRequestedFPS, webCamTextureToMatHelper.rotate90Degree);
|
||||
}
|
||||
#else
|
||||
webCamTextureToMatHelper.requestedIsFrontFacing = !webCamTextureToMatHelper.IsFrontFacing ();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -559,6 +723,36 @@ namespace FaceMaskExample
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the enable noise filter toggle value changed event.
|
||||
/// </summary>
|
||||
public void OnEnableNoiseFilterToggleValueChanged ()
|
||||
{
|
||||
if (enableNoiseFilterToggle.isOn) {
|
||||
enableNoiseFilter = true;
|
||||
foreach (var key in lowPassFilterDict.Keys) {
|
||||
lowPassFilterDict [key].Reset ();
|
||||
}
|
||||
foreach (var key in opticalFlowFilterDict.Keys) {
|
||||
opticalFlowFilterDict [key].Reset ();
|
||||
}
|
||||
} else {
|
||||
enableNoiseFilter = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the enable color correction toggle value changed event.
|
||||
/// </summary>
|
||||
public void OnEnableColorCorrectionToggleValueChanged ()
|
||||
{
|
||||
if (enableColorCorrectionToggle.isOn) {
|
||||
enableColorCorrection = true;
|
||||
} else {
|
||||
enableColorCorrection = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the filter non frontal faces toggle value changed event.
|
||||
/// </summary>
|
||||
|
@ -602,27 +796,48 @@ namespace FaceMaskExample
|
|||
{
|
||||
RemoveFaceMask ();
|
||||
|
||||
ExampleMaskData maskData = ExampleDataSet.GetData();
|
||||
if (faceMaskDatas.Count == 0)
|
||||
return;
|
||||
|
||||
faceMaskTexture = Resources.Load (maskData.fileName) as Texture2D;
|
||||
faceMaskMat = new Mat (faceMaskTexture.height, faceMaskTexture.width, CvType.CV_8UC4);
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
Debug.Log ("faceMaskMat ToString " + faceMaskMat.ToString ());
|
||||
FaceMaskData maskData = faceMaskDatas[faceMaskDataIndex];
|
||||
faceMaskDataIndex = (faceMaskDataIndex < faceMaskDatas.Count - 1) ? faceMaskDataIndex + 1 : 0;
|
||||
|
||||
if(maskData.landmarkPoints != null){
|
||||
faceRectInMask = maskData.faceRect;
|
||||
faceLandmarkPointsInMask = maskData.landmarkPoints;
|
||||
}else{
|
||||
faceRectInMask = DetectFace (faceMaskMat);
|
||||
faceLandmarkPointsInMask = DetectFaceLandmarkPoints (faceMaskMat, faceRectInMask);
|
||||
if (maskData == null) {
|
||||
Debug.LogError ("maskData == null");
|
||||
return;
|
||||
}
|
||||
|
||||
ExampleDataSet.Next();
|
||||
if (maskData.image == null) {
|
||||
Debug.LogError ("image == null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (maskData.landmarkPoints.Count != 68) {
|
||||
Debug.LogError ("landmarkPoints.Count != 68");
|
||||
return;
|
||||
}
|
||||
|
||||
faceMaskTexture = maskData.image;
|
||||
faceMaskMat = new Mat (faceMaskTexture.height, faceMaskTexture.width, CvType.CV_8UC4);
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
|
||||
if(maskData.isDynamicMode){
|
||||
faceRectInMask = DetectFace (faceMaskMat);
|
||||
faceLandmarkPointsInMask = DetectFaceLandmarkPoints (faceMaskMat, faceRectInMask);
|
||||
|
||||
maskData.faceRect = faceRectInMask;
|
||||
maskData.landmarkPoints = faceLandmarkPointsInMask;
|
||||
}else{
|
||||
faceRectInMask = maskData.faceRect;
|
||||
faceLandmarkPointsInMask = maskData.landmarkPoints;
|
||||
}
|
||||
|
||||
if (faceRectInMask.width == 0 && faceRectInMask.height == 0){
|
||||
RemoveFaceMask ();
|
||||
Debug.Log ("A face could not be detected from the input image.");
|
||||
Debug.LogError ("A face could not be detected from the input image.");
|
||||
}
|
||||
|
||||
enableColorCorrectionToggle.isOn = maskData.enableColorCorrection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -677,6 +892,7 @@ namespace FaceMaskExample
|
|||
faceMaskMat.Dispose ();
|
||||
faceMaskMat = null;
|
||||
}
|
||||
|
||||
rectangleTracker.Reset ();
|
||||
meshOverlay.Reset ();
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче