我用Qt Creator 2.4.1 (Qt 4.8.4)和OpenCV 2.4.2开发了一个应用程序,可以从文件夹中读取图像并显示它们。
它使用cv:: videoccapture和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()));
}
我不明白为什么每次读取图像时内存使用量都会上升,我每次读取图像时都会释放图像,并且一旦完成释放序列。但也许我错过了什么?
EDIT:函数QPixmap convert16uc1(Mat img)
是导致内存泄漏的原因。我必须使用这个函数,因为我正在使用16位灰度图像,Qt无法读取。我用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
。
如果你不能在这里发布convert16uc1,尝试在openv中使用imwrite暂时保存图像并在Qt中加载图像。分析convert16uc1
.
或者不调用convert16uc1(src),而是使用之前在Qt中加载的其他常量图像调用addPixmap
。
我找到了导致问题的原因以及如何修复它,阅读此线程。
来自Qt文档:
void QGraphicsScene::removeItem (QGraphicsItem * item)
从场景中删除项目item及其所有子项目。项目的所有权被传递给调用者(即,QGraphicsScene将不再删除项目时销毁)。
参见addItem()。
一旦QGraphicsScene::removeItem(QGraphicsItem *item) '被调用,QGraphicsScene将不再删除项目时销毁。
修复:FenetrePrinc::tick()
:
函数removeItem(img_src)
:之后调用delete img_src
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();
}