使用 opencv 的内存泄漏:VideoCapture

Memory leak using opencv : VideoCapture

我用 Qt Creator 2.4.1 (Qt 4.8.4) 和 OpenCV 2.4.2 开发了一个应用程序,它从文件夹中读取图像并显示它们。

它使用 cv::VideoCapture 和 QGraphicsScene/QGraphicsView。它运行良好,但是我遇到了内存泄漏:如果我在任务管理器中查看消耗的内存,每次读取新图像时内存都会增加并最终崩溃。

我的主window是用Qt Designer创建的,它是一个class继承了QMainWindow。上面有一个 QGraphicsView view_src,还有一个按钮:buttonStart

这是一个代码示例:Class 声明:

using namespace std;
using namespace cv;

namespace Ui {
    class FenetrePrinc;
}

class FenetrePrinc : public QMainWindow {
    Q_OBJECT
public:
    explicit FenetrePrinc(QWidget *parent = 0);
    ~FenetrePrinc();

public slots:
    virtual void start();
    virtual void tick();
    virtual void stop_timer();

private:
    Ui::FenetrePrinc *ui;

    QString filename;
    QGraphicsScene *scene_src;
    QGraphicsItem *img_src;

    VideoCapture sequence;

    Mat src;
};

Class 定义:

FenetrePrinc::FenetrePrinc(QWidget *parent) : QMainWindow(parent), ui(new Ui::FenetrePrinc){

    ui->setupUi(this);
    scene_src = new QGraphicsScene();
    timer = new QTimer(this);

    img_src = scene_src->addPixmap(QPixmap("vide.jpg"));
    ui->view_src->setScene(scene_src);

    connect(ui->buttonStart, SIGNAL(clicked()), this, SLOT(start()));
}

FenetrePrinc::~FenetrePrinc(){
    delete scene_src;
    delete img_src;
    delete ui;
}

void FenetrePrinc::start(){
    if(src.empty())
        sequence.open(filename.toStdString());

    connect(timer, SIGNAL(timeout()), this, SLOT(tick()));
    timer->start(1000/24);   //24 frames per second

    disconnect(ui->buttonStart, SIGNAL(clicked()), this, SLOT(start()));
    connect(ui->buttonStart, SIGNAL(clicked()), this, SLOT(stop_timer()));
}

void FenetrePrinc::tick(){
    sequence >> src;

    if(src.empty())
    {
        sequence.release();
        stop_timer();
        return;
    }

    scene_src->removeItem(img_src);
    img_src = scene_src->addPixmap(convert16uc1(src));

    src.release();
}

void FenetrePrinc::stop_timer(){
    timer->stop();
    disconnect(timer, SIGNAL(timeout()), this, SLOT(tick()));

    disconnect(ui->buttonStart, SIGNAL(clicked()), this, SLOT(stop_timer()));
    connect(ui->buttonStart, SIGNAL(clicked()), this, SLOT(start()));
}

我不明白为什么每次读取图像时内存使用量都会上升,我确实在每次读取图像时释放图像,并在完成后释放序列。但也许我错过了什么?

编辑: 函数 QPixmap convert16uc1(Mat img) 是内存泄漏的原因。我必须使用此功能,因为我正在处理 Qt 无法读取的 16 位灰度图像。我使用 OpenCV 打开图像并执行图像处理,并使用 Qt 显示图像。

函数代码如下:

QPixmap FenetrePrinc::convert16uc1(const cv::Mat& source)
{
  quint16* pSource = (quint16*) source.data;
  int pixelCounts = source.cols * source.rows;

  QImage dest(source.cols, source.rows, QImage::Format_RGB32);

  char* pDest = (char*) dest.bits();

  for (int i = 0; i < pixelCounts; i++)
  {
    quint8 value = (quint8) ((*(pSource)) >> 8);
    *(pDest++) = value;  // B
    *(pDest++) = value;  // G
    *(pDest++) = value;  // R
    *(pDest++) = 0;      // Alpha
    pSource++;
  }
  return QPixmap::fromImage(dest);
}

很有可能是 convert16uc1

如果这里不能postconvert16uc1,尝试使用imwrite将图像临时保存在opencv中,然后在Qt中加载图像。如果memleak消失了。分析 convert16uc1.

或者不调用 convert16uc1(src) 但调用 addPixmap 使用之前在 Qt 中加载的一些其他常量图像。

阅读这篇 thread

我找到了导致问题的原因以及解决方法

来自 Qt 文档:

void QGraphicsScene::removeItem ( QGraphicsItem * item )

Removes the item item and all its children from the scene. The ownership of item is passed on to the caller (i.e., QGraphicsScene will no longer delete item when destroyed).

See also addItem().

一旦 QGraphicsScene::removeItem(QGraphicsItem *item)` 被调用,QGraphicsScene 在销毁时将不再删除该项目。

修复:在 removeItem(img_src) 之后调用 delete img_src:在函数 FenetrePrinc::tick() 中:

void FenetrePrinc::tick(){
    sequence >> src;

    if(src.empty())
    {
        sequence.release();
        stop_timer();
        return;
    }

    scene_src->removeItem(img_src);
    delete img_src;
    img_src = scene_src->addPixmap(convert16uc1(src));

    src.release();
}