123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- #if !UNITY_WSA_10_0
- using OpenCVForUnity.CoreModule;
- using OpenCVForUnity.ImgcodecsModule;
- using OpenCVForUnity.ImgprocModule;
- using OpenCVForUnity.ObjdetectModule;
- using OpenCVForUnity.UnityUtils;
- using System;
- using System.Collections;
- using UnityEngine;
- using UnityEngine.SceneManagement;
- using Rect = OpenCVForUnity.CoreModule.Rect;
- namespace OpenCVForUnityExample
- {
- /// <summary>
- /// FaceRecognizerSF Example
- /// An example of human face recognition using the FaceRecognizerSF class.
- /// https://github.com/opencv/opencv/blob/master/samples/dnn/face_detect.cpp
- /// https://docs.opencv.org/4.5.4/d0/dd4/tutorial_dnn_face.html
- /// </summary>
- public class FaceRecognizerSFExample : MonoBehaviour
- {
- /// <summary>
- /// Filter out faces of score < score_threshold.
- /// </summary>
- float scoreThreshold = 0.9f;
- /// <summary>
- /// Suppress bounding boxes of iou >= nms_threshold
- /// </summary>
- float nmsThreshold = 0.3f;
- /// <summary>
- /// Keep top_k bounding boxes before NMS.
- /// </summary>
- int topK = 5000;
- /// <summary>
- /// FD_MODEL_FILENAME
- /// </summary>
- protected static readonly string FD_MODEL_FILENAME = "OpenCVForUnity/objdetect/face_detection_yunet_2023mar.onnx";
- /// <summary>
- /// The fd model filepath.
- /// </summary>
- string fd_model_filepath;
- /// <summary>
- /// The cosine similar thresh.
- /// </summary>
- double cosine_similar_thresh = 0.363;
- /// <summary>
- /// The l2norm similar thresh.
- /// </summary>
- double l2norm_similar_thresh = 1.128;
- /// <summary>
- /// SF_MODEL_FILENAME
- /// </summary>
- protected static readonly string SF_MODEL_FILENAME = "OpenCVForUnity/objdetect/face_recognition_sface_2021dec.onnx";
- /// <summary>
- /// The sf model filepath.
- /// </summary>
- string sf_model_filepath;
- /// <summary>
- /// IMAGE_0_FILENAME
- /// </summary>
- protected static readonly string IMAGE_0_FILENAME = "OpenCVForUnity/face/facerec_0.bmp";
- /// <summary>
- /// The image 0 filepath.
- /// </summary>
- string image_0_filepath;
- /// <summary>
- /// IMAGE_1_FILENAME
- /// </summary>
- protected static readonly string IMAGE_1_FILENAME = "OpenCVForUnity/face/facerec_1.bmp";
- /// <summary>
- /// The image 1 filepath.
- /// </summary>
- string image_1_filepath;
- /// <summary>
- /// SAMPLE_IMAGE_FILENAME
- /// </summary>
- protected static readonly string SAMPLE_IMAGE_FILENAME = "OpenCVForUnity/face/facerec_sample.bmp";
- /// <summary>
- /// The sample image filepath.
- /// </summary>
- string sample_image_filepath;
- #if UNITY_WEBGL
- IEnumerator getFilePath_Coroutine;
- #endif
- // Use this for initialization
- void Start()
- {
- #if UNITY_WEBGL
- getFilePath_Coroutine = GetFilePath ();
- StartCoroutine (getFilePath_Coroutine);
- #else
- fd_model_filepath = Utils.getFilePath(FD_MODEL_FILENAME);
- sf_model_filepath = Utils.getFilePath(SF_MODEL_FILENAME);
- image_0_filepath = Utils.getFilePath(IMAGE_0_FILENAME);
- image_1_filepath = Utils.getFilePath(IMAGE_1_FILENAME);
- sample_image_filepath = Utils.getFilePath(SAMPLE_IMAGE_FILENAME);
- Run();
- #endif
- }
- #if UNITY_WEBGL
- private IEnumerator GetFilePath()
- {
- var getFilePathAsync_fd_Coroutine = Utils.getFilePathAsync(FD_MODEL_FILENAME, (result) => {
- fd_model_filepath = result;
- });
- yield return getFilePathAsync_fd_Coroutine;
- var getFilePathAsync_sf_Coroutine = Utils.getFilePathAsync(SF_MODEL_FILENAME, (result) => {
- sf_model_filepath = result;
- });
- yield return getFilePathAsync_sf_Coroutine;
- var getFilePathAsync_0_Coroutine = Utils.getFilePathAsync (IMAGE_0_FILENAME, (result) => {
- image_0_filepath = result;
- });
- yield return getFilePathAsync_0_Coroutine;
- var getFilePathAsync_1_Coroutine = Utils.getFilePathAsync (IMAGE_1_FILENAME, (result) => {
- image_1_filepath = result;
- });
- yield return getFilePathAsync_1_Coroutine;
- var getFilePathAsync_sample_Coroutine = Utils.getFilePathAsync (SAMPLE_IMAGE_FILENAME, (result) => {
- sample_image_filepath = result;
- });
- yield return getFilePathAsync_sample_Coroutine;
- getFilePath_Coroutine = null;
- Run ();
- }
- #endif
- private void Run()
- {
- //if true, The error log of the Native side OpenCV will be displayed on the Unity Editor Console.
- Utils.setDebugMode(true);
- if (string.IsNullOrEmpty(image_0_filepath) || string.IsNullOrEmpty(image_1_filepath) || string.IsNullOrEmpty(sample_image_filepath))
- {
- Debug.LogError(IMAGE_0_FILENAME + " or " + IMAGE_1_FILENAME + " or " + SAMPLE_IMAGE_FILENAME + " is not loaded. Please move from “OpenCVForUnity/StreamingAssets/OpenCVForUnity/” to “Assets/StreamingAssets/OpenCVForUnity/” folder.");
- }
- Mat testSampleMat = Imgcodecs.imread(sample_image_filepath, Imgcodecs.IMREAD_COLOR);
- Mat image0Mat = Imgcodecs.imread(image_0_filepath, Imgcodecs.IMREAD_COLOR);
- Mat image1Mat = Imgcodecs.imread(image_1_filepath, Imgcodecs.IMREAD_COLOR);
- int imageSizeW = 112;
- int imageSizeH = 112;
- Mat resultMat = new Mat(imageSizeH * 2, imageSizeW * 2, CvType.CV_8UC3, new Scalar(127, 127, 127, 255));
- if (string.IsNullOrEmpty(fd_model_filepath) || string.IsNullOrEmpty(sf_model_filepath))
- {
- Debug.LogError(FD_MODEL_FILENAME + " or " + SF_MODEL_FILENAME + " is not loaded. Please read “StreamingAssets/OpenCVForUnity/objdetect/setup_objdetect_module.pdf” to make the necessary setup.");
- Imgproc.putText(resultMat, "model file is not loaded.", new Point(5, resultMat.rows() - 30), Imgproc.FONT_HERSHEY_SIMPLEX, 0.7, new Scalar(255, 255, 255), 2, Imgproc.LINE_AA, false);
- Imgproc.putText(resultMat, "Please read console message.", new Point(5, resultMat.rows() - 10), Imgproc.FONT_HERSHEY_SIMPLEX, 0.7, new Scalar(255, 255, 255), 2, Imgproc.LINE_AA, false);
- }
- else
- {
- FaceDetectorYN faceDetector = FaceDetectorYN.create(fd_model_filepath, "", new Size(imageSizeW, imageSizeH), scoreThreshold, nmsThreshold, topK);
- FaceRecognizerSF faceRecognizer = FaceRecognizerSF.create(sf_model_filepath, "");
- // Detect faces.
- faceDetector.setInputSize(testSampleMat.size());
- Mat faces_sample = new Mat();
- faceDetector.detect(testSampleMat, faces_sample);
- if (faces_sample.rows() < 1)
- {
- Debug.Log("Cannot find a face in " + SAMPLE_IMAGE_FILENAME + ".");
- }
- faceDetector.setInputSize(image0Mat.size());
- Mat faces_0 = new Mat();
- faceDetector.detect(image0Mat, faces_0);
- if (faces_0.rows() < 1)
- {
- Debug.Log("Cannot find a face in " + IMAGE_0_FILENAME + ".");
- }
- faceDetector.setInputSize(image1Mat.size());
- Mat faces_1 = new Mat();
- faceDetector.detect(image1Mat, faces_1);
- if (faces_1.rows() < 1)
- {
- Debug.Log("Cannot find a face in " + IMAGE_1_FILENAME + ".");
- }
- /*
- // Draw results on the input image.
- DrawDetection(faces_sample.row(0),testSampleMat);
- DrawDetection(faces_0.row(0), image0Mat);
- DrawDetection(faces_1.row(0), image1Mat);
- */
- // Aligning and cropping facial image through the first face of faces detected.
- Mat aligned_face_sample = new Mat();
- faceRecognizer.alignCrop(testSampleMat, faces_sample.row(0), aligned_face_sample);
- Mat aligned_face_0 = new Mat();
- faceRecognizer.alignCrop(image0Mat, faces_0.row(0), aligned_face_0);
- Mat aligned_face_1 = new Mat();
- faceRecognizer.alignCrop(image1Mat, faces_1.row(0), aligned_face_1);
- // Run feature extraction with given aligned_face.
- Mat feature_sample = new Mat();
- faceRecognizer.feature(aligned_face_sample, feature_sample);
- feature_sample = feature_sample.clone();
- Mat feature_0 = new Mat();
- faceRecognizer.feature(aligned_face_0, feature_0);
- feature_0 = feature_0.clone();
- Mat feature_1 = new Mat();
- faceRecognizer.feature(aligned_face_1, feature_1);
- feature_1 = feature_1.clone();
- // Match the face features.
- bool sample_0_match = Match(faceRecognizer, feature_sample, feature_0);
- bool sample_1_match = Match(faceRecognizer, feature_sample, feature_1);
- Debug.Log("Match(" + SAMPLE_IMAGE_FILENAME + ", " + IMAGE_0_FILENAME + "): " + sample_0_match);
- Debug.Log("Match(" + SAMPLE_IMAGE_FILENAME + ", " + IMAGE_1_FILENAME + "): " + sample_1_match);
- // Draw the recognition result.
- aligned_face_sample.copyTo(resultMat.submat(new Rect(new Point(imageSizeW / 2, 0), aligned_face_sample.size())));
- aligned_face_0.copyTo(resultMat.submat(new Rect(new Point(0, imageSizeH), aligned_face_0.size())));
- aligned_face_1.copyTo(resultMat.submat(new Rect(new Point(imageSizeW, imageSizeH), aligned_face_1.size())));
- Imgproc.putText(resultMat, "TestSample", new Point(imageSizeW / 2 + 5, 15), Imgproc.FONT_HERSHEY_SIMPLEX, 0.4, new Scalar(255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
- Imgproc.putText(resultMat, "Image0", new Point(5, imageSizeH + 15), Imgproc.FONT_HERSHEY_SIMPLEX, 0.4, new Scalar(255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
- Imgproc.putText(resultMat, "Image1", new Point(imageSizeW + 5, imageSizeH + 15), Imgproc.FONT_HERSHEY_SIMPLEX, 0.4, new Scalar(255, 255, 255, 255), 1, Imgproc.LINE_AA, false);
- if (sample_0_match)
- Imgproc.rectangle(resultMat, new Rect(0, imageSizeH, imageSizeW, imageSizeH), new Scalar(255, 0, 0, 255), 2);
- if (sample_1_match)
- Imgproc.rectangle(resultMat, new Rect(imageSizeW, imageSizeH, imageSizeW, imageSizeH), new Scalar(255, 0, 0, 255), 2);
- }
- Texture2D texture = new Texture2D(resultMat.cols(), resultMat.rows(), TextureFormat.RGB24, false);
- Utils.matToTexture2D(resultMat, texture);
- gameObject.GetComponent<Renderer>().material.mainTexture = texture;
- Utils.setDebugMode(false);
- }
- // Update is called once per frame
- void Update()
- {
- }
- /// <summary>
- /// Raises the destroy event.
- /// </summary>
- void OnDestroy()
- {
- #if UNITY_WEBGL
- if (getFilePath_Coroutine != null) {
- StopCoroutine (getFilePath_Coroutine);
- ((IDisposable)getFilePath_Coroutine).Dispose ();
- }
- #endif
- }
- /// <summary>
- /// Raises the back button click event.
- /// </summary>
- public void OnBackButtonClick()
- {
- SceneManager.LoadScene("OpenCVForUnityExample");
- }
- protected void DrawDetection(Mat d, Mat frame)
- {
- float[] buf = new float[15];
- d.get(0, 0, buf);
- Scalar color = new Scalar(255, 255, 0, 255);
- Imgproc.rectangle(frame, new Point(buf[0], buf[1]), new Point(buf[0] + buf[2], buf[1] + buf[3]), color, 2);
- Imgproc.circle(frame, new Point(buf[4], buf[5]), 2, color, 2);
- Imgproc.circle(frame, new Point(buf[6], buf[7]), 2, color, 2);
- Imgproc.circle(frame, new Point(buf[8], buf[9]), 2, color, 2);
- Imgproc.circle(frame, new Point(buf[10], buf[11]), 2, color, 2);
- Imgproc.circle(frame, new Point(buf[12], buf[13]), 2, color, 2);
- }
- protected bool Match(FaceRecognizerSF faceRecognizer, Mat feature1, Mat feature2)
- {
- double cos_score = faceRecognizer.match(feature1, feature2, FaceRecognizerSF.FR_COSINE);
- bool cos_match = (cos_score >= cosine_similar_thresh);
- Debug.Log((cos_match ? "They have the same identity;" : "They have different identities;") + "\n"
- + " Cosine Similarity: " + cos_score + ", threshold: " + cosine_similar_thresh + ". (higher value means higher similarity, max 1.0)");
- double L2_score = faceRecognizer.match(feature1, feature2, FaceRecognizerSF.FR_NORM_L2);
- bool L2_match = (L2_score <= l2norm_similar_thresh);
- Debug.Log((L2_match ? "They have the same identity;" : "They have different identities;") + "\n"
- + " NormL2 Distance: " + L2_score + ", threshold: " + l2norm_similar_thresh + ". (lower value means higher similarity, min 0.0)");
- return cos_match && L2_match;
- }
- }
- }
- #endif
|