Files
2023-06-05 23:22:41 +05:00

157 lines
5.2 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] FixedImageSource _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.correctFaceHeight ? true : false);
if(_detectedCounter.Count == 64)
{
var trueCounter = _detectedCounter.Count(x => x == true);
var falseCounter = _detectedCounter.Count(x => x == false);
Debug.LogWarning($"распознаваний: верных - {trueCounter}, неверных - {falseCounter}");
if(!_isDetected && trueCounter > falseCounter)
{
_isDetected = true;
OnDetectionStatusChanged?.Invoke(_isDetected);
Debug.LogWarning("лицо определено");
}
else if(_isDetected && trueCounter < falseCounter)
{
_isDetected = false;
OnDetectionStatusChanged?.Invoke(_isDetected);
Debug.LogWarning("лицо потеряно");
}
_detectedCounter = new List<bool>();
}
}
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
}
}