将现有的OpenCV应用程序包含到Qt GUI中

时间:2016-05-26 22:51:44

标签: linux qt opencv

我想将现有的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 version 4.8.6

感谢您的意见

2 个答案:

答案 0 :(得分:0)

我还没有真正解决过我想要的问题。但现在它正在发挥作用。如果有人遇到同样的问题,也许我的解决方案可以提供一些想法。如果你想用qt显示视频或者你有OpenCV库的问题,也许我可以提供帮助。

以下是一些代码片段。他们的评论不是很多,但我希望这个概念很明确:

首先,我有一个带有标签的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大小与视频分辨率不同

答案 1 :(得分:0)

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 ++中。