takuya-takeuchi / UltraFaceDotNet

C# version of Ultra-Light-Fast-Generic-Face-Detector-1MB for Windows, MacOS, Linux, iOS and Android

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Memory leak

NeuralAnt opened this issue · comments

Hi, thank you for your efforts.
I would like to use your library, but there is a memory leak somewher.
If I instanciate only one UltraFace and get only one Mat Cv2.ImRead(imageFile) and than use ultraFace.Detect in a loop, it leaks memory very fast.
Can you help me with that?

Hi Takuya,

I have found it! It's in the GenerateBBox method:

` private void GenerateBBox(ICollection boundingBoxCollection, Mat scores, Mat boxes, float scoreThreshold, int numAnchors)
{
for (var i = 0; i < numAnchors; i++)
if (scores.Channel(0)[i * 2 + 1] > scoreThreshold)
{
var rects = new FaceInfo();
var xCenter = boxes.Channel(0)[i * 4] * CenterVariance * this._Priors[i][2] + this._Priors[i][0];
var yCenter = boxes.Channel(0)[i * 4 + 1] * CenterVariance * this._Priors[i][3] + this._Priors[i][1];
var w = Math.Exp(boxes.Channel(0)[i * 4 + 2] * SizeVariance) * this._Priors[i][2];
var h = Math.Exp(boxes.Channel(0)[i * 4 + 3] * SizeVariance) * this._Priors[i][3];

                rects.X1 = Clip(xCenter - w / 2.0, 1) * this._ImageW;
                rects.Y1 = Clip(yCenter - h / 2.0, 1) * this._ImageH;
                rects.X2 = Clip(xCenter + w / 2.0, 1) * this._ImageW;
                rects.Y2 = Clip(yCenter + h / 2.0, 1) * this._ImageH;
                rects.Score = Clip(scores.Channel(0)[i * 2 + 1], 1);

                boundingBoxCollection.Add(rects);
            }
    }`

Can you chek if my understanding is correct, and my soltuion is ok?
`private void GenerateBBox(ICollection boundingBoxCollection, Mat scores, Mat boxes, float scoreThreshold, int numAnchors)
{

        var scoresChannelZero = scores.Channel(0);
        var boxesChannelZero = boxes.Channel(0);

        for (var i = 0; i < numAnchors; i++)
            if (scoresChannelZero[i * 2 + 1] > scoreThreshold)
            {
                var rects = new FaceInfo();
                var xCenter = boxesChannelZero[i * 4] * CenterVariance * this._Priors[i][2] + this._Priors[i][0];
                var yCenter = boxesChannelZero[i * 4 + 1] * CenterVariance * this._Priors[i][3] + this._Priors[i][1];
                var w = Math.Exp(boxesChannelZero[i * 4 + 2] * SizeVariance) * this._Priors[i][2];
                var h = Math.Exp(boxesChannelZero[i * 4 + 3] * SizeVariance) * this._Priors[i][3];

                rects.X1 = Clip(xCenter - w / 2.0, 1) * this._ImageW;
                rects.Y1 = Clip(yCenter - h / 2.0, 1) * this._ImageH;
                rects.X2 = Clip(xCenter + w / 2.0, 1) * this._ImageW;
                rects.Y2 = Clip(yCenter + h / 2.0, 1) * this._ImageH;
                rects.Score = Clip(scoresChannelZero[i * 2 + 1], 1);

                boundingBoxCollection.Add(rects);
            }

        scoresChannelZero.Dispose();
        boxesChannelZero.Dispose();
    }`

We coul use using blocks, I just wanted to be explicit.

Thank you for kindly support and good investigation!!
Exactly. NccDotNet.Mat.Channel(int) returns new Mat object.
So result of Channel method should be disposed.

OK, let me test fixed code.

@NeuralAnt
OK. Fixed.
Could you check the latest develop branch?
You can test by only compiling UltraFaceDotNet without NcnnDotNet module.

After your confirmation, I will publish new nuget package 1.0.0.1.