Возникла следующая проблема, в данный момент работаю над программой распознования блоков с использованием библиотеки OpenCV (в качестве видеообработчика с использованием класса VideoCapture) и библиотеки детектора Alturus.Yolo (Использующим веса Yolov3).
Во время разработки модумя видеосчитывания возникла проблема, связанная с утечками памяти (картинка 1) , которые я не могу определить (недостаток знаний/проблемы внутри библиотеки).
Так же проблемы происходят при самой детекции, метод Alturus.Yolo.Detect() занимает от 181мс до 525мс (картинка 2), что очень замедляет картинку на выходе.
Вопросы в следующем:
- В чем может быть причина утечки? (Код прилагаю, пытался переписывать архитектуру и проводить Dispose() свойства pictureBox.Image, это снижало утечку, но:
а) при изменении размера выдавало постоянно ошибку
б) при увеличении окна утечка продолжалась) - Почему альтурус (при использовании GPU) съедает 2-3 гб при инициализации и при детекции занимает ресурс процессора на 200-525 мс? Это проблема библиотеки или я что-то делаю не так по архитектуре?
3)Насколько имеет уничтожать ресурсы picturebox с помощью Dispose()?
4)Есть ли возможность выводить сначала картинку с видеообработчика и параллельно в другом потоке вести обработку? И насколько это может, в теории, исправить ситуацию?
Ниже прикладываю фрагменты кода, которые могут понадобится
Код
private void _startVideo_Click(object sender, EventArgs e)
{
if(_videoPath != null)
{
#region LegacyThreadAltorus
//Проверкан на существование потока с Altorus
if (_altorusThread == null)
{
_altorusThread = new Thread(() =>
{
while (true)
{
if (_videoBox.InvokeRequired)
{
MethodInvoker mi = new MethodInvoker(() =>
{
_videoBox.Image = DetectFrame(StartVideo(_videoPath));
/_videoBox.Image = BitmapConverter.ToBitmap(StartVideo(_videoPath));/
});
mi.Invoke();
}
Cv2.WaitKey(_fps);
}
})
{
IsBackground = true,
Name = "Altorus Thread"
};
}
if(_altorusThread.ThreadState == (ThreadState.Background | ThreadState.Suspended))
{
_altorusThread.Resume();
}
else if(_altorusThread.ThreadState == (ThreadState.Background | ThreadState.Unstarted))
{
_altorusThread.Start();
}
#endregion
}
else
{
MessageBox.Show("Видео еще не загружено!");
};
}
/// <summary>
/// Запуск видео
/// </summary>
/// <returns>Возвращает frame в формате Bitmap</returns>
private Mat StartVideo(string path)
{
//Инициализация видеообоаботчика
if(_capture == null)
{
if(path != null)
{
_capture = new VideoCapture(path);
_fps = (int)(1000 / _capture.Fps);
}
else
{
MessageBox.Show("Вы не выбрали видео!");
}
}
Mat mat = new Mat();
_capture.Read(mat);
if (!mat.Empty())
{
/*_videoBox.Image = BitmapConverter.ToBitmap(mat);*/
/*_videoBox.Image = DetectFrame(mat);*/
return mat;
}
else
{
MessageBox.Show("Что-то пошло не так с загрузкой видео");
return null;
}
}
/// <summary>
/// Детекция ванн на изображении (Altorus.Yolo)
/// </summary>
/// <returns>Изображение типа Image с отрисованной детекцией</returns>
/// <remarks>Иначе возвращается null</remarks>
private Bitmap DetectFrame(Mat mat)
{
//Конвертация и подготовка средств отрисовки
Bitmap finalImage = BitmapConverter.ToBitmap(mat);
Graphics graphics = Graphics.FromImage(finalImage);
Font font = new Font("Consolas", 18, FontStyle.Bold);
SolidBrush brush = new SolidBrush(Color.White);
Pen pen = new Pen(Color.Aqua, 2);
//Детекция и отрисовка
try
{
List<YoloItem> items = _wrapper.Detect(mat.ToBytes()).ToList();
foreach (YoloItem item in items)
{
Point rectPoint = new Point(item.X, item.Y);
Size rectSize = new Size(item.Width, item.Height);
Rectangle rect = new Rectangle(rectPoint, rectSize);
graphics.DrawRectangle(pen, rect);
graphics.DrawString(item.Type, font, brush, rectPoint);
}
items.Clear();
}
catch(Exception e)
{
MessageBox.Show($"Error Altorus: {e}");
}
return finalImage;
}