takuya-takeuchi / DlibDotNet

Dlib .NET wrapper written in C++ and C# for Windows, MacOS, Linux and iOS
MIT License
486 stars 134 forks source link

ram exponencial consumption #208

Open danijerez opened 4 years ago

danijerez commented 4 years ago

I've been doing some benchmarks capturing rectangles of faces in a continuous loop and the RAM consumption seems exponential, is it possible that there is some memory leak somewhere? In EMGU it doesn't happen when I apply a shape.

takuya-takeuchi commented 4 years ago

please attach source code.

danijerez commented 4 years ago

abjoint the test that I am doing in Unity, although it also happens to me with a similar code in windows forms

using DlibDotNet;
using System.IO;
using UnityEngine;

public class Camera : MonoBehaviour
{
    public static WebCamTexture backCam;
    public string filePath;
    private ShapePredictor sp;
    private Texture2D snap;

    void Start()
    {
        if (backCam == null)
            backCam = new WebCamTexture();

        filePath = Path.GetTempFileName();
        sp = ShapePredictor.Deserialize(Path.Combine(Application.dataPath, "Resources/shape_predictor_68_face_landmarks.dat"));

        if (!backCam.isPlaying)
            backCam.Play();

    }

    private void Update()
    {
        if (backCam != null && backCam.isPlaying)
        {
            snap = new Texture2D(backCam.width, backCam.height);
            snap.SetPixels(backCam.GetPixels());
            snap.Apply();

            File.WriteAllBytes(filePath, snap.EncodeToPNG());

            using (var fd = Dlib.GetFrontalFaceDetector())
            {
                var img = Dlib.LoadImage<RgbPixel>(filePath);
                var faces = fd.Operator(img);

                foreach (var face in faces)
                {
                    // find the landmark points for this face
                    var shape = sp.Detect(img, face);

                    // draw the landmark points on the image
                    for (var i = 0; i < shape.Parts; i++)
                    {
                        var point = shape.GetPart((uint)i);
                        var rect = new Rectangle(point);
                        Dlib.DrawRectangle(img, rect, color: new RgbPixel(255, 255, 255), thickness: 2);
                    }
                }

                if (faces.Length > 0)
                    Dlib.SavePng(img, filePath);

                var rawData = File.ReadAllBytes(filePath);
                var texture = new Texture2D(backCam.width, backCam.height);
                texture.LoadImage(rawData);

                GetComponent<Renderer>().material.mainTexture = texture;

            }
        }

    }
}
takuya-takeuchi commented 4 years ago

@danijerez img, faces and shape are disposable object. You must dispose them.

danijerez commented 4 years ago

ok, i will try it, thanks!

How do you make a dispose of faces? (Rectagle [])

danijerez commented 4 years ago

I have added all the possible disposes and the ram continues to act the same, the consumption is exponential.

using DlibDotNet;
using System;
using System.IO;
using UnityEngine;

public class Camera : MonoBehaviour
{
    public static WebCamTexture backCam;
    public string filePath;
    private ShapePredictor sp;
    private Texture2D snap;

    void Start()
    {
        if (backCam == null)
            backCam = new WebCamTexture();

        filePath = Path.GetTempFileName();
        sp = ShapePredictor.Deserialize(Path.Combine(Application.dataPath, "Resources/shape_predictor_68_face_landmarks.dat"));

        if (!backCam.isPlaying)
            backCam.Play();

    }

    private void Update()
    {
        if (backCam != null && backCam.isPlaying)
        {
            snap = new Texture2D(backCam.width, backCam.height);
            snap.SetPixels(backCam.GetPixels());
            snap.Apply();

            File.WriteAllBytes(filePath, snap.EncodeToPNG());

            using (var fd = Dlib.GetFrontalFaceDetector())
            {
                var img = Dlib.LoadImage<RgbPixel>(filePath);
                var faces = fd.Operator(img);

                foreach (var face in faces)
                {
                    // find the landmark points for this face
                    var shape = sp.Detect(img, face);

                    // draw the landmark points on the image
                    for (var i = 0; i < shape.Parts; i++)
                    {
                        var point = shape.GetPart((uint)i);
                        var rect = new Rectangle(point);
                        Dlib.DrawRectangle(img, rect, color: new RgbPixel(255, 255, 255), thickness: 2);
                    }

                    shape.Dispose();
                }

                if (faces.Length > 0)
                    Dlib.SavePng(img, filePath);

                faces = null;
                img.Dispose();
                var rawData = File.ReadAllBytes(filePath);
                var texture = new Texture2D(backCam.width, backCam.height);
                texture.LoadImage(rawData);

                GetComponent<Renderer>().material.mainTexture = texture;
                GC.Collect();
            }
        }

    }
}
Megadino commented 4 years ago

@danijerez you create two Texture2D objects on every web camera frame, but I don't see a code that release/destroy those textures and frees a memory they consumed. GC.Collect() is not enough to release Unity objects. You need to use Unity specific calls to release Texture2D.

You can do a simple test to understand if the issue in DLib or Unity - just don't create new Texture2D but use a static bitmap in your sample which doesn't change on every frame and then check if memory leak is still there. If not - then it's Unity, not DLib.

danijerez commented 4 years ago

I have already discovered the problem, it is what you mentioned @Megadino had to use the Destroy of unity for the texture.

Thank you!