【问题标题】:Include existing OpenCV Application into Qt GUI将现有的 OpenCV 应用程序包含到 Qt GUI 中
【发布时间】:2016-09-25 03:12:13
【问题描述】:

我想将现有的 openCV 应用程序包含到使用 Qt 创建的 GUI 中。我在stackoverflow上发现了一些类似的问题

QT How to embed an application into QT widget

Run another executable in my Qt app

问题是,我不想像使用 QProcess 那样简单地启动 openCV 应用程序。 OpenCV 应用程序有一个“MouseListener”,所以如果我点击窗口,它仍然应该调用 openCV 应用程序的函数。此外,我想在 Qt GUI 的标签中显示检测到的坐标。因此它必须是某种交互。

我已阅读有关 createwindowContainer 函数 (http://blog.qt.io/blog/2013/02/19/introducing-qwidgetcreatewindowcontainer/) 的信息,但由于我对 Qt 不是很熟悉,我不确定这是否是正确的选择以及如何使用它。

我使用的是 Linux Mint 17.2、opencv 版本 3.1.0 和 Qt 版本 4.8.6

感谢您的意见

【问题讨论】:

  • 在新项目中使用你的简历代码有什么问题?
  • 那我得把它适配到Qt界面。例如,当我对鼠标单击图像做出反应时,我必须实现 QMouseEvents 等等。如果我只是在一个窗口中显示我的旧 opencv 应用程序,鼠标点击仍将在我的原始应用程序中处理。
  • 不确定这个函数是否仍然存在,但过去你可以调用 cvGetWindowHandle 来获取一个 win api 窗口句柄。也许你可以在 Qt 中嵌入那个。
  • 啊 linux... 不知道 cvGetWindowHandle 是如何工作的

标签: linux qt opencv


【解决方案1】:

我并没有真正解决我一开始想要的问题。但现在它正在工作。如果有人有同样的问题,也许我的解决方案可以提供一些想法。如果您想在 qt 中显示视频,或者您在使用 OpenCV 库时遇到问题,也许我可以提供帮助。

以下是一些代码 sn-ps。他们没有太多评论,但我希望这个概念很清楚:

首先,我有一个带有标签的 MainWindow,我将其提升为我的 CustomLabel 的类型。 CustomLabel 是我的容器,用于显示视频并对鼠标输入做出反应。

CustomLabel::CustomLabel(QWidget* parent) : QLabel(parent), currentImage(NULL), 
tickrate_ms(33), vid_fps(0), video_width(0), video_height(0), myTimer(NULL), cap(NULL)
{
// init variables
showPoints = true;
calculatedCenter = cv::Point(0,0);
oldCenter = cv::Point(0,0);
currentState = STATE_NO_STREAM;
NOF_corners = 30; //default init value
termcrit = cv::TermCriteria(cv::TermCriteria::COUNT | cv::TermCriteria::EPS, 30,0.01);
// enable mouse Tracking
this->setMouseTracking(true);
// connect signals with slots
QObject::connect(getMainWindow(), SIGNAL(sendFileOpen()), this, SLOT(onOpenClick()));
QObject::connect(getMainWindow(), SIGNAL(sendWebcamOpen()), this, SLOT(onWebcamBtnOpen()));
QObject::connect(getMainWindow(), SIGNAL(closeVideoStreamSignal()), this, SLOT(onCloseVideoStream()));
}

你必须覆盖paintEvent-Method:

void CustomLabel::paintEvent(QPaintEvent *e){
QPainter painter(this);

// When no image is loaded, paint the window black
if (!currentImage){
    painter.fillRect(QRectF(QPoint(0, 0), QSize(width(), height())), Qt::black);
    QWidget::paintEvent(e);
    return;
}

// Draw a frame from the video
drawVideoFrame(painter);

QWidget::paintEvent(e);
}

paintEvent 中调用的方法:

void CustomLabel::drawVideoFrame(QPainter &painter){
painter.drawImage(QRectF(QPoint(0, 0), QSize(width(), height())), *currentImage, 
QRectF(QPoint(0, 0), currentImage->size()));
}

并且在我的计时器的每一个滴答声中,我都会调用 onTick()

void CustomLabel::onTick() {
/* This method is called every couple of milliseconds.
 * It reads from the OpenCV's capture interface and saves a frame as QImage
 * the state machine is implemented here. every tick is handled
 */
if(cap->isOpened()){
    switch(currentState) {
    case STATE_IDLE:
        if (!cap->read(currentFrame)){
            qDebug() << "cvWindow::_tick !!! Failed to read frame from the capture interface in STATE_IDLE";
        }
        break;
    case STATE_DRAWING:
        if (!cap->read(currentFrame)){
            qDebug() << "cvWindow::_tick !!! Failed to read frame from the capture interface in STATE_DRAWING";
        }
        currentFrame.copyTo(currentCopy);
        cv::circle(currentCopy, cv::Point(focusPt.x*xScale, focusPt.y*yScale), 
sqrt((focusPt.x - currentMousePos.x())*(focusPt.x - currentMousePos.x())*xScale*xScale+(focusPt.y - currentMousePos.y())*
(focusPt.y - currentMousePos.y())*yScale*yScale), cv::Scalar(0, 0, 255), 2, 8, 0);
        //qDebug() << "focus pt x " <<  focusPt.x << "y " << focusPt.y;
        break;
    case STATE_TRACKING:
        if (!cap->read(currentFrame)){
            qDebug() << "cvWindow::_tick !!! Failed to read frame from the capture interface in STATE_TRACKING";
        }
        cv::cvtColor(currentFrame, currentFrame, CV_BGR2GRAY, 0);
        if(initGrayFrame){
            currentGrayFrame.copyTo(previousGrayFrame);
            initGrayFrame = false;
            return;
        }
        cv::calcOpticalFlowPyrLK(previousGrayFrame, currentFrame, previousPts, currentPts, featuresFound, err, cv::Size(21, 21),
                                 3, termcrit, 0, 1e-4);
        AcquireNewPoints();
        currentCopy = CalculateCenter(currentFrame, currentPts);
        if(showPoints){
            DrawPoints(currentCopy, currentPts);
        }
        break;
    case STATE_LOST_POLE:
        currentState = STATE_IDLE;
        initGrayFrame = true;
        cv::cvtColor(currentFrame, currentFrame, CV_GRAY2BGR);
        break;
    default:
        break;
    }
    // if not tracking, draw currentFrame
    // OpenCV uses BGR order, convert it to RGB
    if(currentState == STATE_IDLE) {
        cv::cvtColor(currentFrame, currentFrame, CV_BGR2RGB);
        memcpy(currentImage->scanLine(0), (unsigned char*)currentFrame.data, currentImage->width() * currentImage->height() * currentFrame.channels()); 
    } else {
        cv::cvtColor(currentCopy, currentCopy, CV_BGR2RGB);
        memcpy(currentImage->scanLine(0), (unsigned char*)currentCopy.data, currentImage->width() * currentImage->height() * currentCopy.channels());
        previousGrayFrame = currentFrame;
        previousPts = currentPts;
    }
}
// Trigger paint event to redraw the window
update();
}

不要介意 yScale 和 xScale 因素,它们只是用于 opencv 绘图功能,因为 customLabel 大小与视频分辨率不同

【讨论】:

    【解决方案2】:

    OpenCV 仅用于图像处理。如果您知道将 cv::Mat 转换为任何其他需要的格式,则可以将 OpenCV 包含在任何 GUI 开发工具包中。对于 Qt,您可以将 cv::Mat 转换为 QImage,然后在 Qt SDK 的任何地方使用它。此示例显示 OpenCV 和 Qt 集成,包括线程和网络摄像头访问。使用 OpenCV 访问网络摄像头,接收到的 cv::Mat 被转换为 QImage 并渲染到 QLabel 上。 https://github.com/nickdademo/qt-opencv-multithreaded 该代码包含 MatToQImage() 函数,该函数显示了从 cv::Mat 到 QImage 的转换。集成非常简单,因为一切都在 C++ 中。

    【讨论】:

    • 感谢您的回答。我已经解决了我的问题,但没有线程。你可以在上面看到我的部分解决方案;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-13
    • 1970-01-01
    • 1970-01-01
    • 2020-11-25
    • 1970-01-01
    • 1970-01-01
    • 2014-07-13
    相关资源
    最近更新 更多