using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; // using OpenCVSharp; using OpenCVForUnity; using OpenCVForUnity.CoreModule; using OpenCVForUnity.ImgprocModule; using OpenCVForUnity.UnityUtils; using OpenCVForUnity.ObjdetectModule; /// /// 面部识别 /// public class FacialRecognitionHandler : MonoBehaviour { public static FacialRecognitionHandler Instance; private Mat gray; // 灰度图,方便识别 private Mat rotatedNewMat; private MatOfRect faceRect; // 识别到的人脸的区域 private CascadeClassifier classifier; // 人脸识别分类器 private string cascadePath = Application.streamingAssetsPath + "/haarcascade_frontalface_alt2.xml"; [SerializeField] private float timer = 0; #region 配置 private int resultPreviewTexture2DWidth = 480; private int resultPreviewTexture2DHeight = 270; #endregion // ================================================== private void Awake() => Instance = this; private void Start() => Init(); private void OnDestroy() => Dispose(); // ================================================== private void Init() { // LogAllWebCam(); gray = new Mat(); // 初始化Mat faceRect = new MatOfRect(); // 初始化识别到的人脸的区域 classifier = new CascadeClassifier(cascadePath); // 初始化人脸识别分类器 previewMat = new Mat(); resultPreviewTexture2D = new Texture2D(resultPreviewTexture2DWidth, resultPreviewTexture2DHeight, TextureFormat.RGBA32, false); return; } // ================================================== #region 资源释放 private void Dispose() { if (rotatedNewMat != null) { rotatedNewMat.Dispose(); rotatedNewMat = null; } if (previewMat != null) { previewMat.Dispose(); previewMat = null; } if (resultPreviewTexture2D != null) { Destroy(resultPreviewTexture2D); resultPreviewTexture2D = null; } return; } #endregion // ================================================== #region 面部识别 public void DetectFace(Mat rgbaMat) { // rotatedNewMat = MatRotate(rgbaMat.clone()); // 旋转原数据 rotatedNewMat = rgbaMat.clone(); // 原数据 Imgproc.cvtColor(rotatedNewMat, gray, Imgproc.COLOR_RGBA2GRAY); // 将获取到的摄像头画面转化为灰度图并赋值给gray // mat/面部矩形向量组/识别精度越高越快越不准/面部识别次数2次以上算识别/?性能优化/最小检测尺寸/最大检测尺寸 // classifier.detectMultiScale(gray, faceRect, 1.1d, 2, 2, new Size(20, 20), new Size()); // 检测gray中的人脸 classifier.detectMultiScale(gray, faceRect, 1.1d, 6, 2, new Size(20, 20), new Size()); OpenCVForUnity.CoreModule.Rect[] rects = faceRect.toArray(); if (rects.Length > 0) { for (int i = 0; i < rects.Length; i++) { 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即为框的宽和高 } timer += Time.deltaTime; if (timer > .3f) { Debug.Log("检测到面部"); AVProVideoManager.Instance.StartPlayVideo(); } } else { // if (timer > 0) // 缓慢减少检测值 // { // timer -= Time.deltaTime / 2; // if (timer < 0) // { // timer = 0; // } // } timer = 0; } // 深复制识别、画框数据并显示 UpdateResultPreview(rotatedNewMat); return; } #endregion // ================================================== #region 预览画面 private bool allowPreview = false; public void SwitchPreview(bool value) { allowPreview = value; return; } [SerializeField] private Image resultPreviewImage; private Mat previewMat; private Texture2D resultPreviewTexture2D; private void UpdateResultPreview(Mat value) { if (!allowPreview) { return; } if (resultPreviewImage == null) { return; } previewMat = value.clone(); Utils.matToTexture2D(previewMat, resultPreviewTexture2D); resultPreviewImage.sprite = Sprite.Create(resultPreviewTexture2D, new UnityEngine.Rect(0, 0, resultPreviewTexture2D.width, resultPreviewTexture2D.height), Vector2.zero); return; } #endregion // ================================================== /// /// Mat旋转方法 /// /// /// private Mat MatRotate(Mat orginalMat) { Mat rotatedMat = new Mat(orginalMat.height(), orginalMat.width(), CvType.CV_8UC4, new Scalar(0, 0, 0, 255)); // DEBUG:宽高可能相反 // mat旋转 Point center = new Point(orginalMat.cols() / 2f, orginalMat.rows() / 2f); Mat mat = Imgproc.getRotationMatrix2D(center, 90, 1); Imgproc.warpAffine(orginalMat, rotatedMat, mat, orginalMat.size()); return rotatedMat; } /// /// 预览有多少相机 /// private void LogAllWebCam() { Debug.Log($"Found {WebCamTexture.devices.Length} devices"); foreach (WebCamDevice webcamDevice in WebCamTexture.devices) { Debug.Log($"{webcamDevice.name}...[OK]"); } return; } }