Qt信号槽cv :: Mat无法读取内存访问冲突

时间:2017-07-10 13:21:50

标签: qt opencv signals-slots access-violation memory-access

我有一个Microsoft visual studio应用程序,它从相机中抓取帧,我试图在Qt应用程序中显示这些帧。我正在使用OpenCV对帧进行一些处理,因此帧是Mat对象。我使用QThreads来并行化应用程序。当我尝试从CameraThread类发出Mat信号时,我收到了Access Violation读取位置。

的main.cpp

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    MainWindow window;
    window.show();

    return app.exec();
}

mainwindow.cpp

#include "main_window.h"

MainWindow::MainWindow()
{
    // create a horizontal widget
    main_layout = new QVBoxLayout;

    QHBoxLayout* row1 = new QHBoxLayout;
    QHBoxLayout* row2 = new QHBoxLayout;

    for (int i = 0; i < 1; i++) {
        camera_array[i] = new CameraWidget(i);
        if (i < 4)
            row1->addWidget(camera_array[i]);
        else
            row2->addWidget(camera_array[i]);
    }

    main_layout->addLayout(row1);
    main_layout->addLayout(row2);

    // make the central widget the main layout window
    central = new QWidget();
    central->setLayout(main_layout);
    setCentralWidget(central);
}

camerawidget.cpp

#include "stdafx.h"
#include "camera_widget.h"

CameraWidget::CameraWidget(int id)
{
    camera_id = id;

    qRegisterMetaType<cv::Mat>("cv::Mat");

    current_frame = cv::imread("camera_1.png");

    thread = new CameraThread(camera_id);
    QObject::connect(thread, SIGNAL(renderFrame(cv::Mat)), this, SLOT(updateFrame(cv::Mat)));
    thread->start();

}

CameraWidget::~CameraWidget()
{
    qDebug("camera widget destructor");
    thread->wait(5000);
}

// initializeGL() function is called just once, before paintGL() is called.
void CameraWidget::initializeGL()
{
    qglClearColor(Qt::black);
    glDisable(GL_DEPTH_TEST);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, 480.0f, 640.0f, 0.0f, 0.0f, 1.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnable(GL_TEXTURE_2D);

    glGenTextures(3, &texture);

    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glBindTexture(GL_TEXTURE_2D, texture);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 480.0f, 640.0f, GL_BGR, GL_UNSIGNED_BYTE, NULL);

    glDisable(GL_TEXTURE_2D);
}

void CameraWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, 480.0f, 640.0f, 0.0f, 0.0f, 1.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnable(GL_TEXTURE_2D);

    current_frame_i = QImage(current_frame.data, current_frame.cols, current_frame.rows, current_frame.cols * 3, QImage::Format_RGB888);

    glBindTexture(GL_TEXTURE_2D, texture);

    // ******************************
    // getting access violation here
    // ******************************   
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 480.0f, 640.0f, 0.0f, GL_BGR, GL_UNSIGNED_BYTE, current_frame.ptr());

    glBegin(GL_QUADS);
        glTexCoord2i(0, 1); glVertex2i(0, 640.0f);
        glTexCoord2i(0, 0); glVertex2i(0, 0);
        glTexCoord2i(1, 0); glVertex2i(480.0f, 0);
        glTexCoord2i(1, 1); glVertex2i(480.0f, 640.0f);
    glEnd();

    glFlush();
}

void CameraWidget::resizeGL(int w, int h)
{
    // setup viewport, projection etc.
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, 480.0f, 640.0f, 0.0f, 0.0f, 1.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void CameraWidget::updateFrame(cv::Mat image)
{
    current_frame = image;
    update();
}

camerathread.cpp

CameraThread::CameraThread(int id) 
{
    camera_q = new bounded_frame_queue(50);

}

void CameraThread::run()
{
    cv::Mat image;
    while (true) {
        if (!camera_q->empty()) {
            image = camera_q->pop();
            if (!image.empty())
                emit renderFrame(image);
        }
        else {
            msleep(1);
        }
    }

}

当我从camerathread.cpp发出renderFrame时,我得到一个访问冲突读取位置。我无法读取camerawidget.cpp中的current_frame.ptr()值。

有人可以指导我如何解决这个问题吗?

1 个答案:

答案 0 :(得分:3)

我看到的是:

  1. 您从队列中获取图像。根据{{​​3}}:

    垫&安培; cv :: Mat :: operator =(const Mat&amp; m)

  2.   

    指定的右侧矩阵。矩阵赋值是O(1)   操作。这意味着不会复制任何数据,但会共享数据   并且参考计数器(如果有的话)递增。在分配之前   新数据,旧数据通过Mat :: release。

    取消引用
    1. 然后在发出信号时将其作为cv::Mat image(按值)传递。 OpenCV docs再次不会复制任何数据:
    2.   

      将(作为整体或部分)分配给构造的数组   矩阵。这些构造函数不会复制任何数据。相反,标题   指向m数据或其子数组是构造和关联的   它。参考计数器(如果有)递增。所以,当你修改   使用这样的构造函数形成的矩阵,你也修改了   m的相应元素。如果你想拥有一份独立的副本   在子数组中,使用Mat :: clone()。

      1. 您的数据指针在UI线程上排队

      2. 您从第1页

      3. 获得/尝试获取新帧触发释放
      4. 您的排队广告位已执行并崩溃...

      5. 建议:我没有多少工作,但似乎cv::Mat::clone类似于你需要的深层复制,以防止在UI线程使用它之前释放内存。

        或者,当您从队列中弹出图像时,可能就足够了:

        cv::Mat image = camera_q->pop();