Я пишу приложение C, которое захватывает изображения с веб-камеры с помощью OpenCv, а затем сохраняет изображения в файл. Он работает на Raspian OS Wheezy против OpenCv 2.3.1-11.
Если я просто открываю и закрываю веб-камеру, так что утечки памяти нет, поэтому я не думаю, что столкнулся с более старой ошибкой в отношении "налога на открытие веб-камеры":
CvCapture* capture;
while (1) {
// No increase in memory consumption at all
capture = cvCreateCameraCapture(0);
cvReleaseCapture(&capture);
}
Однако, когда я на самом деле начинаю приобретать изображения, потребление памяти взрывается, и каждая итерация разыгрывает еще 2 МБ в памяти. Я подтвердил с помощью free -s 2
в командной строке при ручном запуске захвата изображения и заметил, что в конечном итоге мое приложение жалуется на то, что у вас недостаточно памяти для получения изображений.
capture = cvCreateCameraCapture(0);
while (1) {
if (capture) {
frame = cvQueryFrame(capture);
}
if (frame) {
CvSize size = cvSize(100, 100);
tmp = cvCreateImage(size, IPL_DEPTH_8U, 3);
cvResize(frame, tmp, CV_INTER_CUBIC);
// Do some stuff with tmp
}
}
cvReleaseCapture(&capture);
Я проверил различные сообщения в Интернете, и он говорит, что я не поддерживаю изменение данных, хранящихся в frame
. Если я использую cvReleaseImage
в frame
, это не влияет. Фактически, использование памяти взрывается только из вызова cvQueryFrame
. Даже следующий пример ниже вызывает эту проблему:
capture = cvCreateCameraCapture(0);
while (1) {
if (capture) {
frame = cvQueryFrame(capture);
}
}
cvReleaseCapture(&capture);
Как мне решить это?
Должен ли я по-настоящему работать с C++ API (на данный момент это не совсем выбор), или есть ли другие способы? Это приложение Gtk + -2.0, и единственными заголовками, которые я включаю, являются:
/*******************************************************************************
* Preprocessor Directives
******************************************************************************/
#include "opencv/cxcore.h"
#include "opencv2/highgui/highgui_c.h"
#include "opencv2/imgproc/imgproc_c.h"
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
Есть смесь opencv
и opencv2
там, казалось бы, но я не могу найти способ иметь только заголовки opencv
и иметь доступ к камере без них. Я был обеспокоен, возможно, это вызывает определенные фрагменты C++ - только код, который будет инициализирован неопределенным образом. Любая помощь в устранении утечки памяти или, при необходимости, создание эквивалентного кода в C++ без утечки будет очень полезной.
Спасибо за помощь.
После значительного тестирования выяснилось, что OpenCv 2.3.1-11 имеет некоторое неудобное поведение при работе с pthread
s.
Если я просто использую следующее в цикле в main()
, никаких проблем нет.
int main()
{
CvCapture* capture;
IplImage* frame;
IplImage* tmp;
capture = cvCreateCameraCapture(0);
while (1) {
if (capture) {
frame = cvQueryFrame(capture);
}
if (frame) {
CvSize size = cvSize(100, 100);
tmp = cvCreateImage(size, IPL_DEPTH_8U, 3);
cvResize(frame, tmp, CV_INTER_CUBIC);
// Do some stuff with tmp
// release tmp:
cvReleaseImage(&tmp);
}
}
cvReleaseCapture(&capture);
}
Если я использую один и тот же цикл в pthread
, это приведет к по меньшей мере 2 МБ потери памяти на итерацию. Однако, если в pthread
я только один раз вызываю capture = cvCreateCameraCapture(0)
и cvReleaseCapture(&capture)
, проблема больше не присутствует.
Кроме того, если я вызываю cvCreateCameraCapture(0)
в главном и присваиваю ему что-то доступное из потока (т. cvCreateCameraCapture(0)
Глобальную переменную или сохраняя ее в переменной контекста, передающей указатель на поток, когда я создаю поток) Я получаю поведение утечки памяти при каждом вызове в pthread
в cvQueryFrame()
.
Короче говоря, если вы используете API C (устаревший, я знаю) в многопоточной программе, существует множество способов, которыми вы можете стрелять себе в ногу. Спасибо всем за ваш вклад.
Это не утечка для меня:
#include <opencv2\opencv.hpp>
int main()
{
CvCapture* capture;
IplImage* frame;
capture = cvCreateCameraCapture(0);
while (1)
{
if (capture)
{
frame = cvQueryFrame(capture);
}
}
cvReleaseCapture(&capture);
}
Очевидно, что это происходит:
int main()
{
CvCapture* capture;
IplImage* frame;
IplImage* tmp;
capture = cvCreateCameraCapture(0);
while (1) {
if (capture) {
frame = cvQueryFrame(capture);
}
if (frame) {
CvSize size = cvSize(100, 100);
tmp = cvCreateImage(size, IPL_DEPTH_8U, 3);
cvResize(frame, tmp, CV_INTER_CUBIC);
// Do some stuff with tmp
}
}
cvReleaseCapture(&capture);
}
Хотя этот не течет:
int main()
{
CvCapture* capture;
IplImage* frame;
IplImage* tmp;
capture = cvCreateCameraCapture(0);
while (1) {
if (capture) {
frame = cvQueryFrame(capture);
}
if (frame) {
CvSize size = cvSize(100, 100);
tmp = cvCreateImage(size, IPL_DEPTH_8U, 3);
cvResize(frame, tmp, CV_INTER_CUBIC);
// Do some stuff with tmp
// release tmp:
cvReleaseImage(&tmp);
}
}
cvReleaseCapture(&capture);
}
Можете ли вы попробовать последний пример? Если он протекает, у вас, вероятно, действительно есть проблемы с неправильными заголовками или связанными библиотеками.
cvReleaseCapture(&capture)
никогда не cvReleaseCapture(&capture)
из-за while(1)
это тоже своего рода утечка, но использование памяти не должно увеличиваться со временем для последнего примера.
main()
, но когда он запускается в отдельном pthread
возобновляется утечка памяти.
Я проверил сегодня [01/04/2015], по текущему файлу wheezy/main repository. Dev-пакеты opencv (кроме gpu) связаны с openCV 2.4.1. Здесь шаги тестирования:
Установить пакеты:
sudo apt-get install cmake build-essential libopencv-core-dev libcv-dev libcvaux-dev libhighgui-dev libopencv-calib3d-dev libopencv-contrib-dev libopencv-core-dev libopencv-dev libopencv-features2d-dev libopencv-flann-dev libopencv-highgui-dev libopencv-imgproc-dev libopencv-legacy-dev libopencv-ml-dev libopencv-objdetect-dev libopencv-video-dev
Проверьте установленную версию библиотек openCv:
sudo ldconfig -v | grep opencv
Результат:
libopencv_imgproc.so.2.4 -> libopencv_imgproc.so.2.4.1
libopencv_highgui.so.2.4 -> libopencv_highgui.so.2.4.1
libopencv_legacy.so.2.4 -> libopencv_legacy.so.2.4.1
libopencv_objdetect.so.2.4 -> libopencv_objdetect.so.2.4.1
libopencv_calib3d.so.2.4 -> libopencv_calib3d.so.2.4.1
libopencv_videostab.so.2.4 -> libopencv_videostab.so.2.4.1
libopencv_ml.so.2.4 -> libopencv_ml.so.2.4.1
libopencv_core.so.2.4 -> libopencv_core.so.2.4.1
libopencv_ts.so.2.4 -> libopencv_ts.so.2.4.1
libopencv_stitching.so.2.4 -> libopencv_stitching.so.2.4.1
libopencv_photo.so.2.4 -> libopencv_photo.so.2.4.1
libopencv_flann.so.2.4 -> libopencv_flann.so.2.4.1
libopencv_features2d.so.2.4 -> libopencv_features2d.so.2.4.1
libopencv_video.so.2.4 -> libopencv_video.so.2.4.1
ibopencv_contrib.so.2.4 -> libopencv_contrib.so.2.4.1
Тестовая программа
#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <errno.h>
#include "opencv/cxcore.h"
#include "opencv2/highgui/highgui_c.h"
#include "opencv2/imgproc/imgproc_c.h"
int main(int argc, char * const argv[])
{
struct rusage usage;
long max_resident_set_size = 0;
long frame_no = 0;
CvCapture* capture;
IplImage* frame;
capture = cvCreateCameraCapture(0);
if (!capture) {
// error getting webcam
return 1;
}
// test 100 frames to check memory usage
while (frame_no < 100) {
frame = cvQueryFrame(capture);
frame_no++;
errno = 0;
getrusage(RUSAGE_SELF, &usage);
if (errno == EFAULT)
printf("Error: EFAULT\n");
else if (errno == EINVAL)
printf("Error: EINVAL\n");
else if (max_resident_set_size != usage.ru_maxrss) {
printf("frame %ld maximum resident set size: %ld\n", frame_no, usage.ru_maxrss);
printf("frame %ld maximum resident set size diff : %ld\n", frame_no, (usage.ru_maxrss - max_resident_set_size));
max_resident_set_size = usage.ru_maxrss;
}
}
cvReleaseCapture(&capture);
return 0;
}
У меня нет проблемы с памятью, используя вышеприведенный код с OpenCV 2.4.
Я предлагаю вам удалить пакет openCV 2.3.1, обновить систему и установить последние версии и использовать нотацию OpenCV2.
Чтобы указать установленные пакеты:
sudo dpkg --get-selections | grep -v deinstall | grep cv
Надеюсь, это поможет.
cvReleaseImage on frame, it has no effect
Как вы знаете, это не имеет никакого эффекта? Если вы используете диспетчер задач или какой-либо другой инструмент ОС для определения утечки памяти, не используйте его. Использование таких инструментов не будет определять утечку памяти.free -s 2
на консоли, я вижу падение общего объема доступной системной памяти каждый раз, когда я вручную запускаю получение другого изображения. Я также могу профилировать приложение и подтвердить, что оно расходует больше памяти.