How to extract the shape predictor from “mmod_dog_hipsterizer.dat”

First of all, please look at this article. Hipsterize Your Dog With Deep Learning (dlib.net)

The “mmod_dog_hipsterizer.dat” cannot be used as a shape predictor data because it is distributed in a state in which combines multiple files. I will introduce here because I wrote the code for the use of the dog face shape predictor data in “DlibFaceLandmarkDetector”.

This example scene was created based on the “DlibFaceLandmarkDetector/Examples/CatDetectionExample”.

  • Replace the “CatDetectionExample.cs” that is attached to Quad to this script code.
  • Set to the dog image to the texture2D inspector.
  • The file that you downloaded and unzipped from here must be put to the “streamingAssets” folder.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;

#if UNITY_5_3 || UNITY_5_3_OR_NEWER
using UnityEngine.SceneManagement;
#endif
using DlibFaceLandmarkDetector;

namespace DlibFaceLandmarkDetectorSample
{
    /// <summary>
    /// Dog detection example.
    /// </summary>
    public class DogDetectionExample : MonoBehaviour
    {

        /// <summary>
        /// The texture2 d.
        /// </summary>
        public Texture2D texture2D; //https://github.com/davisking/dlib/raw/master/examples/faces/dogs.jpg

        private Texture2D m_tex;
        private int m_width, m_height;
        private Color[] m_linesColor = null;

        // Use this for initialization
        void Start ()
        {

            gameObject.transform.localScale = new Vector3 (texture2D.width, texture2D.height, 1);
            Debug.Log ("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation);
            
            float width = gameObject.transform.localScale.x;
            float height = gameObject.transform.localScale.y;
            
            float widthScale = (float)Screen.width / width;
            float heightScale = (float)Screen.height / height;
            if (widthScale < heightScale) {
                Camera.main.orthographicSize = (width * (float)Screen.height / (float)Screen.width) / 2;
            } else {
                Camera.main.orthographicSize = height / 2;
            }


            // How to extract the shape_predictor from "mmod_dog_hipsterizer.dat".
            // The file that you downloaded and unzipped from "http://dlib.net/files/mmod_dog_hipsterizer.dat.bz2" must be put to the "streamingAsset" folder.

            // Specify a file to read from and to create.
            string pathSource = Utils.getFilePath ("mmod_dog_hipsterizer.dat");
            string pathNew = Application.streamingAssetsPath + "/shape_predictor_6_dog_face_landmarks.dat";

            using (FileStream fsSource = new FileStream(pathSource,
                                                        FileMode.Open, FileAccess.Read)) {
                // Read the source file into a byte array.
                byte[] bytes = new byte[27776662];
                int numBytesToRead = bytes.Length;
                int numBytesRead = 0;

                fsSource.Seek (729946, SeekOrigin.Begin);
                // Read may return anything from 0 to numBytesToRead.
                fsSource.Read (bytes, numBytesRead, numBytesToRead);
                
                // Write the byte array to the other FileStream.
                using (FileStream fsNew = new FileStream(pathNew,
                                                         FileMode.Create, FileAccess.Write)) {
                    fsNew.Write (bytes, 0, numBytesToRead);
                }
            }

            FaceLandmarkDetector faceLandmarkDetector = new FaceLandmarkDetector (Utils.getFilePath (Utils.getFilePath ("shape_predictor_6_dog_face_landmarks.dat")));

            m_tex = new Texture2D (texture2D.width, texture2D.height);
            m_tex.SetPixels (0, 0, texture2D.width, texture2D.height, texture2D.GetPixels ());
            m_tex.Apply ();
            
            m_width = m_tex.width;
            m_height = m_tex.height;
            
            if (m_linesColor == null || m_linesColor.Length != m_width) {
                m_linesColor = null;
                m_linesColor = new Color[m_width];
            }
            faceLandmarkDetector.SetImage (m_tex);

            //detectResult is set manually.
            List<Rect> detectResult = new List<Rect> ();
            detectResult.Add (new Rect (115, 135, 215, 200));
            detectResult.Add (new Rect (552, 136, 225, 225));
            detectResult.Add (new Rect (153, 609, 175, 175));
            detectResult.Add (new Rect (520, 600, 220, 210));


            foreach (var rect in detectResult) {
                Debug.Log ("face : " + rect);

                //detect landmark points
                List<Vector2> points = faceLandmarkDetector.DetectLandmark (rect);
                
                Debug.Log ("face points count : " + points.Count);
                if (points.Count > 0) {
                    foreach (var point in points) {
                        Debug.Log ("face point : x " + point.x + " y " + point.y);

                        // draw landmark point
                        // Note. Since faceLandmarkDetector.DrawDetectLandmarkResult method to draw the landmark points is not available, have to use a texture2D.SetPixels method.
                        DrawRectangleFill ((int)point.x, m_height - (int)point.y, (int)point.x + 8, m_height - (int)point.y + 8, Color.green);

                    }
                    //DrawRectangleFill (1, 1, 8, 8, Color.green);

                    //draw landmark points
                    //faceLandmarkDetector.DrawDetectLandmarkResult (texture2D, 0, 255, 0, 255);
                }

                //draw face rects
                //faceLandmarkDetector.DrawDetectResult (texture2D, 255, 0, 0, 255, 3);
            }
            m_tex.Apply ();

            faceLandmarkDetector.Dispose ();

            gameObject.GetComponent<Renderer> ().material.mainTexture = m_tex;
        }
    
        // Update is called once per frame
        void Update ()
        {
    
        }

        public void OnBackButton ()
        {
            #if UNITY_5_3 || UNITY_5_3_OR_NEWER
            SceneManager.LoadScene ("DlibFaceLandmarkDetectorSample");
            #else
            Application.LoadLevel ("DlibFaceLandmarkDetectorSample");
            #endif
        }

        public void DrawRectangleFill (int x1, int y1, int x2, int y2, Color col)
        {
            if (x1 > x2) {
                int tmp = x1;
                x1 = x2;
                x2 = tmp;
            }
            if (y1 > y2) {
                int tmp = y1;
                y1 = y2;
                y2 = tmp;
            }
            if (x1 < 0 && x2 < 0)
                return;
            if (x1 >= m_width && x2 >= m_width)
                return;
            if (y1 < 0 && y2 < 0)
                return;
            if (y1 >= m_height && y2 >= m_height)
                return;
            if (x1 < 0)
                x1 = 0;
            if (x2 >= m_width)
                x2 = m_width - 1;
            if (y1 < 0)
                y1 = 0;
            if (y2 >= m_height - 1)
                y2 = m_height - 1;
            
            int scanLineSize = x2 - x1 + 1;
            for (int x = 0; x < scanLineSize; x++)
                m_linesColor [x] = col;
            for (int y = y1; y <= y2; y++)
                m_tex.SetPixels (x1, y, scanLineSize, 1, m_linesColor);
        }
    }
}

Note: Since the “FaceLandmarkDetector.DrawDetectLandmarkResult” method to draw landmark points is not available (This method supports only 68 landmark points), have to use the “Texture2D.SetPixels” method.

This image is the result image of executing the dog face shape predictor using “DlibFaceLandmarkDetector”.

how_to_use_dog_shape_predictor