158 lines
5.1 KiB
C#
158 lines
5.1 KiB
C#
using System;
|
|
using UnityEngine;
|
|
using UI = UnityEngine.UI;
|
|
using Klak.TestTools;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
using Zenject;
|
|
using BodyPix;
|
|
|
|
namespace UltraFace
|
|
{
|
|
public sealed class Visualizer : MonoBehaviour
|
|
{
|
|
#region Editable attributes
|
|
|
|
[SerializeField] bool _useBodyTracking;
|
|
[SerializeField] ImageSource _source = null;
|
|
|
|
[SerializeField, Range(0, 1)] float _threshold = 0.5f;
|
|
[SerializeField] ResourceSet _faceResources = null;
|
|
[SerializeField] Shader _visualizer = null;
|
|
[SerializeField] Texture2D _texture = null;
|
|
[SerializeField] UI.RawImage _facePreviewUI = null;
|
|
|
|
FaceDetector _faceDetector;
|
|
Material _faceMaterial;
|
|
ComputeBuffer _drawArgs;
|
|
|
|
[Space(16)]
|
|
[SerializeField] Shader _bodyShader = null;
|
|
[SerializeField] RenderTexture _background = null;
|
|
[SerializeField] BodyPix.ResourceSet _bodyResources;
|
|
[SerializeField] UI.RawImage _bodyPreviewUI = null;
|
|
[SerializeField] float _bodyThreshold;
|
|
|
|
BodyDetector _bodyDetector;
|
|
Material _bodyMaterial;
|
|
|
|
[Inject] private DetectionSetup _detectionSetup;
|
|
|
|
public int faceCounter => _faceDetector.Detections.Count();
|
|
public float minFaceHeight
|
|
{
|
|
get
|
|
{
|
|
if(_faceDetector.Detections.Count() == 0)
|
|
return 0f;
|
|
else
|
|
return _faceDetector.Detections.Min(face => face.y2 - face.y1);
|
|
}
|
|
}
|
|
public float maxFaceHeight
|
|
{
|
|
get
|
|
{
|
|
if(_faceDetector.Detections.Count() == 0)
|
|
return 0f;
|
|
else
|
|
return _faceDetector.Detections.Max(face => face.y2 - face.y1);
|
|
}
|
|
}
|
|
|
|
public Action<bool> OnDetectionStatusChanged;
|
|
private List<bool> _detectedCounter;
|
|
private bool _isDetected;
|
|
|
|
#endregion
|
|
|
|
#region MonoBehaviour implementation
|
|
|
|
void Start()
|
|
{
|
|
_faceDetector = new FaceDetector(_faceResources);
|
|
_faceMaterial = new Material(_visualizer);
|
|
_drawArgs = new ComputeBuffer(4, sizeof(uint), ComputeBufferType.IndirectArguments);
|
|
_drawArgs.SetData(new [] {6, 0, 0, 0});
|
|
_detectedCounter = new List<bool>();
|
|
|
|
_bodyDetector = new BodyDetector(_bodyResources, 320, 240);
|
|
_bodyMaterial = new Material(_bodyShader);
|
|
//_bodyPreviewUI.material = _bodyMaterial;
|
|
}
|
|
|
|
public void Init()
|
|
{
|
|
OnDetectionStatusChanged?.Invoke(false);
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if(_useBodyTracking)
|
|
{
|
|
_bodyDetector.ProcessImage(_source.Texture);
|
|
_bodyMaterial.SetTexture("_BgTexture", _background);
|
|
_bodyMaterial.SetTexture("_CameraTexture", _source.Texture);
|
|
_bodyMaterial.SetTexture("_MaskTexture", _bodyDetector.MaskTexture);
|
|
_bodyMaterial.SetFloat("_Threshold", _bodyThreshold);
|
|
_bodyPreviewUI.texture = _source.Texture;
|
|
}
|
|
|
|
_faceDetector.ProcessImage(_source.Texture, _threshold);
|
|
_facePreviewUI.texture = _source.Texture;
|
|
|
|
if(!_detectionSetup.isValidate) return;
|
|
|
|
_detectedCounter.Add(maxFaceHeight > _detectionSetup.minFaceHeight ? true : false);
|
|
if(_detectedCounter.Count == 128)
|
|
{
|
|
var trueCounter = _detectedCounter.Count(x => x == true);
|
|
|
|
if(!_isDetected && trueCounter >= 64)
|
|
{
|
|
if(maxFaceHeight < _detectionSetup.minFaceHeight) return;
|
|
_isDetected = true;
|
|
OnDetectionStatusChanged?.Invoke(_isDetected);
|
|
Debug.LogWarning("лицо определено");
|
|
}
|
|
else if(_isDetected && trueCounter < 64)
|
|
{
|
|
_isDetected = false;
|
|
OnDetectionStatusChanged?.Invoke(_isDetected);
|
|
Debug.LogWarning("лицо потеряно");
|
|
}
|
|
_detectedCounter = new List<bool>();
|
|
}
|
|
|
|
if(Input.GetKeyDown(KeyCode.Space))
|
|
OnDetectionStatusChanged?.Invoke(!_isDetected);
|
|
}
|
|
|
|
void OnRenderObject()
|
|
{
|
|
return;
|
|
|
|
_faceDetector.SetIndirectDrawCount(_drawArgs);
|
|
_faceMaterial.SetFloat("_Threshold", _threshold);
|
|
_faceMaterial.SetTexture("_Texture", _texture);
|
|
_faceMaterial.SetBuffer("_Detections", _faceDetector.DetectionBuffer);
|
|
_faceMaterial.SetPass(_texture == null ? 0 : 1);
|
|
Graphics.DrawProceduralIndirectNow(MeshTopology.Triangles, _drawArgs, 0);
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
_faceDetector?.Dispose();
|
|
Destroy(_faceMaterial);
|
|
_drawArgs?.Dispose();
|
|
|
|
_bodyDetector?.Dispose();
|
|
_bodyDetector = null;
|
|
|
|
Destroy(_bodyMaterial);
|
|
_bodyMaterial = null;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |