天天看點

Unity使用OpencvForUnity人臉識别并截取人臉區域

我使用的是unity版本是2019.2.0f

OpenCV for Unity 2.3.3

需要自取連結:https://pan.baidu.com/s/1jTyrX69zsYQWOnJxolfI9w 

提取碼:smtv 

之前的連結找不到了 下面是2.2.4版本的

連結: https://pan.baidu.com/s/1IAipTQxarDSVWJMtuwfs5A

提取碼: 9wvk 

using UnityEngine;
using UnityEngine.SceneManagement;
using System;
using System.Collections;
using System.Collections.Generic;
using OpenCVForUnity.ObjdetectModule;
using OpenCVForUnity.CoreModule;
using OpenCVForUnity.ImgprocModule;
using OpenCVForUnity.UnityUtils;
using OpenCVForUnity.ImgcodecsModule;
using UnityEngine.UI;
using OpenCVForUnity.UnityUtils.Helper;

namespace OpenCVForUnityExample
{
    /// <summary>
    /// Face Detection Example
    /// An example of human face detection using the CascadeClassifier class.
    /// http://docs.opencv.org/3.2.0/db/d28/tutorial_cascade_classifier.html
    /// </summary>
    public class MyFaceDetection : MonoBehaviour
    {
        public static MyFaceDetection instance;
        CascadeClassifier cascade;
        public RawImage icon;

#if UNITY_WEBGL && !UNITY_EDITOR
        IEnumerator getFilePath_Coroutine;
#endif
        private void Awake()
        {
            if (instance == null)
            {
                instance = this;
            }
        }
        // Use this for initialization
        void Start ()
        {
#if UNITY_WEBGL && !UNITY_EDITOR
            getFilePath_Coroutine = Utils.getFilePathAsync("haarcascade_frontalface_alt.xml", 
            (result) => {
                getFilePath_Coroutine = null;

                cascade = new CascadeClassifier ();
                cascade.load(result);
                if (cascade.empty ()) {
                    Debug.LogError ("cascade file is not loaded. Please copy from “OpenCVForUnity/StreamingAssets/” to “Assets/StreamingAssets/” folder. ");
                }
           
                Run ();
            }, 
            (result, progress) => {
                Debug.Log ("getFilePathAsync() progress : " + result + " " + Mathf.CeilToInt (progress * 100) + "%");
            });
            StartCoroutine (getFilePath_Coroutine);
#else
            //cascade = new CascadeClassifier (Utils.getFilePath ("lbpcascade_frontalface.xml"));
            cascade = new CascadeClassifier ();
            cascade.load (Utils.getFilePath ("haarcascade_frontalface_alt.xml"));
            #if !UNITY_WSA_10_0
            if (cascade.empty ()) {
                Debug.LogError ("cascade file is not loaded. Please copy from “OpenCVForUnity/StreamingAssets/” to “Assets/StreamingAssets/” folder. ");
            }
            #endif
           // Run ();
            #endif
        }

        public bool Run ()
        {
            //加載圖檔
            Texture2D imgTexture = Resources.Load ("photo") as Texture2D;
            //轉成Mat
            Mat imgMat = new Mat (imgTexture.height, imgTexture.width, CvType.CV_8UC4);
            Utils.texture2DToMat (imgTexture, imgMat);
            //轉為灰階圖像
            Mat grayMat = new Mat ();
            Imgproc.cvtColor (imgMat, grayMat, Imgproc.COLOR_RGBA2GRAY);
            Imgproc.equalizeHist (grayMat, grayMat);
            //檢測圖像中的所有臉
            MatOfRect faces = new MatOfRect ();
            if (cascade != null)
                cascade.detectMultiScale (grayMat, faces, 1.1, 3, 2, 
                    new Size (50, 50), new Size ());
            OpenCVForUnity.CoreModule.Rect[] rects = faces.toArray();            
            if (faces.toArray().Length == 1)
            {
                Debug.Log("識别到人臉" + faces.toArray().Length);
                //**********顯示人臉區域
                for (int i = 0; i < rects.Length; i++)
                {
                    Debug.Log("detect faces " + rects[i]);

                    Imgproc.rectangle(imgMat, new Point(rects[i].x, rects[i].y), new Point(rects[i].x + rects[i].width, rects[i].y + rects[i].height), new Scalar(255, 0, 0, 255), 2);
                }
                Texture2D texture = new Texture2D(imgMat.cols(), imgMat.rows(), TextureFormat.RGBA32, false);
                Utils.matToTexture2D(imgMat, texture);
                icon.texture  = texture;
                //截取人臉部分
                InterceptImg(rects[0]);
                return true;
            }
            else
            {
                Debug.Log("未識别到人臉");
                return false;
            }      
        }

        /// <summary>
        /// Raises the destroy event.
        /// </summary>
        void OnDestroy ()
        {
            #if UNITY_WEBGL && !UNITY_EDITOR
            if (getFilePath_Coroutine != null) {
                StopCoroutine (getFilePath_Coroutine);
                ((IDisposable)getFilePath_Coroutine).Dispose ();
            }
            #endif
        }
        /// <summary>
        /// 截取圖檔
        /// </summary>
        /// <param name="rect">要截取的區域</param>
        void InterceptImg(OpenCVForUnity.CoreModule.Rect rect)
        {
            //加載要截取的圖檔
            Texture2D imgTexture = Resources.Load("photo") as Texture2D;
            Mat cameraMat = new Mat(imgTexture.height, imgTexture.width, CvType.CV_8UC4);
            Utils.texture2DToMat(imgTexture, cameraMat);
            //截取需要的部分 rect為上面檢測的人臉區域
            Mat croppedImage = new Mat(cameraMat, rect);
            //色彩轉換 如果不加 圖檔顔色會不對
            Imgproc.cvtColor(croppedImage, croppedImage, Imgproc.COLOR_RGBA2BGRA);
            //這裡截取到的圖檔為倒的 使用這個方法翻轉一下
            Core.flip(croppedImage, croppedImage, 1);
            //儲存到Assets目錄下
            Imgcodecs.imwrite(Application.dataPath + "/cap.png", croppedImage);
        }
    }
}
           

以上為人臉識别+截取圖檔的全部代碼,也加上了注釋

這裡要注意的方法是

cascade.detectMultiScale (grayMat, faces, 1.1, 3, 2, new Size (50, 50), new Size ());

detectMultiScale(image, objects, scaleFactor, minNeighbors, flags, minSize, maxSize)其中參數我百度翻譯了一下

<param name="image">包含檢測到對象的圖像的CV_8U類型的矩陣</param>

 <param name="objects">矩形向量如果每個矩形包含檢測到的對象,則矩形可能部分位于原始圖像之外。</param>

<param name="scaleFactor">指定在每個圖像比例上縮小圖像大小的程度。</param>

<param name="minNeighbors">指定每個候選矩形應保留多少個鄰居。minNeighbors 值越大,檢測的準确度越高,不過耗時也越久.酌情調整.</param>

<param name="flags">與函數cvHaarDetectObjects中的舊級聯具有相同含義的參數。它不用于新的級聯。</param>

<param name="minSize">最小可能的對象大小。小于該值的對象将被忽略。可以根據Screen 尺寸的一定比例來設定,别設定太小,不然會有一些錯誤幹擾結果</param>

<param name="maxSize">最大可能的對象大小。大于該值的對象将被忽略。如果maxSize==minSize模型是按單個比例計算的。最大可檢測尺寸,酌情調整.</param>

在做這個功能的時候,我是要拍照然後識别人臉的,拍照儲存的我之前有寫在這裡

以上,Over