Qt信号槽cv :: Mat无法读取内存访问冲突 [英] Qt signal slot cv::Mat unable to read memory access violation

查看:418
本文介绍了Qt信号槽cv :: Mat无法读取内存访问冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Microsoft Visual Studio应用程序,该应用程序正在从相机中抓取帧,我正在尝试在Qt应用程序中显示这些帧.我正在使用OpenCV对框架进行一些处理,因此框架是Mat对象.我使用QThreads来并行化应用程序.尝试从CameraThread类发出Mat信号时,出现读取访问冲突的地方.

I have a Microsoft visual studio application that is grabbing frames from cameras and I am trying to display those frames in a Qt application. I am doing some processing with the frames using OpenCV, so the frames are Mat objects. I use QThreads to parallelize the application. I am getting a Access Violation reading location when I try to emit a Mat signal from my CameraThread class.

main.cpp

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

    MainWindow window;
    window.show();

    return app.exec();
}

mainwindow.cpp

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

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.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()值.

When I emit renderFrame from the camerathread.cpp, I get an access violation reading location. I cannot read the current_frame.ptr() value in camerawidget.cpp.

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

Can someone direct me on how I can fix this issue?

推荐答案

我所看到的正在发生:

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

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

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

分配的右侧矩阵.矩阵分配为O(1) 手术.这意味着没有数据被复制,但是数据是共享的 并且参考计数器(如果有)增加.分配之前 新数据,则通过Mat :: release取消对旧数据的引用.

Assigned, right-hand-side matrix. Matrix assignment is an O(1) operation. This means that no data is copied but the data is shared and the reference counter, if any, is incremented. Before assigning new data, the old data is de-referenced via Mat::release .

  1. 然后在发出信号时将其作为cv::Mat image(按值)传递. 复制构造函数不会再复制任何数据:
  1. Then you pass it as cv::Mat image (by value) when emitting signal. The copy constructor again doesn't copy any data:

(全部或部分)分配给构造的数组 矩阵.这些构造函数不会复制任何数据.而是标题 指向m个数据或其子数组并与之关联 它.参考计数器(如果有)增加.因此,当您修改 使用此类构造函数形成的矩阵,您还可以修改 m的对应元素.如果您想拥有一个独立的副本 子数组,请使用Mat :: clone().

Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied by these constructors. Instead, the header pointing to m data or its sub-array is constructed and associated with it. The reference counter, if any, is incremented. So, when you modify the matrix formed using such a constructor, you also modify the corresponding elements of m . If you want to have an independent copy of the sub-array, use Mat::clone() .

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

  1. Your data pointers are queued on UI thread

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

You get/try-get new frame triggering release from p.1

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

Your queued slot is executed and crashes...

建议:我并没有做太多工作,但是看起来像cv::Mat::clone这样的事情是您需要做一个深拷贝,以防止在UI线程使用它之前释放内存.

Suggestion: I haven't worked much with it, but it seems something like cv::Mat::clone to make a deep copy is what you need, to prevent release of memory before it would be used by UI thread.

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

Or possibly it would be enough to define image right when you pop it from queue:

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

这篇关于Qt信号槽cv :: Mat无法读取内存访问冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆