update 1.0.0
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0a4656c4fb866c742b5b03bc5b557c0c
|
||||
folderAsset: yes
|
||||
timeCreated: 1481919542
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6c14b2aabbafe6e48aa33810b4d3cd2e
|
||||
folderAsset: yes
|
||||
timeCreated: 1481920337
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,66 @@
|
|||
Shader "Hide/FadeShader" {
|
||||
Properties
|
||||
{
|
||||
_MainTex ("Base (RGB), Alpha (A)", 2D) = "black" {}
|
||||
_Color ("Color", Color) = (1, 1, 1, 1)
|
||||
_Fade ("Fade", Range(0,1)) = 0
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
LOD 100
|
||||
|
||||
Tags
|
||||
{
|
||||
"Queue" = "Transparent"
|
||||
"IgnoreProjector" = "True"
|
||||
"RenderType" = "Transparent"
|
||||
"PreviewType"="Plane"
|
||||
}
|
||||
Lighting Off
|
||||
ZWrite Off
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata_t
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float2 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float4 vertex : SV_POSITION;
|
||||
half2 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
float4 _MainTex_ST;
|
||||
float4 _Color;
|
||||
float _Fade;
|
||||
|
||||
v2f vert (appdata_t v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
|
||||
o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag (v2f i) : COLOR
|
||||
{
|
||||
fixed4 base = tex2D(_MainTex, i.texcoord) * (_Color);
|
||||
|
||||
base.w = base.w * (1 - _Fade);
|
||||
return base;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 62d9b85face5173458f9fc79fcac7d20
|
||||
timeCreated: 1482000749
|
||||
licenseType: Free
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,175 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: mesh_material
|
||||
m_Shader: {fileID: 4800000, guid: 62d9b85face5173458f9fc79fcac7d20, type: 3}
|
||||
m_ShaderKeywords:
|
||||
m_LightmapFlags: 5
|
||||
m_CustomRenderQueue: -1
|
||||
m_SavedProperties:
|
||||
serializedVersion: 2
|
||||
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: _BumpMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailNormalMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _ParallaxMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _OcclusionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _EmissionMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailMask
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _DetailAlbedoMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _MetallicGlossMap
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _FadeTex
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
data:
|
||||
first:
|
||||
name: _RuleTex
|
||||
second:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
data:
|
||||
first:
|
||||
name: _Cutoff
|
||||
second: .5
|
||||
data:
|
||||
first:
|
||||
name: _SrcBlend
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _DstBlend
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Parallax
|
||||
second: .0199999996
|
||||
data:
|
||||
first:
|
||||
name: _ZWrite
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _Glossiness
|
||||
second: .5
|
||||
data:
|
||||
first:
|
||||
name: _BumpScale
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _OcclusionStrength
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _DetailNormalMapScale
|
||||
second: 1
|
||||
data:
|
||||
first:
|
||||
name: _UVSec
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _EmissionScaleUI
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Mode
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Metallic
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Trans
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Rule
|
||||
second: 0
|
||||
data:
|
||||
first:
|
||||
name: _Vague
|
||||
second: .25
|
||||
m_Colors:
|
||||
data:
|
||||
first:
|
||||
name: _EmissionColor
|
||||
second: {r: 0, g: 0, b: 0, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _Color
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _EmissionColorUI
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
||||
data:
|
||||
first:
|
||||
name: _FadeColor
|
||||
second: {r: 1, g: 1, b: 1, a: 1}
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1c7f2a21195b29a45a2605423d0ab4bb
|
||||
timeCreated: 1481980266
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: quad_material
|
||||
m_Shader: {fileID: 10750, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords:
|
||||
m_LightmapFlags: 5
|
||||
m_CustomRenderQueue: -1
|
||||
m_SavedProperties:
|
||||
serializedVersion: 2
|
||||
m_TexEnvs:
|
||||
data:
|
||||
first:
|
||||
name: _MainTex
|
||||
second:
|
||||
m_Texture: {fileID: 2800000, guid: 930bad9a49e0e4d4f953e03509cea6ad, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats: {}
|
||||
m_Colors: {}
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 15698121b1adac346859c37d6b52726c
|
||||
timeCreated: 1481920346
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9fccf8951e3e8ef4c8df84b8e9b3a2af
|
||||
folderAsset: yes
|
||||
timeCreated: 1481980728
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,98 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &102270
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
serializedVersion: 4
|
||||
m_Component:
|
||||
- 4: {fileID: 418932}
|
||||
- 33: {fileID: 3310974}
|
||||
- 64: {fileID: 6496772}
|
||||
- 23: {fileID: 2378456}
|
||||
- 114: {fileID: 11487226}
|
||||
m_Layer: 0
|
||||
m_Name: TrackedMesh
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &418932
|
||||
Transform:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 102270}
|
||||
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 &2378456
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 102270}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: 1c7f2a21195b29a45a2605423d0ab4bb, type: 2}
|
||||
m_SubsetIndices:
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_UseLightProbes: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_PreserveUVs: 1
|
||||
m_ImportantGI: 0
|
||||
m_AutoUVMaxDistance: .5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
--- !u!33 &3310974
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 102270}
|
||||
m_Mesh: {fileID: 4300002, guid: b87e7b82bde36d14b8be320b8772fea7, type: 3}
|
||||
--- !u!64 &6496772
|
||||
MeshCollider:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 102270}
|
||||
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 &11487226
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 100100000}
|
||||
m_GameObject: {fileID: 102270}
|
||||
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
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications: []
|
||||
m_RemovedComponents: []
|
||||
m_ParentPrefab: {fileID: 0}
|
||||
m_RootGameObject: {fileID: 102270}
|
||||
m_IsPrefabParent: 1
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6c2fbaa5846552f4a813a214779197dd
|
||||
timeCreated: 1481982798
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8a180bc8a88f50248bb53c8ccfd3c3a8
|
||||
timeCreated: 1483809590
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cac99c3cb04e63247a7417e6779861da
|
||||
folderAsset: yes
|
||||
timeCreated: 1481920777
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 419a4402b9c043942b41eb0d902bcf1a
|
||||
folderAsset: yes
|
||||
timeCreated: 1481920777
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,501 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OpenCVForUnity.RectangleTrack
|
||||
{
|
||||
|
||||
public class RectangleTracker : IDisposable
|
||||
{
|
||||
public List<TrackedObject> TrackedObjects
|
||||
{
|
||||
get { return trackedObjects; }
|
||||
}
|
||||
private List<TrackedObject> trackedObjects;
|
||||
|
||||
|
||||
public TrackerParameters TrackerParameters
|
||||
{
|
||||
get { return trackerParameters; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
trackerParameters = value;
|
||||
}
|
||||
}
|
||||
private TrackerParameters trackerParameters;
|
||||
|
||||
|
||||
public List<float> weightsPositionsSmoothing
|
||||
{
|
||||
get { return _weightsPositionsSmoothing; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
_weightsPositionsSmoothing = value;
|
||||
}
|
||||
}
|
||||
private List<float> _weightsPositionsSmoothing = new List<float>();
|
||||
|
||||
public List<float> weightsSizesSmoothing
|
||||
{
|
||||
get { return _weightsSizesSmoothing; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
_weightsSizesSmoothing = value;
|
||||
}
|
||||
}
|
||||
private List<float> _weightsSizesSmoothing = new List<float>();
|
||||
|
||||
public RectangleTracker(TrackerParameters trackerParamerers = null)
|
||||
{
|
||||
trackedObjects = new List<TrackedObject>();
|
||||
|
||||
if (trackerParamerers != null)
|
||||
{
|
||||
this.trackerParameters = trackerParamerers;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.trackerParameters = new TrackerParameters();
|
||||
}
|
||||
|
||||
_weightsPositionsSmoothing.Add(1);
|
||||
_weightsSizesSmoothing.Add(0.5f);
|
||||
_weightsSizesSmoothing.Add(0.3f);
|
||||
_weightsSizesSmoothing.Add(0.2f);
|
||||
}
|
||||
|
||||
public enum TrackedRectState : int
|
||||
{
|
||||
NEW_RECTANGLE = -1,
|
||||
INTERSECTED_RECTANGLE = -2
|
||||
}
|
||||
|
||||
|
||||
public void GetObjects(List<Rect> result, bool smoothing = true)
|
||||
{
|
||||
result.Clear();
|
||||
|
||||
int count = trackedObjects.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Rect r;
|
||||
if (smoothing)
|
||||
{
|
||||
r = getSmoothingRect(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = trackedObjects[i].position;
|
||||
}
|
||||
|
||||
if (trackedObjects[i].state > TrackedState.NEW_DISPLAYED && trackedObjects[i].state < TrackedState.NEW_HIDED)
|
||||
result.Add(r);
|
||||
|
||||
//LOGD("DetectionBasedTracker::process: found a object with SIZE %d x %d, rect={%d, %d, %d x %d}", r.width, r.height, r.x, r.y, r.width, r.height);
|
||||
//Debug.Log("GetObjects" + r.width + " " + r.height + " " + r.x + " " + r.y + " " + r.width + " " + r.height + " " + trackedObjects[i].state + " " + trackedObjects[i].numDetectedFrames + " " + trackedObjects[i].numFramesNotDetected);
|
||||
}
|
||||
}
|
||||
|
||||
public void GetObjects(List<TrackedRect> result, bool smoothing = true)
|
||||
{
|
||||
result.Clear();
|
||||
|
||||
int count = trackedObjects.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Rect r;
|
||||
if (smoothing)
|
||||
{
|
||||
r = getSmoothingRect(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = trackedObjects[i].position;
|
||||
}
|
||||
|
||||
result.Add(new TrackedRect(trackedObjects[i].id, r, trackedObjects[i].state, trackedObjects[i].numDetectedFrames, trackedObjects[i].numFramesNotDetected));
|
||||
|
||||
//LOGD("DetectionBasedTracker::process: found a object with SIZE %d x %d, rect={%d, %d, %d x %d}", r.width, r.height, r.x, r.y, r.width, r.height);
|
||||
//Debug.Log("GetObjects" + r.width + " " + r.height + " " + r.x + " " + r.y + " " + r.width + " " + r.height + " " + trackedObjects[i].state + " " + trackedObjects[i].numDetectedFrames + " " + trackedObjects[i].numFramesNotDetected);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTrackedObjects(List<Rect> detectedObjects)
|
||||
{
|
||||
if (detectedObjects == null)
|
||||
throw new ArgumentNullException("detectedObjects");
|
||||
|
||||
Rect[] correctionRects = CreateCorrectionBySpeedOfRects();
|
||||
|
||||
int N1 = (int)trackedObjects.Count;
|
||||
int N2 = (int)detectedObjects.Count;
|
||||
|
||||
for (int i = 0; i < N1; i++)
|
||||
{
|
||||
trackedObjects[i].numDetectedFrames++;
|
||||
}
|
||||
|
||||
int[] correspondence = Enumerable.Repeat<int>((int)TrackedRectState.NEW_RECTANGLE, N2).ToArray();
|
||||
|
||||
|
||||
for (int i = 0; i < N1; i++)
|
||||
{
|
||||
TrackedObject curObject = trackedObjects[i];
|
||||
|
||||
int bestIndex = -1;
|
||||
int bestArea = -1;
|
||||
|
||||
//int numpositions = (int)curObject.lastPositions.Count;
|
||||
|
||||
//if (numpositions > 0) UnityEngine.Debug.LogError("numpositions > 0 is false");
|
||||
|
||||
//Rect prevRect = curObject.lastPositions[numpositions - 1];
|
||||
Rect prevRect = correctionRects[i];
|
||||
|
||||
for (int j = 0; j < N2; j++)
|
||||
{
|
||||
if (correspondence[j] >= 0)
|
||||
{
|
||||
//Debug.Log("DetectionBasedTracker::updateTrackedObjects: j=" + j + " is rejected, because it has correspondence=" + correspondence[j]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (correspondence[j] != (int)TrackedRectState.NEW_RECTANGLE)
|
||||
{
|
||||
//Debug.Log("DetectionBasedTracker::updateTrackedObjects: j=" + j + " is rejected, because it is intersected with another rectangle");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsCollideByRectangle(prevRect, detectedObjects[j], trackerParameters.coeffRectangleOverlap))
|
||||
{
|
||||
Rect r = Intersect(prevRect, detectedObjects[j]);
|
||||
if ((r.width > 0) && (r.height > 0))
|
||||
{
|
||||
//Debug.Log("DetectionBasedTracker::updateTrackedObjects: There is intersection between prevRect and detectedRect r={" + r.x + ", " + r.y + ", " + r.width + ", " + r.height + "]");
|
||||
|
||||
correspondence[j] = (int)TrackedRectState.INTERSECTED_RECTANGLE;
|
||||
|
||||
if (r.area() > bestArea)
|
||||
{
|
||||
//Debug.Log("DetectionBasedTracker::updateTrackedObjects: The area of intersection is " + r.area() + " it is better than bestArea= " + bestArea);
|
||||
|
||||
bestIndex = j;
|
||||
bestArea = (int)r.area();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestIndex >= 0)
|
||||
{
|
||||
//Debug.Log("DetectionBasedTracker::updateTrackedObjects: The best correspondence for i=" + i + " is j=" + bestIndex);
|
||||
|
||||
correspondence[bestIndex] = i;
|
||||
|
||||
Rect bestRect = detectedObjects[bestIndex];
|
||||
|
||||
for (int j = 0; j < N2; j++)
|
||||
{
|
||||
if (correspondence[j] >= 0)
|
||||
continue;
|
||||
|
||||
if (IsCollideByRectangle(detectedObjects[j], bestRect, trackerParameters.coeffRectangleOverlap))
|
||||
{
|
||||
Rect r = Intersect(detectedObjects[j], bestRect);
|
||||
|
||||
if ((r.width > 0) && (r.height > 0))
|
||||
{
|
||||
//Debug.Log("DetectionBasedTracker::updateTrackedObjects: Found intersection between rectangles j= " + j + " and bestIndex= " + bestIndex + " rectangle j= " + j + " is marked as intersected");
|
||||
|
||||
correspondence[j] = (int)TrackedRectState.INTERSECTED_RECTANGLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Debug.Log("DetectionBasedTracker::updateTrackedObjects: There is no correspondence for i= " + i);
|
||||
curObject.numFramesNotDetected++;
|
||||
}
|
||||
}
|
||||
|
||||
//Debug.Log("DetectionBasedTracker::updateTrackedObjects: start second cycle");
|
||||
for (int j = 0; j < N2; j++)
|
||||
{
|
||||
int i = correspondence[j];
|
||||
if (i >= 0)
|
||||
{//add position
|
||||
//Debug.Log("DetectionBasedTracker::updateTrackedObjects: add position");
|
||||
|
||||
trackedObjects[i].lastPositions.Add(detectedObjects[j]);
|
||||
while ((int)trackedObjects[i].lastPositions.Count > (int)trackerParameters.numLastPositionsToTrack)
|
||||
{
|
||||
trackedObjects[i].lastPositions.Remove(trackedObjects[i].lastPositions[0]);
|
||||
}
|
||||
trackedObjects[i].numFramesNotDetected = 0;
|
||||
if (trackedObjects[i].state != TrackedState.DELETED) trackedObjects[i].state = TrackedState.DISPLAYED;
|
||||
}
|
||||
else if (i == (int)TrackedRectState.NEW_RECTANGLE)
|
||||
{ //new object
|
||||
//Debug.Log("DetectionBasedTracker::updateTrackedObjects: new object");
|
||||
|
||||
trackedObjects.Add(new TrackedObject(detectedObjects[j]));
|
||||
}
|
||||
else
|
||||
{
|
||||
//Debug.Log("DetectionBasedTracker::updateTrackedObjects: was auxiliary intersection");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int t = 0;
|
||||
TrackedObject it;
|
||||
while (t < trackedObjects.Count)
|
||||
{
|
||||
it = trackedObjects[t];
|
||||
|
||||
if (it.state == TrackedState.DELETED)
|
||||
{
|
||||
trackedObjects.Remove(it);
|
||||
}
|
||||
else if ((it.numFramesNotDetected > trackerParameters.maxTrackLifetime)//ALL
|
||||
||
|
||||
((it.numDetectedFrames <= trackerParameters.numStepsToWaitBeforeFirstShow)
|
||||
&&
|
||||
(it.numFramesNotDetected > trackerParameters.numStepsToTrackWithoutDetectingIfObjectHasNotBeenShown))
|
||||
)
|
||||
{
|
||||
it.state = TrackedState.DELETED;
|
||||
t++;
|
||||
}
|
||||
else if (it.state >= TrackedState.DISPLAYED)//DISPLAYED, NEW_DISPLAYED, HIDED
|
||||
{
|
||||
|
||||
if (it.numDetectedFrames < trackerParameters.numStepsToWaitBeforeFirstShow)
|
||||
{
|
||||
it.state = TrackedState.PENDING;
|
||||
}
|
||||
else if (it.numDetectedFrames == trackerParameters.numStepsToWaitBeforeFirstShow)
|
||||
{
|
||||
//i, trackedObjects[i].numDetectedFrames, innerParameters.numStepsToWaitBeforeFirstShow);
|
||||
it.state = TrackedState.NEW_DISPLAYED;
|
||||
}
|
||||
else if (it.numFramesNotDetected == trackerParameters.numStepsToShowWithoutDetecting)
|
||||
{
|
||||
it.state = TrackedState.NEW_HIDED;
|
||||
}
|
||||
else if (it.numFramesNotDetected > trackerParameters.numStepsToShowWithoutDetecting)
|
||||
{
|
||||
it.state = TrackedState.HIDED;
|
||||
}
|
||||
|
||||
t++;
|
||||
}
|
||||
else//NEW
|
||||
{
|
||||
t++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Rect[] CreateCorrectionBySpeedOfRects()
|
||||
{
|
||||
//Debug.Log("DetectionBasedTracker::process: get _rectsWhereRegions from previous positions");
|
||||
Rect[] rectsWhereRegions = new Rect[trackedObjects.Count];
|
||||
|
||||
int count = trackedObjects.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int n = trackedObjects[i].lastPositions.Count;
|
||||
//if (n > 0) UnityEngine.Debug.LogError("n > 0 is false");
|
||||
|
||||
Rect r = trackedObjects[i].lastPositions[n - 1].clone();
|
||||
/*
|
||||
if (r.area() == 0)
|
||||
{
|
||||
Debug.Log("DetectionBasedTracker::process: ERROR: ATTENTION: strange algorithm's behavior: trackedObjects[i].rect() is empty");
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
|
||||
//correction by speed of rectangle
|
||||
if (n > 1)
|
||||
{
|
||||
Point center = centerRect(r);
|
||||
Point center_prev = centerRect(trackedObjects[i].lastPositions[n - 2]);
|
||||
Point shift = new Point((center.x - center_prev.x) * trackerParameters.coeffObjectSpeedUsingInPrediction,
|
||||
(center.y - center_prev.y) * trackerParameters.coeffObjectSpeedUsingInPrediction);
|
||||
|
||||
r.x += (int)Math.Round(shift.x);
|
||||
r.y += (int)Math.Round(shift.y);
|
||||
}
|
||||
|
||||
rectsWhereRegions[i] = r;
|
||||
}
|
||||
|
||||
return rectsWhereRegions;
|
||||
}
|
||||
|
||||
private Point centerRect(Rect r)
|
||||
{
|
||||
return new Point(r.x + (r.width / 2), r.y + (r.height / 2));
|
||||
}
|
||||
|
||||
private Rect getSmoothingRect(int i)
|
||||
{
|
||||
//Debug.Log("trackedObjects[i].numFramesNotDetected: " + trackedObjects[i].numFramesNotDetected);
|
||||
|
||||
List<float> weightsSizesSmoothing = _weightsSizesSmoothing;
|
||||
List<float> weightsPositionsSmoothing = _weightsPositionsSmoothing;
|
||||
|
||||
List<Rect> lastPositions = trackedObjects[i].lastPositions;
|
||||
|
||||
int N = lastPositions.Count;
|
||||
if (N <= 0)
|
||||
{
|
||||
Debug.Log("DetectionBasedTracker::calcTrackedObjectPositionToShow: ERROR: no positions for i=" + i);
|
||||
return new Rect();
|
||||
}
|
||||
|
||||
int Nsize = Math.Min(N, (int)weightsSizesSmoothing.Count);
|
||||
int Ncenter = Math.Min(N, (int)weightsPositionsSmoothing.Count);
|
||||
|
||||
Point center = new Point();
|
||||
double w = 0, h = 0;
|
||||
if (Nsize > 0)
|
||||
{
|
||||
double sum = 0;
|
||||
for (int j = 0; j < Nsize; j++)
|
||||
{
|
||||
int k = N - j - 1;
|
||||
w += lastPositions[k].width * weightsSizesSmoothing[j];
|
||||
h += lastPositions[k].height * weightsSizesSmoothing[j];
|
||||
sum += weightsSizesSmoothing[j];
|
||||
}
|
||||
w /= sum;
|
||||
h /= sum;
|
||||
}
|
||||
else
|
||||
{
|
||||
w = lastPositions[N - 1].width;
|
||||
h = lastPositions[N - 1].height;
|
||||
}
|
||||
|
||||
if (Ncenter > 0)
|
||||
{
|
||||
double sum = 0;
|
||||
for (int j = 0; j < Ncenter; j++)
|
||||
{
|
||||
int k = N - j - 1;
|
||||
Point tl = lastPositions[k].tl();
|
||||
Point br = lastPositions[k].br();
|
||||
Point c1;
|
||||
|
||||
c1 = new Point(tl.x * 0.5f, tl.y * 0.5f);
|
||||
Point c2;
|
||||
|
||||
c2 = new Point(br.x * 0.5f, br.y * 0.5f);
|
||||
c1 = new Point(c1.x + c2.x, c1.y + c2.y);
|
||||
|
||||
center = new Point(center.x + (c1.x * weightsPositionsSmoothing[j]), center.y + (c1.y * weightsPositionsSmoothing[j]));
|
||||
sum += weightsPositionsSmoothing[j];
|
||||
}
|
||||
center = new Point(center.x * (1 / sum), center.y * (1 / sum));
|
||||
}
|
||||
else
|
||||
{
|
||||
int k = N - 1;
|
||||
Point tl = lastPositions[k].tl();
|
||||
Point br = lastPositions[k].br();
|
||||
Point c1;
|
||||
|
||||
c1 = new Point(tl.x * 0.5f, tl.y * 0.5f);
|
||||
Point c2;
|
||||
|
||||
c2 = new Point(br.x * 0.5f, br.y * 0.5f);
|
||||
|
||||
center = new Point(c1.x + c2.x, c1.y + c2.y);
|
||||
}
|
||||
Point tl2 = new Point(center.x - (w * 0.5f), center.y - (h * 0.5f));
|
||||
Rect res = new Rect((int)Math.Round(tl2.x), (int)Math.Round(tl2.y), (int)Math.Round(w), (int)Math.Round(h));
|
||||
|
||||
//Debug.Log("DetectionBasedTracker::calcTrackedObjectPositionToShow: Result for i=" + i + ": {" + res.x + ", " + res.y + ", " + res.width + ", " + res.height + "}");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
trackedObjects.Clear();
|
||||
}
|
||||
|
||||
private Rect Intersect(Rect a, Rect b)
|
||||
{
|
||||
int x1 = Math.Max(a.x, b.x);
|
||||
int x2 = Math.Min(a.x + a.width, b.x + b.width);
|
||||
int y1 = Math.Max(a.y, b.y);
|
||||
int y2 = Math.Min(a.y + a.height, b.y + b.height);
|
||||
|
||||
if (x2 >= x1 && y2 >= y1)
|
||||
return new Rect(x1, y1, x2 - x1, y2 - y1);
|
||||
else
|
||||
return new Rect();
|
||||
}
|
||||
/*
|
||||
private bool IsCollideByCircle(Rect a, Rect b, float coeffRectangleOverlap)
|
||||
{
|
||||
int r1 = (int)(a.width / 2.0f);
|
||||
int r2 = (int)(b.width / 2.0f);
|
||||
int px1 = a.x + r1;
|
||||
int py1 = a.y + r1;
|
||||
int px2 = b.x + r2;
|
||||
int py2 = b.y + r2;
|
||||
|
||||
if ((px2 - px1) * (px2 - px1) + (py2 - py1) * (py2 - py1) <= (r1 + r2) * (r1 + r2) * coeffRectangleOverlap)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
private bool IsCollideByRectangle(Rect a, Rect b, float coeffRectangleOverlap)
|
||||
{
|
||||
int mw = (int)(a.width * coeffRectangleOverlap);
|
||||
int mh = (int)(a.height * coeffRectangleOverlap);
|
||||
int mx1 = (int)(a.x + (a.width - mw) / 2.0f);
|
||||
int my1 = (int)(a.x + (a.height - mh) / 2.0f);
|
||||
int mx2 = (int)(mx1 + mw);
|
||||
int my2 = (int)(my1 + mh);
|
||||
|
||||
int ew = (int)(b.width * coeffRectangleOverlap);
|
||||
int eh = (int)(b.height * coeffRectangleOverlap);
|
||||
int ex1 = (int)(b.x + (b.width - ew) / 2.0f);
|
||||
int ey1 = (int)(b.x + (b.height - eh) / 2.0f);
|
||||
int ex2 = (int)(ex1 + ew);
|
||||
int ey2 = (int)(ey1 + eh);
|
||||
|
||||
if (mx1 <= ex2 && ex1 <= mx2 && my1 <= ey2 && ey1 <= my2)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 07e4b92dd6ea99d46b184b3c16346b74
|
||||
timeCreated: 1481920777
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,53 @@
|
|||
using PositionsVector = System.Collections.Generic.List<OpenCVForUnity.Rect>;
|
||||
|
||||
namespace OpenCVForUnity.RectangleTrack
|
||||
{
|
||||
|
||||
public enum TrackedState : int
|
||||
{
|
||||
|
||||
NEW = 0,
|
||||
PENDING = 1,
|
||||
NEW_DISPLAYED = 2,
|
||||
DISPLAYED =3,
|
||||
NEW_HIDED = 4,
|
||||
HIDED = 5,
|
||||
DELETED = 6
|
||||
}
|
||||
|
||||
public class TrackedObject
|
||||
{
|
||||
public PositionsVector lastPositions;
|
||||
public int numDetectedFrames;
|
||||
public int numFramesNotDetected;
|
||||
public int id;
|
||||
public TrackedState state;
|
||||
public OpenCVForUnity.Rect position
|
||||
{
|
||||
get { return lastPositions[lastPositions.Count - 1].clone(); }
|
||||
}
|
||||
|
||||
|
||||
static private int _id = 0;
|
||||
|
||||
public TrackedObject(OpenCVForUnity.Rect rect)
|
||||
{
|
||||
lastPositions = new PositionsVector();
|
||||
|
||||
numDetectedFrames = 1;
|
||||
numFramesNotDetected = 0;
|
||||
state = TrackedState.NEW;
|
||||
|
||||
lastPositions.Add(rect.clone());
|
||||
|
||||
_id = getNextId();
|
||||
id = _id;
|
||||
}
|
||||
|
||||
static int getNextId()
|
||||
{
|
||||
_id++;
|
||||
return _id;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: be925ca4987066b44999e368e2998d73
|
||||
timeCreated: 1481920777
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,19 @@
|
|||
namespace OpenCVForUnity.RectangleTrack
|
||||
{
|
||||
public class TrackedRect : Rect
|
||||
{
|
||||
public int numDetectedFrames;
|
||||
public int numFramesNotDetected;
|
||||
public int id;
|
||||
public TrackedState state;
|
||||
|
||||
public TrackedRect(int id, Rect rect, TrackedState state, int numDetectedFrames, int numFramesNotDetected)
|
||||
: base(rect.x, rect.y, rect.width, rect.height)
|
||||
{
|
||||
this.numDetectedFrames = numDetectedFrames;
|
||||
this.numFramesNotDetected = numFramesNotDetected;
|
||||
this.id = id;
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ea62936eb7bff934396d4f5f77237fd2
|
||||
timeCreated: 1481920777
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,33 @@
|
|||
namespace OpenCVForUnity.RectangleTrack
|
||||
{
|
||||
|
||||
public class TrackerParameters
|
||||
{
|
||||
public int numLastPositionsToTrack = 4;
|
||||
public int numStepsToWaitBeforeFirstShow = 6;
|
||||
public int numStepsToTrackWithoutDetectingIfObjectHasNotBeenShown = 3;
|
||||
public int numStepsToShowWithoutDetecting = 3;
|
||||
|
||||
public int maxTrackLifetime = 5;
|
||||
|
||||
public float coeffObjectSpeedUsingInPrediction = 0.8f;
|
||||
public float coeffRectangleOverlap = 0.7f;
|
||||
|
||||
public TrackerParameters() {
|
||||
}
|
||||
|
||||
public TrackerParameters Clone()
|
||||
{
|
||||
TrackerParameters trackerParameters = new TrackerParameters();
|
||||
trackerParameters.numLastPositionsToTrack = numLastPositionsToTrack;
|
||||
trackerParameters.numStepsToWaitBeforeFirstShow = numStepsToWaitBeforeFirstShow;
|
||||
trackerParameters.numStepsToTrackWithoutDetectingIfObjectHasNotBeenShown = numStepsToTrackWithoutDetectingIfObjectHasNotBeenShown;
|
||||
trackerParameters.numStepsToShowWithoutDetecting = numStepsToShowWithoutDetecting;
|
||||
trackerParameters.maxTrackLifetime = maxTrackLifetime;
|
||||
trackerParameters.coeffObjectSpeedUsingInPrediction = coeffObjectSpeedUsingInPrediction;
|
||||
trackerParameters.coeffRectangleOverlap = coeffRectangleOverlap;
|
||||
|
||||
return trackerParameters;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d000e76268a8c4b4db04c3839c374ac1
|
||||
timeCreated: 1481920777
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d1e51e8d94b2e7949aefa30124982c6e
|
||||
folderAsset: yes
|
||||
timeCreated: 1481920749
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,313 @@
|
|||
g DlibFaceLandmark68Mesh
|
||||
v 81 4 0
|
||||
v 79 -16 0
|
||||
v 75 -37 0
|
||||
v 70 -57 0
|
||||
v 61 -76 0
|
||||
v 49 -93 0
|
||||
v 34 -105 0
|
||||
v 18 -114 0
|
||||
v -1 -115 0
|
||||
v -20 -111 0
|
||||
v -36 -99 0
|
||||
v -49 -82 0
|
||||
v -58 -62 0
|
||||
v -63 -40 0
|
||||
v -66 -19 0
|
||||
v -66 3 0
|
||||
v -63 25 0
|
||||
v 74 15 0
|
||||
v 68 27 0
|
||||
v 54 29 0
|
||||
v 41 27 0
|
||||
v 26 22 0
|
||||
v 6 25 0
|
||||
v -7 34 0
|
||||
v -23 41 0
|
||||
v -39 42 0
|
||||
v -50 32 0
|
||||
v 15 11 0
|
||||
v 14 -4 0
|
||||
v 12 -18 0
|
||||
v 11 -33 0
|
||||
v 23 -43 0
|
||||
v 16 -46 0
|
||||
v 7 -48 0
|
||||
v -1 -44 0
|
||||
v -8 -39 0
|
||||
v 58 7 0
|
||||
v 51 13 0
|
||||
v 40 14 0
|
||||
v 32 7 0
|
||||
v 40 3 0
|
||||
v 51 3 0
|
||||
v -7 12 0
|
||||
v -15 21 0
|
||||
v -26 24 0
|
||||
v -35 19 0
|
||||
v -28 13 0
|
||||
v -17 11 0
|
||||
v 30 -74 0
|
||||
v 21 -69 0
|
||||
v 13 -66 0
|
||||
v 5 -66 0
|
||||
v -1 -63 0
|
||||
v -12 -63 0
|
||||
v -22 -66 0
|
||||
v -15 -74 0
|
||||
v -5 -78 0
|
||||
v 2 -80 0
|
||||
v 10 -80 0
|
||||
v 20 -79 0
|
||||
v 25 -74 0
|
||||
v 12 -71 0
|
||||
v 5 -71 0
|
||||
v -2 -69 0
|
||||
v -18 -67 0
|
||||
v -3 -70 0
|
||||
v 4 -72 0
|
||||
v 11 -73 0
|
||||
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -0.9999999
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -0.9999999
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -0.9999999
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -0.9999999
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -0.9999999
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -0.9999999
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -0.9999999
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -1
|
||||
vn 0 0 -0.9999999
|
||||
vn 0 0 -0.9999999
|
||||
vn 0 0 -1
|
||||
vn 0 0 -0.9999999
|
||||
|
||||
vt 0.21875 0.5114943
|
||||
vt 0.2256944 0.454023
|
||||
vt 0.2395833 0.3936782
|
||||
vt 0.2569444 0.3362069
|
||||
vt 0.2881944 0.2816092
|
||||
vt 0.3298611 0.2327586
|
||||
vt 0.3819444 0.1982759
|
||||
vt 0.4375 0.1724138
|
||||
vt 0.5034722 0.1695402
|
||||
vt 0.5694444 0.1810345
|
||||
vt 0.625 0.2155172
|
||||
vt 0.6701389 0.2643678
|
||||
vt 0.7013889 0.3218391
|
||||
vt 0.71875 0.3850575
|
||||
vt 0.7291667 0.4454023
|
||||
vt 0.7291667 0.5086207
|
||||
vt 0.71875 0.5718391
|
||||
vt 0.2430556 0.5431035
|
||||
vt 0.2638889 0.5775862
|
||||
vt 0.3125 0.5833333
|
||||
vt 0.3576389 0.5775862
|
||||
vt 0.4097222 0.5632184
|
||||
vt 0.4791667 0.5718391
|
||||
vt 0.5243056 0.5977011
|
||||
vt 0.5798611 0.6178161
|
||||
vt 0.6354167 0.6206896
|
||||
vt 0.6736111 0.5919541
|
||||
vt 0.4479167 0.5316092
|
||||
vt 0.4513889 0.4885058
|
||||
vt 0.4583333 0.4482759
|
||||
vt 0.4618056 0.4051724
|
||||
vt 0.4201389 0.3764368
|
||||
vt 0.4444444 0.3678161
|
||||
vt 0.4756944 0.362069
|
||||
vt 0.5034722 0.3735632
|
||||
vt 0.5277778 0.387931
|
||||
vt 0.2986111 0.520115
|
||||
vt 0.3229167 0.5373563
|
||||
vt 0.3611111 0.5402299
|
||||
vt 0.3888889 0.520115
|
||||
vt 0.3611111 0.5086207
|
||||
vt 0.3229167 0.5086207
|
||||
vt 0.5243056 0.5344828
|
||||
vt 0.5520833 0.5603448
|
||||
vt 0.5902778 0.5689655
|
||||
vt 0.6215278 0.5545977
|
||||
vt 0.5972222 0.5373563
|
||||
vt 0.5590278 0.5316092
|
||||
vt 0.3958333 0.2873563
|
||||
vt 0.4270833 0.3017241
|
||||
vt 0.4548611 0.3103448
|
||||
vt 0.4826389 0.3103448
|
||||
vt 0.5034722 0.3189655
|
||||
vt 0.5416667 0.3189655
|
||||
vt 0.5763889 0.3103448
|
||||
vt 0.5520833 0.2873563
|
||||
vt 0.5173611 0.2758621
|
||||
vt 0.4930556 0.2701149
|
||||
vt 0.4652778 0.2701149
|
||||
vt 0.4305556 0.2729885
|
||||
vt 0.4131944 0.2873563
|
||||
vt 0.4583333 0.295977
|
||||
vt 0.4826389 0.295977
|
||||
vt 0.5069444 0.3017241
|
||||
vt 0.5625 0.3074713
|
||||
vt 0.5104167 0.2988506
|
||||
vt 0.4861111 0.2931035
|
||||
vt 0.4618056 0.2902299
|
||||
|
||||
usemtl Hide/TransShader
|
||||
usemap Hide/TransShader
|
||||
f 1/1/1 2/2/2 37/37/37
|
||||
f 2/2/2 42/42/42 37/37/37
|
||||
f 2/2/2 32/32/32 42/42/42
|
||||
f 42/42/42 32/32/32 41/41/41
|
||||
f 41/41/41 32/32/32 30/30/30
|
||||
f 41/41/41 30/30/30 40/40/40
|
||||
f 40/40/40 30/30/30 29/29/29
|
||||
f 40/40/40 29/29/29 28/28/28
|
||||
f 40/40/40 28/28/28 22/22/22
|
||||
f 39/39/39 40/40/40 22/22/22
|
||||
f 21/21/21 39/39/39 22/22/22
|
||||
f 38/38/38 39/39/39 21/21/21
|
||||
f 38/38/38 21/21/21 20/20/20
|
||||
f 19/19/19 38/38/38 20/20/20
|
||||
f 19/19/19 37/37/37 38/38/38
|
||||
f 18/18/18 37/37/37 19/19/19
|
||||
f 1/1/1 37/37/37 18/18/18
|
||||
f 37/37/37 42/42/42 38/38/38
|
||||
f 38/38/38 42/42/42 41/41/41
|
||||
f 38/38/38 41/41/41 39/39/39
|
||||
f 39/39/39 41/41/41 40/40/40
|
||||
f 46/46/46 16/16/16 17/17/17
|
||||
f 47/47/47 16/16/16 46/46/46
|
||||
f 47/47/47 36/36/36 16/16/16
|
||||
f 48/48/48 36/36/36 47/47/47
|
||||
f 30/30/30 36/36/36 48/48/48
|
||||
f 43/43/43 30/30/30 48/48/48
|
||||
f 29/29/29 30/30/30 43/43/43
|
||||
f 28/28/28 29/29/29 43/43/43
|
||||
f 28/28/28 43/43/43 23/23/23
|
||||
f 23/23/23 43/43/43 44/44/44
|
||||
f 23/23/23 44/44/44 24/24/24
|
||||
f 24/24/24 44/44/44 45/45/45
|
||||
f 24/24/24 45/45/45 25/25/25
|
||||
f 25/25/25 45/45/45 26/26/26
|
||||
f 45/45/45 46/46/46 26/26/26
|
||||
f 26/26/26 46/46/46 27/27/27
|
||||
f 46/46/46 17/17/17 27/27/27
|
||||
f 45/45/45 47/47/47 46/46/46
|
||||
f 48/48/48 47/47/47 45/45/45
|
||||
f 44/44/44 48/48/48 45/45/45
|
||||
f 43/43/43 48/48/48 44/44/44
|
||||
f 21/21/21 22/22/22 24/24/24
|
||||
f 22/22/22 23/23/23 24/24/24
|
||||
f 22/22/22 28/28/28 23/23/23
|
||||
f 30/30/30 32/32/32 31/31/31
|
||||
f 30/30/30 31/31/31 36/36/36
|
||||
f 31/31/31 32/32/32 33/33/33
|
||||
f 31/31/31 33/33/33 34/34/34
|
||||
f 31/31/31 34/34/34 35/35/35
|
||||
f 31/31/31 35/35/35 36/36/36
|
||||
f 2/2/2 3/3/3 32/32/32
|
||||
f 3/3/3 4/4/4 32/32/32
|
||||
f 36/36/36 15/15/15 16/16/16
|
||||
f 36/36/36 14/14/14 15/15/15
|
||||
f 34/34/34 51/51/51 52/52/52
|
||||
f 33/33/33 51/51/51 34/34/34
|
||||
f 32/32/32 51/51/51 33/33/33
|
||||
f 32/32/32 50/50/50 51/51/51
|
||||
f 32/32/32 49/49/49 50/50/50
|
||||
f 4/4/4 49/49/49 32/32/32
|
||||
f 4/4/4 5/5/5 49/49/49
|
||||
f 5/5/5 6/6/6 49/49/49
|
||||
f 49/49/49 6/6/6 60/60/60
|
||||
f 6/6/6 7/7/7 60/60/60
|
||||
f 60/60/60 7/7/7 59/59/59
|
||||
f 59/59/59 7/7/7 8/8/8
|
||||
f 59/59/59 8/8/8 58/58/58
|
||||
f 58/58/58 8/8/8 9/9/9
|
||||
f 58/58/58 9/9/9 10/10/10
|
||||
f 58/58/58 10/10/10 57/57/57
|
||||
f 57/57/57 10/10/10 11/11/11
|
||||
f 57/57/57 11/11/11 56/56/56
|
||||
f 56/56/56 11/11/11 12/12/12
|
||||
f 56/56/56 12/12/12 55/55/55
|
||||
f 55/55/55 12/12/12 13/13/13
|
||||
f 55/55/55 13/13/13 14/14/14
|
||||
f 36/36/36 55/55/55 14/14/14
|
||||
f 36/36/36 54/54/54 55/55/55
|
||||
f 36/36/36 53/53/53 54/54/54
|
||||
f 35/35/35 53/53/53 36/36/36
|
||||
f 34/34/34 53/53/53 35/35/35
|
||||
f 34/34/34 52/52/52 53/53/53
|
||||
f 49/49/49 61/61/61 50/50/50
|
||||
f 49/49/49 60/60/60 61/61/61
|
||||
f 50/50/50 62/62/62 51/51/51
|
||||
f 50/50/50 61/61/61 62/62/62
|
||||
f 61/61/61 60/60/60 68/68/68
|
||||
f 60/60/60 59/59/59 68/68/68
|
||||
f 51/51/51 62/62/62 52/52/52
|
||||
f 52/52/52 62/62/62 63/63/63
|
||||
f 68/68/68 59/59/59 67/67/67
|
||||
f 67/67/67 59/59/59 58/58/58
|
||||
f 52/52/52 64/64/64 53/53/53
|
||||
f 52/52/52 63/63/63 64/64/64
|
||||
f 67/67/67 57/57/57 66/66/66
|
||||
f 67/67/67 58/58/58 57/57/57
|
||||
f 53/53/53 64/64/64 54/54/54
|
||||
f 54/54/54 64/64/64 65/65/65
|
||||
f 66/66/66 56/56/56 65/65/65
|
||||
f 66/66/66 57/57/57 56/56/56
|
||||
f 54/54/54 65/65/65 55/55/55
|
||||
f 65/65/65 56/56/56 55/55/55
|
|
@ -0,0 +1,77 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b87e7b82bde36d14b8be320b8772fea7
|
||||
timeCreated: 1483122680
|
||||
licenseType: Free
|
||||
ModelImporter:
|
||||
serializedVersion: 18
|
||||
fileIDToRecycleName:
|
||||
100000: //RootNode
|
||||
100002: FaceMesh
|
||||
100004: DlibFaceLandmark68Mesh
|
||||
400000: //RootNode
|
||||
400002: FaceMesh
|
||||
400004: DlibFaceLandmark68Mesh
|
||||
2300000: FaceMesh
|
||||
2300002: DlibFaceLandmark68Mesh
|
||||
3300000: FaceMesh
|
||||
3300002: DlibFaceLandmark68Mesh
|
||||
4300000: FaceMesh
|
||||
4300002: DlibFaceLandmark68Mesh
|
||||
materials:
|
||||
importMaterials: 0
|
||||
materialName: 0
|
||||
materialSearch: 1
|
||||
animations:
|
||||
legacyGenerateAnimations: 4
|
||||
bakeSimulation: 0
|
||||
optimizeGameObjects: 0
|
||||
motionNodeName:
|
||||
animationCompression: 1
|
||||
animationRotationError: .5
|
||||
animationPositionError: .5
|
||||
animationScaleError: .5
|
||||
animationWrapMode: 0
|
||||
extraExposedTransformPaths: []
|
||||
clipAnimations: []
|
||||
isReadable: 1
|
||||
meshes:
|
||||
lODScreenPercentages: []
|
||||
globalScale: 1
|
||||
meshCompression: 0
|
||||
addColliders: 0
|
||||
importBlendShapes: 0
|
||||
swapUVChannels: 0
|
||||
generateSecondaryUV: 0
|
||||
useFileUnits: 1
|
||||
optimizeMeshForGPU: 0
|
||||
keepQuads: 0
|
||||
weldVertices: 1
|
||||
secondaryUVAngleDistortion: 8
|
||||
secondaryUVAreaDistortion: 15.000001
|
||||
secondaryUVHardAngle: 88
|
||||
secondaryUVPackMargin: 4
|
||||
useFileScale: 1
|
||||
tangentSpace:
|
||||
normalSmoothAngle: 60
|
||||
splitTangentsAcrossUV: 0
|
||||
normalImportMode: 0
|
||||
tangentImportMode: 1
|
||||
importAnimation: 1
|
||||
copyAvatar: 0
|
||||
humanDescription:
|
||||
human: []
|
||||
skeleton: []
|
||||
armTwist: .5
|
||||
foreArmTwist: .5
|
||||
upperLegTwist: .5
|
||||
legTwist: .5
|
||||
armStretch: .0500000007
|
||||
legStretch: .0500000007
|
||||
feetSpacing: 0
|
||||
rootMotionBoneName:
|
||||
lastHumanDescriptionAvatarSource: {instanceID: 0}
|
||||
animationType: 0
|
||||
additionalBone: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
После Ширина: | Высота: | Размер: 3.8 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 930bad9a49e0e4d4f953e03509cea6ad
|
||||
timeCreated: 1481920749
|
||||
licenseType: Free
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 1
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: -1
|
||||
maxTextureSize: 512
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: 0
|
||||
nPOTScale: 1
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: 0
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
После Ширина: | Высота: | Размер: 127 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 15fcadce448f349488a1b74f026ce010
|
||||
timeCreated: 1483294900
|
||||
licenseType: Free
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 4
|
||||
maxTextureSize: 512
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
После Ширина: | Высота: | Размер: 126 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7777667c554b97c4cbe1120b7dcea0a4
|
||||
timeCreated: 1483294901
|
||||
licenseType: Free
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 4
|
||||
maxTextureSize: 512
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
После Ширина: | Высота: | Размер: 148 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 48eaa7a1d574ef647af0a2e1834f7250
|
||||
timeCreated: 1483294901
|
||||
licenseType: Free
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 4
|
||||
maxTextureSize: 512
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
После Ширина: | Высота: | Размер: 112 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4fd4dcb14f9983446b7b67f68114e9ba
|
||||
timeCreated: 1483294901
|
||||
licenseType: Free
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 4
|
||||
maxTextureSize: 512
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
После Ширина: | Высота: | Размер: 134 KiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b1d066fd26876b04c9d7f88c65d0a68a
|
||||
timeCreated: 1483294901
|
||||
licenseType: Free
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 4
|
||||
maxTextureSize: 512
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
После Ширина: | Высота: | Размер: 1.4 MiB |
|
@ -0,0 +1,55 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4796bf2415d8dc146b669a2d8680f963
|
||||
timeCreated: 1481920749
|
||||
licenseType: Free
|
||||
TextureImporter:
|
||||
fileIDToRecycleName: {}
|
||||
serializedVersion: 2
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
linearTexture: 0
|
||||
correctGamma: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
cubemapConvolutionSteps: 8
|
||||
cubemapConvolutionExponent: 1.5
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 4
|
||||
maxTextureSize: 1024
|
||||
textureSettings:
|
||||
filterMode: -1
|
||||
aniso: -1
|
||||
mipBias: -1
|
||||
wrapMode: -1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
rGBM: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 0
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: .5, y: .5}
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
spritePackingTag:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c7ad3f05dc719a0439f11658cf226ca5
|
||||
folderAsset: yes
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e6b1c061d75dec44b8b04657ceef9ee9
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 47d6f4267b82db945b369373fdaa8fed
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 070ebc21b7e5e204f82421ed10dbe8dc
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5c77f16fe1d24ce4dab1f841c0eac8df
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 63f1fb189940f464fbdb7d5b31d3eb06
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 81e7dc48b1dc0684c94514c609651308
|
||||
folderAsset: yes
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 172e02f113885e441808191b26575189
|
||||
folderAsset: yes
|
||||
timeCreated: 1483198025
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,237 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FaceMaskSample
|
||||
{
|
||||
public static class SampleDataSet
|
||||
{
|
||||
private static int index = 0;
|
||||
public static int Index
|
||||
{
|
||||
get { return index; }
|
||||
}
|
||||
|
||||
public static int Length
|
||||
{
|
||||
get { return filenames.Length; }
|
||||
}
|
||||
|
||||
private static string[] filenames = new string[5]{
|
||||
"face_mask1",
|
||||
"face_mask2",
|
||||
"face_mask3",
|
||||
"face_mask4",
|
||||
"face_mask5"
|
||||
};
|
||||
|
||||
private 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)
|
||||
};
|
||||
|
||||
private 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 SampleMaskData GetData(){
|
||||
return new SampleMaskData(filenames[index], faceRcts[index], landmarkPoints[index]);
|
||||
}
|
||||
|
||||
public static SampleMaskData GetData(int index){
|
||||
return new SampleMaskData(filenames[index], faceRcts[index], landmarkPoints[index]);
|
||||
}
|
||||
|
||||
public static void Next(){
|
||||
index++;
|
||||
if(index == filenames.Length)
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public class SampleMaskData
|
||||
{
|
||||
private string filename;
|
||||
public string FileName
|
||||
{
|
||||
get { return this.filename; }
|
||||
}
|
||||
|
||||
private Rect faceRect;
|
||||
public Rect FaceRect
|
||||
{
|
||||
get { return this.faceRect; }
|
||||
}
|
||||
|
||||
private List<Vector2> landmarkPoints;
|
||||
public List<Vector2> LandmarkPoints
|
||||
{
|
||||
get { return this.landmarkPoints; }
|
||||
}
|
||||
|
||||
public SampleMaskData(string filename, Rect faceRect, List<Vector2> landmarkPoints){
|
||||
this.filename = filename;
|
||||
this.faceRect = faceRect;
|
||||
this.landmarkPoints = landmarkPoints;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7c80dd142a6fcc744a2f10f3a3aa4d49
|
||||
timeCreated: 1483125206
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,64 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
using UnityEngine.SceneManagement;
|
||||
#endif
|
||||
|
||||
namespace FaceMaskSample
|
||||
{
|
||||
/// <summary>
|
||||
/// Face mask sample.
|
||||
/// </summary>
|
||||
public class FaceMaskSample : MonoBehaviour
|
||||
{
|
||||
|
||||
// Use this for initialization
|
||||
void Start ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnShowLicenseButton ()
|
||||
{
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
SceneManager.LoadScene ("ShowLicense");
|
||||
#else
|
||||
Application.LoadLevel ("ShowLicense");
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OnTexture2DFaceMaskSample ()
|
||||
{
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
SceneManager.LoadScene ("Texture2DFaceMaskSample");
|
||||
#else
|
||||
Application.LoadLevel ("Texture2DFaceMaskSample");
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OnVideoCaptureFaceMaskSample ()
|
||||
{
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
SceneManager.LoadScene ("VideoCaptureFaceMaskSample");
|
||||
#else
|
||||
Application.LoadLevel ("VideoCaptureFaceMaskSample");
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OnWebCamTextureFaceMaskSample ()
|
||||
{
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
SceneManager.LoadScene ("WebCamTextureFaceMaskSample");
|
||||
#else
|
||||
Application.LoadLevel ("WebCamTextureFaceMaskSample");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: facc282ddcd086e46a52c5e4dee1cb0e
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b40af3c3b03f5ef4d9d20289b6781a69
|
||||
folderAsset: yes
|
||||
timeCreated: 1481980040
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,139 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FaceMaskSample
|
||||
{
|
||||
public class ObjectPool : MonoBehaviour
|
||||
{
|
||||
public GameObject prefab;
|
||||
public int maxCount = 100;
|
||||
public int prepareCount = 0;
|
||||
|
||||
[SerializeField]
|
||||
private int interval = 1;
|
||||
|
||||
private List<GameObject> pooledObjectList = new List<GameObject>();
|
||||
private IEnumerator removeObjectCheckCoroutine;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (interval > 0){
|
||||
removeObjectCheckCoroutine = RemoveObjectCheck();
|
||||
StartCoroutine(removeObjectCheckCoroutine);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (removeObjectCheckCoroutine != null){
|
||||
StopCoroutine(removeObjectCheckCoroutine);
|
||||
removeObjectCheckCoroutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
DestroyAllObjects ();
|
||||
}
|
||||
|
||||
public int Interval
|
||||
{
|
||||
get
|
||||
{
|
||||
return interval;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (interval != value)
|
||||
{
|
||||
interval = value;
|
||||
|
||||
if (removeObjectCheckCoroutine != null){
|
||||
StopCoroutine(removeObjectCheckCoroutine);
|
||||
removeObjectCheckCoroutine = null;
|
||||
}
|
||||
if (interval > 0){
|
||||
removeObjectCheckCoroutine = RemoveObjectCheck();
|
||||
StartCoroutine(removeObjectCheckCoroutine);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GameObject GetInstance()
|
||||
{
|
||||
return GetInstance(transform);
|
||||
}
|
||||
|
||||
public GameObject GetInstance(Transform parent)
|
||||
{
|
||||
if (prefab == null){
|
||||
Debug.LogWarning("prefab object is not set.");
|
||||
return null;
|
||||
}
|
||||
|
||||
pooledObjectList.RemoveAll((obj) => obj == null);
|
||||
|
||||
foreach (GameObject obj in pooledObjectList)
|
||||
{
|
||||
if (obj.activeSelf == false)
|
||||
{
|
||||
obj.SetActive(true);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
if (pooledObjectList.Count < maxCount)
|
||||
{
|
||||
GameObject obj = (GameObject)GameObject.Instantiate(prefab);
|
||||
obj.SetActive(true);
|
||||
obj.transform.parent = parent;
|
||||
pooledObjectList.Add(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
IEnumerator RemoveObjectCheck()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
RemoveObject(prepareCount);
|
||||
yield return new WaitForSeconds(interval);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveObject(int max)
|
||||
{
|
||||
if (pooledObjectList.Count > max)
|
||||
{
|
||||
|
||||
int needRemoveCount = pooledObjectList.Count - max;
|
||||
foreach (GameObject obj in pooledObjectList.ToArray())
|
||||
{
|
||||
if (needRemoveCount == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (obj.activeSelf == false)
|
||||
{
|
||||
pooledObjectList.Remove(obj);
|
||||
Destroy(obj);
|
||||
needRemoveCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DestroyAllObjects ()
|
||||
{
|
||||
foreach (var obj in pooledObjectList)
|
||||
{
|
||||
Destroy(obj);
|
||||
}
|
||||
pooledObjectList.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 26c6457357aaf0541a7914ce67900b0e
|
||||
timeCreated: 1481980241
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FaceMaskSample
|
||||
{
|
||||
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter), typeof(MeshCollider))]
|
||||
public class TrackedMesh : MonoBehaviour
|
||||
{
|
||||
|
||||
private MeshFilter meshFilter;
|
||||
|
||||
private MeshRenderer meshRenderer;
|
||||
|
||||
private MeshCollider meshCollider;
|
||||
|
||||
public MeshFilter MeshFilter
|
||||
{
|
||||
get { return meshFilter; }
|
||||
}
|
||||
public MeshRenderer MeshRenderer
|
||||
{
|
||||
get { return meshRenderer; }
|
||||
}
|
||||
public MeshCollider MeshCollider
|
||||
{
|
||||
get { return meshCollider; }
|
||||
}
|
||||
|
||||
public int Id
|
||||
{
|
||||
get { return id; }
|
||||
set { id = value; }
|
||||
}
|
||||
private int id = 0;
|
||||
|
||||
public Material Material
|
||||
{
|
||||
get { return material; }
|
||||
}
|
||||
private Material material;
|
||||
|
||||
|
||||
void Awake()
|
||||
{
|
||||
meshFilter = this.GetComponent<MeshFilter>();
|
||||
meshRenderer = this.GetComponent<MeshRenderer>();
|
||||
meshCollider = this.GetComponent<MeshCollider>();
|
||||
|
||||
if (meshRenderer.material == null)
|
||||
throw new Exception("Material does not exist.");
|
||||
|
||||
material = meshRenderer.material;
|
||||
}
|
||||
|
||||
void OnDestroy(){
|
||||
if(meshFilter != null && meshFilter.mesh != null){
|
||||
DestroyImmediate(meshFilter.mesh);
|
||||
}
|
||||
if(meshRenderer != null && meshRenderer.materials != null){
|
||||
foreach(var m in meshRenderer.materials){
|
||||
DestroyImmediate(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c47754ddde934e14c95f9de06ad6413d
|
||||
timeCreated: 1481980241
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,210 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using OpenCVForUnity.RectangleTrack;
|
||||
|
||||
namespace FaceMaskSample
|
||||
{
|
||||
public class TrackedMeshOverlay : MonoBehaviour
|
||||
{
|
||||
public int Interval = 1;
|
||||
public int PoolSize = 10;
|
||||
|
||||
[SerializeField]
|
||||
private GameObject baseObject;
|
||||
public GameObject BaseObject
|
||||
{
|
||||
get {
|
||||
return baseObject;
|
||||
}
|
||||
set {
|
||||
baseObject = value;
|
||||
setBaseObject(baseObject);
|
||||
}
|
||||
}
|
||||
|
||||
public float Width
|
||||
{
|
||||
get {
|
||||
return targetWidth;
|
||||
}
|
||||
}
|
||||
|
||||
public float Height
|
||||
{
|
||||
get {
|
||||
return targetHeight;
|
||||
}
|
||||
}
|
||||
|
||||
protected Transform targetTransform;
|
||||
protected float targetWidth = 0;
|
||||
protected float targetHeight = 0;
|
||||
protected Transform overlayTransform;
|
||||
protected ObjectPool objectPool;
|
||||
protected Dictionary<int, TrackedMesh> showingObjects = new Dictionary<int, TrackedMesh>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
init("MeshOverlay");
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
overlayTransform = null;
|
||||
targetTransform = null;
|
||||
targetWidth = 0;
|
||||
targetHeight = 0;
|
||||
showingObjects.Clear();
|
||||
if(objectPool != null)
|
||||
{
|
||||
Destroy(objectPool.gameObject);
|
||||
objectPool = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected GameObject getPoolObject(Transform parent)
|
||||
{
|
||||
if(objectPool == null) return null;
|
||||
|
||||
GameObject newObj = objectPool.GetInstance(parent);
|
||||
if(newObj != null){
|
||||
newObj.transform.parent = parent;
|
||||
return newObj;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void init(String name)
|
||||
{
|
||||
GameObject obj = new GameObject(name);
|
||||
overlayTransform = obj.transform;
|
||||
overlayTransform.parent = gameObject.transform.parent;
|
||||
UpdateOverlayTransform();
|
||||
|
||||
if(baseObject != null)
|
||||
setBaseObject (baseObject);
|
||||
}
|
||||
|
||||
protected virtual void setBaseObject (GameObject obj)
|
||||
{
|
||||
if (obj.GetComponent<TrackedMesh>() == null)
|
||||
{
|
||||
Debug.LogWarning("Object is not TrackedMesh.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(objectPool != null){
|
||||
Destroy(objectPool);
|
||||
}
|
||||
|
||||
objectPool = overlayTransform.gameObject.AddComponent<ObjectPool>();
|
||||
objectPool.prefab = obj;
|
||||
objectPool.maxCount = PoolSize;
|
||||
objectPool.prepareCount = (int)PoolSize / 2;
|
||||
objectPool.Interval = Interval;
|
||||
}
|
||||
|
||||
public virtual void UpdateOverlayTransform(Transform targetTransform)
|
||||
{
|
||||
if (targetTransform == null)
|
||||
{
|
||||
this.targetTransform = null;
|
||||
return;
|
||||
}
|
||||
|
||||
targetWidth = targetTransform.localScale.x;
|
||||
targetHeight = targetTransform.localScale.y;
|
||||
this.targetTransform = targetTransform;
|
||||
overlayTransform.localPosition = new Vector3(targetTransform.localPosition.x, targetTransform.localPosition.y, targetTransform .localPosition.z - 0.1f);
|
||||
}
|
||||
|
||||
public virtual void UpdateOverlayTransform()
|
||||
{
|
||||
Renderer renderer = gameObject.GetComponent<Renderer>();
|
||||
if(renderer == null) return;
|
||||
|
||||
targetWidth = renderer.bounds.size.x;
|
||||
targetHeight = renderer.bounds.size.y;
|
||||
Vector3 center = renderer.bounds.center;
|
||||
Debug.Log(targetWidth + " " + targetHeight + " " + center);
|
||||
overlayTransform.localPosition = new Vector3(center.x, center.y, center.z - 0.1f);
|
||||
}
|
||||
|
||||
public virtual TrackedMesh GetObjectById(int id)
|
||||
{
|
||||
if (showingObjects.ContainsKey(id))
|
||||
{
|
||||
return showingObjects[id];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual TrackedMesh CreateObject(int id, Texture2D tex = null)
|
||||
{
|
||||
if (!showingObjects.ContainsKey(id)){
|
||||
GameObject obj = getPoolObject(overlayTransform);
|
||||
if (obj == null) return null;
|
||||
TrackedMesh tm = obj.GetComponent<TrackedMesh>();
|
||||
if (tm != null)
|
||||
{
|
||||
tm.Id = id;
|
||||
tm.transform.localPosition = new Vector3(0, 0, 0);
|
||||
tm.transform.localRotation = new Quaternion();
|
||||
tm.transform.localScale = new Vector3(1, 1, 1);
|
||||
if (tex != null) tm.Material.mainTexture = tex;
|
||||
showingObjects.Add(id, tm);
|
||||
}
|
||||
return tm;
|
||||
}
|
||||
else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void UpdateObject(int id, Vector3[] vertices, int[] triangles = null, Vector2[] uv = null)
|
||||
{
|
||||
if (showingObjects.ContainsKey(id)){
|
||||
|
||||
TrackedMesh tm = showingObjects[id];
|
||||
|
||||
if(vertices.Length != tm.MeshFilter.mesh.vertices.Length) Debug.LogError("The number of vertices does not match.");
|
||||
tm.MeshFilter.mesh.vertices = vertices;
|
||||
|
||||
if (triangles != null)
|
||||
{
|
||||
tm.MeshFilter.mesh.triangles = triangles;
|
||||
}
|
||||
if (uv != null)
|
||||
{
|
||||
tm.MeshFilter.mesh.uv = uv;
|
||||
}
|
||||
|
||||
tm.MeshFilter.mesh.RecalculateBounds();
|
||||
tm.MeshFilter.mesh.RecalculateNormals();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void DeleteObject(int id)
|
||||
{
|
||||
if (showingObjects.ContainsKey(id))
|
||||
{
|
||||
if(showingObjects[id] != null)
|
||||
showingObjects[id].gameObject.SetActive(false);
|
||||
showingObjects.Remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Reset()
|
||||
{
|
||||
foreach (int key in showingObjects.Keys)
|
||||
{
|
||||
if(showingObjects[key] != null)
|
||||
showingObjects[key].gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
showingObjects.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 59726869b6e135846a8945aadc9b78d9
|
||||
timeCreated: 1481980241
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,38 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
using UnityEngine.SceneManagement;
|
||||
#endif
|
||||
|
||||
namespace FaceMaskSample
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Show license.
|
||||
/// </summary>
|
||||
public class ShowLicense : MonoBehaviour
|
||||
{
|
||||
|
||||
// Use this for initialization
|
||||
void Start ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnBackButton ()
|
||||
{
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
SceneManager.LoadScene ("FaceMaskSample");
|
||||
#else
|
||||
Application.LoadLevel ("FaceMaskSample");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4b8251a771a9a044bb64efaf0fa43495
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,432 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using DlibFaceLandmarkDetector;
|
||||
using OpenCVForUnity;
|
||||
using WebGLFileUploader;
|
||||
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
using UnityEngine.SceneManagement;
|
||||
#endif
|
||||
|
||||
namespace FaceMaskSample
|
||||
{
|
||||
/// <summary>
|
||||
/// Texture2D face mask sample.
|
||||
/// </summary>
|
||||
public class Texture2DFaceMaskSample : MonoBehaviour
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The image texture.
|
||||
/// </summary>
|
||||
Texture2D imgTexture;
|
||||
|
||||
/// <summary>
|
||||
/// The cascade.
|
||||
/// </summary>
|
||||
CascadeClassifier cascade;
|
||||
|
||||
/// <summary>
|
||||
/// The face landmark detector.
|
||||
/// </summary>
|
||||
FaceLandmarkDetector faceLandmarkDetector;
|
||||
|
||||
/// <summary>
|
||||
/// The is showing face rects.
|
||||
/// </summary>
|
||||
public bool isShowingFaceRects = false;
|
||||
|
||||
/// <summary>
|
||||
/// The is showing face rects toggle.
|
||||
/// </summary>
|
||||
public Toggle isShowingFaceRectsToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The use Dlib face detector flag.
|
||||
/// </summary>
|
||||
public bool useDlibFaceDetecter = true;
|
||||
|
||||
/// <summary>
|
||||
/// The use dlib face detecter toggle.
|
||||
/// </summary>
|
||||
public Toggle useDlibFaceDetecterToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The is filtering non frontal faces.
|
||||
/// </summary>
|
||||
public bool isFilteringNonFrontalFaces;
|
||||
|
||||
/// <summary>
|
||||
/// The is filtering non frontal faces toggle.
|
||||
/// </summary>
|
||||
public Toggle isFilteringNonFrontalFacesToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The frontal face rate lower limit.
|
||||
/// </summary>
|
||||
[Range (0.0f, 1.0f)]
|
||||
public float
|
||||
frontalFaceRateLowerLimit = 0.85f;
|
||||
|
||||
/// <summary>
|
||||
/// The is showing debug face points.
|
||||
/// </summary>
|
||||
public bool isShowingDebugFacePoints = false;
|
||||
|
||||
/// <summary>
|
||||
/// The is showing debug face points toggle.
|
||||
/// </summary>
|
||||
public Toggle isShowingDebugFacePointsToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The is upload image button.
|
||||
/// </summary>
|
||||
public Button uploadImageButton;
|
||||
|
||||
/// <summary>
|
||||
/// The mesh overlay.
|
||||
/// </summary>
|
||||
private TrackedMeshOverlay meshOverlay;
|
||||
|
||||
/// <summary>
|
||||
/// The haarcascade_frontalface_alt_xml_filepath.
|
||||
/// </summary>
|
||||
private string haarcascade_frontalface_alt_xml_filepath;
|
||||
|
||||
/// <summary>
|
||||
/// The shape_predictor_68_face_landmarks_dat_filepath.
|
||||
/// </summary>
|
||||
private string shape_predictor_68_face_landmarks_dat_filepath;
|
||||
|
||||
|
||||
// Use this for initialization
|
||||
void Start ()
|
||||
{
|
||||
WebGLFileUploadManager.SetImageEncodeSetting (true);
|
||||
WebGLFileUploadManager.SetAllowedFileName ("\\.(png|jpe?g|gif)$");
|
||||
WebGLFileUploadManager.SetImageShrinkingSize (640, 480);
|
||||
WebGLFileUploadManager.FileUploadEventHandler += fileUploadHandler;
|
||||
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
StartCoroutine(getFilePathCoroutine());
|
||||
#else
|
||||
haarcascade_frontalface_alt_xml_filepath = OpenCVForUnity.Utils.getFilePath ("haarcascade_frontalface_alt.xml");
|
||||
shape_predictor_68_face_landmarks_dat_filepath = DlibFaceLandmarkDetector.Utils.getFilePath ("shape_predictor_68_face_landmarks.dat");
|
||||
Run ();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
private IEnumerator getFilePathCoroutine ()
|
||||
{
|
||||
var getFilePathAsync_0_Coroutine = StartCoroutine (OpenCVForUnity.Utils.getFilePathAsync ("haarcascade_frontalface_alt.xml", (result) => {
|
||||
haarcascade_frontalface_alt_xml_filepath = result;
|
||||
}));
|
||||
var getFilePathAsync_1_Coroutine = StartCoroutine (DlibFaceLandmarkDetector.Utils.getFilePathAsync ("shape_predictor_68_face_landmarks.dat", (result) => {
|
||||
shape_predictor_68_face_landmarks_dat_filepath = result;
|
||||
}));
|
||||
|
||||
yield return getFilePathAsync_0_Coroutine;
|
||||
yield return getFilePathAsync_1_Coroutine;
|
||||
|
||||
Run ();
|
||||
uploadImageButton.interactable = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
private void Run ()
|
||||
{
|
||||
meshOverlay = this.GetComponent<TrackedMeshOverlay> ();
|
||||
|
||||
isShowingFaceRectsToggle.isOn = isShowingFaceRects;
|
||||
useDlibFaceDetecterToggle.isOn = useDlibFaceDetecter;
|
||||
isFilteringNonFrontalFacesToggle.isOn = isFilteringNonFrontalFaces;
|
||||
isShowingDebugFacePointsToggle.isOn = isShowingDebugFacePoints;
|
||||
|
||||
if (imgTexture == null)
|
||||
imgTexture = Resources.Load ("family") as Texture2D;
|
||||
|
||||
gameObject.transform.localScale = new Vector3 (imgTexture.width, imgTexture.height, 1);
|
||||
Debug.Log ("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation);
|
||||
|
||||
meshOverlay.UpdateOverlayTransform ();
|
||||
meshOverlay.Reset ();
|
||||
|
||||
|
||||
float width = 0;
|
||||
float height = 0;
|
||||
width = gameObject.transform.localScale.x;
|
||||
height = gameObject.transform.localScale.y;
|
||||
|
||||
float widthScale = (float)Screen.width / width;
|
||||
float heightScale = (float)Screen.height / height;
|
||||
if (widthScale < heightScale) {
|
||||
Camera.main.orthographicSize = (width * (float)Screen.height / (float)Screen.width) / 2;
|
||||
} else {
|
||||
Camera.main.orthographicSize = height / 2;
|
||||
}
|
||||
|
||||
Mat rgbaMat = new Mat (imgTexture.height, imgTexture.width, CvType.CV_8UC4);
|
||||
|
||||
OpenCVForUnity.Utils.texture2DToMat (imgTexture, rgbaMat);
|
||||
Debug.Log ("rgbaMat ToString " + rgbaMat.ToString ());
|
||||
|
||||
if (faceLandmarkDetector == null)
|
||||
faceLandmarkDetector = new FaceLandmarkDetector (shape_predictor_68_face_landmarks_dat_filepath);
|
||||
|
||||
FrontalFaceParam frontalFaceParam = new FrontalFaceParam ();
|
||||
|
||||
|
||||
// face detection.
|
||||
List<OpenCVForUnity.Rect> detectResult = new List<OpenCVForUnity.Rect> ();
|
||||
if (useDlibFaceDetecter) {
|
||||
OpenCVForUnityUtils.SetImage (faceLandmarkDetector, rgbaMat);
|
||||
List<UnityEngine.Rect> result = faceLandmarkDetector.Detect ();
|
||||
|
||||
foreach (var unityRect in result) {
|
||||
detectResult.Add (new OpenCVForUnity.Rect ((int)unityRect.x, (int)unityRect.y, (int)unityRect.width, (int)unityRect.height));
|
||||
}
|
||||
} else {
|
||||
if (cascade == null)
|
||||
cascade = new CascadeClassifier (haarcascade_frontalface_alt_xml_filepath);
|
||||
if (cascade.empty ()) {
|
||||
Debug.LogError ("cascade file is not loaded.Please copy from “FaceTrackerSample/StreamingAssets/” to “Assets/StreamingAssets/” folder. ");
|
||||
}
|
||||
|
||||
// convert image to greyscale.
|
||||
Mat gray = new Mat ();
|
||||
Imgproc.cvtColor (rgbaMat, gray, Imgproc.COLOR_RGBA2GRAY);
|
||||
|
||||
// detect Faces.
|
||||
MatOfRect faces = new MatOfRect ();
|
||||
Imgproc.equalizeHist (gray, gray);
|
||||
cascade.detectMultiScale (gray, faces, 1.1f, 2, 0 | Objdetect.CASCADE_SCALE_IMAGE, new OpenCVForUnity.Size (gray.cols () * 0.05, gray.cols () * 0.05), new Size ());
|
||||
//Debug.Log ("faces " + faces.dump ());
|
||||
|
||||
detectResult = faces.toList ();
|
||||
|
||||
// Adjust to Dilb's result.
|
||||
foreach (OpenCVForUnity.Rect r in detectResult) {
|
||||
r.y += (int)(r.height * 0.1f);
|
||||
}
|
||||
|
||||
gray.Dispose ();
|
||||
}
|
||||
|
||||
// detect face landmark.
|
||||
OpenCVForUnityUtils.SetImage (faceLandmarkDetector, rgbaMat);
|
||||
List<List<Vector2>> landmarkPoints = new List<List<Vector2>> ();
|
||||
foreach (var openCVRect in detectResult) {
|
||||
UnityEngine.Rect rect = new UnityEngine.Rect (openCVRect.x, openCVRect.y, openCVRect.width, openCVRect.height);
|
||||
|
||||
Debug.Log ("face : " + rect);
|
||||
//OpenCVForUnityUtils.DrawFaceRect(imgMat, rect, new Scalar(255, 0, 0, 255), 2);
|
||||
|
||||
List<Vector2> points = faceLandmarkDetector.DetectLandmark (rect);
|
||||
//OpenCVForUnityUtils.DrawFaceLandmark(imgMat, points, new Scalar(0, 255, 0, 255), 2);
|
||||
landmarkPoints.Add (points);
|
||||
}
|
||||
|
||||
// mask faces.
|
||||
int[] face_nums = new int[landmarkPoints.Count];
|
||||
for (int i = 0; i < face_nums.Length; i++) {
|
||||
face_nums [i] = i;
|
||||
}
|
||||
face_nums = face_nums.OrderBy (i => System.Guid.NewGuid ()).ToArray ();
|
||||
|
||||
float offsetX = meshOverlay.Width / 2f;
|
||||
float offsetY = meshOverlay.Height / 2f;
|
||||
float maskImageWidth = imgTexture.width;
|
||||
float maskImageHeight = imgTexture.height;
|
||||
|
||||
TrackedMesh tm;
|
||||
for (int i = 0; i < face_nums.Length; i++) {
|
||||
|
||||
meshOverlay.CreateObject (i, imgTexture);
|
||||
tm = meshOverlay.GetObjectById (i);
|
||||
|
||||
Vector3[] vertices = tm.MeshFilter.mesh.vertices;
|
||||
if (vertices.Length == landmarkPoints [face_nums [i]].Count) {
|
||||
for (int j = 0; j < vertices.Length; j++) {
|
||||
vertices [j].x = landmarkPoints [face_nums [i]] [j].x - offsetX;
|
||||
vertices [j].y = offsetY - landmarkPoints [face_nums [i]] [j].y;
|
||||
}
|
||||
}
|
||||
Vector2[] uv = tm.MeshFilter.mesh.uv;
|
||||
if (uv.Length == landmarkPoints [face_nums [0]].Count) {
|
||||
for (int jj = 0; jj < uv.Length; jj++) {
|
||||
uv [jj].x = landmarkPoints [face_nums [0]] [jj].x / maskImageWidth;
|
||||
uv [jj].y = (maskImageHeight - landmarkPoints [face_nums [0]] [jj].y) / maskImageHeight;
|
||||
}
|
||||
}
|
||||
meshOverlay.UpdateObject (i, vertices, null, uv);
|
||||
|
||||
// filter nonfrontalface.
|
||||
if (isFilteringNonFrontalFaces && frontalFaceParam.getFrontalFaceRate (landmarkPoints [i]) < frontalFaceRateLowerLimit) {
|
||||
tm.Material.SetFloat ("_Fade", 1f);
|
||||
} else {
|
||||
tm.Material.SetFloat ("_Fade", 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
// draw face rects.
|
||||
if (isShowingFaceRects) {
|
||||
int ann = face_nums[0];
|
||||
UnityEngine.Rect rect_ann = new UnityEngine.Rect (detectResult [ann].x, detectResult [ann].y, detectResult [ann].width, detectResult [ann].height);
|
||||
OpenCVForUnityUtils.DrawFaceRect (rgbaMat, rect_ann, new Scalar (255, 255, 0, 255), 2);
|
||||
|
||||
int bob = 0;
|
||||
for (int i = 1; i < face_nums.Length; i ++) {
|
||||
bob = face_nums [i];
|
||||
UnityEngine.Rect rect_bob = new UnityEngine.Rect (detectResult [bob].x, detectResult [bob].y, detectResult [bob].width, detectResult [bob].height);
|
||||
OpenCVForUnityUtils.DrawFaceRect (rgbaMat, rect_bob, new Scalar (255, 0, 0, 255), 2);
|
||||
}
|
||||
}
|
||||
|
||||
// draw face points.
|
||||
if (isShowingDebugFacePoints) {
|
||||
for (int i = 0; i < landmarkPoints.Count; i++) {
|
||||
OpenCVForUnityUtils.DrawFaceLandmark (rgbaMat, landmarkPoints [i], new Scalar (0, 255, 0, 255), 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Texture2D texture = new Texture2D (rgbaMat.cols (), rgbaMat.rows (), TextureFormat.RGBA32, false);
|
||||
OpenCVForUnity.Utils.matToTexture2D (rgbaMat, texture);
|
||||
gameObject.transform.GetComponent<Renderer> ().material.mainTexture = texture;
|
||||
|
||||
frontalFaceParam.Dispose ();
|
||||
rgbaMat.Dispose ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the destroy event.
|
||||
/// </summary>
|
||||
void OnDestroy ()
|
||||
{
|
||||
WebGLFileUploadManager.FileUploadEventHandler -= fileUploadHandler;
|
||||
WebGLFileUploadManager.Dispose ();
|
||||
|
||||
if (faceLandmarkDetector != null)
|
||||
faceLandmarkDetector.Dispose ();
|
||||
|
||||
if (cascade != null)
|
||||
cascade.Dispose ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the back button event.
|
||||
/// </summary>
|
||||
public void OnBackButton ()
|
||||
{
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
SceneManager.LoadScene ("FaceMaskSample");
|
||||
#else
|
||||
Application.LoadLevel ("FaceMaskSample");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the shuffle button event.
|
||||
/// </summary>
|
||||
public void OnShuffleButton ()
|
||||
{
|
||||
if (imgTexture != null)
|
||||
Run ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the is showing face rects toggle event.
|
||||
/// </summary>
|
||||
public void OnIsShowingFaceRectsToggle ()
|
||||
{
|
||||
if (isShowingFaceRectsToggle.isOn) {
|
||||
isShowingFaceRects = true;
|
||||
} else {
|
||||
isShowingFaceRects = false;
|
||||
}
|
||||
|
||||
if (imgTexture != null)
|
||||
Run ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the use Dlib face detector toggle event.
|
||||
/// </summary>
|
||||
public void OnUseDlibFaceDetecterToggle ()
|
||||
{
|
||||
if (useDlibFaceDetecterToggle.isOn) {
|
||||
useDlibFaceDetecter = true;
|
||||
} else {
|
||||
useDlibFaceDetecter = false;
|
||||
}
|
||||
|
||||
if (imgTexture != null)
|
||||
Run ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the is filtering non frontal faces toggle event.
|
||||
/// </summary>
|
||||
public void OnIsFilteringNonFrontalFacesToggle ()
|
||||
{
|
||||
if (isFilteringNonFrontalFacesToggle.isOn) {
|
||||
isFilteringNonFrontalFaces = true;
|
||||
} else {
|
||||
isFilteringNonFrontalFaces = false;
|
||||
}
|
||||
|
||||
if (imgTexture != null)
|
||||
Run ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the is showing debug face points toggle event.
|
||||
/// </summary>
|
||||
public void OnIsShowingDebugFacePointsToggle ()
|
||||
{
|
||||
if (isShowingDebugFacePointsToggle.isOn) {
|
||||
isShowingDebugFacePoints = true;
|
||||
} else {
|
||||
isShowingDebugFacePoints = false;
|
||||
}
|
||||
|
||||
if (imgTexture != null)
|
||||
Run ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the upload image button event.
|
||||
/// </summary>
|
||||
public void OnUploadImageButton ()
|
||||
{
|
||||
WebGLFileUploadManager.PopupDialog (null, "Select image file (.png|.jpg|.gif)");
|
||||
}
|
||||
|
||||
private void fileUploadHandler (UploadedFileInfo[] result)
|
||||
{
|
||||
|
||||
if (result.Length == 0) {
|
||||
Debug.Log ("File upload Error!");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (UploadedFileInfo file in result) {
|
||||
if (file.isSuccess) {
|
||||
Debug.Log ("file.filePath: " + file.filePath + " exists:" + File.Exists (file.filePath));
|
||||
|
||||
imgTexture = new Texture2D (2, 2);
|
||||
byte[] byteArray = File.ReadAllBytes (file.filePath);
|
||||
imgTexture.LoadImage (byteArray);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
Run ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cd66fda4a37976f45ac5f300538ea3a5
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 296e6f34a61e0fe4cbdd1655787c3764
|
||||
folderAsset: yes
|
||||
timeCreated: 1483013079
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,240 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using OpenCVForUnity;
|
||||
|
||||
namespace FaceMaskSample
|
||||
{
|
||||
public class FrontalFaceParam : IDisposable
|
||||
{
|
||||
|
||||
// Calib3d.solvePnP.
|
||||
Matrix4x4 transformationM = new Matrix4x4 ();
|
||||
MatOfPoint3f objectPoints;
|
||||
MatOfPoint2f imagePoints;
|
||||
Mat rvec;
|
||||
Mat tvec;
|
||||
Mat rotM;
|
||||
Mat camMatrix;
|
||||
MatOfDouble distCoeffs;
|
||||
Matrix4x4 invertYM;
|
||||
Matrix4x4 invertZM;
|
||||
Matrix4x4 ARM;
|
||||
|
||||
// normalize.
|
||||
float normWidth = 200;
|
||||
float normHeight = 200;
|
||||
List<Vector2> normPoints;
|
||||
|
||||
public FrontalFaceParam ()
|
||||
{
|
||||
invertYM = Matrix4x4.TRS (Vector3.zero, Quaternion.identity, new Vector3 (1, -1, 1));
|
||||
//Debug.Log ("invertYM " + invertYM.ToString ());
|
||||
|
||||
invertZM = Matrix4x4.TRS (Vector3.zero, Quaternion.identity, new Vector3 (1, 1, -1));
|
||||
//Debug.Log ("invertZM " + invertZM.ToString ());
|
||||
|
||||
// set 3d face object points.
|
||||
objectPoints = new MatOfPoint3f (
|
||||
new Point3 (-31, 72, 86),//l eye
|
||||
new Point3 (31, 72, 86),//r eye
|
||||
new Point3 (0, 40, 114),//nose
|
||||
new Point3 (-20, 15, 90),//l mouth //new Point3(-22, 17, 90),//l mouth
|
||||
new Point3 (20, 15, 90),//r mouth //new Point3(22, 17, 90),//r mouth
|
||||
new Point3 (-69, 76, -2),//l ear
|
||||
new Point3 (69, 76, -2)//r ear
|
||||
);
|
||||
imagePoints = new MatOfPoint2f ();
|
||||
rvec = new Mat ();
|
||||
tvec = new Mat ();
|
||||
rotM = new Mat (3, 3, CvType.CV_64FC1);
|
||||
|
||||
|
||||
float max_d = Mathf.Max (normHeight, normWidth);
|
||||
camMatrix = new Mat (3, 3, CvType.CV_64FC1);
|
||||
camMatrix.put (0, 0, max_d);
|
||||
camMatrix.put (0, 1, 0);
|
||||
camMatrix.put (0, 2, normWidth / 2.0f);
|
||||
camMatrix.put (1, 0, 0);
|
||||
camMatrix.put (1, 1, max_d);
|
||||
camMatrix.put (1, 2, normHeight / 2.0f);
|
||||
camMatrix.put (2, 0, 0);
|
||||
camMatrix.put (2, 1, 0);
|
||||
camMatrix.put (2, 2, 1.0f);
|
||||
|
||||
distCoeffs = new MatOfDouble (0, 0, 0, 0);
|
||||
//Debug.Log("distCoeffs " + distCoeffs.dump());
|
||||
|
||||
|
||||
normPoints = new List<Vector2> (68);
|
||||
for (int i = 0; i < 68; i++) {
|
||||
normPoints.Add (new Vector2 (0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
objectPoints.Dispose ();
|
||||
imagePoints.Dispose ();
|
||||
rvec.Dispose ();
|
||||
tvec.Dispose ();
|
||||
rotM.Dispose ();
|
||||
camMatrix.Dispose ();
|
||||
distCoeffs.Dispose ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the frontal face angle.
|
||||
/// </summary>
|
||||
/// <returns>The frontal face angle.</returns>
|
||||
/// <param name="points">Points.</param>
|
||||
public virtual Vector3 getFrontalFaceAngle (List<Vector2> points)
|
||||
{
|
||||
if (points.Count != 68)
|
||||
throw new ArgumentNullException ("Invalid landmark_points.");
|
||||
|
||||
if (camMatrix == null)
|
||||
throw new ArgumentNullException ("Invalid camMatrix.");
|
||||
|
||||
// normalize.
|
||||
float normScale = Math.Abs (points [30].y - points [8].y) / (normHeight / 2);
|
||||
Vector2 normDiff = points [30] * normScale - new Vector2 (normWidth / 2, normHeight / 2);
|
||||
|
||||
for (int i = 0; i < points.Count; i++) {
|
||||
normPoints [i] = points [i] * normScale - normDiff;
|
||||
}
|
||||
// Debug.Log ("points[30] " + points[30]);
|
||||
// Debug.Log ("normPoints[30] " + normPoints[30]);
|
||||
// Debug.Log ("normScale " + normScale);
|
||||
// Debug.Log ("normDiff " + normDiff);
|
||||
|
||||
imagePoints.fromArray (
|
||||
new Point ((normPoints [38].x + normPoints [41].x) / 2, (normPoints [38].y + normPoints [41].y) / 2),//l eye
|
||||
new Point ((normPoints [43].x + normPoints [46].x) / 2, (normPoints [43].y + normPoints [46].y) / 2),//r eye
|
||||
new Point (normPoints [33].x, normPoints [33].y),//nose
|
||||
new Point (normPoints [48].x, normPoints [48].y),//l mouth
|
||||
new Point (normPoints [54].x, normPoints [54].y), //r mouth ,
|
||||
new Point (normPoints [0].x, normPoints [0].y),//l ear
|
||||
new Point (normPoints [16].x, normPoints [16].y)//r ear
|
||||
);
|
||||
|
||||
|
||||
Calib3d.solvePnP (objectPoints, imagePoints, camMatrix, distCoeffs, rvec, tvec);
|
||||
|
||||
Calib3d.Rodrigues (rvec, rotM);
|
||||
|
||||
transformationM.SetRow (0, new Vector4 ((float)rotM.get (0, 0) [0], (float)rotM.get (0, 1) [0], (float)rotM.get (0, 2) [0], (float)tvec.get (0, 0) [0]));
|
||||
transformationM.SetRow (1, new Vector4 ((float)rotM.get (1, 0) [0], (float)rotM.get (1, 1) [0], (float)rotM.get (1, 2) [0], (float)tvec.get (1, 0) [0]));
|
||||
transformationM.SetRow (2, new Vector4 ((float)rotM.get (2, 0) [0], (float)rotM.get (2, 1) [0], (float)rotM.get (2, 2) [0], (float)tvec.get (2, 0) [0]));
|
||||
transformationM.SetRow (3, new Vector4 (0, 0, 0, 1));
|
||||
|
||||
ARM = invertYM * transformationM * invertZM;
|
||||
|
||||
return ExtractRotationFromMatrix (ref ARM).eulerAngles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the frontal face rate.
|
||||
/// </summary>
|
||||
/// <returns>The frontal face rate.</returns>
|
||||
/// <param name="points">Points.</param>
|
||||
public float getFrontalFaceRate (List<Vector2> points)
|
||||
{
|
||||
|
||||
Vector3 angles = getFrontalFaceAngle (points);
|
||||
float rotateX = (angles.x > 180) ? angles.x - 360 : angles.x;
|
||||
float rotateY = (angles.y > 180) ? angles.y - 360 : angles.y;
|
||||
|
||||
// Debug.Log ("angles " + angles);
|
||||
// Debug.Log ("ratio " + (1.0f - (Mathf.Max (Mathf.Abs (rotateX), Mathf.Abs (rotateY)) / 90)));
|
||||
|
||||
return 1.0f - (Mathf.Max (Mathf.Abs (rotateX), Mathf.Abs (rotateY)) / 90);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract translation from transform matrix.
|
||||
/// </summary>
|
||||
/// <param name="matrix">Transform matrix. This parameter is passed by reference
|
||||
/// to improve performance; no changes will be made to it.</param>
|
||||
/// <returns>
|
||||
/// Translation offset.
|
||||
/// </returns>
|
||||
public static Vector3 ExtractTranslationFromMatrix (ref Matrix4x4 matrix)
|
||||
{
|
||||
Vector3 translate;
|
||||
translate.x = matrix.m03;
|
||||
translate.y = matrix.m13;
|
||||
translate.z = matrix.m23;
|
||||
return translate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract rotation quaternion from transform matrix.
|
||||
/// </summary>
|
||||
/// <param name="matrix">Transform matrix. This parameter is passed by reference
|
||||
/// to improve performance; no changes will be made to it.</param>
|
||||
/// <returns>
|
||||
/// Quaternion representation of rotation transform.
|
||||
/// </returns>
|
||||
public static Quaternion ExtractRotationFromMatrix (ref Matrix4x4 matrix)
|
||||
{
|
||||
Vector3 forward;
|
||||
forward.x = matrix.m02;
|
||||
forward.y = matrix.m12;
|
||||
forward.z = matrix.m22;
|
||||
|
||||
Vector3 upwards;
|
||||
upwards.x = matrix.m01;
|
||||
upwards.y = matrix.m11;
|
||||
upwards.z = matrix.m21;
|
||||
|
||||
return Quaternion.LookRotation (forward, upwards);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract scale from transform matrix.
|
||||
/// </summary>
|
||||
/// <param name="matrix">Transform matrix. This parameter is passed by reference
|
||||
/// to improve performance; no changes will be made to it.</param>
|
||||
/// <returns>
|
||||
/// Scale vector.
|
||||
/// </returns>
|
||||
public static Vector3 ExtractScaleFromMatrix (ref Matrix4x4 matrix)
|
||||
{
|
||||
Vector3 scale;
|
||||
scale.x = new Vector4 (matrix.m00, matrix.m10, matrix.m20, matrix.m30).magnitude;
|
||||
scale.y = new Vector4 (matrix.m01, matrix.m11, matrix.m21, matrix.m31).magnitude;
|
||||
scale.z = new Vector4 (matrix.m02, matrix.m12, matrix.m22, matrix.m32).magnitude;
|
||||
return scale;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extract position, rotation and scale from TRS matrix.
|
||||
/// </summary>
|
||||
/// <param name="matrix">Transform matrix. This parameter is passed by reference
|
||||
/// to improve performance; no changes will be made to it.</param>
|
||||
/// <param name="localPosition">Output position.</param>
|
||||
/// <param name="localRotation">Output rotation.</param>
|
||||
/// <param name="localScale">Output scale.</param>
|
||||
public static void DecomposeMatrix (ref Matrix4x4 matrix, out Vector3 localPosition, out Quaternion localRotation, out Vector3 localScale)
|
||||
{
|
||||
localPosition = ExtractTranslationFromMatrix (ref matrix);
|
||||
localRotation = ExtractRotationFromMatrix (ref matrix);
|
||||
localScale = ExtractScaleFromMatrix (ref matrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set transform component from TRS matrix.
|
||||
/// </summary>
|
||||
/// <param name="transform">Transform component.</param>
|
||||
/// <param name="matrix">Transform matrix. This parameter is passed by reference
|
||||
/// to improve performance; no changes will be made to it.</param>
|
||||
public static void SetTransformFromMatrix (Transform transform, ref Matrix4x4 matrix)
|
||||
{
|
||||
transform.localPosition = ExtractTranslationFromMatrix (ref matrix);
|
||||
transform.localRotation = ExtractRotationFromMatrix (ref matrix);
|
||||
transform.localScale = ExtractScaleFromMatrix (ref matrix);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9ca261b0c69717b40a4763cddf124abc
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,46 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
public class ObjExporter {
|
||||
|
||||
public static string MeshToString(MeshFilter mf) {
|
||||
Mesh m = mf.mesh;
|
||||
Material[] mats = mf.GetComponent<Renderer>().sharedMaterials;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("g ").Append(mf.name).Append("\n");
|
||||
foreach(Vector3 v in m.vertices) {
|
||||
sb.Append(string.Format("v {0} {1} {2}\n",v.x,v.y,v.z));
|
||||
}
|
||||
sb.Append("\n");
|
||||
foreach(Vector3 v in m.normals) {
|
||||
sb.Append(string.Format("vn {0} {1} {2}\n",v.x,v.y,v.z));
|
||||
}
|
||||
sb.Append("\n");
|
||||
foreach(Vector3 v in m.uv) {
|
||||
sb.Append(string.Format("vt {0} {1}\n",v.x,v.y));
|
||||
}
|
||||
for (int material=0; material < m.subMeshCount; material ++) {
|
||||
sb.Append("\n");
|
||||
sb.Append("usemtl ").Append(mats[material].name).Append("\n");
|
||||
sb.Append("usemap ").Append(mats[material].name).Append("\n");
|
||||
|
||||
int[] triangles = m.GetTriangles(material);
|
||||
for (int i=0;i<triangles.Length;i+=3) {
|
||||
sb.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n",
|
||||
triangles[i]+1, triangles[i+1]+1, triangles[i+2]+1));
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static void MeshToFile(MeshFilter mf, string filename) {
|
||||
using (StreamWriter sw = new StreamWriter(filename))
|
||||
{
|
||||
sw.Write(MeshToString(mf));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0f4a7800f23a22c4b8f18fbc172e95d1
|
||||
timeCreated: 1483013071
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,97 @@
|
|||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using OpenCVForUnity;
|
||||
using DlibFaceLandmarkDetector;
|
||||
|
||||
namespace FaceMaskSample
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility class for the integration of DlibFaceLandmarkDetector and OpenCVForUnity.
|
||||
/// </summary>
|
||||
public static class OpenCVForUnityUtils
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Sets the image.
|
||||
/// </summary>
|
||||
/// <param name="faceLandmarkDetector">Face landmark detector.</param>
|
||||
/// <param name="imgMat">Image mat.</param>
|
||||
public static void SetImage (FaceLandmarkDetector faceLandmarkDetector, Mat imgMat)
|
||||
{
|
||||
if (!imgMat.isContinuous ()) {
|
||||
throw new ArgumentException ("imgMat.isContinuous() must be true.");
|
||||
}
|
||||
faceLandmarkDetector.SetImage ((IntPtr)imgMat.dataAddr (), imgMat.width (), imgMat.height (), (int)imgMat.elemSize ());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the face rect.
|
||||
/// </summary>
|
||||
/// <param name="imgMat">Image mat.</param>
|
||||
/// <param name="rect">Rect.</param>
|
||||
/// <param name="color">Color.</param>
|
||||
/// <param name="thickness">Thickness.</param>
|
||||
public static void DrawFaceRect (Mat imgMat, UnityEngine.Rect rect, Scalar color, int thickness)
|
||||
{
|
||||
Imgproc.rectangle (imgMat, new Point (rect.xMin, rect.yMin), new Point (rect.xMax, rect.yMax), color, thickness);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the 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)
|
||||
{
|
||||
// //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 == 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);
|
||||
|
||||
for (int i = 28; i <= 30; ++i)
|
||||
Imgproc.line (imgMat, new Point (points [i].x, points [i].y), new Point (points [i - 1].x, points [i - 1].y), color, thickness);
|
||||
|
||||
for (int i = 18; i <= 21; ++i)
|
||||
Imgproc.line (imgMat, new Point (points [i].x, points [i].y), new Point (points [i - 1].x, points [i - 1].y), color, thickness);
|
||||
for (int i = 23; i <= 26; ++i)
|
||||
Imgproc.line (imgMat, new Point (points [i].x, points [i].y), new Point (points [i - 1].x, points [i - 1].y), color, thickness);
|
||||
for (int i = 31; i <= 35; ++i)
|
||||
Imgproc.line (imgMat, new Point (points [i].x, points [i].y), new Point (points [i - 1].x, points [i - 1].y), color, thickness);
|
||||
Imgproc.line (imgMat, new Point (points [30].x, points [30].y), new Point (points [35].x, points [35].y), color, thickness);
|
||||
|
||||
for (int i = 37; i <= 41; ++i)
|
||||
Imgproc.line (imgMat, new Point (points [i].x, points [i].y), new Point (points [i - 1].x, points [i - 1].y), color, thickness);
|
||||
Imgproc.line (imgMat, new Point (points [36].x, points [36].y), new Point (points [41].x, points [41].y), color, thickness);
|
||||
|
||||
for (int i = 43; i <= 47; ++i)
|
||||
Imgproc.line (imgMat, new Point (points [i].x, points [i].y), new Point (points [i - 1].x, points [i - 1].y), color, thickness);
|
||||
Imgproc.line (imgMat, new Point (points [42].x, points [42].y), new Point (points [47].x, points [47].y), color, thickness);
|
||||
|
||||
for (int i = 49; i <= 59; ++i)
|
||||
Imgproc.line (imgMat, new Point (points [i].x, points [i].y), new Point (points [i - 1].x, points [i - 1].y), color, thickness);
|
||||
Imgproc.line (imgMat, new Point (points [48].x, points [48].y), new Point (points [59].x, points [59].y), color, thickness);
|
||||
|
||||
for (int i = 61; i <= 67; ++i)
|
||||
Imgproc.line (imgMat, new Point (points [i].x, points [i].y), new Point (points [i - 1].x, points [i - 1].y), color, thickness);
|
||||
Imgproc.line (imgMat, new Point (points [60].x, points [60].y), new Point (points [67].x, points [67].y), color, thickness);
|
||||
} else {
|
||||
for (int i = 0; i < points.Count; i++) {
|
||||
Imgproc.circle (imgMat, new Point (points [i].x, points [i].y), 2, color, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c3854081962f5bd4586e18509191e82a
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,510 @@
|
|||
using OpenCVForUnity;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace FaceMaskSample
|
||||
{
|
||||
/// <summary>
|
||||
/// Web cam texture to mat helper.
|
||||
/// </summary>
|
||||
public class WebCamTextureToMatHelper : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the device.
|
||||
/// </summary>
|
||||
public string requestDeviceName = null;
|
||||
|
||||
/// <summary>
|
||||
/// The width.
|
||||
/// </summary>
|
||||
public int requestWidth = 640;
|
||||
|
||||
/// <summary>
|
||||
/// The height.
|
||||
/// </summary>
|
||||
public int requestHeight = 480;
|
||||
|
||||
/// <summary>
|
||||
/// Should use front facing.
|
||||
/// </summary>
|
||||
public bool requestIsFrontFacing = false;
|
||||
|
||||
/// <summary>
|
||||
/// The flip vertical.
|
||||
/// </summary>
|
||||
public bool flipVertical = false;
|
||||
|
||||
/// <summary>
|
||||
/// The flip horizontal.
|
||||
/// </summary>
|
||||
public bool flipHorizontal = false;
|
||||
|
||||
/// <summary>
|
||||
/// The timeout frame count.
|
||||
/// </summary>
|
||||
public int timeoutFrameCount = 300;
|
||||
|
||||
/// <summary>
|
||||
/// The on inited event.
|
||||
/// </summary>
|
||||
public UnityEvent OnInitedEvent;
|
||||
|
||||
/// <summary>
|
||||
/// The on disposed event.
|
||||
/// </summary>
|
||||
public UnityEvent OnDisposedEvent;
|
||||
|
||||
/// <summary>
|
||||
/// The on error occurred event.
|
||||
/// </summary>
|
||||
public ErrorUnityEvent OnErrorOccurredEvent;
|
||||
|
||||
/// <summary>
|
||||
/// The web cam texture.
|
||||
/// </summary>
|
||||
WebCamTexture webCamTexture;
|
||||
|
||||
/// <summary>
|
||||
/// The web cam device.
|
||||
/// </summary>
|
||||
WebCamDevice webCamDevice;
|
||||
|
||||
/// <summary>
|
||||
/// The rgba mat.
|
||||
/// </summary>
|
||||
Mat rgbaMat;
|
||||
|
||||
/// <summary>
|
||||
/// The rotated rgba mat
|
||||
/// </summary>
|
||||
Mat rotatedRgbaMat;
|
||||
|
||||
/// <summary>
|
||||
/// The colors.
|
||||
/// </summary>
|
||||
Color32[] colors;
|
||||
|
||||
/// <summary>
|
||||
/// The init waiting.
|
||||
/// </summary>
|
||||
bool initWaiting = false;
|
||||
|
||||
/// <summary>
|
||||
/// The init done.
|
||||
/// </summary>
|
||||
bool initDone = false;
|
||||
|
||||
/// <summary>
|
||||
/// The screenOrientation.
|
||||
/// </summary>
|
||||
ScreenOrientation screenOrientation = ScreenOrientation.Unknown;
|
||||
|
||||
[System.Serializable]
|
||||
public enum ErrorCode :int
|
||||
{
|
||||
CAMERA_DEVICE_NOT_EXIST = 0,
|
||||
TIMEOUT = 1,
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class ErrorUnityEvent : UnityEngine.Events.UnityEvent<ErrorCode>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update ()
|
||||
{
|
||||
if (initDone) {
|
||||
if (screenOrientation != Screen.orientation) {
|
||||
StartCoroutine (init ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init this instance.
|
||||
/// </summary>
|
||||
public void Init ()
|
||||
{
|
||||
if (initWaiting)
|
||||
return;
|
||||
|
||||
if (OnInitedEvent == null)
|
||||
OnInitedEvent = new UnityEvent ();
|
||||
if (OnDisposedEvent == null)
|
||||
OnDisposedEvent = new UnityEvent ();
|
||||
if (OnErrorOccurredEvent == null)
|
||||
OnErrorOccurredEvent = new ErrorUnityEvent ();
|
||||
|
||||
StartCoroutine (init ());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init this instance.
|
||||
/// </summary>
|
||||
/// <param name="deviceName">Device name.</param>
|
||||
/// <param name="requestWidth">Request width.</param>
|
||||
/// <param name="requestHeight">Request height.</param>
|
||||
/// <param name="requestIsFrontFacing">If set to <c>true</c> request is front facing.</param>
|
||||
/// <param name="OnInited">On inited.</param>
|
||||
public void Init (string deviceName, int requestWidth, int requestHeight, bool requestIsFrontFacing)
|
||||
{
|
||||
if (initWaiting)
|
||||
return;
|
||||
|
||||
this.requestDeviceName = deviceName;
|
||||
this.requestWidth = requestWidth;
|
||||
this.requestHeight = requestHeight;
|
||||
this.requestIsFrontFacing = requestIsFrontFacing;
|
||||
if (OnInitedEvent == null)
|
||||
OnInitedEvent = new UnityEvent ();
|
||||
if (OnDisposedEvent == null)
|
||||
OnDisposedEvent = new UnityEvent ();
|
||||
if (OnErrorOccurredEvent == null)
|
||||
OnErrorOccurredEvent = new ErrorUnityEvent ();
|
||||
|
||||
StartCoroutine (init ());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init this instance by coroutine.
|
||||
/// </summary>
|
||||
private IEnumerator init ()
|
||||
{
|
||||
if (initDone)
|
||||
dispose ();
|
||||
|
||||
initWaiting = true;
|
||||
|
||||
if (!String.IsNullOrEmpty (requestDeviceName)) {
|
||||
//Debug.Log ("deviceName is "+requestDeviceName);
|
||||
webCamTexture = new WebCamTexture (requestDeviceName, requestWidth, requestHeight);
|
||||
} else {
|
||||
//Debug.Log ("deviceName is null");
|
||||
// Checks how many and which cameras are available on the device
|
||||
for (int cameraIndex = 0; cameraIndex < WebCamTexture.devices.Length; cameraIndex++) {
|
||||
if (WebCamTexture.devices [cameraIndex].isFrontFacing == requestIsFrontFacing) {
|
||||
|
||||
//Debug.Log (cameraIndex + " name " + WebCamTexture.devices [cameraIndex].name + " isFrontFacing " + WebCamTexture.devices [cameraIndex].isFrontFacing);
|
||||
webCamDevice = WebCamTexture.devices [cameraIndex];
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestWidth, requestHeight);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (webCamTexture == null) {
|
||||
if (WebCamTexture.devices.Length > 0) {
|
||||
webCamDevice = WebCamTexture.devices [0];
|
||||
webCamTexture = new WebCamTexture (webCamDevice.name, requestWidth, requestHeight);
|
||||
} else {
|
||||
//Debug.Log("Camera device does not exist.");
|
||||
initWaiting = false;
|
||||
|
||||
if (OnErrorOccurredEvent != null)
|
||||
OnErrorOccurredEvent.Invoke (ErrorCode.CAMERA_DEVICE_NOT_EXIST);
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
||||
//Debug.Log ("name " + webCamTexture.name + " width " + webCamTexture.width + " height " + webCamTexture.height + " fps " + webCamTexture.requestedFPS);
|
||||
|
||||
// Starts the camera
|
||||
webCamTexture.Play ();
|
||||
|
||||
int initCount = 0;
|
||||
bool isTimeout = false;
|
||||
|
||||
while (true) {
|
||||
if (initCount > timeoutFrameCount) {
|
||||
isTimeout = true;
|
||||
break;
|
||||
}
|
||||
// If you want to use webcamTexture.width and webcamTexture.height on iOS, you have to wait until webcamTexture.didUpdateThisFrame == 1, otherwise these two values will be equal to 16. (http://forum.unity3d.com/threads/webcamtexture-and-error-0x0502.123922/)
|
||||
#if UNITY_IOS && !UNITY_EDITOR && (UNITY_4_6_3 || UNITY_4_6_4 || UNITY_5_0_0 || UNITY_5_0_1)
|
||||
else if (webCamTexture.width > 16 && webCamTexture.height > 16) {
|
||||
#else
|
||||
else if (webCamTexture.didUpdateThisFrame) {
|
||||
#if UNITY_IOS && !UNITY_EDITOR && UNITY_5_2
|
||||
while (webCamTexture.width <= 16) {
|
||||
if (initCount > timeoutFrameCount) {
|
||||
isTimeout = true;
|
||||
break;
|
||||
}else {
|
||||
initCount++;
|
||||
}
|
||||
webCamTexture.GetPixels32 ();
|
||||
yield return new WaitForEndOfFrame ();
|
||||
}
|
||||
if (isTimeout) break;
|
||||
#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);
|
||||
|
||||
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);
|
||||
|
||||
//Debug.Log ("Screen.orientation " + Screen.orientation);
|
||||
screenOrientation = Screen.orientation;
|
||||
|
||||
#if !UNITY_EDITOR && !(UNITY_STANDALONE || UNITY_WEBGL)
|
||||
if (screenOrientation == ScreenOrientation.Portrait || screenOrientation == ScreenOrientation.PortraitUpsideDown) {
|
||||
rotatedRgbaMat = new Mat (webCamTexture.width, webCamTexture.height, CvType.CV_8UC4);
|
||||
}
|
||||
#endif
|
||||
|
||||
initWaiting = false;
|
||||
initDone = true;
|
||||
|
||||
if (OnInitedEvent != null)
|
||||
OnInitedEvent.Invoke ();
|
||||
|
||||
break;
|
||||
} else {
|
||||
initCount++;
|
||||
yield return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (isTimeout) {
|
||||
//Debug.Log("Init time out.");
|
||||
webCamTexture.Stop ();
|
||||
webCamTexture = null;
|
||||
initWaiting = false;
|
||||
|
||||
if (OnErrorOccurredEvent != null)
|
||||
OnErrorOccurredEvent.Invoke (ErrorCode.TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ises the inited.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if inited was ised, <c>false</c> otherwise.</returns>
|
||||
public bool IsInited ()
|
||||
{
|
||||
return initDone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Play this instance.
|
||||
/// </summary>
|
||||
public void Play ()
|
||||
{
|
||||
if (initDone)
|
||||
webCamTexture.Play ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pause this instance.
|
||||
/// </summary>
|
||||
public void Pause ()
|
||||
{
|
||||
if (initDone)
|
||||
webCamTexture.Pause ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop this instance.
|
||||
/// </summary>
|
||||
public void Stop ()
|
||||
{
|
||||
if (initDone)
|
||||
webCamTexture.Stop ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ises the playing.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if playing was ised, <c>false</c> otherwise.</returns>
|
||||
public bool IsPlaying ()
|
||||
{
|
||||
if (!initDone)
|
||||
return false;
|
||||
return webCamTexture.isPlaying;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the web cam texture.
|
||||
/// </summary>
|
||||
/// <returns>The web cam texture.</returns>
|
||||
public WebCamTexture GetWebCamTexture ()
|
||||
{
|
||||
return (initDone) ? webCamTexture : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the web cam device.
|
||||
/// </summary>
|
||||
/// <returns>The web cam device.</returns>
|
||||
public WebCamDevice GetWebCamDevice ()
|
||||
{
|
||||
return webCamDevice;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dids the update this frame.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c>, if update this frame was dided, <c>false</c> otherwise.</returns>
|
||||
public bool DidUpdateThisFrame ()
|
||||
{
|
||||
if (!initDone)
|
||||
return false;
|
||||
|
||||
#if UNITY_IOS && !UNITY_EDITOR && (UNITY_4_6_3 || UNITY_4_6_4 || UNITY_5_0_0 || UNITY_5_0_1)
|
||||
if (webCamTexture.width > 16 && webCamTexture.height > 16) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return webCamTexture.didUpdateThisFrame;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mat.
|
||||
/// </summary>
|
||||
/// <returns>The mat.</returns>
|
||||
public Mat GetMat ()
|
||||
{
|
||||
if (!initDone || !webCamTexture.isPlaying) {
|
||||
if (rotatedRgbaMat != null) {
|
||||
return rotatedRgbaMat;
|
||||
} else {
|
||||
return rgbaMat;
|
||||
}
|
||||
}
|
||||
|
||||
Utils.webCamTextureToMat (webCamTexture, rgbaMat, colors);
|
||||
|
||||
if (rotatedRgbaMat != null) {
|
||||
|
||||
using (Mat transposeRgbaMat = rgbaMat.t ()) {
|
||||
Core.flip (transposeRgbaMat, rotatedRgbaMat, 1);
|
||||
}
|
||||
|
||||
flipMat (rotatedRgbaMat);
|
||||
|
||||
return rotatedRgbaMat;
|
||||
} else {
|
||||
|
||||
flipMat (rgbaMat);
|
||||
|
||||
return rgbaMat;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flips the mat.
|
||||
/// </summary>
|
||||
/// <param name="mat">Mat.</param>
|
||||
private void flipMat (Mat mat)
|
||||
{
|
||||
int flipCode = int.MinValue;
|
||||
|
||||
if (webCamDevice.isFrontFacing) {
|
||||
if (webCamTexture.videoRotationAngle == 0) {
|
||||
flipCode = 1;
|
||||
} else if (webCamTexture.videoRotationAngle == 90) {
|
||||
flipCode = 1;
|
||||
}
|
||||
if (webCamTexture.videoRotationAngle == 180) {
|
||||
flipCode = 0;
|
||||
} else if (webCamTexture.videoRotationAngle == 270) {
|
||||
flipCode = 0;
|
||||
}
|
||||
} else {
|
||||
if (webCamTexture.videoRotationAngle == 180) {
|
||||
flipCode = -1;
|
||||
} else if (webCamTexture.videoRotationAngle == 270) {
|
||||
flipCode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (flipVertical) {
|
||||
if (flipCode == int.MinValue) {
|
||||
flipCode = 0;
|
||||
} else if (flipCode == 0) {
|
||||
flipCode = int.MinValue;
|
||||
} else if (flipCode == 1) {
|
||||
flipCode = -1;
|
||||
} else if (flipCode == -1) {
|
||||
flipCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (flipHorizontal) {
|
||||
if (flipCode == int.MinValue) {
|
||||
flipCode = 1;
|
||||
} else if (flipCode == 0) {
|
||||
flipCode = -1;
|
||||
} else if (flipCode == 1) {
|
||||
flipCode = int.MinValue;
|
||||
} else if (flipCode == -1) {
|
||||
flipCode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (flipCode > int.MinValue) {
|
||||
Core.flip (mat, mat, flipCode);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the buffer colors.
|
||||
/// </summary>
|
||||
/// <returns>The buffer colors.</returns>
|
||||
public Color32[] GetBufferColors ()
|
||||
{
|
||||
return colors;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// To release the resources for the init method.
|
||||
/// </summary>
|
||||
private void dispose ()
|
||||
{
|
||||
initWaiting = false;
|
||||
initDone = false;
|
||||
|
||||
if (webCamTexture != null) {
|
||||
webCamTexture.Stop ();
|
||||
webCamTexture = null;
|
||||
}
|
||||
if (rgbaMat != null) {
|
||||
rgbaMat.Dispose ();
|
||||
rgbaMat = null;
|
||||
}
|
||||
if (rotatedRgbaMat != null) {
|
||||
rotatedRgbaMat.Dispose ();
|
||||
rotatedRgbaMat = null;
|
||||
}
|
||||
|
||||
if (OnDisposedEvent != null)
|
||||
OnDisposedEvent.Invoke ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases all resource used by the <see cref="WebCamTextureToMatHelper"/> object.
|
||||
/// </summary>
|
||||
/// <remarks>Call <see cref="Dispose"/> when you are finished using the <see cref="WebCamTextureToMatHelper"/>. The
|
||||
/// <see cref="Dispose"/> method leaves the <see cref="WebCamTextureToMatHelper"/> in an unusable state. After
|
||||
/// calling <see cref="Dispose"/>, you must release all references to the <see cref="WebCamTextureToMatHelper"/> so
|
||||
/// the garbage collector can reclaim the memory that the <see cref="WebCamTextureToMatHelper"/> was occupying.</remarks>
|
||||
public void Dispose ()
|
||||
{
|
||||
if (initDone)
|
||||
dispose ();
|
||||
|
||||
colors = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bafc15da02fe850489635791dda2bbdf
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,712 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using DlibFaceLandmarkDetector;
|
||||
using OpenCVForUnity;
|
||||
using OpenCVForUnity.RectangleTrack;
|
||||
using WebGLFileUploader;
|
||||
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
using UnityEngine.SceneManagement;
|
||||
#endif
|
||||
|
||||
namespace FaceMaskSample
|
||||
{
|
||||
/// <summary>
|
||||
/// Face Mask from VideoCapture Sample.
|
||||
/// </summary>
|
||||
public class VideoCaptureFaceMaskSample : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The width of the frame.
|
||||
/// </summary>
|
||||
private double frameWidth = 320;
|
||||
|
||||
/// <summary>
|
||||
/// The height of the frame.
|
||||
/// </summary>
|
||||
private double frameHeight = 240;
|
||||
|
||||
/// <summary>
|
||||
/// The capture.
|
||||
/// </summary>
|
||||
VideoCapture capture;
|
||||
|
||||
/// <summary>
|
||||
/// The rgb mat.
|
||||
/// </summary>
|
||||
Mat rgbMat;
|
||||
|
||||
/// <summary>
|
||||
/// The gray mat.
|
||||
/// </summary>
|
||||
Mat grayMat;
|
||||
|
||||
/// <summary>
|
||||
/// The texture.
|
||||
/// </summary>
|
||||
Texture2D texture;
|
||||
|
||||
/// <summary>
|
||||
/// The cascade.
|
||||
/// </summary>
|
||||
CascadeClassifier cascade;
|
||||
|
||||
/// <summary>
|
||||
/// The face landmark detector.
|
||||
/// </summary>
|
||||
FaceLandmarkDetector faceLandmarkDetector;
|
||||
|
||||
/// <summary>
|
||||
/// The detection based tracker.
|
||||
/// </summary>
|
||||
RectangleTracker rectangleTracker;
|
||||
|
||||
/// <summary>
|
||||
/// The frontal face parameter.
|
||||
/// </summary>
|
||||
FrontalFaceParam frontalFaceParam;
|
||||
|
||||
/// <summary>
|
||||
/// The is showing face rects.
|
||||
/// </summary>
|
||||
public bool isShowingFaceRects = false;
|
||||
|
||||
/// <summary>
|
||||
/// The is showing face rects toggle.
|
||||
/// </summary>
|
||||
public Toggle isShowingFaceRectsToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The use Dlib face detector flag.
|
||||
/// </summary>
|
||||
public bool useDlibFaceDetecter = true;
|
||||
|
||||
/// <summary>
|
||||
/// The use dlib face detecter toggle.
|
||||
/// </summary>
|
||||
public Toggle useDlibFaceDetecterToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The is filtering non frontal faces.
|
||||
/// </summary>
|
||||
public bool isFilteringNonFrontalFaces;
|
||||
|
||||
/// <summary>
|
||||
/// The is filtering non frontal faces toggle.
|
||||
/// </summary>
|
||||
public Toggle isFilteringNonFrontalFacesToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The frontal face rate lower limit.
|
||||
/// </summary>
|
||||
[Range (0.0f, 1.0f)]
|
||||
public float
|
||||
frontalFaceRateLowerLimit;
|
||||
|
||||
/// <summary>
|
||||
/// The is showing debug face points.
|
||||
/// </summary>
|
||||
public bool isShowingDebugFacePoints = false;
|
||||
|
||||
/// <summary>
|
||||
/// The is showing debug face points toggle.
|
||||
/// </summary>
|
||||
public Toggle isShowingDebugFacePointsToggle;
|
||||
|
||||
/// <summary>
|
||||
/// The is upload face mask button.
|
||||
/// </summary>
|
||||
public Button uploadFaceMaskButton;
|
||||
|
||||
/// <summary>
|
||||
/// The mesh overlay.
|
||||
/// </summary>
|
||||
private TrackedMeshOverlay meshOverlay;
|
||||
|
||||
/// <summary>
|
||||
/// The Shader.PropertyToID for "_Fade".
|
||||
/// </summary>
|
||||
private int shader_FadeID;
|
||||
|
||||
/// <summary>
|
||||
/// The face mask texture.
|
||||
/// </summary>
|
||||
private Texture2D faceMaskTexture;
|
||||
|
||||
/// <summary>
|
||||
/// The face mask mat.
|
||||
/// </summary>
|
||||
private Mat faceMaskMat;
|
||||
|
||||
/// <summary>
|
||||
/// The detected face rect in mask mat.
|
||||
/// </summary>
|
||||
private UnityEngine.Rect faceRectInMask;
|
||||
|
||||
/// <summary>
|
||||
/// The detected face landmark points in mask mat.
|
||||
/// </summary>
|
||||
private List<Vector2> faceLandmarkPointsInMask;
|
||||
|
||||
/// <summary>
|
||||
/// The haarcascade_frontalface_alt_xml_filepath.
|
||||
/// </summary>
|
||||
private string haarcascade_frontalface_alt_xml_filepath;
|
||||
|
||||
/// <summary>
|
||||
/// The shape_predictor_68_face_landmarks_dat_filepath.
|
||||
/// </summary>
|
||||
private string shape_predictor_68_face_landmarks_dat_filepath;
|
||||
|
||||
/// <summary>
|
||||
/// The couple_avi_filepath.
|
||||
/// </summary>
|
||||
private string couple_avi_filepath;
|
||||
|
||||
// Use this for initialization
|
||||
void Start ()
|
||||
{
|
||||
WebGLFileUploadManager.SetImageEncodeSetting (true);
|
||||
WebGLFileUploadManager.SetAllowedFileName ("\\.(png|jpe?g|gif)$");
|
||||
WebGLFileUploadManager.SetImageShrinkingSize (640, 480);
|
||||
WebGLFileUploadManager.FileUploadEventHandler += fileUploadHandler;
|
||||
|
||||
capture = new VideoCapture ();
|
||||
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
StartCoroutine(getFilePathCoroutine());
|
||||
#else
|
||||
haarcascade_frontalface_alt_xml_filepath = OpenCVForUnity.Utils.getFilePath ("haarcascade_frontalface_alt.xml");
|
||||
shape_predictor_68_face_landmarks_dat_filepath = DlibFaceLandmarkDetector.Utils.getFilePath ("shape_predictor_68_face_landmarks.dat");
|
||||
couple_avi_filepath = OpenCVForUnity.Utils.getFilePath ("dance.avi");
|
||||
Run ();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
private IEnumerator getFilePathCoroutine()
|
||||
{
|
||||
var getFilePathAsync_0_Coroutine = StartCoroutine (OpenCVForUnity.Utils.getFilePathAsync ("haarcascade_frontalface_alt.xml", (result) => {
|
||||
haarcascade_frontalface_alt_xml_filepath = result;
|
||||
}));
|
||||
var getFilePathAsync_1_Coroutine = StartCoroutine (DlibFaceLandmarkDetector.Utils.getFilePathAsync ("shape_predictor_68_face_landmarks.dat", (result) => {
|
||||
shape_predictor_68_face_landmarks_dat_filepath = result;
|
||||
}));
|
||||
var getFilePathAsync_2_Coroutine = StartCoroutine (OpenCVForUnity.Utils.getFilePathAsync ("dance.avi", (result) => {
|
||||
couple_avi_filepath = result;
|
||||
}));
|
||||
|
||||
yield return getFilePathAsync_0_Coroutine;
|
||||
yield return getFilePathAsync_1_Coroutine;
|
||||
yield return getFilePathAsync_2_Coroutine;
|
||||
|
||||
Run ();
|
||||
uploadFaceMaskButton.interactable = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
private void Run ()
|
||||
{
|
||||
meshOverlay = this.GetComponent<TrackedMeshOverlay> ();
|
||||
shader_FadeID = Shader.PropertyToID("_Fade");
|
||||
|
||||
rectangleTracker = new RectangleTracker ();
|
||||
|
||||
faceLandmarkDetector = new FaceLandmarkDetector (shape_predictor_68_face_landmarks_dat_filepath);
|
||||
|
||||
frontalFaceParam = new FrontalFaceParam ();
|
||||
|
||||
rgbMat = new Mat ();
|
||||
|
||||
capture.open (couple_avi_filepath);
|
||||
|
||||
if (capture.isOpened ()) {
|
||||
Debug.Log ("capture.isOpened() true");
|
||||
} else {
|
||||
Debug.Log ("capture.isOpened() false");
|
||||
}
|
||||
|
||||
|
||||
Debug.Log ("CAP_PROP_FORMAT: " + capture.get (Videoio.CAP_PROP_FORMAT));
|
||||
Debug.Log ("CV_CAP_PROP_PREVIEW_FORMAT: " + capture.get (Videoio.CV_CAP_PROP_PREVIEW_FORMAT));
|
||||
Debug.Log ("CAP_PROP_POS_MSEC: " + capture.get (Videoio.CAP_PROP_POS_MSEC));
|
||||
Debug.Log ("CAP_PROP_POS_FRAMES: " + capture.get (Videoio.CAP_PROP_POS_FRAMES));
|
||||
Debug.Log ("CAP_PROP_POS_AVI_RATIO: " + capture.get (Videoio.CAP_PROP_POS_AVI_RATIO));
|
||||
Debug.Log ("CAP_PROP_FRAME_COUNT: " + capture.get (Videoio.CAP_PROP_FRAME_COUNT));
|
||||
Debug.Log ("CAP_PROP_FPS: " + capture.get (Videoio.CAP_PROP_FPS));
|
||||
Debug.Log ("CAP_PROP_FRAME_WIDTH: " + capture.get (Videoio.CAP_PROP_FRAME_WIDTH));
|
||||
Debug.Log ("CAP_PROP_FRAME_HEIGHT: " + capture.get (Videoio.CAP_PROP_FRAME_HEIGHT));
|
||||
|
||||
|
||||
texture = new Texture2D ((int)(frameWidth), (int)(frameHeight), TextureFormat.RGBA32, 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;
|
||||
if (widthScale < heightScale) {
|
||||
Camera.main.orthographicSize = ((float)frameWidth * (float)Screen.height / (float)Screen.width) / 2;
|
||||
} else {
|
||||
Camera.main.orthographicSize = (float)frameHeight / 2;
|
||||
}
|
||||
|
||||
gameObject.GetComponent<Renderer> ().material.mainTexture = texture;
|
||||
|
||||
meshOverlay.UpdateOverlayTransform ();
|
||||
|
||||
|
||||
grayMat = new Mat ((int)frameHeight, (int)frameWidth, CvType.CV_8UC1);
|
||||
cascade = new CascadeClassifier (haarcascade_frontalface_alt_xml_filepath);
|
||||
if (cascade.empty ()) {
|
||||
Debug.LogError ("cascade file is not loaded.Please copy from “FaceTrackerSample/StreamingAssets/” to “Assets/StreamingAssets/” folder. ");
|
||||
}
|
||||
|
||||
isShowingFaceRectsToggle.isOn = isShowingFaceRects;
|
||||
useDlibFaceDetecterToggle.isOn = useDlibFaceDetecter;
|
||||
isFilteringNonFrontalFacesToggle.isOn = isFilteringNonFrontalFaces;
|
||||
isShowingDebugFacePointsToggle.isOn = isShowingDebugFacePoints;
|
||||
|
||||
OnChangeFaceMaskButton ();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update ()
|
||||
{
|
||||
//Loop play
|
||||
if (capture.get (Videoio.CAP_PROP_POS_FRAMES) >= capture.get (Videoio.CAP_PROP_FRAME_COUNT))
|
||||
capture.set (Videoio.CAP_PROP_POS_FRAMES, 0);
|
||||
|
||||
//error PlayerLoop called recursively! on iOS.reccomend WebCamTexture.
|
||||
if (capture.grab ()) {
|
||||
|
||||
capture.retrieve (rgbMat, 0);
|
||||
|
||||
Imgproc.cvtColor (rgbMat, rgbMat, Imgproc.COLOR_BGR2RGB);
|
||||
//Debug.Log ("Mat toString " + rgbMat.ToString ());
|
||||
|
||||
|
||||
//face detection.
|
||||
List<OpenCVForUnity.Rect> detectResult = new List<OpenCVForUnity.Rect> ();
|
||||
if (useDlibFaceDetecter) {
|
||||
OpenCVForUnityUtils.SetImage (faceLandmarkDetector, rgbMat);
|
||||
List<UnityEngine.Rect> result = faceLandmarkDetector.Detect ();
|
||||
|
||||
foreach (var unityRect in result) {
|
||||
detectResult.Add (new OpenCVForUnity.Rect ((int)unityRect.x, (int)unityRect.y, (int)unityRect.width, (int)unityRect.height));
|
||||
}
|
||||
} else {
|
||||
// convert image to greyscale.
|
||||
Imgproc.cvtColor (rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);
|
||||
|
||||
using (Mat equalizeHistMat = new Mat ())
|
||||
using (MatOfRect faces = new MatOfRect ()) {
|
||||
Imgproc.equalizeHist (grayMat, equalizeHistMat);
|
||||
|
||||
cascade.detectMultiScale (equalizeHistMat, faces, 1.1f, 2, 0 | Objdetect.CASCADE_SCALE_IMAGE, new OpenCVForUnity.Size (equalizeHistMat.cols () * 0.15, equalizeHistMat.cols () * 0.15), new Size ());
|
||||
|
||||
detectResult = faces.toList ();
|
||||
|
||||
// Adjust to Dilb's result.
|
||||
foreach (OpenCVForUnity.Rect r in detectResult) {
|
||||
r.y += (int)(r.height * 0.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// face traking.
|
||||
rectangleTracker.UpdateTrackedObjects (detectResult);
|
||||
List<TrackedRect> trackedRects = new List<TrackedRect> ();
|
||||
rectangleTracker.GetObjects (trackedRects, true);
|
||||
|
||||
// detect face landmark.
|
||||
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);
|
||||
landmarkPoints.Add (points);
|
||||
}
|
||||
|
||||
// face masking.
|
||||
if (faceMaskTexture != null && landmarkPoints.Count >= 1) {
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
|
||||
float offsetX = meshOverlay.Width / 2f;
|
||||
float offsetY = meshOverlay.Height / 2f;
|
||||
float maskImageWidth = faceMaskTexture.width;
|
||||
float maskImageHeight = faceMaskTexture.height;
|
||||
|
||||
TrackedRect tr;
|
||||
TrackedMesh tm;
|
||||
for (int i = 0; i < trackedRects.Count; i++) {
|
||||
tr = trackedRects [i];
|
||||
|
||||
if (tr.state == TrackedState.NEW) {
|
||||
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 - offsetX;
|
||||
vertices [j].y = offsetY - landmarkPoints [i] [j].y;
|
||||
}
|
||||
}
|
||||
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 nonfrontalface.
|
||||
if (isFilteringNonFrontalFaces && frontalFaceParam.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 offsetX = meshOverlay.Width / 2f;
|
||||
float offsetY = meshOverlay.Height / 2f;
|
||||
float maskImageWidth = texture.width;
|
||||
float maskImageHeight = texture.height;
|
||||
|
||||
TrackedRect tr;
|
||||
TrackedMesh tm;
|
||||
for (int i = 0; i < trackedRects.Count; i++) {
|
||||
tr = trackedRects [i];
|
||||
|
||||
if (tr.state == TrackedState.NEW) {
|
||||
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 - offsetX;
|
||||
vertices [j].y = offsetY - landmarkPoints[i][j].y;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// filter nonfrontalface.
|
||||
if (isFilteringNonFrontalFaces && frontalFaceParam.getFrontalFaceRate (landmarkPoints [i]) < frontalFaceRateLowerLimit) {
|
||||
tm.Material.SetFloat (shader_FadeID, 1f);
|
||||
}
|
||||
|
||||
} else if (tr.state == TrackedState.DELETED) {
|
||||
meshOverlay.DeleteObject (tr.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw face rects.
|
||||
if (isShowingFaceRects) {
|
||||
for (int i = 0; i < detectResult.Count; i++) {
|
||||
UnityEngine.Rect rect = new UnityEngine.Rect (detectResult [i].x, detectResult [i].y, detectResult [i].width, detectResult [i].height);
|
||||
OpenCVForUnityUtils.DrawFaceRect (rgbMat, rect, new Scalar (255, 0, 0, 255), 2);
|
||||
}
|
||||
|
||||
for (int i = 0; i < trackedRects.Count; i++) {
|
||||
UnityEngine.Rect rect = new UnityEngine.Rect (trackedRects [i].x, trackedRects [i].y, trackedRects [i].width, trackedRects [i].height);
|
||||
OpenCVForUnityUtils.DrawFaceRect (rgbMat, rect, new Scalar (255, 255, 0, 255), 2);
|
||||
//Imgproc.putText (rgbMat, " " + frontalFaceParam.getAngleOfFrontalFace (landmarkPoints [i]), new Point (rect.xMin, rect.yMin - 10), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 2, Imgproc.LINE_AA, false);
|
||||
//Imgproc.putText (rgbMat, " " + frontalFaceParam.getFrontalFaceRate (landmarkPoints [i]), new Point (rect.xMin, rect.yMin - 10), Core.FONT_HERSHEY_SIMPLEX, 0.5, new Scalar (255, 255, 255, 255), 2, Imgproc.LINE_AA, false);
|
||||
}
|
||||
}
|
||||
|
||||
// draw face points.
|
||||
if (isShowingDebugFacePoints) {
|
||||
for (int i = 0; i < landmarkPoints.Count; i++) {
|
||||
OpenCVForUnityUtils.DrawFaceLandmark (rgbMat, landmarkPoints [i], new Scalar (0, 255, 0, 255), 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// display face mask image.
|
||||
if (faceMaskTexture != null && faceMaskMat != null) {
|
||||
if (isShowingFaceRects) {
|
||||
OpenCVForUnityUtils.DrawFaceRect (faceMaskMat, faceRectInMask, new Scalar (255, 0, 0, 255), 2);
|
||||
}
|
||||
if (isShowingDebugFacePoints) {
|
||||
OpenCVForUnityUtils.DrawFaceLandmark (faceMaskMat, faceLandmarkPointsInMask, new Scalar (0, 255, 0, 255), 2);
|
||||
}
|
||||
|
||||
float scale = (rgbMat.width () / 4f) / faceMaskMat.width ();
|
||||
float tx = rgbMat.width () - faceMaskMat.width () * scale;
|
||||
float ty = 0.0f;
|
||||
Mat trans = new Mat (2, 3, CvType.CV_32F);//1.0, 0.0, tx, 0.0, 1.0, ty);
|
||||
trans.put (0, 0, scale);
|
||||
trans.put (0, 1, 0.0f);
|
||||
trans.put (0, 2, tx);
|
||||
trans.put (1, 0, 0.0f);
|
||||
trans.put (1, 1, scale);
|
||||
trans.put (1, 2, ty);
|
||||
|
||||
Imgproc.warpAffine (faceMaskMat, rgbMat, trans, rgbMat.size (), Imgproc.INTER_LINEAR, Core.BORDER_TRANSPARENT, new Scalar (0));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the disable event.
|
||||
/// </summary>
|
||||
void OnDestroy ()
|
||||
{
|
||||
WebGLFileUploadManager.FileUploadEventHandler -= fileUploadHandler;
|
||||
WebGLFileUploadManager.Dispose ();
|
||||
|
||||
capture.release ();
|
||||
|
||||
if (rgbMat != null)
|
||||
rgbMat.Dispose ();
|
||||
if (grayMat != null)
|
||||
grayMat.Dispose ();
|
||||
|
||||
if (rectangleTracker != null)
|
||||
rectangleTracker.Dispose ();
|
||||
|
||||
if (faceLandmarkDetector != null)
|
||||
faceLandmarkDetector.Dispose ();
|
||||
|
||||
if (frontalFaceParam != null)
|
||||
frontalFaceParam.Dispose ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the back button event.
|
||||
/// </summary>
|
||||
public void OnBackButton ()
|
||||
{
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
SceneManager.LoadScene ("FaceMaskSample");
|
||||
#else
|
||||
Application.LoadLevel ("FaceMaskSample");
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the is showing face rects toggle event.
|
||||
/// </summary>
|
||||
public void OnIsShowingFaceRectsToggle ()
|
||||
{
|
||||
if (isShowingFaceRectsToggle.isOn) {
|
||||
isShowingFaceRects = true;
|
||||
} else {
|
||||
isShowingFaceRects = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the use Dlib face detector toggle event.
|
||||
/// </summary>
|
||||
public void OnUseDlibFaceDetecterToggle ()
|
||||
{
|
||||
if (useDlibFaceDetecterToggle.isOn) {
|
||||
useDlibFaceDetecter = true;
|
||||
} else {
|
||||
useDlibFaceDetecter = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the is filtering non frontal faces toggle event.
|
||||
/// </summary>
|
||||
public void OnIsFilteringNonFrontalFacesToggle ()
|
||||
{
|
||||
if (isFilteringNonFrontalFacesToggle.isOn) {
|
||||
isFilteringNonFrontalFaces = true;
|
||||
} else {
|
||||
isFilteringNonFrontalFaces = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the is showing debug face points toggle event.
|
||||
/// </summary>
|
||||
public void OnIsShowingDebugFacePointsToggle ()
|
||||
{
|
||||
if (isShowingDebugFacePointsToggle.isOn) {
|
||||
isShowingDebugFacePoints = true;
|
||||
} else {
|
||||
isShowingDebugFacePoints = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the set face mask button event.
|
||||
/// </summary>
|
||||
public void OnChangeFaceMaskButton ()
|
||||
{
|
||||
removeFaceMask ();
|
||||
|
||||
SampleMaskData maskData = SampleDataSet.GetData();
|
||||
|
||||
faceMaskTexture = Resources.Load (maskData.FileName) as Texture2D;
|
||||
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{
|
||||
faceRectInMask = detectFace (faceMaskMat);
|
||||
faceLandmarkPointsInMask = detectFaceLandmarkPoints (faceMaskMat, faceRectInMask);
|
||||
}
|
||||
|
||||
SampleDataSet.Next();
|
||||
|
||||
if (faceRectInMask.width == 0 && faceRectInMask.height == 0){
|
||||
removeFaceMask ();
|
||||
Debug.Log ("A face could not be detected from the input image.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the upload face mask button event.
|
||||
/// </summary>
|
||||
public void OnUploadFaceMaskButton ()
|
||||
{
|
||||
WebGLFileUploadManager.PopupDialog (null, "Select frontal face image file (.png|.jpg|.gif)");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the remove face mask button event.
|
||||
/// </summary>
|
||||
public void OnRemoveFaceMaskButton ()
|
||||
{
|
||||
removeFaceMask ();
|
||||
}
|
||||
|
||||
private void removeFaceMask ()
|
||||
{
|
||||
faceMaskTexture = null;
|
||||
if (faceMaskMat != null) {
|
||||
faceMaskMat.Dispose ();
|
||||
faceMaskMat = null;
|
||||
}
|
||||
rectangleTracker.Reset ();
|
||||
meshOverlay.Reset ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Files the upload handler.
|
||||
/// </summary>
|
||||
/// <param name="result">Result.</param>
|
||||
private void fileUploadHandler (UploadedFileInfo[] result)
|
||||
{
|
||||
|
||||
if (result.Length == 0) {
|
||||
Debug.Log ("File upload Error!");
|
||||
return;
|
||||
}
|
||||
|
||||
removeFaceMask ();
|
||||
|
||||
foreach (UploadedFileInfo file in result) {
|
||||
if (file.isSuccess) {
|
||||
Debug.Log ("file.filePath: " + file.filePath + " exists:" + File.Exists (file.filePath));
|
||||
|
||||
faceMaskTexture = new Texture2D (2, 2);
|
||||
byte[] byteArray = File.ReadAllBytes (file.filePath);
|
||||
faceMaskTexture.LoadImage (byteArray);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (faceMaskTexture != null) {
|
||||
faceMaskMat = new Mat (faceMaskTexture.height, faceMaskTexture.width, CvType.CV_8UC3);
|
||||
OpenCVForUnity.Utils.texture2DToMat (faceMaskTexture, faceMaskMat);
|
||||
Debug.Log ("faceMaskMat ToString " + faceMaskMat.ToString ());
|
||||
faceRectInMask = detectFace (faceMaskMat);
|
||||
faceLandmarkPointsInMask = detectFaceLandmarkPoints (faceMaskMat, faceRectInMask);
|
||||
|
||||
if (faceRectInMask.width == 0 && faceRectInMask.height == 0){
|
||||
removeFaceMask ();
|
||||
Debug.Log ("A face could not be detected from the input image.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private UnityEngine.Rect detectFace (Mat mat)
|
||||
{
|
||||
if (useDlibFaceDetecter) {
|
||||
OpenCVForUnityUtils.SetImage (faceLandmarkDetector, mat);
|
||||
List<UnityEngine.Rect> result = faceLandmarkDetector.Detect ();
|
||||
if (result.Count >= 1)
|
||||
return result [0];
|
||||
} else {
|
||||
|
||||
using (Mat grayMat = new Mat ())
|
||||
using (Mat equalizeHistMat = new Mat ())
|
||||
using (MatOfRect faces = new MatOfRect ()) {
|
||||
// convert image to greyscale.
|
||||
Imgproc.cvtColor (mat, grayMat, Imgproc.COLOR_RGB2GRAY);
|
||||
Imgproc.equalizeHist (grayMat, equalizeHistMat);
|
||||
|
||||
cascade.detectMultiScale (equalizeHistMat, faces, 1.1f, 2, 0 | Objdetect.CASCADE_SCALE_IMAGE, new OpenCVForUnity.Size (equalizeHistMat.cols () * 0.15, equalizeHistMat.cols () * 0.15), new Size ());
|
||||
|
||||
List<OpenCVForUnity.Rect> faceList = faces.toList ();
|
||||
if (faceList.Count >= 1) {
|
||||
UnityEngine.Rect r = new UnityEngine.Rect (faceList [0].x, faceList [0].y, faceList [0].width, faceList [0].height);
|
||||
// Adjust to Dilb's result.
|
||||
r.y += (int)(r.height * 0.1f);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new UnityEngine.Rect ();
|
||||
}
|
||||
|
||||
private List<Vector2> detectFaceLandmarkPoints (Mat mat, UnityEngine.Rect rect)
|
||||
{
|
||||
OpenCVForUnityUtils.SetImage (faceLandmarkDetector, mat);
|
||||
List<Vector2> points = faceLandmarkDetector.DetectLandmark (rect);
|
||||
|
||||
return points;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a5cd7c2c97f800a46842b9454eb9f2f9
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 32541e47a39a06242ab093e9b213e99e
|
||||
timeCreated: 1481920838
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,26 @@
|
|||
FaceMask Sample
|
||||
====================
|
||||
|
||||
Overview
|
||||
-----
|
||||
<https://www.assetstore.unity3d.com/#!/content/79999>
|
||||
|
||||
Demo Video
|
||||
-----
|
||||
[![](http://img.youtube.com/vi/YNBz31vx15U/0.jpg)](https://www.youtube.com/watch?v=YNBz31vx15U)
|
||||
|
||||
Demo
|
||||
-----
|
||||
- WebGL
|
||||
<https://enoxsoftware.github.io/FaceMaskSample/webgl_sample/index.html>
|
||||
- WebGL(using shape_predictor_68_face_landmarks_for_mobile.dat)
|
||||
<https://enoxsoftware.github.io/FaceMaskSample/webgl_sample_for_mobile/index.html>
|
||||
- Android
|
||||
<https://play.google.com/store/apps/details?id=com.enoxsoftware.facemasksample>
|
||||
|
||||
Manual
|
||||
-----
|
||||
[ReadMe.pdf](/FaceMaskSample/ReadMe.pdf)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 058ff8aa85554aa4cbe51a95c5ed9ccb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b5b15518ef2238443905fff4839cfaec
|
||||
timeCreated: 1483051440
|
||||
licenseType: Free
|
||||
MovieImporter:
|
||||
serializedVersion: 1
|
||||
quality: .5
|
||||
linearTexture: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e5e282d2065baf7408f080371d55511f
|
||||
timeCreated: 1468559965
|
||||
licenseType: Store
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8104e65283de4d544acdad30db854ad2
|
||||
timeCreated: 1467795760
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f2131656efcef9a42af1c7ab2dcaf829
|
||||
folderAsset: yes
|
||||
timeCreated: 1478281627
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6786a1b68a0f46c47b9d4dbdea15e3ac
|
||||
folderAsset: yes
|
||||
timeCreated: 1478290721
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c552ab2acc359714380f21e2d83dc27e
|
||||
folderAsset: yes
|
||||
timeCreated: 1478290740
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,977 @@
|
|||
var LibraryFileUploadManager = {
|
||||
|
||||
$Unity_FileUploadManager: {
|
||||
detectOS:function(ua) {
|
||||
switch (true) {
|
||||
case /Android/.test(ua): return "Android";
|
||||
case /iPhone|iPad|iPod/.test(ua): return "iOS";
|
||||
case /Windows/.test(ua): return "Windows";
|
||||
case /Mac OS X/.test(ua): return "Mac";
|
||||
case /CrOS/.test(ua): return "Chrome OS";
|
||||
case /Firefox/.test(ua): return "Firefox OS";
|
||||
}
|
||||
return "";
|
||||
},
|
||||
|
||||
resample_hermite:function (img, W, H, W2, H2){
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = W2;
|
||||
canvas.height = H2;
|
||||
var ctx = canvas.getContext('2d');
|
||||
var img2 = ctx.createImageData(W2, H2);
|
||||
var data = img.data;
|
||||
var data2 = img2.data;
|
||||
var ratio_w = W / W2;
|
||||
var ratio_h = H / H2;
|
||||
var ratio_w_half = Math.ceil(ratio_w/2);
|
||||
var ratio_h_half = Math.ceil(ratio_h/2);
|
||||
for(var j = 0; j < H2; j++){
|
||||
for(var i = 0; i < W2; i++){
|
||||
var x2 = (i + j*W2) * 4;
|
||||
var weight = 0;
|
||||
var weights = 0;
|
||||
var gx_r = 0, gx_g = 0, gx_b = 0, gx_a = 0;
|
||||
var center_y = (j + 0.5) * ratio_h;
|
||||
for(var yy = Math.floor(j * ratio_h); yy < (j + 1) * ratio_h; yy++){
|
||||
var dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half;
|
||||
var center_x = (i + 0.5) * ratio_w;
|
||||
var w0 = dy*dy;
|
||||
for(var xx = Math.floor(i * ratio_w); xx < (i + 1) * ratio_w; xx++){
|
||||
var dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half;
|
||||
var w = Math.sqrt(w0 + dx*dx);
|
||||
if(w >= -1 && w <= 1){
|
||||
weight = 2 * w*w*w - 3*w*w + 1;
|
||||
if(weight > 0){
|
||||
dx = 4*(xx + yy*W);
|
||||
gx_r += weight * data[dx];
|
||||
gx_g += weight * data[dx + 1];
|
||||
gx_b += weight * data[dx + 2];
|
||||
gx_a += weight * data[dx + 3];
|
||||
weights += weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data2[x2] = gx_r / weights;
|
||||
data2[x2 + 1] = gx_g / weights;
|
||||
data2[x2 + 2] = gx_b / weights;
|
||||
data2[x2 + 3] = gx_a / weights;
|
||||
}
|
||||
}
|
||||
ctx.putImageData(img2, 0, 0);
|
||||
return canvas;
|
||||
},
|
||||
getOrientation:function (imgDataURL){
|
||||
var byteString = atob(imgDataURL.split(',')[1]);
|
||||
var orientaion = byteStringToOrientation(byteString);
|
||||
return orientaion;
|
||||
|
||||
function byteStringToOrientation(img){
|
||||
var head = 0;
|
||||
var orientation;
|
||||
while (1){
|
||||
if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 218) {break;}
|
||||
if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 216) {
|
||||
head += 2;
|
||||
}
|
||||
else {
|
||||
var length = img.charCodeAt(head + 2) * 256 + img.charCodeAt(head + 3);
|
||||
var endPoint = head + length + 2;
|
||||
if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 225) {
|
||||
var segment = img.slice(head, endPoint);
|
||||
var bigEndian = segment.charCodeAt(10) == 77;
|
||||
if (bigEndian) {
|
||||
var count = segment.charCodeAt(18) * 256 + segment.charCodeAt(19);
|
||||
} else {
|
||||
var count = segment.charCodeAt(18) + segment.charCodeAt(19) * 256;
|
||||
}
|
||||
for (var i=0;i<count;i++){
|
||||
var field = segment.slice(20 + 12 * i, 32 + 12 * i);
|
||||
if ((bigEndian && field.charCodeAt(1) == 18) || (!bigEndian && field.charCodeAt(0) == 18)) {
|
||||
orientation = bigEndian ? field.charCodeAt(9) : field.charCodeAt(8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
head = endPoint;
|
||||
}
|
||||
if (head > img.length){break;}
|
||||
}
|
||||
return orientation;
|
||||
}
|
||||
},
|
||||
detectSubsampling:function (img) {
|
||||
var iw = img.naturalWidth, ih = img.naturalHeight;
|
||||
if (iw * ih > 1024 * 1024) {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = canvas.height = 1;
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, -iw + 1, 0);
|
||||
return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
detectVerticalSquash:function (img, iw, ih) {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = 1;
|
||||
canvas.height = ih;
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, 0, 0);
|
||||
var data = ctx.getImageData(0, 0, 1, ih).data;
|
||||
var sy = 0;
|
||||
var ey = ih;
|
||||
var py = ih;
|
||||
while (py > sy) {
|
||||
var alpha = data[(py - 1) * 4 + 3];
|
||||
if (alpha === 0) {
|
||||
ey = py;
|
||||
} else {
|
||||
sy = py;
|
||||
}
|
||||
py = (ey + sy) >> 1;
|
||||
}
|
||||
var ratio = (py / ih);
|
||||
return (ratio===0)?1:ratio;
|
||||
},
|
||||
transformCoordinate:function (canvas, width, height, orientation) {
|
||||
if (orientation > 4) {
|
||||
canvas.width = height;
|
||||
canvas.height = width;
|
||||
} else {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
}
|
||||
var ctx = canvas.getContext('2d');
|
||||
switch (orientation) {
|
||||
case 2:
|
||||
// horizontal flip
|
||||
ctx.translate(width, 0);
|
||||
ctx.scale(-1, 1);
|
||||
break;
|
||||
case 3:
|
||||
// 180 rotate left
|
||||
ctx.translate(width, height);
|
||||
ctx.rotate(Math.PI);
|
||||
break;
|
||||
case 4:
|
||||
// vertical flip
|
||||
ctx.translate(0, height);
|
||||
ctx.scale(1, -1);
|
||||
break;
|
||||
case 5:
|
||||
// vertical flip + 90 rotate right
|
||||
ctx.rotate(0.5 * Math.PI);
|
||||
ctx.scale(1, -1);
|
||||
break;
|
||||
case 6:
|
||||
// 90 rotate right
|
||||
ctx.rotate(0.5 * Math.PI);
|
||||
ctx.translate(0, -height);
|
||||
break;
|
||||
case 7:
|
||||
// horizontal flip + 90 rotate right
|
||||
ctx.rotate(0.5 * Math.PI);
|
||||
ctx.translate(width, -height);
|
||||
ctx.scale(-1, 1);
|
||||
break;
|
||||
case 8:
|
||||
// 90 rotate left
|
||||
ctx.rotate(-0.5 * Math.PI);
|
||||
ctx.translate(-width, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
dataURLtoArrayBuffer:function (dataurl) {
|
||||
var bin = atob(dataurl.split("base64,")[1]);
|
||||
var len = bin.length;
|
||||
var barr = new Uint8Array(len);
|
||||
for (var i = 0; i < len; i++) {
|
||||
barr[i] = bin.charCodeAt(i);
|
||||
}
|
||||
return barr.buffer;
|
||||
},
|
||||
|
||||
isInitialized:false,
|
||||
isDebug:false,
|
||||
isDropInput:false,
|
||||
isOverlay:false,
|
||||
isPopupDialog:false,
|
||||
enableImageEncoding:true,
|
||||
imageEncodingThreshold:0,
|
||||
imageShrinkingSizeWidth:640,
|
||||
imageShrinkingSizeHeight:480,
|
||||
jsCallCsCallback:null,
|
||||
filenameRegStr:".*",
|
||||
descriptionStr:null,
|
||||
popupDialogCompleteFunc:null,
|
||||
ERROR_CODE:{
|
||||
NONE : 0,
|
||||
NOT_FOUND_ERR : 1,
|
||||
SECURITY_ERR : 2,
|
||||
ABORT_ERR : 3,
|
||||
NOT_READABLE_ERRF : 4,
|
||||
ENCODING_ERR : 5,
|
||||
IMG_LOAD_ERR : 6,
|
||||
FS_IO_ERR : 7,
|
||||
NOT_ALLOWED_FILENAME : 8,
|
||||
|
||||
},
|
||||
checkExistAPI:function() {
|
||||
return (!window.File || !window.FileReader || !window.Promise) ? false : true;
|
||||
},
|
||||
createRequiredHTML:function() {
|
||||
var fileUploaderElem = document.getElementById('file_uploader');
|
||||
if(fileUploaderElem == null){
|
||||
var canvas = document.getElementById('canvas');
|
||||
var fileUploaderElem = document.createElement('div');
|
||||
fileUploaderElem.id = 'file_uploader';
|
||||
canvas.parentNode.insertBefore(fileUploaderElem, canvas.nextSibling);
|
||||
}
|
||||
|
||||
var fileListElem = document.getElementById('file_uploader_file_list');
|
||||
if(fileListElem == null){
|
||||
var fileUploaderElem = document.getElementById('file_uploader');
|
||||
var fileListElem = document.createElement('div');
|
||||
fileListElem.id = 'file_uploader_file_list';
|
||||
fileUploaderElem.parentNode.insertBefore(fileListElem, fileUploaderElem.nextSibling);
|
||||
}
|
||||
},
|
||||
handleFileSelect:function (evt) {
|
||||
var files; // FileList object.
|
||||
if(Unity_FileUploadManager.isDropInput){
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
files = evt.dataTransfer.files;
|
||||
document.getElementById('file_drop_area').classList.remove('onDragOver');
|
||||
}else{
|
||||
files = evt.target.files;
|
||||
}
|
||||
|
||||
document.getElementById('file_uploader_file_list').innerHTML = '';
|
||||
|
||||
var dirpathStr = "fileuploader";
|
||||
var filenameReg = new RegExp(Unity_FileUploadManager.filenameRegStr, 'i');
|
||||
var imageFileTypeReg = new RegExp("image\/(png|jpeg|gif)$", 'i');
|
||||
|
||||
|
||||
// create data directory.
|
||||
try {
|
||||
var stat = FS.stat('/' + dirpathStr);
|
||||
} catch (e) {
|
||||
FS.mkdir('/' + dirpathStr);
|
||||
}
|
||||
|
||||
|
||||
function readImageFile(result) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
//if(Unity_FileUploadManager.isDebug) console.log("readImageFile: " + result.file.name);
|
||||
|
||||
var maxWidth = Unity_FileUploadManager.imageShrinkingSizeWidth;
|
||||
var maxHeight = Unity_FileUploadManager.imageShrinkingSizeHeight;
|
||||
var file = result.file;
|
||||
if (!file.type.match(/^image\/(png|jpeg|gif)$/)) return;
|
||||
var img = new Image();
|
||||
var reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
var data = e.target.result;
|
||||
|
||||
img.onload = function() {
|
||||
|
||||
var iw = img.naturalWidth, ih = img.naturalHeight;
|
||||
var width = iw, height = ih;
|
||||
|
||||
var orientation;
|
||||
|
||||
// In the case of JPEG, obtain Orientation (rotation) information from EXIF.
|
||||
if (data.split(',')[0].match('jpeg')) {
|
||||
orientation = Unity_FileUploadManager.getOrientation(data);
|
||||
}
|
||||
// If it is not JPEG or EXIF is not JPEG, set it to the standard value.
|
||||
orientation = orientation || 1;
|
||||
|
||||
// For example, rotate 90 degrees, if the aspect ratio changes, change the maximum width and height beforehand.
|
||||
if (orientation > 4) {
|
||||
var tmpMaxWidth = maxWidth;
|
||||
maxWidth = maxHeight;
|
||||
maxHeight = tmpMaxWidth;
|
||||
}
|
||||
|
||||
if(width > maxWidth || height > maxHeight) {
|
||||
var ratio = width/maxWidth;
|
||||
if(ratio <= height/maxHeight) {
|
||||
ratio = height/maxHeight;
|
||||
}
|
||||
width = Math.floor(img.width/ratio);
|
||||
height = Math.floor(img.height/ratio);
|
||||
}
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.save();
|
||||
|
||||
// Rotate Canvas from EXIF's Orientation information.
|
||||
Unity_FileUploadManager.transformCoordinate(canvas, width, height, orientation);
|
||||
|
||||
// Avoid iPhone subsampling problems.
|
||||
var subsampled = Unity_FileUploadManager.detectSubsampling(img);
|
||||
if (subsampled) {
|
||||
iw /= 2;
|
||||
ih /= 2;
|
||||
}
|
||||
var d = 1024; // size of tiling canvas
|
||||
var tmpCanvas = document.createElement('canvas');
|
||||
tmpCanvas.width = tmpCanvas.height = d;
|
||||
var tmpCtx = tmpCanvas.getContext('2d');
|
||||
var vertSquashRatio = Unity_FileUploadManager.detectVerticalSquash(img, iw, ih);
|
||||
var dw = Math.ceil(d * width / iw);
|
||||
var dh = Math.ceil(d * height / ih / vertSquashRatio);
|
||||
var sy = 0;
|
||||
var dy = 0;
|
||||
while (sy < ih) {
|
||||
var sx = 0;
|
||||
var dx = 0;
|
||||
while (sx < iw) {
|
||||
tmpCtx.clearRect(0, 0, d, d);
|
||||
tmpCtx.drawImage(img, -sx, -sy);
|
||||
var imageData = tmpCtx.getImageData(0, 0, d, d);
|
||||
var resampled = Unity_FileUploadManager.resample_hermite(imageData, d, d, dw, dh);
|
||||
ctx.drawImage(resampled, 0, 0, dw, dh, dx, dy, dw, dh);
|
||||
sx += d;
|
||||
dx += dw;
|
||||
}
|
||||
sy += d;
|
||||
dy += dh;
|
||||
}
|
||||
ctx.restore();
|
||||
tmpCanvas = tmpCtx = null;
|
||||
|
||||
//display new Image.
|
||||
var displaySrc = ctx.canvas.toDataURL('image/jpeg', .9);
|
||||
|
||||
/*
|
||||
var displayImg = document.createElement('img');
|
||||
displayImg.id = 'preview';
|
||||
displayImg.setAttribute('src', displaySrc);
|
||||
displayImg.setAttribute('alt', file.name);
|
||||
displayImg.setAttribute('style','max-width:90%;max-height:90%');
|
||||
document.getElementById('file_uploader_file_list').appendChild(displayImg);
|
||||
*/
|
||||
|
||||
// dataURL to ArrayBuffer.
|
||||
result.buf = Unity_FileUploadManager.dataURLtoArrayBuffer(displaySrc);
|
||||
result.name = result.file.name.match(/(.*)(?:\.([^.]+$))/)[1] + ".jpg";
|
||||
result.size = result.buf.byteLength;
|
||||
result.type = "image/jpeg";
|
||||
|
||||
resolve(writeFileToFS(result));
|
||||
}
|
||||
img.onerror = function () {
|
||||
result.errorCode = Unity_FileUploadManager.ERROR_CODE.IMG_LOAD_ERR;
|
||||
resolve(result);
|
||||
}
|
||||
img.src = data;
|
||||
}
|
||||
reader.onerror = function (event) {
|
||||
result.errorCode = reader.error.code;//Unity_FileUploadManager.ERROR_CODE1~5
|
||||
resolve(result);
|
||||
}
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
function readBinaryFile(result) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
//if(Unity_FileUploadManager.isDebug) console.log("readBinaryFile: " + result.file.name);
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (event) {
|
||||
result.buf = reader.result;
|
||||
resolve(writeFileToFS(result));
|
||||
}
|
||||
reader.onerror = function (event) {
|
||||
result.errorCode = reader.error.code;//Unity_FileUploadManager.ERROR_CODE1~5
|
||||
resolve(result);
|
||||
}
|
||||
|
||||
reader.readAsArrayBuffer(result.file);
|
||||
});
|
||||
}
|
||||
|
||||
function writeFileToFS(result) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
|
||||
//if(Unity_FileUploadManager.isDebug) console.log("writeFileToFS: " + result.name);
|
||||
|
||||
try {
|
||||
var filePath = '/' + dirpathStr + '/' + escape(result.name);
|
||||
var u8Arr = new Uint8Array(result.buf);
|
||||
var stream = FS.open(filePath, 'w+');
|
||||
FS.write(stream, u8Arr, 0, u8Arr.length, 0);
|
||||
FS.close(stream);
|
||||
|
||||
delete result.buf;
|
||||
delete u8arr;
|
||||
|
||||
//debug
|
||||
//var stat = FS.stat(filePath);
|
||||
//console.log(stat);
|
||||
//
|
||||
|
||||
result.filePath = filePath;
|
||||
result.isSuccess = true;
|
||||
resolve(result);
|
||||
} catch (e) {
|
||||
//if(Unity_FileUploadManager.isDebug) console.log("writeFileToFS: " + result.name + " " + e);
|
||||
|
||||
result.errorCode = Unity_FileUploadManager.ERROR_CODE.FS_IO_ERR;
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function callbackCS(results) {
|
||||
|
||||
var returnStr;
|
||||
if(results != null){
|
||||
var destFileArray = [];
|
||||
var len = results.length;
|
||||
for (var i=0; i<len; i++){
|
||||
var result = results[i];
|
||||
var file = result.file;
|
||||
var o = {"name":result.name, "type":result.type, "size":result.size, "lastModified":file.lastModified, "filePath":result.filePath, "isSuccess":result.isSuccess, "errorCode":result.errorCode};
|
||||
destFileArray.push(o);
|
||||
}
|
||||
|
||||
var object = {"files":destFileArray};
|
||||
var fileUploadDataJSON = JSON.stringify(object);
|
||||
|
||||
returnStr = fileUploadDataJSON;
|
||||
}else{
|
||||
returnStr = "";
|
||||
}
|
||||
|
||||
var buffer = _malloc(lengthBytesUTF8(returnStr) + 1);
|
||||
writeStringToMemory(returnStr, buffer);
|
||||
Runtime.dynCall('vi', Unity_FileUploadManager.jsCallCsCallback, [buffer]);
|
||||
_free(buffer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
_Unity_FileUploadManager_Disable();
|
||||
|
||||
var results = [];
|
||||
for (var i = 0, f; f = files[i]; i++) {
|
||||
results.push({"file":f, "name":f.name, "size":f.size, "type":f.type, "buf":null, "filePath":"", "isSuccess":false, "errorCode":Unity_FileUploadManager.ERROR_CODE.NONE});
|
||||
}
|
||||
|
||||
Promise.resolve()
|
||||
.then(function(){
|
||||
return Promise.all(results.map(function(result){
|
||||
return new Promise(function(resolve, reject){
|
||||
|
||||
//Allowed file name?
|
||||
if(filenameReg.test(result.file.name)){
|
||||
//Image File?
|
||||
if(Unity_FileUploadManager.enableImageEncoding && Unity_FileUploadManager.imageEncodingThreshold <= result.file.size && imageFileTypeReg.test(result.file.type)){
|
||||
resolve(readImageFile(result));
|
||||
}else{
|
||||
resolve(readBinaryFile(result));
|
||||
}
|
||||
}else{
|
||||
|
||||
result.errorCode = Unity_FileUploadManager.ERROR_CODE.NOT_ALLOWED_FILENAME;
|
||||
resolve(result);
|
||||
}
|
||||
|
||||
})
|
||||
}))
|
||||
})
|
||||
.then(function(results){
|
||||
|
||||
if(Unity_FileUploadManager.isDebug) Unity_FileUploadManager.outputFileList(results);
|
||||
callbackCS(results);
|
||||
_Unity_FileUploadManager_Enable();
|
||||
if(Unity_FileUploadManager.popupDialogCompleteFunc != null) Unity_FileUploadManager.popupDialogCompleteFunc();
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.log(err);
|
||||
|
||||
callbackCS(null);
|
||||
_Unity_FileUploadManager_Enable();
|
||||
if(Unity_FileUploadManager.popupDialogCompleteFunc != null) Unity_FileUploadManager.popupDialogCompleteFunc();
|
||||
});
|
||||
|
||||
},
|
||||
handleDragOver:function (evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
|
||||
|
||||
document.getElementById('file_drop_area').classList.add('onDragOver');
|
||||
},
|
||||
handleDragEnter:function (evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
},
|
||||
handleDragLeave:function (evt) {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
document.getElementById('file_drop_area').classList.remove('onDragOver');
|
||||
},
|
||||
outputFileList: function (results) {
|
||||
|
||||
var output = [];
|
||||
var len = results.length;
|
||||
for (var i=0; i<len; i++){
|
||||
var result = results[i];
|
||||
var f = result.file;
|
||||
|
||||
output.push('<li' , (result.isSuccess)?'':' style="color: #bbb"' , '>', escape(result.name), ' (', result.type || 'n/a', ') - ',
|
||||
result.size, ' bytes, last modified: ',
|
||||
f.lastModified, (result.isSuccess) ? ' filePath=' : ' errorCode=', (result.isSuccess) ? result.filePath : result.errorCode,'</li>');
|
||||
|
||||
console.log("result" + i + ": " + f.name + " " + f.size + " " + f.type + " " + f.lastModified + " / " + result.name + " " + result.size + " " + result.type + " " + result.isSuccess + " " + result.filePath + " " + result.errorCode);
|
||||
}
|
||||
document.getElementById('file_uploader_file_list').innerHTML += "<ul>" + output.join('') + "</ul>";
|
||||
}
|
||||
},
|
||||
Unity_FileUploadManager_IsInitialized: function()
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_IsInitialized()");
|
||||
return Unity_FileUploadManager.isInitialized;
|
||||
},
|
||||
Unity_FileUploadManager_InitFileUploader: function(isDropInput, isOverlay)
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_InitFileUploader()");
|
||||
|
||||
Unity_FileUploadManager.isDropInput = isDropInput;
|
||||
Unity_FileUploadManager.isOverlay = isOverlay;
|
||||
|
||||
|
||||
if(!Unity_FileUploadManager.checkExistAPI()) {
|
||||
console.log("Does not exist API necessary.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Unity_FileUploadManager.createRequiredHTML();
|
||||
var fileUploaderElem = document.getElementById('file_uploader');
|
||||
var fileListElem = document.getElementById('file_uploader_file_list');
|
||||
|
||||
|
||||
if(Unity_FileUploadManager.isDropInput){
|
||||
Unity_FileUploadManager.descriptionStr = "Drop files here";
|
||||
|
||||
fileUploaderElem.innerHTML = '<div id="file_drop_area">' + Unity_FileUploadManager.descriptionStr + '</div>';
|
||||
|
||||
var dropAreaElem = document.getElementById('file_drop_area');
|
||||
// Setup the dnd listeners.
|
||||
dropAreaElem.addEventListener('dragover', Unity_FileUploadManager.handleDragOver, false);
|
||||
dropAreaElem.addEventListener('drop', Unity_FileUploadManager.handleFileSelect, false);
|
||||
dropAreaElem.addEventListener('dragenter', Unity_FileUploadManager.handleDragEnter, false);
|
||||
dropAreaElem.addEventListener('dragleave', Unity_FileUploadManager.handleDragLeave, false);
|
||||
|
||||
fileUploaderElem.classList.add('isDropInput');
|
||||
}else{
|
||||
Unity_FileUploadManager.descriptionStr = "Select files";
|
||||
|
||||
var html = '<label for="file_input" id="file_input_button">' +
|
||||
' <div id="file_input_description">' + Unity_FileUploadManager.descriptionStr + '</div>' +
|
||||
' <input type="file" id="file_input" name="files[]" style="display:none;" multiple />' +
|
||||
'</label>';
|
||||
fileUploaderElem.innerHTML = html;
|
||||
|
||||
// Setup the input listeners.
|
||||
document.getElementById('file_input').addEventListener('change', Unity_FileUploadManager.handleFileSelect, false);
|
||||
|
||||
fileUploaderElem.classList.add('isButtonInput');
|
||||
}
|
||||
fileUploaderElem.classList.remove('hidden');
|
||||
|
||||
fileListElem.innerHTML = '';
|
||||
if(Unity_FileUploadManager.isDebug) {
|
||||
fileListElem.classList.remove('hidden');
|
||||
}else{
|
||||
fileListElem.classList.add('hidden');
|
||||
}
|
||||
|
||||
|
||||
var canvasElem = document.getElementById('canvas');
|
||||
if(isOverlay){
|
||||
|
||||
fileUploaderElem.style.setProperty("width", canvasElem.width + "px", "important");
|
||||
fileUploaderElem.style.setProperty("height", canvasElem.height + "px", "important");
|
||||
|
||||
fileUploaderElem.classList.add('overlay_canvas');
|
||||
|
||||
if(Unity_FileUploadManager.isDropInput){
|
||||
var dropAreaElem = document.getElementById('file_drop_area');
|
||||
dropAreaElem.classList.add('overlay');
|
||||
}else{
|
||||
var inputButtonElem = document.getElementById('file_input_button');
|
||||
inputButtonElem.classList.add('overlay');
|
||||
}
|
||||
}
|
||||
Unity_FileUploadManager.isInitialized = true;
|
||||
|
||||
return Unity_FileUploadManager.isInitialized;
|
||||
},
|
||||
|
||||
/*
|
||||
Unity_FileUploadManager_InitUGUIButton: function()
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_InitUGUIButton()");
|
||||
|
||||
Unity_FileUploadManager.isDropInput = false;
|
||||
Unity_FileUploadManager.isOverlay = false;
|
||||
|
||||
var fileInputElem = document.getElementById('file_input');
|
||||
|
||||
var e = document.createEvent("MouseEvents");
|
||||
e.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false,
|
||||
false, false, false, 0, null);
|
||||
fileInputElem.dispatchEvent(e);
|
||||
|
||||
return Unity_FileUploadManager.isInitialized;
|
||||
},
|
||||
*/
|
||||
|
||||
|
||||
Unity_FileUploadManager_PopupDialog: function(titleText, uploadBtnText, cancelBtnText)
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_PopupDialog()");
|
||||
|
||||
titleText = Pointer_stringify(titleText);
|
||||
uploadBtnText = Pointer_stringify(uploadBtnText);
|
||||
cancelBtnText = Pointer_stringify(cancelBtnText);
|
||||
|
||||
Unity_FileUploadManager.isDropInput = false;
|
||||
Unity_FileUploadManager.isPopupDialog = true;
|
||||
|
||||
if(!Unity_FileUploadManager.checkExistAPI()) {
|
||||
console.log("Does not exist API necessary.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Unity_FileUploadManager.createRequiredHTML();
|
||||
Unity_FileUploadManager.descriptionStr = "Select files";
|
||||
|
||||
var html = ' <div id="popup_dialog">' +
|
||||
' <div id="popup_dialog_title">Here is title</div>' +
|
||||
' <div id="popup_dialog_file_input_button_warp">' +
|
||||
' <label for="file_input" id="popup_dialog_file_input_button">' +
|
||||
' <div id="file_input_description">Select files</div>' +
|
||||
' <input type="file" id="file_input" name="files[]" style="display:none;" multiple />' +
|
||||
' </label>' +
|
||||
' </div>' +
|
||||
' <div id="popup_dialog_cancel_button_warp">' +
|
||||
' <input id="popup_dialog_cancel_button" type="button" value="Cancel">' +
|
||||
' </div>' +
|
||||
'</div>';
|
||||
|
||||
var popup_dialog_warpElem = document.getElementById('popup_dialog_warp');
|
||||
if(popup_dialog_warpElem == null){
|
||||
popup_dialog_warpElem = document.createElement('div');
|
||||
popup_dialog_warpElem.id = 'popup_dialog_warp';
|
||||
document.body.appendChild( popup_dialog_warpElem );
|
||||
}
|
||||
popup_dialog_warpElem.innerHTML = html;
|
||||
popup_dialog_warpElem.style.display = "";
|
||||
|
||||
Unity_FileUploadManager.popupDialogCompleteFunc = function (){
|
||||
document.getElementById("canvas").style.display="";
|
||||
_Unity_FileUploadManager_Dispose();
|
||||
};
|
||||
|
||||
|
||||
// Setup the input listeners.
|
||||
var fileInputElem = document.getElementById('file_input');
|
||||
fileInputElem.addEventListener('change', (function(e) {
|
||||
return function f(e) {
|
||||
fileInputElem.removeEventListener('change', f, false);
|
||||
document.getElementById("popup_dialog_file_input_button_warp").style.display = "none";
|
||||
document.getElementById("popup_dialog_cancel_button_warp").style.display = "none";
|
||||
document.getElementById("popup_dialog_title").innerHTML = 'Now Loading...';
|
||||
Unity_FileUploadManager.handleFileSelect(e);
|
||||
}
|
||||
})(1), false);
|
||||
|
||||
|
||||
var cancelBtn = document.getElementById("popup_dialog_cancel_button");
|
||||
cancelBtn.addEventListener('click', (function(x) {
|
||||
return function f() {
|
||||
cancelBtn.removeEventListener('click', f, false);
|
||||
Unity_FileUploadManager.popupDialogCompleteFunc();
|
||||
}
|
||||
})(1), false);
|
||||
|
||||
document.getElementById("popup_dialog_title").innerText = (titleText != '') ? titleText : 'File Uploader';
|
||||
document.getElementById("file_input_description").innerText = (uploadBtnText != '') ? uploadBtnText : Unity_FileUploadManager.descriptionStr;
|
||||
document.getElementById("popup_dialog_cancel_button").value = (cancelBtnText != '') ? cancelBtnText : 'Cancel';
|
||||
|
||||
Unity_FileUploadManager.isInitialized = true;
|
||||
|
||||
return Unity_FileUploadManager.isInitialized;
|
||||
},
|
||||
Unity_FileUploadManager_HideUnityScreenIfHtmlOverlayCant: function(){
|
||||
if( navigator.userAgent.indexOf("Chrome/") < 0 ){
|
||||
document.getElementById("canvas").style.display="none";
|
||||
}
|
||||
},
|
||||
Unity_FileUploadManager_IsRunningOnEdgeBrowser: function(){
|
||||
if( navigator.userAgent.indexOf("Edge/") < 0 ){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
Unity_FileUploadManager_Dispose: function()
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_Dispose()");
|
||||
|
||||
|
||||
var fileUploaderElem = document.getElementById('file_uploader');
|
||||
|
||||
if(Unity_FileUploadManager.isOverlay){
|
||||
fileUploaderElem.style.removeProperty("width");
|
||||
fileUploaderElem.style.removeProperty("height");
|
||||
fileUploaderElem.classList.remove('overlay_canvas');
|
||||
}
|
||||
|
||||
|
||||
if(Unity_FileUploadManager.isDropInput){
|
||||
var dropAreaElem = document.getElementById('file_drop_area');
|
||||
// Remove the dnd listeners.
|
||||
dropAreaElem.removeEventListener('dragover', Unity_FileUploadManager.handleDragOver, false);
|
||||
dropAreaElem.removeEventListener('drop', Unity_FileUploadManager.handleFileSelect, false);
|
||||
dropAreaElem.removeEventListener('dragenter', Unity_FileUploadManager.handleDragEnter, false);
|
||||
dropAreaElem.removeEventListener('dragleave', Unity_FileUploadManager.handleDragLeave, false);
|
||||
|
||||
fileUploaderElem.innerHTML = '';
|
||||
fileUploaderElem.classList.remove('isDropInput');
|
||||
}else{
|
||||
// Remove the input listeners.
|
||||
document.getElementById('file_input').removeEventListener('change', Unity_FileUploadManager.handleFileSelect, false);
|
||||
|
||||
fileUploaderElem.innerHTML = '';
|
||||
fileUploaderElem.classList.remove('isButtonInput');
|
||||
}
|
||||
fileUploaderElem.classList.add('hidden');
|
||||
|
||||
var fileListElem = document.getElementById('file_uploader_file_list');
|
||||
fileListElem.innerHTML = '';
|
||||
fileListElem.classList.add('hidden');
|
||||
|
||||
|
||||
if(Unity_FileUploadManager.isPopupDialog){
|
||||
Unity_FileUploadManager.popupDialogCompleteFunc = null;
|
||||
document.getElementById("popup_dialog_warp").style.display = "none";
|
||||
document.getElementById('popup_dialog_warp').innerHTML = '';
|
||||
}
|
||||
|
||||
|
||||
Unity_FileUploadManager.jsCallCsCallback = null;
|
||||
|
||||
Unity_FileUploadManager.isInitialized = false;
|
||||
Unity_FileUploadManager.isDropInput = false;
|
||||
Unity_FileUploadManager.isOverlay = false;
|
||||
Unity_FileUploadManager.isPopupDialog = false;
|
||||
},
|
||||
Unity_FileUploadManager_SetCallback: function(callback)
|
||||
{
|
||||
//console.log("Unity_FileUploadManager_SetCallback()");
|
||||
Unity_FileUploadManager.jsCallCsCallback = callback;
|
||||
},
|
||||
Unity_FileUploadManager_IsDropInput: function()
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_IsDropInput()");
|
||||
return Unity_FileUploadManager.isDropInput;
|
||||
},
|
||||
Unity_FileUploadManager_IsOverlay: function()
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_IsOverlay()");
|
||||
return Unity_FileUploadManager.isOverlay;
|
||||
},
|
||||
Unity_FileUploadManager_IsPopupDialog: function()
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_IsPopupDialog()");
|
||||
return Unity_FileUploadManager.isPopupDialog;
|
||||
},
|
||||
Unity_FileUploadManager_SetDebug: function(value)
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_IsDebug()");
|
||||
Unity_FileUploadManager.isDebug = value;
|
||||
|
||||
var fileListElem = document.getElementById('file_uploader_file_list');
|
||||
if(fileListElem != null){
|
||||
if(Unity_FileUploadManager.isDebug) {
|
||||
fileListElem.classList.remove('hidden');
|
||||
}else{
|
||||
fileListElem.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
},
|
||||
Unity_FileUploadManager_SetDescription: function(descriptionStr)
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_SetDescription()");
|
||||
|
||||
var descriptionStr = Pointer_stringify(descriptionStr);
|
||||
if(Unity_FileUploadManager.isDropInput){
|
||||
if(descriptionStr == "") descriptionStr = "Drop files here";
|
||||
var fileDropArea = document.getElementById('file_drop_area');
|
||||
if(fileDropArea) fileDropArea.textContent = descriptionStr;
|
||||
}else{
|
||||
if(descriptionStr == "") descriptionStr = "Select files";
|
||||
var fileInputDescripton = document.getElementById('file_input_description');
|
||||
if(fileInputDescripton) fileInputDescripton.innerHTML = descriptionStr;
|
||||
}
|
||||
Unity_FileUploadManager.descriptionStr = descriptionStr;
|
||||
},
|
||||
Unity_FileUploadManager_SetAllowedFileName: function(filenameRegStr)
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_SetAllowedFileName()");
|
||||
|
||||
var filenameRegStr = Pointer_stringify(filenameRegStr);
|
||||
if(filenameRegStr == "") filenameRegStr = ".*";
|
||||
Unity_FileUploadManager.filenameRegStr = filenameRegStr;
|
||||
},
|
||||
Unity_FileUploadManager_SetImageEncodeSetting: function(enable, threshold)
|
||||
{
|
||||
Unity_FileUploadManager.enableImageEncoding = enable;
|
||||
if(threshold >= 0) Unity_FileUploadManager.imageEncodingThreshold = threshold;
|
||||
},
|
||||
Unity_FileUploadManager_SetImageShrinkingSize: function(width, height)
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_SetImageShrinkingSize()");
|
||||
|
||||
Unity_FileUploadManager.imageShrinkingSizeWidth = width>0 ? width : 1;
|
||||
Unity_FileUploadManager.imageShrinkingSizeHeight = height>0 ? height : 1;
|
||||
},
|
||||
Unity_FileUploadManager_SetInputArea: function(x, y, width, height)
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_SetInputArea()");
|
||||
|
||||
if(Unity_FileUploadManager.isPopupDialog) return;
|
||||
|
||||
var targetElem;
|
||||
if(Unity_FileUploadManager.isDropInput){
|
||||
targetElem = document.getElementById('file_drop_area');
|
||||
}else{
|
||||
targetElem = document.getElementById('file_input_button');
|
||||
}
|
||||
|
||||
if(x < 0 || y < 0 || width < 0 || height < 0){
|
||||
targetElem.style.top = '';
|
||||
targetElem.style.left = '';
|
||||
targetElem.style.width = '';
|
||||
targetElem.style.height = '';
|
||||
targetElem.style.lineHeight = '';
|
||||
}else{
|
||||
targetElem.style.top = x + 'px';
|
||||
targetElem.style.left = y + 'px';
|
||||
targetElem.style.width = width + 'px';
|
||||
targetElem.style.height = height + 'px';
|
||||
targetElem.style.lineHeight = height + 'px';
|
||||
}
|
||||
},
|
||||
Unity_FileUploadManager_Show: function()
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_Show()");
|
||||
|
||||
var fileUploaderElem = document.getElementById('file_uploader');
|
||||
fileUploaderElem.classList.remove('hidden');
|
||||
|
||||
var fileListElem = document.getElementById('file_uploader_file_list');
|
||||
if(Unity_FileUploadManager.isDebug) fileListElem.classList.remove('hidden');
|
||||
},
|
||||
Unity_FileUploadManager_Hide: function()
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_Hide()");
|
||||
|
||||
var fileUploaderElem = document.getElementById('file_uploader');
|
||||
fileUploaderElem.classList.add('hidden');
|
||||
|
||||
var fileListElem = document.getElementById('file_uploader_file_list');
|
||||
fileListElem.classList.add('hidden');
|
||||
},
|
||||
Unity_FileUploadManager_Enable: function()
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_Enable()");
|
||||
|
||||
if(Unity_FileUploadManager.isDropInput){
|
||||
var fileDropArea = document.getElementById('file_drop_area');
|
||||
if(fileDropArea) fileDropArea.classList.remove('disable');
|
||||
}else{
|
||||
var fileInputButton = document.getElementById('file_input_button');
|
||||
if(fileInputButton) fileInputButton.classList.remove('disable');
|
||||
}
|
||||
},
|
||||
Unity_FileUploadManager_Disable: function()
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_Disable()");
|
||||
|
||||
if(Unity_FileUploadManager.isDropInput){
|
||||
var fileDropArea = document.getElementById('file_drop_area');
|
||||
if(fileDropArea) fileDropArea.classList.add('disable');
|
||||
}else{
|
||||
var fileInputButton = document.getElementById('file_input_button');
|
||||
if(fileInputButton) fileInputButton.classList.add('disable');
|
||||
}
|
||||
},
|
||||
Unity_FileUploadManager_Click: function()
|
||||
{
|
||||
if(Unity_FileUploadManager.isDebug) console.log("Unity_FileUploadManager_Click()");
|
||||
|
||||
if(!Unity_FileUploadManager.isDropInput){
|
||||
var fileInputElem = document.getElementById('file_input');
|
||||
|
||||
console.log(fileInputElem);
|
||||
|
||||
var e = document.createEvent("MouseEvents");
|
||||
e.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false,
|
||||
false, false, false, 0, null);
|
||||
fileInputElem.dispatchEvent(e);
|
||||
}
|
||||
|
||||
|
||||
var foobarElem = document.getElementById('foobar');
|
||||
var e = document.createEvent("MouseEvents");
|
||||
e.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false,
|
||||
false, false, false, 0, null);
|
||||
foobarElem.dispatchEvent(e);
|
||||
|
||||
|
||||
|
||||
},
|
||||
Unity_FileUploadManager_GetOS: function()
|
||||
{
|
||||
var returnStr = Unity_FileUploadManager.detectOS(navigator.userAgent);
|
||||
var buffer = _malloc(lengthBytesUTF8(returnStr) + 1);
|
||||
writeStringToMemory(returnStr, buffer);
|
||||
return buffer;
|
||||
},
|
||||
Unity_FileUploadManager_IsMobile: function()
|
||||
{
|
||||
var ua = navigator.userAgent;
|
||||
var os = Unity_FileUploadManager.detectOS(ua);
|
||||
return (/Android|iOS/.test(os) || /Windows Phone/.test(ua));
|
||||
},
|
||||
Unity_FileUploadManager_GetUserAgent: function()
|
||||
{
|
||||
var returnStr = navigator.userAgent;
|
||||
var buffer = _malloc(lengthBytesUTF8(returnStr) + 1);
|
||||
writeStringToMemory(returnStr, buffer);
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
autoAddDeps(LibraryFileUploadManager, '$Unity_FileUploadManager');
|
||||
autoAddDeps(LibraryFileUploadManager, 'Unity_FileUploadManager_Dispose');
|
||||
autoAddDeps(LibraryFileUploadManager, 'Unity_FileUploadManager_Enable');
|
||||
autoAddDeps(LibraryFileUploadManager, 'Unity_FileUploadManager_Disable');
|
||||
|
||||
mergeInto(LibraryManager.library, LibraryFileUploadManager);
|
|
@ -0,0 +1,49 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8067a755102339c4a894c0498d066b8f
|
||||
timeCreated: 1478295301
|
||||
licenseType: Free
|
||||
PluginImporter:
|
||||
serializedVersion: 1
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
isPreloaded: 0
|
||||
platformData:
|
||||
Any:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
Editor:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
DefaultValueInitialized: true
|
||||
OS: AnyOS
|
||||
Linux:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: x86
|
||||
Linux64:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: x86_64
|
||||
OSXIntel:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
OSXIntel64:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
WebGL:
|
||||
enabled: 1
|
||||
settings: {}
|
||||
Win:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
Win64:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ff9a23be45dc9bd46b5beb6fbcd1ca8c
|
||||
folderAsset: yes
|
||||
timeCreated: 1478290818
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ad142859d38701141b769da33e91b16b
|
||||
folderAsset: yes
|
||||
timeCreated: 1478445263
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,108 @@
|
|||
using System.Collections;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using WebGLFileUploader;
|
||||
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
using UnityEngine.SceneManagement;
|
||||
#endif
|
||||
|
||||
namespace WebGLFileUploaderSample
|
||||
{
|
||||
/// <summary>
|
||||
/// File Upload sample.
|
||||
/// </summary>
|
||||
public class FileUploadSample : MonoBehaviour
|
||||
{
|
||||
|
||||
// Use this for initialization
|
||||
void Start ()
|
||||
{
|
||||
|
||||
Debug.Log("WebGLFileUploadManager.getOS: " + WebGLFileUploadManager.getOS);
|
||||
Debug.Log("WebGLFileUploadManager.isMOBILE: " + WebGLFileUploadManager.IsMOBILE);
|
||||
Debug.Log("WebGLFileUploadManager.getUserAgent: " + WebGLFileUploadManager.GetUserAgent);
|
||||
|
||||
WebGLFileUploadManager.SetDebug(true);
|
||||
if (
|
||||
#if UNITY_WEBGL && !UNITY_EDITOR
|
||||
WebGLFileUploadManager.IsMOBILE
|
||||
#else
|
||||
Application.isMobilePlatform
|
||||
#endif
|
||||
) {
|
||||
if(!WebGLFileUploadManager.IsInitialized) WebGLFileUploadManager.InitFileUploader (false);
|
||||
WebGLFileUploadManager.SetDescription("Select image files (.png|.jpg|.gif)");
|
||||
|
||||
}else{
|
||||
if(!WebGLFileUploadManager.IsInitialized) WebGLFileUploadManager.InitFileUploader (true);
|
||||
WebGLFileUploadManager.SetDescription("Drop image files (.png|.jpg|.gif) here");
|
||||
}
|
||||
WebGLFileUploadManager.SetImageEncodeSetting(true);
|
||||
WebGLFileUploadManager.SetAllowedFileName("\\.(png|jpe?g|gif)$");
|
||||
WebGLFileUploadManager.SetImageShrinkingSize(1280 ,960);
|
||||
WebGLFileUploadManager.FileUploadEventHandler += fileUploadHandler;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void OnDestroy ()
|
||||
{
|
||||
WebGLFileUploadManager.FileUploadEventHandler -= fileUploadHandler;
|
||||
WebGLFileUploadManager.Dispose();
|
||||
}
|
||||
|
||||
private void fileUploadHandler(UploadedFileInfo[] result){
|
||||
|
||||
if(result.Length == 0) {
|
||||
Debug.Log("File upload Error!");
|
||||
}else{
|
||||
Debug.Log("File upload success! (result.Length: " + result.Length + ")");
|
||||
}
|
||||
|
||||
foreach(UploadedFileInfo file in result){
|
||||
if(file.isSuccess){
|
||||
Debug.Log("file.filePath: " + file.filePath + " exists:" + File.Exists(file.filePath));
|
||||
|
||||
Texture2D texture = new Texture2D (2, 2);
|
||||
byte[] byteArray = File.ReadAllBytes (file.filePath);
|
||||
texture.LoadImage (byteArray);
|
||||
gameObject.GetComponent<Renderer> ().material.mainTexture = texture;
|
||||
|
||||
Debug.Log("File.ReadAllBytes:byte[].Length: " + byteArray.Length);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBackButton ()
|
||||
{
|
||||
#if UNITY_5_3 || UNITY_5_3_OR_NEWER
|
||||
SceneManager.LoadScene ("WebGLFileUploaderSample");
|
||||
#else
|
||||
Application.LoadLevel ("WebGLFileUploaderSample");
|
||||
#endif
|
||||
}
|
||||
|
||||
public void OnButtonOverlayToggleButton ()
|
||||
{
|
||||
WebGLFileUploadManager.InitFileUploader(false, !WebGLFileUploadManager.IsOverlay);
|
||||
}
|
||||
|
||||
public void OnDropOverlayToggleButton ()
|
||||
{
|
||||
WebGLFileUploadManager.InitFileUploader(true, !WebGLFileUploadManager.IsOverlay);
|
||||
}
|
||||
|
||||
public void OnPopupDialogButton ()
|
||||
{
|
||||
WebGLFileUploadManager.PopupDialog(null, "Select image files (.png|.jpg|.gif)");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 74c8910a0e9ba4246b45db5c8e0600cc
|
||||
timeCreated: 1478290954
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 994ec4107af5eac48b07baa79707593e
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|