【问题标题】:Memory leak using opencv : VideoCapture使用 opencv 的内存泄漏:VideoCapture
【发布时间】:2015-08-12 02:40:17
【问题描述】:

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

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

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

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

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;
};

类定义:

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);
}

【问题讨论】:

  • 请尝试使用更新的 opencv 版本,2.4.2 太旧了
  • 如果你不使用Qt显示图像(只读取图像而不显示),它是否也会泄漏内存?
  • 你能发布你的convert16uc1函数吗?是否必须发布 Qt pixmap 元素?
  • 根据stackoverflow.com/questions/26612391/…请在addPixmap之前尝试scene_src-&gt;clear()
  • @berak:我在 Qt 中也大量使用 stoll 2.4.2。来自相机和硬盘的图像的演出。没有内存泄漏。它不是 OpenCV,当然也不是 Qt。

标签: c++ qt opencv memory-leaks


【解决方案1】:

很可能是convert16uc1

如果您无法在此处发布 convert16uc1,请尝试使用 imwrite 将图像临时保存在 opencv 中并在 Qt 中加载图像。如果 memleak 消失。分析convert16uc1

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

【讨论】:

  • 是的,你是对的,如果我将scene_src-&gt;addPixmap(convert16uc1(srt)) 更改为scene_src-&gt;addPixmap(QPixmap("vide.jpg")),我就不再有内存泄漏了。我已编辑我的问题以添加 convert16uc1 代码。
  • 我按照你的建议做了:我没有使用 QPixmap convert16uc1(Mat source) 将我的图像从 OpenCV 转换为 Qt,而是使用 ìmwrite` 临时保存图像,并使用 Qt 加载此图像。使用这种技术,我不再有内存泄漏。
  • @zarachbaal:这只是一个测试建议!这将是非常缓慢的转换。我会试试你的代码,可能会找到原因。
  • 是的,我知道这不是一个真正的解决方案,我只是尝试过,它可以工作,但这非常慢!我认为原因是 convert16uc1 中的QPixmap::fromImage(dest);。有一个重载版本无需复制即可转换,但它是在 Qt 5.3 中实现的,我使用的是 Qt 4.8.4。
  • @zarachbaal: fromImage 几乎不是问题。 QImage 在堆栈上创建。离开函数作用域时删除。
【解决方案2】:

阅读此thread,我找到了导致问题的原因以及解决方法。

来自 Qt 文档:

void QGraphicsScene::removeItem ( QGraphicsItem * item )

从场景中移除项目项及其所有子项。项目的所有权被传递给调用者(即,QGraphicsScene 在销毁时将不再删除项目)。

另见 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();
}

【讨论】:

    猜你喜欢
    • 2014-03-01
    • 2022-07-27
    • 1970-01-01
    • 1970-01-01
    • 2020-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-05
    相关资源
    最近更新 更多