FacialRecognitionHandler.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.UI;
  5. // using OpenCVSharp;
  6. using OpenCVForUnity;
  7. using OpenCVForUnity.CoreModule;
  8. using OpenCVForUnity.ImgprocModule;
  9. using OpenCVForUnity.UnityUtils;
  10. using OpenCVForUnity.ObjdetectModule;
  11. /// <summary>
  12. /// 面部识别
  13. /// </summary>
  14. public class FacialRecognitionHandler : MonoBehaviour
  15. {
  16. public static FacialRecognitionHandler Instance;
  17. private Mat gray; // 灰度图,方便识别
  18. private Mat rotatedNewMat;
  19. private MatOfRect faceRect; // 识别到的人脸的区域
  20. private CascadeClassifier classifier; // 人脸识别分类器
  21. private string cascadePath = Application.streamingAssetsPath + "/haarcascade_frontalface_alt2.xml";
  22. [SerializeField] private float timer = 0;
  23. #region 配置
  24. private int resultPreviewTexture2DWidth = 480;
  25. private int resultPreviewTexture2DHeight = 270;
  26. #endregion
  27. // ==================================================
  28. private void Awake() => Instance = this;
  29. private void Start() => Init();
  30. private void OnDestroy() => Dispose();
  31. // ==================================================
  32. private void Init()
  33. {
  34. // LogAllWebCam();
  35. gray = new Mat(); // 初始化Mat
  36. faceRect = new MatOfRect(); // 初始化识别到的人脸的区域
  37. classifier = new CascadeClassifier(cascadePath); // 初始化人脸识别分类器
  38. previewMat = new Mat();
  39. resultPreviewTexture2D = new Texture2D(resultPreviewTexture2DWidth, resultPreviewTexture2DHeight, TextureFormat.RGBA32, false);
  40. return;
  41. }
  42. // ==================================================
  43. #region 资源释放
  44. private void Dispose()
  45. {
  46. if (rotatedNewMat != null)
  47. {
  48. rotatedNewMat.Dispose();
  49. rotatedNewMat = null;
  50. }
  51. if (previewMat != null)
  52. {
  53. previewMat.Dispose();
  54. previewMat = null;
  55. }
  56. if (resultPreviewTexture2D != null)
  57. {
  58. Destroy(resultPreviewTexture2D);
  59. resultPreviewTexture2D = null;
  60. }
  61. return;
  62. }
  63. #endregion
  64. // ==================================================
  65. #region 面部识别
  66. public void DetectFace(Mat rgbaMat)
  67. {
  68. // rotatedNewMat = MatRotate(rgbaMat.clone()); // 旋转原数据
  69. rotatedNewMat = rgbaMat.clone(); // 原数据
  70. Imgproc.cvtColor(rotatedNewMat, gray, Imgproc.COLOR_RGBA2GRAY); // 将获取到的摄像头画面转化为灰度图并赋值给gray
  71. // mat/面部矩形向量组/识别精度越高越快越不准/面部识别次数2次以上算识别/?性能优化/最小检测尺寸/最大检测尺寸
  72. // classifier.detectMultiScale(gray, faceRect, 1.1d, 2, 2, new Size(20, 20), new Size()); // 检测gray中的人脸
  73. classifier.detectMultiScale(gray, faceRect, 1.1d, 6, 2, new Size(20, 20), new Size());
  74. OpenCVForUnity.CoreModule.Rect[] rects = faceRect.toArray();
  75. if (rects.Length > 0)
  76. {
  77. for (int i = 0; i < rects.Length; i++)
  78. {
  79. Imgproc.rectangle(rotatedNewMat, new Point(rects[i].x, rects[i].y), new Point(rects[i].x + rects[i].width, rects[i].y + rects[i].height), new Scalar(0, 255, 0, 255), 2); //在原本的画面中画框,框出人脸额位置,其中rects[i].x和rects[i].y为框的左上角的顶点,rects[i].width、rects[i].height即为框的宽和高
  80. }
  81. timer += Time.deltaTime;
  82. if (timer > .3f)
  83. {
  84. Debug.Log("检测到面部");
  85. AVProVideoManager.Instance.StartPlayVideo();
  86. }
  87. }
  88. else
  89. {
  90. // if (timer > 0) // 缓慢减少检测值
  91. // {
  92. // timer -= Time.deltaTime / 2;
  93. // if (timer < 0)
  94. // {
  95. // timer = 0;
  96. // }
  97. // }
  98. timer = 0;
  99. }
  100. // 深复制识别、画框数据并显示
  101. UpdateResultPreview(rotatedNewMat);
  102. return;
  103. }
  104. #endregion
  105. // ==================================================
  106. #region 预览画面
  107. private bool allowPreview = false;
  108. public void SwitchPreview(bool value)
  109. {
  110. allowPreview = value;
  111. return;
  112. }
  113. [SerializeField] private Image resultPreviewImage;
  114. private Mat previewMat;
  115. private Texture2D resultPreviewTexture2D;
  116. private void UpdateResultPreview(Mat value)
  117. {
  118. if (!allowPreview)
  119. {
  120. return;
  121. }
  122. if (resultPreviewImage == null)
  123. {
  124. return;
  125. }
  126. previewMat = value.clone();
  127. Utils.matToTexture2D(previewMat, resultPreviewTexture2D);
  128. resultPreviewImage.sprite = Sprite.Create(resultPreviewTexture2D, new UnityEngine.Rect(0, 0, resultPreviewTexture2D.width, resultPreviewTexture2D.height), Vector2.zero);
  129. return;
  130. }
  131. #endregion
  132. // ==================================================
  133. /// <summary>
  134. /// Mat旋转方法
  135. /// </summary>
  136. /// <param name="orginalMat"></param>
  137. /// <returns></returns>
  138. private Mat MatRotate(Mat orginalMat)
  139. {
  140. Mat rotatedMat = new Mat(orginalMat.height(), orginalMat.width(), CvType.CV_8UC4, new Scalar(0, 0, 0, 255)); // DEBUG:宽高可能相反
  141. // mat旋转
  142. Point center = new Point(orginalMat.cols() / 2f, orginalMat.rows() / 2f);
  143. Mat mat = Imgproc.getRotationMatrix2D(center, 90, 1);
  144. Imgproc.warpAffine(orginalMat, rotatedMat, mat, orginalMat.size());
  145. return rotatedMat;
  146. }
  147. /// <summary>
  148. /// 预览有多少相机
  149. /// </summary>
  150. private void LogAllWebCam()
  151. {
  152. Debug.Log($"Found {WebCamTexture.devices.Length} devices");
  153. foreach (WebCamDevice webcamDevice in WebCamTexture.devices)
  154. {
  155. Debug.Log($"{webcamDevice.name}...<color=green>[OK]</color>");
  156. }
  157. return;
  158. }
  159. }