Утечка памяти в OpenCV

Компьютерное зрение, OpenCV

Утечка памяти в OpenCV

Сообщение Lictor » 21 сен 2017, 19:29

Добрый день.

Пишу программу по распознаванию двух типов документов, использую для этого каскад Хаара, сам каскад раотает хорошо, проблем по распознаванию нет, но есть проблема с утечкеой памяти.
Код: Выделить всё
//////////////////////////////////Заголовочные функции//////////////////////////////////
#include <opencv2/opencv.hpp>   //модуль обработки изображений и компьютерного зрения
#include <opencv2/highgui.hpp> //ввод/вывод изображений и видео, захват видео и т.п.
#include <stdlib.h> //функции, занимающиеся выделением памяти, контроль процесса выполнения программы, преобразования типов и другие.
#include <stdio.h>      //определения макросов, константы и объявления функций и типов
#include <opencv/cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <algorithm>
#include <iostream>
#include <math.h>

/////////////////////////////Используемые пространства имен/////////////////////////////
using namespace std;
using namespace cv;

/////////////////////////////Переменные (глобальные)/////////////////////////////
IplImage* frame=0;  //для вывода изображения с камеры, цветное изображение
IplImage* gray = 0;  //перевод видео в ч/б
Mat grayMat; // для поиска каскадом Хаара A
Mat grayMatB; // для поиска каскадом Хаара Б
IplImage* gray2 = 0; //вывод обработанного видео

int main(int argc, char* argv[])
{
    CvCapture* capture = cvCreateCameraCapture(CV_CAP_ANY); //получаем любую подключённую камеру
    assert( capture );  //прекращение программы с выводом ошибки согласно условию в скобках, если условие ложно

    // задаем требуемое разрешение
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 640);//1280);
    //cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 480);//960);
    printf("[i] press Esc for quit!\n");

    // узнаем ширину и высоту кадра. Выводим в консоль
    double width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);  //ширина
    double height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);  //высота
    printf("[i] %.0f x %.0f\n", width, height );  //выводим значения ширины и высоты

    cvNamedWindow("capture", CV_WINDOW_AUTOSIZE);  //создаем окно для отображения картинки

    CascadeClassifier cascadeSymbol; // Объявление каскада A
    bool cascadeSymbolLoad = cascadeSymbol.load("/home/pi/Desktop/SAP_1.0/Haar/cascade_A.xml"); // Загрузка каскада
    assert( cascadeSymbolLoad );

    CascadeClassifier cascadeSymbolB; // Объявление каскада Б
    bool cascadeSymbolLoadB = cascadeSymbolB.load("/home/pi/Desktop/SAP_1.0/Haar/cascade_B.xml"); // Загрузка каскада
    assert( cascadeSymbolLoadB );

    while(true){  //бесконечный цикл для отображения кадров видео

        frame = cvQueryFrame( capture );  // получаем кадр

        gray = cvCreateImage(cvGetSize(frame), 8, 1);

        cvCvtColor(frame, gray, CV_RGB2GRAY);  //переводим в ч/б
/////////////////////////////////////////////////////////////////////////////////////////

  grayMat = cvarrToMat(gray);

    vector<Rect> symbols;
    cascadeSymbol.detectMultiScale(grayMat, symbols); // Поиск с помощью каскада

    for (int i = 0; i < symbols.size(); ++i)
    {
        Rect& p = symbols[i];
        Point symbolBegin   = Point(p.x, p.y);
        Point symbolEnd     = Point(p.x+p.width, p.y+p.height);
        cout << "X: " << p.x << " Y: " << p.y << " Width: " << p.width << " Height: " << p.height << endl;
        rectangle(grayMat, symbolBegin, symbolEnd, Scalar(0,255,0), 2);
        ///////////////////////////////////////////////////////////////
        // Текстовый буффер
        char text_buf[32];
        //Текст в массив
        sprintf(text_buf, "A");
        //Шрифт
        CvFont font;
        cvInitFont( &font, CV_FONT_HERSHEY_COMPLEX,1.0, 1.0, 0, 1, CV_AA);
        //Вывод текста
        IplImage itog;
        gray = &(itog = grayMat);
        cvPutText(gray, text_buf, cvPoint(p.x + 50 + p.width, p.y + 50), &font, cvScalar(0,0,255));
        ///////////////////////////////////////////////////////////////
    }
/////////////////////////////////////////////////////////////////////////////////////////
    gray2 = cvCloneImage(gray);  //промежуточное изображение
    grayMatB = cvarrToMat(gray2);

    vector<Rect> symbolsB;
        cascadeSymbolB.detectMultiScale(grayMatB, symbolsB); // Поиск с помощью каскада

        for (int y = 0; y < symbolsB.size(); ++y)
        {
            Rect& z = symbolsB[y];
            Point symbolBeginB  = Point(z.x, z.y);
            Point symbolEndB        = Point(z.x+z.width, z.y+z.height);
            cout << "X: " << z.x << " Y: " << z.y << " Width: " << z.width << " Height: " << z.height << endl;
            rectangle(grayMatB, symbolBeginB, symbolEndB, Scalar(0,255,0), 2);
            ///////////////////////////////////////////////////////////////
            // Текстовый буффер
            char text_buf[32];
            //Текст в массив
            sprintf(text_buf, "B");
            //Шрифт
            CvFont font;
            cvInitFont( &font, CV_FONT_HERSHEY_COMPLEX,1.0, 1.0, 0, 1, CV_AA);
            //Вывод текста
            IplImage itogB;
            gray = &(itogB = grayMatB);
            cvPutText(gray2, text_buf, cvPoint(z.x + 50 + z.width, z.y + 50), &font, cvScalar(0,0,255));
            ///////////////////////////////////////////////////////////////
        }
/////////////////////////////////////////////////////////////////////////////////////////
        cvShowImage("capture", gray2); // показываем в ранее созданном окне

        char c = cvWaitKey(33); // ждем нажатия клавиши
        if (c == 27) break; //выход из цикла если нажат ESC
        }

    cvReleaseImage(&gray2);
    cvReleaseImage(&gray);
    cvReleaseCapture( &capture ); //освобождаем память
    cvDestroyAllWindows();  //удаляем созданные окна для отображения
    return 0; //по завершению программы возвращаем ноль
}


Если перенести строки
Код: Выделить всё
    cvReleaseImage(&gray2);
    cvReleaseImage(&gray);


в конец цикла
Код: Выделить всё
 for (int i = 0; i < symbols.size(); ++i)


То утечка памяти исчезает, но при распознавании символа происходит вылет с ошибкой:
Код: Выделить всё
[i] press Esc for quit!
[i] 640 x 480
X: 346 Y: 173 Width: 36 Height: 24
OpenCV Error: Bad argument (unrecognized or unsupported array type) in cvReleaseData, file /home/pi/opencv/modules/core/src/array.cpp, line 1010
terminate called after throwing an instance of 'cv::Exception'
  what():  /home/pi/opencv/modules/core/src/array.cpp:1010: error: (-5) unrecognized or unsupported array type in function cvReleaseData


Но просто видео (до момента распознавания) выводит сколь угодно долго без каких-либо проблем.
Lictor
 
Сообщения: 6
Зарегистрирован: 20 авг 2017, 13:02
programming: C++

Re: Утечка памяти в OpenCV

Сообщение noonv » 22 сен 2017, 10:07

Проще вынести создание gray и gray2 за пределы цикла.
Аватара пользователя
noonv
Администратор
 
Сообщения: 538
Зарегистрирован: 05 май 2011, 15:44
Откуда: Калининград
programming: С++

Re: Утечка памяти в OpenCV

Сообщение Lictor » 22 сен 2017, 10:23

noonv писал(а):Проще вынести создание gray и gray2 за пределы цикла.


Да я бы и рад, но их значения постоянно обновляются именно в цикле (видео в opencv это же поток картинок?), их нельзя вынести оттуда.

Кстати, такой код ест память в два раза медленнне и работает без вылетов:
Код: Выделить всё
//////////////////////////////////Заголовочные функции//////////////////////////////////
#include <stdlib.h> //функции, занимающиеся выделением памяти, контроль процесса выполнения программы, преобразования типов и другие.
#include <stdio.h>      //определения макросов, константы и объявления функций и типов
#include <opencv2/opencv.hpp>   //модуль обработки изображений и компьютерного зрения
#include <opencv2/highgui.hpp> //ввод/вывод изображений и видео, захват видео и т.п.
#include <opencv/cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <algorithm>
#include <iostream>
#include <math.h>

/////////////////////////////Используемые пространства имен/////////////////////////////
using namespace std;
using namespace cv;

/////////////////////////////Переменные (глобальные)/////////////////////////////
IplImage* frame=0;  //для вывода изображения с камеры, цветное изображение
IplImage* gray = 0;  //перевод видео в ч/б
Mat grayMat; // для поиска каскадом Хаара A
Mat grayMatB; // для поиска каскадом Хаара Б
IplImage* gray2 = 0; //вывод обработанного видео

int main(int argc, char* argv[])
{
    CvCapture* capture = cvCreateCameraCapture(CV_CAP_ANY); //получаем любую подключённую камеру
    assert( capture );  //прекращение программы с выводом ошибки согласно условию в скобках, если условие ложно

    // задаем требуемое разрешение
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 640);//1280);
    //cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 480);//960);
    printf("[i] press Esc for quit!\n");

    // узнаем ширину и высоту кадра. Выводим в консоль
    double width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);  //ширина
    double height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);  //высота
    printf("[i] %.0f x %.0f\n", width, height );  //выводим значения ширины и высоты

    cvNamedWindow("capture", CV_WINDOW_AUTOSIZE);  //создаем окно для отображения картинки

    CascadeClassifier cascadeSymbol; // Объявление каскада A
    bool cascadeSymbolLoad = cascadeSymbol.load("/home/pi/Desktop/SAP_1.0/Haar/cascade_A.xml"); // Загрузка каскада
    assert( cascadeSymbolLoad );

    CascadeClassifier cascadeSymbolB; // Объявление каскада Б
    bool cascadeSymbolLoadB = cascadeSymbolB.load("/home/pi/Desktop/SAP_1.0/Haar/cascade_B.xml"); // Загрузка каскада
    assert( cascadeSymbolLoadB );

    while(true){  //бесконечный цикл для отображения кадров видео

        frame = cvQueryFrame( capture );  // получаем кадр

        gray = cvCreateImage(cvGetSize(frame), 8, 1);

        cvCvtColor(frame, gray, CV_RGB2GRAY);  //переводим в ч/б
/////////////////////////////////////////////////////////////////////////////////////////

  grayMat = cvarrToMat(gray);

    vector<Rect> symbols;
    cascadeSymbol.detectMultiScale(grayMat, symbols); // Поиск с помощью каскада

    for (int i = 0; i < symbols.size(); ++i)
    {
        Rect& p = symbols[i];
        Point symbolBegin   = Point(p.x, p.y);
        Point symbolEnd     = Point(p.x+p.width, p.y+p.height);
        cout << "X: " << p.x << " Y: " << p.y << " Width: " << p.width << " Height: " << p.height << endl;
        rectangle(grayMat, symbolBegin, symbolEnd, Scalar(0,255,0), 2);
        ///////////////////////////////////////////////////////////////
        // Текстовый буффер
        char text_buf[32];
        //Текст в массив
        sprintf(text_buf, "A");
        //Шрифт
        CvFont font;
        cvInitFont( &font, CV_FONT_HERSHEY_COMPLEX,1.0, 1.0, 0, 1, CV_AA);
        //Вывод текста
        IplImage itog;
        gray = &(itog = grayMat);
        cvPutText(gray, text_buf, cvPoint(p.x + 50 + p.width, p.y + 50), &font, cvScalar(0,0,255));
        ///////////////////////////////////////////////////////////////
    }
/////////////////////////////////////////////////////////////////////////////////////////
    gray2 = cvCloneImage(gray);  //промежуточное изображение
    grayMatB = cvarrToMat(gray2);

    vector<Rect> symbolsB;
        cascadeSymbolB.detectMultiScale(grayMatB, symbolsB); // Поиск с помощью каскада

        for (int y = 0; y < symbolsB.size(); ++y)
        {
            Rect& z = symbolsB[y];
            Point symbolBeginB  = Point(z.x, z.y);
            Point symbolEndB        = Point(z.x+z.width, z.y+z.height);
            cout << "X: " << z.x << " Y: " << z.y << " Width: " << z.width << " Height: " << z.height << endl;
            rectangle(grayMatB, symbolBeginB, symbolEndB, Scalar(0,255,0), 2);
            ///////////////////////////////////////////////////////////////
            // Текстовый буффер
            char text_buf[32];
            //Текст в массив
            sprintf(text_buf, "B");
            //Шрифт
            CvFont font;
            cvInitFont( &font, CV_FONT_HERSHEY_COMPLEX,1.0, 1.0, 0, 1, CV_AA);
            //Вывод текста
            IplImage itogB;
            gray = &(itogB = grayMatB);
            cvPutText(gray2, text_buf, cvPoint(z.x + 50 + z.width, z.y + 50), &font, cvScalar(0,0,255));
            ///////////////////////////////////////////////////////////////
        }
/////////////////////////////////////////////////////////////////////////////////////////
        cvShowImage("capture", gray2); // показываем в ранее созданном окне

        char c = cvWaitKey(33); // ждем нажатия клавиши
        if (c == 27) break; //выход из цикла если нажат ESC
              //  cvReleaseImage(&gray);
                cvReleaseImage(&gray2);
    }

    cvReleaseCapture( &capture ); //освобождаем память
    cvDestroyAllWindows();  //удаляем созданные окна для отображения
    return 0; //по завершению программы возвращаем ноль
}


Но если раскоменить строчку с gray, начинает вылетать в момент распознавания.
Так же пробовал вынести
Код: Выделить всё
  gray = cvCreateImage(cvGetSize(frame), 8, 1);

за пределы цикла (размеры указал), это тоже приводит к вылетанию.
Lictor
 
Сообщения: 6
Зарегистрирован: 20 авг 2017, 13:02
programming: C++

Re: Утечка памяти в OpenCV

Сообщение Lictor » 22 сен 2017, 16:22

Прочитал про умные указатели Ptr<> может мне можно как-то использовать их? Насколько я понимаю, такой указатель автоматически очистит память.
Lictor
 
Сообщения: 6
Зарегистрирован: 20 авг 2017, 13:02
programming: C++

Re: Утечка памяти в OpenCV

Сообщение Lictor » 28 сен 2017, 18:48

Вынес поиск каскадом в отдельную функцию и объявил там локальные переменные. Утечка пропала. Так же заменил часть функций на другие, поддерживающие IplImage*, что сократило число конвертаций и устранило вылеты.
Lictor
 
Сообщения: 6
Зарегистрирован: 20 авг 2017, 13:02
programming: C++


Вернуться в Компьютерное зрение

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4

© 2009-2017 |  О проекте  |  Политика Конфиденциальности  |