Add frame grabber using OpenCV

This commit is contained in:
Maxim Kulkin 2019-06-16 09:52:35 -07:00
parent 8aff3cb9b0
commit d08d63e6e6
10 changed files with 319 additions and 0 deletions

View File

@ -68,6 +68,9 @@ message(STATUS "ENABLE_TINKERFORGE = " ${ENABLE_TINKERFORGE})
option(ENABLE_V4L2 "Enable the V4L2 grabber" ON)
message(STATUS "ENABLE_V4L2 = " ${ENABLE_V4L2})
option(ENABLE_OPENCV "Enable the OpenCV grabber" ON)
message(STATUS "ENABLE_OPENCV = " ${ENABLE_OPENCV})
option(ENABLE_WS2812BPWM "Enable the WS2812b-PWM device" ${DEFAULT_WS2812BPWM} )
message(STATUS "ENABLE_WS2812BPWM = " ${ENABLE_WS2812BPWM})

View File

@ -27,6 +27,9 @@
// Define to enable the osx grabber
#cmakedefine ENABLE_OSX
// Define to enable the opencv grabber
#cmakedefine ENABLE_OPENCV
// Define to enable the bonjour/zeroconf publishing
#cmakedefine ENABLE_ZEROCONF

View File

@ -0,0 +1,27 @@
#pragma once
// Qt includes
#include <QObject>
// util includes
#include <utils/Image.h>
#include <utils/ColorRgb.h>
// grabber includes
#include <opencv2/opencv.hpp>
/// Capture class for OpenCV
class OpenCVGrabber : public QObject
{
Q_OBJECT
public:
OpenCVGrabber(int input, int width, int height);
virtual ~OpenCVGrabber();
public slots:
void grabFrame(Image<ColorRgb> & image);
private:
cv::VideoCapture _capture;
};

View File

@ -0,0 +1,65 @@
#pragma once
// Qt includes
#include <QTimer>
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <hyperion/ImageProcessor.h>
// Grabber includes
#include <grabber/OpenCVGrabber.h>
class OpenCVWrapper : public QObject
{
Q_OBJECT
public:
OpenCVWrapper(int input,
int width,
int height,
int frequency,
int hyperionPriority,
Hyperion * hyperion);
virtual ~OpenCVWrapper();
public slots:
void start();
void stop();
signals:
void emitColors(int priority, const std::vector<ColorRgb> &ledColors, const int timeout_ms);
void emitImage(int priority, const Image<ColorRgb> & image, const int timeout_ms);
private slots:
void grabFrame();
void checkSources();
private:
/// The timeout of the led colors [ms]
const int _timeout_ms;
/// The priority of the led colors
const int _priority;
/// Grab frequency [Hz]
const int _frequency;
/// The OpenCV grabber
OpenCVGrabber _grabber;
/// The processor for transforming images to led colors
ImageProcessor * _processor;
/// The Hyperion instance
Hyperion * _hyperion;
/// The list with computed led colors
std::vector<ColorRgb> _ledColors;
/// Timer which tests if a higher priority source is active
QTimer _priority_check_timer;
QTimer _grab_timer;
};

View File

@ -18,6 +18,10 @@ if (ENABLE_V4L2)
add_subdirectory(v4l2)
endif (ENABLE_V4L2)
if (ENABLE_OPENCV)
add_subdirectory(opencv)
endif (ENABLE_OPENCV)
if (ENABLE_X11)
add_subdirectory(x11)
endif()

View File

@ -0,0 +1,38 @@
find_package(OpenCV REQUIRED)
# Define the current source locations
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber)
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/opencv)
SET(OPENCV_GRABBER_QT_HEADERS
${CURRENT_HEADER_DIR}/OpenCVGrabber.h
${CURRENT_HEADER_DIR}/OpenCVWrapper.h
)
SET(OPENCV_GRABBER_SOURCES
${CURRENT_SOURCE_DIR}/OpenCVGrabber.cpp
${CURRENT_SOURCE_DIR}/OpenCVWrapper.cpp
)
if(ENABLE_QT5)
QT5_WRAP_CPP(OPENCV_GRABBER_HEADERS_MOC ${OPENCV_GRABBER_QT_HEADERS})
else()
QT4_WRAP_CPP(OPENCV_GRABBER_HEADERS_MOC ${OPENCV_GRABBER_QT_HEADERS})
endif()
add_library(opencv-grabber
${OPENCV_GRABBER_HEADERS}
${OPENCV_GRABBER_SOURCES}
${OPENCV_GRABBER_QT_HEADERS}
${OPENCV_GRABBER_HEADERS_MOC}
)
if(ENABLE_QT5)
qt5_use_modules(opencv-grabber Widgets)
endif(ENABLE_QT5)
target_link_libraries(opencv-grabber
hyperion
${QT_LIBRARIES}
${OpenCV_LIBS}
)

View File

@ -0,0 +1,34 @@
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <opencv2/opencv.hpp>
#include "grabber/OpenCVGrabber.h"
OpenCVGrabber::OpenCVGrabber(int input, int width, int height)
: _capture(input)
{
if (width && height) {
_capture.set(CV_CAP_PROP_FRAME_WIDTH, width);
_capture.set(CV_CAP_PROP_FRAME_HEIGHT, height);
}
}
OpenCVGrabber::~OpenCVGrabber()
{
}
void OpenCVGrabber::grabFrame(Image<ColorRgb> & image)
{
cv::Mat frame;
_capture >> frame;
const int width = frame.cols, height = frame.rows;
cv::Mat rgbFrame(width, height, CV_8UC3);
cvtColor(frame, rgbFrame, cv::COLOR_BGR2RGB);
image.resize(width, height);
memcpy(image.memptr(), rgbFrame.ptr(), width * height * 3);
}

View File

@ -0,0 +1,102 @@
#include <QMetaType>
#include <grabber/OpenCVWrapper.h>
#include <hyperion/ImageProcessorFactory.h>
OpenCVWrapper::OpenCVWrapper(
int input,
int width,
int height,
int frequency,
int hyperionPriority,
Hyperion *hyperion) :
_timeout_ms(1000),
_priority(hyperionPriority),
_frequency(frequency),
_grabber(input, width, height),
_processor(ImageProcessorFactory::getInstance().newImageProcessor()),
_hyperion(hyperion),
_ledColors(hyperion->getLedCount(), ColorRgb{0,0,0}),
_priority_check_timer(),
_grab_timer()
{
// register the image type
qRegisterMetaType<Image<ColorRgb>>("Image<ColorRgb>");
qRegisterMetaType<std::vector<ColorRgb>>("std::vector<ColorRgb>");
// send color data to Hyperion using a queued connection to handle the data over to the main event loop
QObject::connect(
this, SIGNAL(emitColors(int,std::vector<ColorRgb>,int)),
_hyperion, SLOT(setColors(int,std::vector<ColorRgb>,int)),
Qt::QueuedConnection);
// setup the higher prio source checker
// this will disable the grabber when a source with hisher priority is active
_priority_check_timer.setInterval(500);
_priority_check_timer.setSingleShot(false);
QObject::connect(&_priority_check_timer, SIGNAL(timeout()), this, SLOT(checkSources()));
_priority_check_timer.start();
_grab_timer.setInterval(1000 / _frequency);
_grab_timer.setSingleShot(false);
QObject::connect(&_grab_timer, SIGNAL(timeout()), this, SLOT(grabFrame()));
}
OpenCVWrapper::~OpenCVWrapper()
{
delete _processor;
}
void OpenCVWrapper::start()
{
if (_grab_timer.isActive())
return;
_grab_timer.start();
std::cout << "OPENCVGRABBER INFO: started" << std::endl;
}
void OpenCVWrapper::stop()
{
if (!_grab_timer.isActive())
return;
_grab_timer.stop();
std::cout << "OPENCVGRABBER INFO: stopped" << std::endl;
}
void OpenCVWrapper::grabFrame()
{
Image<ColorRgb> image;
_grabber.grabFrame(image);
// process the new image
_processor->process(image, _ledColors);
// forward to other hyperions
emit emitImage(_priority, image, _timeout_ms);
// send colors to Hyperion
emit emitColors(_priority, _ledColors, _timeout_ms);
}
void OpenCVWrapper::checkSources()
{
QList<int> activePriorities = _hyperion->getActivePriorities();
for (int x : activePriorities)
{
if (x < _priority)
{
// found a higher priority source: grabber should be disabled
stop();
return;
}
}
// no higher priority source was found: grabber should be enabled
start();
}

View File

@ -31,6 +31,10 @@ if (ENABLE_V4L2)
target_link_libraries(hyperiond v4l2-grabber)
endif ()
if (ENABLE_OPENCV)
target_link_libraries(hyperiond opencv-grabber)
endif ()
if (ENABLE_AMLOGIC)
target_link_libraries(hyperiond amlogic-grabber)
endif ()

View File

@ -46,6 +46,11 @@
#include <grabber/OsxWrapper.h>
#endif
#ifdef ENABLE_OPENCV
// OpenCV grabber
#include <grabber/OpenCVWrapper.h>
#endif
// XBMC Video checker includes
#include <xbmcvideochecker/XBMCVideoChecker.h>
@ -428,6 +433,30 @@ void startGrabberOsx(const Json::Value &config, Hyperion &hyperion, ProtoServer*
}
#endif
#ifdef ENABLE_OPENCV
void startGrabberOpenCV(const Json::Value &config, Hyperion &hyperion, ProtoServer* &protoServer, OpenCVWrapper* &opencvGrabber)
{
// Construct and start the OpenCV grabber if the configuration is present
if (config.isMember("opencvgrabber"))
{
const Json::Value & grabberConfig = config["opencvgrabber"];
opencvGrabber = new OpenCVWrapper(
grabberConfig.get("input", 0).asUInt(),
grabberConfig.get("width", 0).asUInt(),
grabberConfig.get("height", 0).asUInt(),
grabberConfig.get("frequency_Hz", 10).asUInt(),
grabberConfig.get("priority", 900).asInt(),
&hyperion);
QObject::connect(opencvGrabber, SIGNAL(emitImage(int, const Image<ColorRgb>&, const int)), protoServer, SLOT(sendImageToProtoSlaves(int, const Image<ColorRgb>&, const int)) );
opencvGrabber->start();
std::cout << "INFO: OpenCV grabber created and started" << std::endl;
}
}
#endif
int main(int argc, char** argv)
{
std::cout
@ -584,6 +613,16 @@ int main(int argc, char** argv)
#endif
#endif
#ifdef ENABLE_OPENCV
OpenCVWrapper * opencvGrabber = nullptr;
startGrabberOpenCV(config, hyperion, protoServer, opencvGrabber);
#else
if (config.isMember("opencvgrabber"))
{
std::cerr << "ERROR: The OpenCV grabber can not be instantiated, because it has been left out from the build" << std::endl;
}
#endif
// run the application
int rc = app.exec();