Интеграция OpenCV с более крупными программами

Может ли кто-нибудь порекомендовать практическое руководство или предоставить краткий обзор того, что связано с интеграцией OpenCV с более крупными программами на основе графического интерфейса? Какие есть популярные способы сделать это?

В частности, обработка видео с помощью OpenCV при захвате/предварительном просмотре видео без использования HighGUI кажется особенно загадочной. Я надеюсь, что кто-то может демистифицировать это.

Моя конкретная конфигурация либо с Juce, либо с Qt, в зависимости от того, что можно сделать. Кроссплатформенность не критична - если есть отличный способ сделать это в Windows, я могу быть убежден. Важно наличие общественной поддержки.

Я слышал, что HighGUI предназначен исключительно для тестирования и не подходит для реальных приложений. Кто-то порекомендовал библиотеку VideoInput, но она является экспериментальной.


Ключевые моменты из ответов:

  • Используйте Qt (потому что Qt великолепен и имеет большое сообщество).
  • Откройте новый поток для запуска cv::VideoCapture в цикле и сигнала emit после захвата кадра. Используйте механизм Qt msleep, а не OpenCV. Итак, мы по-прежнему используем OpenCV highgui для захвата.
  • Преобразовать cv::Mat в QtImage:

    QImage qtFrame(cvFrame.data, cvFrame.size().width, cvFrame.size().height, cvFrame.step, QImage::Format_RGB888);

    qtFrame = qtFrame.rgbSwapped();

  • Необязательно: рендеринг с помощью GLWidget. Преобразуйте QtImage в GLFormat с помощью встроенного метода Qt:

    m_GLFrame = QGLWidget::convertToGLFormat(frame);

    this->updateGL();


person Matt Montag    schedule 18.10.2011    source источник
comment
Отличное резюме! Я скажу, что не обязательно использовать VideoCapture (например, вы можете использовать CMU1394, драйвер конкретного производителя и т. д.), но невероятно удобно, если он поддерживает вашу камеру из коробки.   -  person mevatron    schedule 19.10.2011
comment
Спасибо за резюме!   -  person Milo    schedule 07.02.2013


Ответы (2)


Вот как я это делаю с Qt. Вы можете использовать все, что может быть полезно для вас :)

/// OpenCV_GLWidget.h
#ifndef OPENCV_GLWIDGET_H_
#define OPENCV_GLWIDGET_H_

#include <qgl.h>
#include <QImage>

class OpenCV_GLWidget: public QGLWidget {
public:
    OpenCV_GLWidget(QWidget * parent = 0, const QGLWidget * shareWidget = 0, Qt::WindowFlags f = 0);
    virtual ~OpenCV_GLWidget();

    void renderImage(const QImage& frame);
protected:
    virtual void paintGL();
    virtual void resizeGL(int width, int height);

private:
    QImage m_GLFrame;
};

#endif /* OPENCV_GLWIDGET_H_ */

/// OpenCV_GLWidget.cpp
#include "OpenCV_GLWidget.h"

OpenCV_GLWidget::OpenCV_GLWidget(QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f) :
QGLWidget(parent, shareWidget, f)
{
    // TODO Auto-generated constructor stub

}

OpenCV_GLWidget::~OpenCV_GLWidget() {
    // TODO Auto-generated destructor stub
}

void OpenCV_GLWidget::renderImage(const QImage& frame)
{
    m_GLFrame = QGLWidget::convertToGLFormat(frame);
    this->updateGL();
}

void OpenCV_GLWidget::resizeGL(int width, int height)
{
    // Setup our viewport to be the entire size of the window
    glViewport(0, 0, width, height);

    // Change to the projection matrix and set orthogonal projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, width, height, 0, 0, 1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void OpenCV_GLWidget::paintGL() {
    glClear (GL_COLOR_BUFFER_BIT);
    glClearColor (0.0, 0.0, 0.0, 1.0);
    if (!m_GLFrame.isNull()) {
        m_GLFrame = m_GLFrame.scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);

        glEnable(GL_TEXTURE_2D);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, m_GLFrame.width(), m_GLFrame.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, m_GLFrame.bits() );
        glBegin(GL_QUADS);
        glTexCoord2f(0, 0); glVertex2f(0, m_GLFrame.height());
        glTexCoord2f(0, 1); glVertex2f(0, 0);
        glTexCoord2f(1, 1); glVertex2f(m_GLFrame.width(), 0);
        glTexCoord2f(1, 0); glVertex2f(m_GLFrame.width(), m_GLFrame.height());
        glEnd();
        glDisable(GL_TEXTURE_2D);

        glFlush();
    }
}

Этот класс обрабатывает рендеринг изображения на продвигаемый QWidget. Затем я создал поток для загрузки виджета. (Здесь я сжульничал, используя архитектуру сигнальных слотов Qt, потому что это было легко... возможно, это не лучший результат в книге, но он должен помочь вам начать).

void VideoThread::run()
{
    cv::VideoCapture video(0);

    while(!m_AbortCapture)
    {
        cv::Mat cvFrame;
        video >> cvFrame;

        cv::Mat gray(cvFrame.size(), CV_8UC1);
        cv::GaussianBlur(cvFrame, cvFrame, cv::Size(5, 5), 9.0, 3.0, cv::BORDER_REPLICATE);
        cv::cvtColor(cvFrame, gray, CV_RGB2GRAY);

        m_ThresholdLock.lock();
        double localThreshold = m_Threshold;
        m_ThresholdLock.unlock();

        if(localThreshold > 0.0)
        {
            qDebug() << "Threshold = " << localThreshold;
            cv::threshold(gray, gray, localThreshold, 255.0,  cv::THRESH_BINARY);
        }

        cv::cvtColor(gray, cvFrame, CV_GRAY2BGR);

        // convert the Mat to a QImage
        QImage qtFrame(cvFrame.data, cvFrame.size().width, cvFrame.size().height, cvFrame.step, QImage::Format_RGB888);
        qtFrame = qtFrame.rgbSwapped();

        // queue the image to the gui
        emit sendImage(qtFrame);
        msleep(20);
    }
}

Мне потребовалось немного времени, чтобы понять это, так что, надеюсь, это поможет вам и другим сэкономить время :D

person mevatron    schedule 18.10.2011
comment
Хороший ответ - вы также можете напрямую отображать QImage, а не OpenGL, просто укажите свой собственный QWidget::paintevent(). Это также дает вам все функции загрузки/сохранения файлов QImage в дополнение к OpenCV. - person Martin Beckett; 18.10.2011
comment
Приятно иметь разные варианты. Стал ли OpenGL быстрее, учитывая отсутствие масштабирования или преобразования изображения? - person Matt Montag; 18.10.2011
comment
@MartinBeckett - я не знал этого о QWidget::paintevent(). Я должен буду проверить это. Я также рассматривал отрисовку в QPixmap, которая работает, но я читал, что если у вас есть видеокарта (как правило, безопасное предположение), виджет OpenGL будет быстрее. Кроме того, OpenGL дает вам хорошую гибкость, если вы хотите делать оверлеи и тому подобное. - person mevatron; 18.10.2011
comment
@Matt - зависит от того, glSubImage может быть быстрее на машинах с приличным аппаратным обеспечением. glPixelBuffer может работать еще быстрее, поскольку может передавать данные асинхронно. Но на машинах с дрянным openGL (встроенные чипсеты Intel) QPainter работает быстрее. - person Martin Beckett; 18.10.2011
comment
Итак, мы запускаем cv::VideoCapture в другом потоке. Я не вижу никакого способа обойти это. Я не думаю, что излучение сигнала имеет большое значение - оно происходит всего 30 раз в секунду. - person Matt Montag; 18.10.2011
comment
@Matt - просто чтобы прояснить это. Рисование QImage (особенно ARGB_Prescaled) в QPainter выполняется очень быстро. Если вы настроили Qt на использование механизма рисования Opengl2, он, вероятно, все равно вызывает glSubTex2D за кулисами. Раньше рисование в QPixmap было медленным. - person Martin Beckett; 19.10.2011
comment
Я не думаю, что это будет работать должным образом, если изображение должно отображаться в формате QGraphicsScene. Если я не ошибаюсь, наличие средства просмотра с включенным рендерингом OpenGL и дополнительным окном просмотра, где вы визуализируете содержимое cv::Mat, приведет к беспорядку. Я бы предпочел использовать QPainter или просто использовать растровое изображение QLabel (не так эффективно, как два других варианта, но очень, очень легко реализовать). - person rbaleksandar; 04.03.2016

Создайте изображение openCV для хранения захваченного изображения.

Выполните обработку, а затем скопируйте данные в изображение, которое вы хотите отобразить (например, QImage)

Вы можете оптимизировать вещи, создав образ opencv cv::Mat, чтобы разделить память с

QImage, но поскольку QImage обычно использует ARGB, а большинство задач обработки изображений лучше выполнять в оттенках серого или RGB, вероятно, лучше копировать изображения и конвертировать между ними с помощью функции opencv cvtColor()

Затем просто включите заголовки opencv и свяжите с библиотеками opencv — в вики opencv есть руководства для вашей конкретной среды.

person Martin Beckett    schedule 18.10.2011