diff --git a/Assets/FaceTrackerExample/FaceTrackerARExample/FaceTrackerARExample.cs b/Assets/FaceTrackerExample/FaceTrackerARExample/FaceTrackerARExample.cs index 2b0302e..b6fb9bb 100644 --- a/Assets/FaceTrackerExample/FaceTrackerARExample/FaceTrackerARExample.cs +++ b/Assets/FaceTrackerExample/FaceTrackerARExample/FaceTrackerARExample.cs @@ -19,7 +19,7 @@ namespace FaceTrackerExample /// This example was referring to http://www.morethantechnical.com/2012/10/17/head-pose-estimation-with-opencv-opengl-revisited-w-code/ /// and use effect asset from http://ktk-kumamoto.hatenablog.com/entry/2014/09/14/092400 /// - [RequireComponent (typeof(WebCamTextureToMatHelper))] + [RequireComponent(typeof(WebCamTextureToMatHelper))] public class FaceTrackerARExample : MonoBehaviour { /// @@ -31,7 +31,7 @@ namespace FaceTrackerExample /// The is showing face points toggle. /// public Toggle isShowingFacePointsToggle; - + /// /// The should draw axes. /// @@ -41,7 +41,7 @@ namespace FaceTrackerExample /// The is showing axes toggle. /// public Toggle isShowingAxesToggle; - + /// /// The should draw head. /// @@ -51,7 +51,7 @@ namespace FaceTrackerExample /// The is showing head toggle. /// public Toggle isShowingHeadToggle; - + /// /// The should draw effects. /// @@ -71,101 +71,101 @@ namespace FaceTrackerExample /// The auto reset mode toggle. /// public Toggle isAutoResetModeToggle; - + /// /// The axes. /// public GameObject axes; - + /// /// The head. /// public GameObject head; - + /// /// The right eye. /// public GameObject rightEye; - + /// /// The left eye. /// public GameObject leftEye; - + /// /// The mouth. /// public GameObject mouth; - + /// /// The rvec noise filter range. /// - [Range (0, 50)] + [Range(0, 50)] public float rvecNoiseFilterRange = 8; - + /// /// The tvec noise filter range. /// - [Range (0, 360)] + [Range(0, 360)] public float tvecNoiseFilterRange = 90; - + /// /// The gray mat. /// Mat grayMat; - + /// /// The texture. /// Texture2D texture; - + /// /// The cascade. /// CascadeClassifier cascade; - + /// /// The face tracker. /// FaceTracker faceTracker; - + /// /// The face tracker parameters. /// FaceTrackerParams faceTrackerParams; - + /// /// The AR camera. /// public Camera ARCamera; - + /// /// The cam matrix. /// Mat camMatrix; - + /// /// The dist coeffs. /// MatOfDouble distCoeffs; - + /// /// The invert Y. /// Matrix4x4 invertYM; - + /// /// The transformation m. /// - Matrix4x4 transformationM = new Matrix4x4 (); - + Matrix4x4 transformationM = new Matrix4x4(); + /// /// The invert Z. /// Matrix4x4 invertZM; - + /// /// The ar m. /// @@ -180,37 +180,37 @@ namespace FaceTrackerExample /// The should move AR camera. /// public bool shouldMoveARCamera; - + /// /// The 3d face object points. /// MatOfPoint3f objectPoints; - + /// /// The image points. /// MatOfPoint2f imagePoints; - + /// /// The rvec. /// Mat rvec; - + /// /// The tvec. /// Mat tvec; - + /// /// The rot m. /// Mat rotM; - + /// /// The old rvec. /// Mat oldRvec; - + /// /// The old tvec. /// @@ -225,20 +225,20 @@ namespace FaceTrackerExample /// The tracker_model_json_filepath. /// private string tracker_model_json_filepath; - + /// /// The haarcascade_frontalface_alt_xml_filepath. /// private string haarcascade_frontalface_alt_xml_filepath; - #if UNITY_WEBGL && !UNITY_EDITOR +#if UNITY_WEBGL && !UNITY_EDITOR IEnumerator getFilePath_Coroutine; - #endif +#endif // Use this for initialization - void Start () + void Start() { - webCamTextureToMatHelper = gameObject.GetComponent (); + webCamTextureToMatHelper = gameObject.GetComponent(); isShowingFacePointsToggle.isOn = isShowingFacePoints; @@ -247,382 +247,417 @@ namespace FaceTrackerExample isShowingEffectsToggle.isOn = isShowingEffects; isAutoResetModeToggle.isOn = isAutoResetMode; - #if UNITY_WEBGL && !UNITY_EDITOR - getFilePath_Coroutine = GetFilePath (); - StartCoroutine (getFilePath_Coroutine); - #else - tracker_model_json_filepath = Utils.getFilePath ("tracker_model.json"); - haarcascade_frontalface_alt_xml_filepath = Utils.getFilePath ("haarcascade_frontalface_alt.xml"); - Run (); - #endif - +#if UNITY_WEBGL && !UNITY_EDITOR + getFilePath_Coroutine = GetFilePath(); + StartCoroutine(getFilePath_Coroutine); +#else + tracker_model_json_filepath = Utils.getFilePath("tracker_model.json"); + haarcascade_frontalface_alt_xml_filepath = Utils.getFilePath("haarcascade_frontalface_alt.xml"); + Run(); +#endif + } - #if UNITY_WEBGL && !UNITY_EDITOR - private IEnumerator GetFilePath () +#if UNITY_WEBGL && !UNITY_EDITOR + private IEnumerator GetFilePath() { - var getFilePathAsync_0_Coroutine = Utils.getFilePathAsync ("tracker_model.json", (result) => { + var getFilePathAsync_0_Coroutine = Utils.getFilePathAsync("tracker_model.json", (result) => + { tracker_model_json_filepath = result; }); yield return getFilePathAsync_0_Coroutine; - var getFilePathAsync_1_Coroutine = Utils.getFilePathAsync ("haarcascade_frontalface_alt.xml", (result) => { + var getFilePathAsync_1_Coroutine = Utils.getFilePathAsync("haarcascade_frontalface_alt.xml", (result) => + { haarcascade_frontalface_alt_xml_filepath = result; }); yield return getFilePathAsync_1_Coroutine; getFilePath_Coroutine = null; - + Run(); } - #endif +#endif - private void Run () + private void Run() { //set 3d face object points. - objectPoints = new MatOfPoint3f (new Point3 (-31, 72, 86),//l eye - new Point3 (31, 72, 86),//r eye - new Point3 (0, 40, 114),//nose - new Point3 (-20, 15, 90),//l mouse - new Point3 (20, 15, 90)//r mouse -// , -// new Point3 (-70, 60, -9),//l ear -// new Point3 (70, 60, -9)//r ear + objectPoints = new MatOfPoint3f(new Point3(-31, 72, 86),//l eye + new Point3(31, 72, 86),//r eye + new Point3(0, 40, 114),//nose + new Point3(-20, 15, 90),//l mouse + new Point3(20, 15, 90),//r mouse + new Point3(-70, 60, -9),//l ear + new Point3(70, 60, -9)//r ear ); - imagePoints = new MatOfPoint2f (); - rvec = new Mat (); - tvec = new Mat (); - rotM = new Mat (3, 3, CvType.CV_64FC1); + imagePoints = new MatOfPoint2f(); + rvec = new Mat(); + tvec = new Mat(); + rotM = new Mat(3, 3, CvType.CV_64FC1); //initialize FaceTracker - faceTracker = new FaceTracker (tracker_model_json_filepath); + faceTracker = new FaceTracker(tracker_model_json_filepath); //initialize FaceTrackerParams - faceTrackerParams = new FaceTrackerParams (); + faceTrackerParams = new FaceTrackerParams(); - cascade = new CascadeClassifier (); - cascade.load (haarcascade_frontalface_alt_xml_filepath); -// if (cascade.empty()) -// { -// Debug.LogError("cascade file is not loaded.Please copy from “FaceTrackerExample/StreamingAssets/” to “Assets/StreamingAssets/” folder. "); -// } + cascade = new CascadeClassifier(); + cascade.load(haarcascade_frontalface_alt_xml_filepath); + //if (cascade.empty()) + //{ + // Debug.LogError("cascade file is not loaded.Please copy from “FaceTrackerExample/StreamingAssets/” to “Assets/StreamingAssets/” folder. "); + //} - #if UNITY_ANDROID && !UNITY_EDITOR +#if UNITY_ANDROID && !UNITY_EDITOR // Avoids the front camera low light issue that occurs in only some Android devices (e.g. Google Pixel, Pixel2). webCamTextureToMatHelper.avoidAndroidFrontCameraLowLightIssue = true; - #endif - webCamTextureToMatHelper.Initialize (); +#endif + webCamTextureToMatHelper.Initialize(); } /// /// Raises the webcam texture to mat helper initialized event. /// - public void OnWebCamTextureToMatHelperInitialized () + public void OnWebCamTextureToMatHelperInitialized() { - Debug.Log ("OnWebCamTextureToMatHelperInitialized"); - - Mat webCamTextureMat = webCamTextureToMatHelper.GetMat (); + Debug.Log("OnWebCamTextureToMatHelperInitialized"); - texture = new Texture2D (webCamTextureMat.cols (), webCamTextureMat.rows (), TextureFormat.RGBA32, false); + Mat webCamTextureMat = webCamTextureToMatHelper.GetMat(); - gameObject.GetComponent ().material.mainTexture = texture; + texture = new Texture2D(webCamTextureMat.cols(), webCamTextureMat.rows(), TextureFormat.RGBA32, false); - gameObject.transform.localScale = new Vector3 (webCamTextureMat.cols (), webCamTextureMat.rows (), 1); - Debug.Log ("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation); + gameObject.GetComponent().material.mainTexture = texture; + + gameObject.transform.localScale = new Vector3(webCamTextureMat.cols(), webCamTextureMat.rows(), 1); + Debug.Log("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation); - float width = webCamTextureMat.width (); - float height = webCamTextureMat.height (); - + float width = webCamTextureMat.width(); + float height = webCamTextureMat.height(); + float imageSizeScale = 1.0f; float widthScale = (float)Screen.width / width; float heightScale = (float)Screen.height / height; - if (widthScale < heightScale) { + if (widthScale < heightScale) + { Camera.main.orthographicSize = (width * (float)Screen.height / (float)Screen.width) / 2; imageSizeScale = (float)Screen.height / (float)Screen.width; - } else { + } + else + { Camera.main.orthographicSize = height / 2; } - - + + //set cameraparam - int max_d = (int)Mathf.Max (width, height); + int max_d = (int)Mathf.Max(width, height); double fx = max_d; double fy = max_d; double cx = width / 2.0f; double cy = height / 2.0f; - camMatrix = new Mat (3, 3, CvType.CV_64FC1); - camMatrix.put (0, 0, fx); - camMatrix.put (0, 1, 0); - camMatrix.put (0, 2, cx); - camMatrix.put (1, 0, 0); - camMatrix.put (1, 1, fy); - camMatrix.put (1, 2, cy); - camMatrix.put (2, 0, 0); - camMatrix.put (2, 1, 0); - camMatrix.put (2, 2, 1.0f); - Debug.Log ("camMatrix " + camMatrix.dump ()); + camMatrix = new Mat(3, 3, CvType.CV_64FC1); + camMatrix.put(0, 0, fx); + camMatrix.put(0, 1, 0); + camMatrix.put(0, 2, cx); + camMatrix.put(1, 0, 0); + camMatrix.put(1, 1, fy); + camMatrix.put(1, 2, cy); + camMatrix.put(2, 0, 0); + camMatrix.put(2, 1, 0); + camMatrix.put(2, 2, 1.0f); + Debug.Log("camMatrix " + camMatrix.dump()); + + distCoeffs = new MatOfDouble(0, 0, 0, 0); + Debug.Log("distCoeffs " + distCoeffs.dump()); - distCoeffs = new MatOfDouble (0, 0, 0, 0); - Debug.Log ("distCoeffs " + distCoeffs.dump ()); - //calibration camera - Size imageSize = new Size (width * imageSizeScale, height * imageSizeScale); + Size imageSize = new Size(width * imageSizeScale, height * imageSizeScale); double apertureWidth = 0; double apertureHeight = 0; double[] fovx = new double[1]; double[] fovy = new double[1]; double[] focalLength = new double[1]; - Point principalPoint = new Point (0, 0); + Point principalPoint = new Point(0, 0); double[] aspectratio = new double[1]; - - Calib3d.calibrationMatrixValues (camMatrix, imageSize, apertureWidth, apertureHeight, fovx, fovy, focalLength, principalPoint, aspectratio); - - Debug.Log ("imageSize " + imageSize.ToString ()); - Debug.Log ("apertureWidth " + apertureWidth); - Debug.Log ("apertureHeight " + apertureHeight); - Debug.Log ("fovx " + fovx [0]); - Debug.Log ("fovy " + fovy [0]); - Debug.Log ("focalLength " + focalLength [0]); - Debug.Log ("principalPoint " + principalPoint.ToString ()); - Debug.Log ("aspectratio " + aspectratio [0]); - - + + Calib3d.calibrationMatrixValues(camMatrix, imageSize, apertureWidth, apertureHeight, fovx, fovy, focalLength, principalPoint, aspectratio); + + Debug.Log("imageSize " + imageSize.ToString()); + Debug.Log("apertureWidth " + apertureWidth); + Debug.Log("apertureHeight " + apertureHeight); + Debug.Log("fovx " + fovx[0]); + Debug.Log("fovy " + fovy[0]); + Debug.Log("focalLength " + focalLength[0]); + Debug.Log("principalPoint " + principalPoint.ToString()); + Debug.Log("aspectratio " + aspectratio[0]); + + //To convert the difference of the FOV value of the OpenCV and Unity. - double fovXScale = (2.0 * Mathf.Atan ((float)(imageSize.width / (2.0 * fx)))) / (Mathf.Atan2 ((float)cx, (float)fx) + Mathf.Atan2 ((float)(imageSize.width - cx), (float)fx)); - double fovYScale = (2.0 * Mathf.Atan ((float)(imageSize.height / (2.0 * fy)))) / (Mathf.Atan2 ((float)cy, (float)fy) + Mathf.Atan2 ((float)(imageSize.height - cy), (float)fy)); - - Debug.Log ("fovXScale " + fovXScale); - Debug.Log ("fovYScale " + fovYScale); - - + double fovXScale = (2.0 * Mathf.Atan((float)(imageSize.width / (2.0 * fx)))) / (Mathf.Atan2((float)cx, (float)fx) + Mathf.Atan2((float)(imageSize.width - cx), (float)fx)); + double fovYScale = (2.0 * Mathf.Atan((float)(imageSize.height / (2.0 * fy)))) / (Mathf.Atan2((float)cy, (float)fy) + Mathf.Atan2((float)(imageSize.height - cy), (float)fy)); + + Debug.Log("fovXScale " + fovXScale); + Debug.Log("fovYScale " + fovYScale); + + //Adjust Unity Camera FOV https://github.com/opencv/opencv/commit/8ed1945ccd52501f5ab22bdec6aa1f91f1e2cfd4 - if (widthScale < heightScale) { - ARCamera.fieldOfView = (float)(fovx [0] * fovXScale); - } else { - ARCamera.fieldOfView = (float)(fovy [0] * fovYScale); + if (widthScale < heightScale) + { + ARCamera.fieldOfView = (float)(fovx[0] * fovXScale); } - - - invertYM = Matrix4x4.TRS (Vector3.zero, Quaternion.identity, new Vector3 (1, -1, 1)); - Debug.Log ("invertYM " + invertYM.ToString ()); - - invertZM = Matrix4x4.TRS (Vector3.zero, Quaternion.identity, new Vector3 (1, 1, -1)); - Debug.Log ("invertZM " + invertZM.ToString ()); + else + { + ARCamera.fieldOfView = (float)(fovy[0] * fovYScale); + } + + + invertYM = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1, -1, 1)); + Debug.Log("invertYM " + invertYM.ToString()); + + invertZM = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1, 1, -1)); + Debug.Log("invertZM " + invertZM.ToString()); - grayMat = new Mat (webCamTextureMat.rows (), webCamTextureMat.cols (), CvType.CV_8UC1); - - axes.SetActive (false); - head.SetActive (false); - rightEye.SetActive (false); - leftEye.SetActive (false); - mouth.SetActive (false); + grayMat = new Mat(webCamTextureMat.rows(), webCamTextureMat.cols(), CvType.CV_8UC1); + + axes.SetActive(false); + head.SetActive(false); + rightEye.SetActive(false); + leftEye.SetActive(false); + mouth.SetActive(false); } /// /// Raises the webcam texture to mat helper disposed event. /// - public void OnWebCamTextureToMatHelperDisposed () + public void OnWebCamTextureToMatHelperDisposed() { - Debug.Log ("OnWebCamTextureToMatHelperDisposed"); - - faceTracker.reset (); + Debug.Log("OnWebCamTextureToMatHelperDisposed"); - grayMat.Dispose (); - camMatrix.Dispose (); - distCoeffs.Dispose (); + faceTracker.reset(); + + grayMat.Dispose(); + camMatrix.Dispose(); + distCoeffs.Dispose(); } /// /// Raises the webcam texture to mat helper error occurred event. /// /// Error code. - public void OnWebCamTextureToMatHelperErrorOccurred (WebCamTextureToMatHelper.ErrorCode errorCode) + public void OnWebCamTextureToMatHelperErrorOccurred(WebCamTextureToMatHelper.ErrorCode errorCode) { - Debug.Log ("OnWebCamTextureToMatHelperErrorOccurred " + errorCode); + Debug.Log("OnWebCamTextureToMatHelperErrorOccurred " + errorCode); } // Update is called once per frame - void Update () + void Update() { - if (webCamTextureToMatHelper.IsPlaying () && webCamTextureToMatHelper.DidUpdateThisFrame ()) { - - Mat rgbaMat = webCamTextureToMatHelper.GetMat (); + if (webCamTextureToMatHelper.IsPlaying() && webCamTextureToMatHelper.DidUpdateThisFrame()) + { + + Mat rgbaMat = webCamTextureToMatHelper.GetMat(); //convert image to greyscale - Imgproc.cvtColor (rgbaMat, grayMat, Imgproc.COLOR_RGBA2GRAY); - - - if (isAutoResetMode || faceTracker.getPoints ().Count <= 0) { -// Debug.Log ("detectFace"); - - //convert image to greyscale - using (Mat equalizeHistMat = new Mat ()) using (MatOfRect faces = new MatOfRect ()) { - - Imgproc.equalizeHist (grayMat, equalizeHistMat); - - cascade.detectMultiScale (equalizeHistMat, faces, 1.1f, 2, 0 - | Objdetect.CASCADE_FIND_BIGGEST_OBJECT - | Objdetect.CASCADE_SCALE_IMAGE, new Size (equalizeHistMat.cols () * 0.15, equalizeHistMat.cols () * 0.15), new Size ()); - - - - if (faces.rows () > 0) { -// Debug.Log ("faces " + faces.dump ()); + Imgproc.cvtColor(rgbaMat, grayMat, Imgproc.COLOR_RGBA2GRAY); - List rectsList = faces.toList (); - List pointsList = faceTracker.getPoints (); - - if (isAutoResetMode) { + + if (isAutoResetMode || faceTracker.getPoints().Count <= 0) + { + // Debug.Log ("detectFace"); + + //convert image to greyscale + using (Mat equalizeHistMat = new Mat()) using (MatOfRect faces = new MatOfRect()) + { + + Imgproc.equalizeHist(grayMat, equalizeHistMat); + + cascade.detectMultiScale(equalizeHistMat, faces, 1.1f, 2, 0 + | Objdetect.CASCADE_FIND_BIGGEST_OBJECT + | Objdetect.CASCADE_SCALE_IMAGE, new Size(equalizeHistMat.cols() * 0.15, equalizeHistMat.cols() * 0.15), new Size()); + + + + if (faces.rows() > 0) + { + // Debug.Log ("faces " + faces.dump ()); + + List rectsList = faces.toList(); + List pointsList = faceTracker.getPoints(); + + if (isAutoResetMode) + { //add initial face points from MatOfRect - if (pointsList.Count <= 0) { - faceTracker.addPoints (faces); -// Debug.Log ("reset faces "); - } else { - - for (int i = 0; i < rectsList.Count; i++) { - - OpenCVForUnity.CoreModule.Rect trackRect = new OpenCVForUnity.CoreModule.Rect (rectsList [i].x + rectsList [i].width / 3, rectsList [i].y + rectsList [i].height / 2, rectsList [i].width / 3, rectsList [i].height / 3); + if (pointsList.Count <= 0) + { + faceTracker.addPoints(faces); + // Debug.Log ("reset faces "); + } + else + { + + for (int i = 0; i < rectsList.Count; i++) + { + + OpenCVForUnity.CoreModule.Rect trackRect = new OpenCVForUnity.CoreModule.Rect(rectsList[i].x + rectsList[i].width / 3, rectsList[i].y + rectsList[i].height / 2, rectsList[i].width / 3, rectsList[i].height / 3); //It determines whether nose point has been included in trackRect. - if (i < pointsList.Count && !trackRect.contains (pointsList [i] [67])) { - rectsList.RemoveAt (i); - pointsList.RemoveAt (i); -// Debug.Log ("remove " + i); + if (i < pointsList.Count && !trackRect.contains(pointsList[i][67])) + { + rectsList.RemoveAt(i); + pointsList.RemoveAt(i); + // Debug.Log ("remove " + i); } - Imgproc.rectangle (rgbaMat, new Point (trackRect.x, trackRect.y), new Point (trackRect.x + trackRect.width, trackRect.y + trackRect.height), new Scalar (0, 0, 255, 255), 2); + Imgproc.rectangle(rgbaMat, new Point(trackRect.x, trackRect.y), new Point(trackRect.x + trackRect.width, trackRect.y + trackRect.height), new Scalar(0, 0, 255, 255), 2); } } - } else { - faceTracker.addPoints (faces); + } + else + { + faceTracker.addPoints(faces); } //draw face rect - for (int i = 0; i < rectsList.Count; i++) { - Imgproc.rectangle (rgbaMat, new Point (rectsList [i].x, rectsList [i].y), new Point (rectsList [i].x + rectsList [i].width, rectsList [i].y + rectsList [i].height), new Scalar (255, 0, 0, 255), 2); + for (int i = 0; i < rectsList.Count; i++) + { + Imgproc.rectangle(rgbaMat, new Point(rectsList[i].x, rectsList[i].y), new Point(rectsList[i].x + rectsList[i].width, rectsList[i].y + rectsList[i].height), new Scalar(255, 0, 0, 255), 2); } - } else { - if (isAutoResetMode) { - faceTracker.reset (); - - rightEye.SetActive (false); - leftEye.SetActive (false); - head.SetActive (false); - mouth.SetActive (false); - axes.SetActive (false); - } - } - } - } - - - //track face points.if face points <= 0, always return false. - if (faceTracker.track (grayMat, faceTrackerParams)) { - if (isShowingFacePoints) faceTracker.draw (rgbaMat, new Scalar (255, 0, 0, 255), new Scalar (0, 255, 0, 255)); - - Imgproc.putText (rgbaMat, "'Tap' or 'Space Key' to Reset", new Point (5, rgbaMat.rows () - 5), Imgproc.FONT_HERSHEY_SIMPLEX, 0.8, new Scalar (255, 255, 255, 255), 2, Imgproc.LINE_AA, false); - - - Point[] points = faceTracker.getPoints () [0]; - - - if (points.Length > 0) { - -// for (int i = 0; i < points.Length; i++) -// { -// Imgproc.putText(rgbaMat, "" + i, new Point(points [i].x, points [i].y), Imgproc.FONT_HERSHEY_SIMPLEX, 0.3, new Scalar(0, 0, 255, 255), 2, Imgproc.LINE_AA, false); -// } - - - imagePoints.fromArray ( - points [31],//l eye - points [36],//r eye - points [67],//nose - points [48],//l mouth - points [54] //r mouth -// , -// points [0],//l ear -// points [14]//r ear - ); - - - Calib3d.solvePnP (objectPoints, imagePoints, camMatrix, distCoeffs, rvec, tvec); - - bool isRefresh = false; - - if (tvec.get (2, 0) [0] > 0 && tvec.get (2, 0) [0] < 1200 * ((float)rgbaMat.cols () / (float)webCamTextureToMatHelper.requestedWidth)) { - - isRefresh = true; - - if (oldRvec == null) { - oldRvec = new Mat (); - rvec.copyTo (oldRvec); - } - if (oldTvec == null) { - oldTvec = new Mat (); - tvec.copyTo (oldTvec); - } - - - //filter Rvec Noise. - using (Mat absDiffRvec = new Mat ()) { - Core.absdiff (rvec, oldRvec, absDiffRvec); - - // Debug.Log ("absDiffRvec " + absDiffRvec.dump()); - - using (Mat cmpRvec = new Mat ()) { - Core.compare (absDiffRvec, new Scalar (rvecNoiseFilterRange), cmpRvec, Core.CMP_GT); - - if (Core.countNonZero (cmpRvec) > 0) isRefresh = false; - } - } - - //filter Tvec Noise. - using (Mat absDiffTvec = new Mat ()) { - Core.absdiff (tvec, oldTvec, absDiffTvec); - - // Debug.Log ("absDiffRvec " + absDiffRvec.dump()); - - using (Mat cmpTvec = new Mat ()) { - Core.compare (absDiffTvec, new Scalar (tvecNoiseFilterRange), cmpTvec, Core.CMP_GT); - - if (Core.countNonZero (cmpTvec) > 0) isRefresh = false; - } - } } - - if (isRefresh) { - - if (isShowingEffects) rightEye.SetActive (true); - if (isShowingEffects) leftEye.SetActive (true); - if (isShowingHead) head.SetActive (true); - if (isShowingAxes) axes.SetActive (true); - - - if ((Mathf.Abs ((float)(points [48].x - points [56].x)) < Mathf.Abs ((float)(points [31].x - points [36].x)) / 2.2 - && Mathf.Abs ((float)(points [51].y - points [57].y)) > Mathf.Abs ((float)(points [31].x - points [36].x)) / 2.9) - || Mathf.Abs ((float)(points [51].y - points [57].y)) > Mathf.Abs ((float)(points [31].x - points [36].x)) / 2.7) { - - if (isShowingEffects) mouth.SetActive (true); - - } else { - if (isShowingEffects) mouth.SetActive (false); - } - - rvec.copyTo (oldRvec); - tvec.copyTo (oldTvec); - - Calib3d.Rodrigues (rvec, rotM); - - transformationM.SetRow (0, new Vector4 ((float)rotM.get (0, 0) [0], (float)rotM.get (0, 1) [0], (float)rotM.get (0, 2) [0], (float)tvec.get (0, 0) [0])); - transformationM.SetRow (1, new Vector4 ((float)rotM.get (1, 0) [0], (float)rotM.get (1, 1) [0], (float)rotM.get (1, 2) [0], (float)tvec.get (1, 0) [0])); - transformationM.SetRow (2, new Vector4 ((float)rotM.get (2, 0) [0], (float)rotM.get (2, 1) [0], (float)rotM.get (2, 2) [0], (float)tvec.get (2, 0) [0])); - transformationM.SetRow (3, new Vector4 (0, 0, 0, 1)); + else + { + if (isAutoResetMode) + { + faceTracker.reset(); + + rightEye.SetActive(false); + leftEye.SetActive(false); + head.SetActive(false); + mouth.SetActive(false); + axes.SetActive(false); + } + } + } + } + + + //track face points.if face points <= 0, always return false. + if (faceTracker.track(grayMat, faceTrackerParams)) + { + if (isShowingFacePoints) faceTracker.draw(rgbaMat, new Scalar(255, 0, 0, 255), new Scalar(0, 255, 0, 255)); + + Imgproc.putText(rgbaMat, "'Tap' or 'Space Key' to Reset", new Point(5, rgbaMat.rows() - 5), Imgproc.FONT_HERSHEY_SIMPLEX, 0.8, new Scalar(255, 255, 255, 255), 2, Imgproc.LINE_AA, false); + + + Point[] points = faceTracker.getPoints()[0]; + + + if (points.Length > 0) + { + + //for (int i = 0; i < points.Length; i++) + //{ + // Imgproc.putText(rgbaMat, "" + i, new Point(points [i].x, points [i].y), Imgproc.FONT_HERSHEY_SIMPLEX, 0.3, new Scalar(0, 0, 255, 255), 2, Imgproc.LINE_AA, false); + //} + + + imagePoints.fromArray( + points[31],//l eye + points[36],//r eye + points[67],//nose + points[48],//l mouth + points[54], //r mouth + points[0],//l ear + points[14]//r ear + ); + + + Calib3d.solvePnP(objectPoints, imagePoints, camMatrix, distCoeffs, rvec, tvec); + + bool isRefresh = false; + + if (tvec.dims() != 0 && tvec.get(2, 0)[0] > 0 && tvec.get(2, 0)[0] < 1200 * ((float)rgbaMat.cols() / (float)webCamTextureToMatHelper.requestedWidth)) + { + + isRefresh = true; + + if (oldRvec == null) + { + oldRvec = new Mat(); + rvec.copyTo(oldRvec); + } + if (oldTvec == null) + { + oldTvec = new Mat(); + tvec.copyTo(oldTvec); + } + + + //filter Rvec Noise. + using (Mat absDiffRvec = new Mat()) + { + Core.absdiff(rvec, oldRvec, absDiffRvec); + + //Debug.Log ("absDiffRvec " + absDiffRvec.dump()); + + using (Mat cmpRvec = new Mat()) + { + Core.compare(absDiffRvec, new Scalar(rvecNoiseFilterRange), cmpRvec, Core.CMP_GT); + + if (Core.countNonZero(cmpRvec) > 0) isRefresh = false; + } + } + + //filter Tvec Noise. + using (Mat absDiffTvec = new Mat()) + { + Core.absdiff(tvec, oldTvec, absDiffTvec); + + //Debug.Log ("absDiffRvec " + absDiffRvec.dump()); + + using (Mat cmpTvec = new Mat()) + { + Core.compare(absDiffTvec, new Scalar(tvecNoiseFilterRange), cmpTvec, Core.CMP_GT); + + if (Core.countNonZero(cmpTvec) > 0) isRefresh = false; + } + } + } + + if (isRefresh) + { + + if (isShowingEffects) rightEye.SetActive(true); + if (isShowingEffects) leftEye.SetActive(true); + if (isShowingHead) head.SetActive(true); + if (isShowingAxes) axes.SetActive(true); + + + if ((Mathf.Abs((float)(points[48].x - points[56].x)) < Mathf.Abs((float)(points[31].x - points[36].x)) / 2.2 + && Mathf.Abs((float)(points[51].y - points[57].y)) > Mathf.Abs((float)(points[31].x - points[36].x)) / 2.9) + || Mathf.Abs((float)(points[51].y - points[57].y)) > Mathf.Abs((float)(points[31].x - points[36].x)) / 2.7) + { + + if (isShowingEffects) mouth.SetActive(true); + + } + else + { + if (isShowingEffects) mouth.SetActive(false); + } + + rvec.copyTo(oldRvec); + tvec.copyTo(oldTvec); + + Calib3d.Rodrigues(rvec, rotM); + + transformationM.SetRow(0, new Vector4((float)rotM.get(0, 0)[0], (float)rotM.get(0, 1)[0], (float)rotM.get(0, 2)[0], (float)tvec.get(0, 0)[0])); + transformationM.SetRow(1, new Vector4((float)rotM.get(1, 0)[0], (float)rotM.get(1, 1)[0], (float)rotM.get(1, 2)[0], (float)tvec.get(1, 0)[0])); + transformationM.SetRow(2, new Vector4((float)rotM.get(2, 0)[0], (float)rotM.get(2, 1)[0], (float)rotM.get(2, 2)[0], (float)tvec.get(2, 0)[0])); + transformationM.SetRow(3, new Vector4(0, 0, 0, 1)); // right-handed coordinates system (OpenCV) to left-handed one (Unity) ARM = invertYM * transformationM; @@ -630,114 +665,126 @@ namespace FaceTrackerExample // Apply Z-axis inverted matrix. ARM = ARM * invertZM; - if (shouldMoveARCamera) { + if (shouldMoveARCamera) + { - if (ARGameObject != null) { + if (ARGameObject != null) + { ARM = ARGameObject.transform.localToWorldMatrix * ARM.inverse; - ARUtils.SetTransformFromMatrix (ARCamera.transform, ref ARM); - ARGameObject.SetActive (true); + ARUtils.SetTransformFromMatrix(ARCamera.transform, ref ARM); + ARGameObject.SetActive(true); } - } else { + } + else + { ARM = ARCamera.transform.localToWorldMatrix * ARM; - if (ARGameObject != null) { - ARUtils.SetTransformFromMatrix (ARGameObject.transform, ref ARM); - ARGameObject.SetActive (true); + if (ARGameObject != null) + { + ARUtils.SetTransformFromMatrix(ARGameObject.transform, ref ARM); + ARGameObject.SetActive(true); } } } } } - -// Imgproc.putText (rgbaMat, "W:" + rgbaMat.width () + " H:" + rgbaMat.height () + " SO:" + Screen.orientation, new Point (5, rgbaMat.rows () - 10), Imgproc.FONT_HERSHEY_SIMPLEX, 1.0, new Scalar (255, 255, 255, 255), 2, Imgproc.LINE_AA, false); - - Utils.fastMatToTexture2D (rgbaMat, texture); + + //Imgproc.putText (rgbaMat, "W:" + rgbaMat.width () + " H:" + rgbaMat.height () + " SO:" + Screen.orientation, new Point (5, rgbaMat.rows () - 10), Imgproc.FONT_HERSHEY_SIMPLEX, 1.0, new Scalar (255, 255, 255, 255), 2, Imgproc.LINE_AA, false); + + Utils.fastMatToTexture2D(rgbaMat, texture); } - - if (Input.GetKeyUp (KeyCode.Space) || Input.touchCount > 0) { - faceTracker.reset (); - if (oldRvec != null) { - oldRvec.Dispose (); + + if (Input.GetKeyUp(KeyCode.Space) || Input.touchCount > 0) + { + faceTracker.reset(); + if (oldRvec != null) + { + oldRvec.Dispose(); oldRvec = null; } - if (oldTvec != null) { - oldTvec.Dispose (); + if (oldTvec != null) + { + oldTvec.Dispose(); oldTvec = null; } - - rightEye.SetActive (false); - leftEye.SetActive (false); - head.SetActive (false); - mouth.SetActive (false); - axes.SetActive (false); - } + + rightEye.SetActive(false); + leftEye.SetActive(false); + head.SetActive(false); + mouth.SetActive(false); + axes.SetActive(false); + } } /// /// Raises the disable event. /// - void OnDisable () + void OnDisable() { - webCamTextureToMatHelper.Dispose (); + webCamTextureToMatHelper.Dispose(); - if (cascade != null) cascade.Dispose (); + if (cascade != null) cascade.Dispose(); - #if UNITY_WEBGL && !UNITY_EDITOR - if (getFilePath_Coroutine != null) { - StopCoroutine (getFilePath_Coroutine); - ((IDisposable)getFilePath_Coroutine).Dispose (); +#if UNITY_WEBGL && !UNITY_EDITOR + if (getFilePath_Coroutine != null) + { + StopCoroutine(getFilePath_Coroutine); + ((IDisposable)getFilePath_Coroutine).Dispose(); } - #endif +#endif } /// /// Raises the back button event. /// - public void OnBackButton () + public void OnBackButton() { - SceneManager.LoadScene ("FaceTrackerExample"); + SceneManager.LoadScene("FaceTrackerExample"); } /// /// Raises the play button event. /// - public void OnPlayButton () + public void OnPlayButton() { - webCamTextureToMatHelper.Play (); + webCamTextureToMatHelper.Play(); } /// /// Raises the pause button event. /// - public void OnPauseButton () + public void OnPauseButton() { - webCamTextureToMatHelper.Pause (); + webCamTextureToMatHelper.Pause(); } /// /// Raises the stop button event. /// - public void OnStopButton () + public void OnStopButton() { - webCamTextureToMatHelper.Stop (); + webCamTextureToMatHelper.Stop(); } /// /// Raises the change camera button event. /// - public void OnChangeCameraButton () + public void OnChangeCameraButton() { - webCamTextureToMatHelper.requestedIsFrontFacing = !webCamTextureToMatHelper.IsFrontFacing (); + webCamTextureToMatHelper.requestedIsFrontFacing = !webCamTextureToMatHelper.IsFrontFacing(); } /// /// Raises the is showing face points toggle event. /// - public void OnIsShowingFacePointsToggle () + public void OnIsShowingFacePointsToggle() { - if (isShowingFacePointsToggle.isOn) { + if (isShowingFacePointsToggle.isOn) + { isShowingFacePoints = true; - } else { + } + else + { isShowingFacePoints = false; } } @@ -745,52 +792,64 @@ namespace FaceTrackerExample /// /// Raises the is showing axes toggle event. /// - public void OnIsShowingAxesToggle () + public void OnIsShowingAxesToggle() { - if (isShowingAxesToggle.isOn) { + if (isShowingAxesToggle.isOn) + { isShowingAxes = true; - } else { + } + else + { isShowingAxes = false; - axes.SetActive (false); + axes.SetActive(false); } } /// /// Raises the is showing head toggle event. /// - public void OnIsShowingHeadToggle () + public void OnIsShowingHeadToggle() { - if (isShowingHeadToggle.isOn) { + if (isShowingHeadToggle.isOn) + { isShowingHead = true; - } else { + } + else + { isShowingHead = false; - head.SetActive (false); + head.SetActive(false); } } /// /// Raises the is showin effects toggle event. /// - public void OnIsShowingEffectsToggle () + public void OnIsShowingEffectsToggle() { - if (isShowingEffectsToggle.isOn) { + if (isShowingEffectsToggle.isOn) + { isShowingEffects = true; - } else { + } + else + { isShowingEffects = false; - rightEye.SetActive (false); - leftEye.SetActive (false); - mouth.SetActive (false); + rightEye.SetActive(false); + leftEye.SetActive(false); + mouth.SetActive(false); } } /// /// Raises the change auto reset mode toggle event. /// - public void OnIsAutoResetModeToggle () + public void OnIsAutoResetModeToggle() { - if (isAutoResetModeToggle.isOn) { + if (isAutoResetModeToggle.isOn) + { isAutoResetMode = true; - } else { + } + else + { isAutoResetMode = false; } } diff --git a/Assets/FaceTrackerExample/ReadMe.pdf b/Assets/FaceTrackerExample/ReadMe.pdf index ecfd6db..80bc085 100644 Binary files a/Assets/FaceTrackerExample/ReadMe.pdf and b/Assets/FaceTrackerExample/ReadMe.pdf differ