This commit is contained in:
EnoxSoftware 2018-05-30 03:24:46 +09:00
Родитель 77b1905165
Коммит c71b4a68f5
61 изменённых файлов: 8733 добавлений и 1633 удалений

Просмотреть файл

@ -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:

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 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

Двоичный файл не отображается.

Просмотреть файл

@ -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 ();
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу