0

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

主文件

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

    MainWindow window;
    window.show();

    return app.exec();
}

主窗口.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();
}

相机线程.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() 值。

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

4

1 回答 1

3

我所看到的正在发生:

  1. 您从队列中获取图像。根据OpenCV 文档

    Mat& cv::Mat::operator= ( const Mat & m )

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

  1. 然后cv::Mat image在发出信号时将其作为(按值)传递。复制构造函数再次不复制任何数据:

(整体或部分)分配给构造矩阵的数组。这些构造函数不会复制任何数据。相反,指向 m 个数据或其子数组的标头被构造并与之关联。引用计数器(如果有)会递增。因此,当您修改使用此类构造函数形成的矩阵时,您也修改了 m 的相应元素。如果您想拥有子数组的独立副本,请使用 Mat::clone() 。

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

  2. 您从 p.1 获取/尝试获取新的帧触发版本

  3. 您排队的插槽已执行并崩溃...

建议:我没有用它做太多工作,但似乎cv::Mat::clone你需要做一个深拷贝,以防止在 UI 线程使用它之前释放内存。

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

cv::Mat image = camera_q->pop();
于 2017-07-10T15:12:40.873 回答