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 OnDetectionStatusChanged; private List _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(); // _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(); } } 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 } }