From d59c94421d210ca43aedaec56f0581eede2d5e92 Mon Sep 17 00:00:00 2001 From: redPanther Date: Fri, 16 Dec 2016 19:48:43 +0100 Subject: [PATCH] Kill "Rainbow lights" when v4l grabber has no signal (#334) * on v4l screenshot, print out nosignal threshold values * separate fractional parameters for no signal detection * fully implement handling for "rainbow grabber" --- config/hyperion.config.json.commented | 10 +++- config/hyperion.config.json.default | 6 ++- include/grabber/V4L2Grabber.h | 22 ++++++++- include/grabber/V4L2Wrapper.h | 3 +- include/utils/ColorRgb.h | 13 +++++ libsrc/grabber/v4l2/V4L2Grabber.cpp | 66 ++++++++++++++++++------- libsrc/grabber/v4l2/V4L2Wrapper.cpp | 6 +++ libsrc/hyperion/hyperion.schema.json | 50 +++++++++++++++++-- src/hyperion-v4l2/ScreenshotHandler.cpp | 40 ++++++++++++++- src/hyperion-v4l2/ScreenshotHandler.h | 4 +- src/hyperion-v4l2/hyperion-v4l2.cpp | 62 ++++++++++++++++++++--- src/hyperiond/hyperiond.cpp | 5 ++ 12 files changed, 251 insertions(+), 36 deletions(-) diff --git a/config/hyperion.config.json.commented b/config/hyperion.config.json.commented index 87fadab7..f70adf19 100644 --- a/config/hyperion.config.json.commented +++ b/config/hyperion.config.json.commented @@ -153,6 +153,10 @@ /// * redSignalThreshold : Signal threshold for the red channel between 0.0 and 1.0 [default=0.0] /// * greenSignalThreshold : Signal threshold for the green channel between 0.0 and 1.0 [default=0.0] /// * blueSignalThreshold : Signal threshold for the blue channel between 0.0 and 1.0 [default=0.0] + /// * signalDetectionVerticalOffsetMin : area for signal detection - horizontal minimum offset value. Values between 0.0 and 1.0 + /// * signalDetectionHorizontalOffsetMin : area for signal detection - vertical minimum offset value. Values between 0.0 and 1.0 + /// * signalDetectionVerticalOffsetMax : area for signal detection - horizontal maximum offset value. Values between 0.0 and 1.0 + /// * signalDetectionHorizontalOffsetMax : area for signal detection - vertical maximum offset value. Values between 0.0 and 1.0 "grabberV4L2" : [ { @@ -173,7 +177,11 @@ "cropBottom" : 0, "redSignalThreshold" : 0.0, "greenSignalThreshold" : 0.0, - "blueSignalThreshold" : 0.0 + "blueSignalThreshold" : 0.0, + "signalDetectionVerticalOffsetMin" : 0.25, + "signalDetectionHorizontalOffsetMin" : 0.25, + "signalDetectionVerticalOffsetMax" : 0.75, + "signalDetectionHorizontalOffsetMax" : 0.75 } ], diff --git a/config/hyperion.config.json.default b/config/hyperion.config.json.default index 129dc5ea..13718051 100644 --- a/config/hyperion.config.json.default +++ b/config/hyperion.config.json.default @@ -105,7 +105,11 @@ "cropBottom" : 0, "redSignalThreshold" : 0.0, "greenSignalThreshold" : 0.0, - "blueSignalThreshold" : 0.0 + "blueSignalThreshold" : 0.0, + "signalDetectionVerticalOffsetMin" : 0.25, + "signalDetectionHorizontalOffsetMin" : 0.25, + "signalDetectionVerticalOffsetMax" : 0.75, + "signalDetectionHorizontalOffsetMax" : 0.75 } ], diff --git a/include/grabber/V4L2Grabber.h b/include/grabber/V4L2Grabber.h index ab779ce7..9f3f9a31 100644 --- a/include/grabber/V4L2Grabber.h +++ b/include/grabber/V4L2Grabber.h @@ -8,6 +8,7 @@ // Qt includes #include #include +#include // util includes #include @@ -35,9 +36,12 @@ public: int height, int frameDecimation, int horizontalPixelDecimation, - int verticalPixelDecimation); + int verticalPixelDecimation + ); virtual ~V4L2Grabber(); + QRectF getSignalDetectionOffset(); + public slots: void setCropping(int cropLeft, int cropRight, @@ -46,11 +50,18 @@ public slots: void set3D(VideoMode mode); - void setSignalThreshold(double redSignalThreshold, + void setSignalThreshold( + double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold); + void setSignalDetectionOffset( + double verticalMin, + double horizontalMin, + double verticalMax, + double horizontalMax); + bool start(); void stop(); @@ -137,4 +148,11 @@ private: Logger * _log; bool _initialized; bool _deviceAutoDiscoverEnabled; + + bool _noSignalDetected; + double _x_frac_min; + double _y_frac_min; + double _x_frac_max; + double _y_frac_max; + }; diff --git a/include/grabber/V4L2Wrapper.h b/include/grabber/V4L2Wrapper.h index e49c7d83..2f6e7915 100644 --- a/include/grabber/V4L2Wrapper.h +++ b/include/grabber/V4L2Wrapper.h @@ -29,11 +29,10 @@ public: public slots: bool start(); - void stop(); void setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom); - + void setSignalDetectionOffset(double verticalMin, double horizontalMin, double verticalMax, double horizontalMax); void set3D(VideoMode mode); // signals: diff --git a/include/utils/ColorRgb.h b/include/utils/ColorRgb.h index bbf9f615..0bdd850a 100644 --- a/include/utils/ColorRgb.h +++ b/include/utils/ColorRgb.h @@ -61,3 +61,16 @@ inline bool operator<=(const ColorRgb & lhs, const ColorRgb & rhs) { return (lhs.red <= rhs.red) && (lhs.green <= rhs.green) && (lhs.blue <= rhs.blue); } + +/// Compare operator to check if a color is 'greater' to another color +inline bool operator>(const ColorRgb & lhs, const ColorRgb & rhs) +{ + return (lhs.red > rhs.red) && (lhs.green > rhs.green) && (lhs.blue > rhs.blue); +} + +/// Compare operator to check if a color is 'greater' than or 'equal' to another color +inline bool operator>=(const ColorRgb & lhs, const ColorRgb & rhs) +{ + return (lhs.red >= rhs.red) && (lhs.green >= rhs.green) && (lhs.blue >= rhs.blue); +} + diff --git a/libsrc/grabber/v4l2/V4L2Grabber.cpp b/libsrc/grabber/v4l2/V4L2Grabber.cpp index 1c3686b5..dcd0e9a4 100644 --- a/libsrc/grabber/v4l2/V4L2Grabber.cpp +++ b/libsrc/grabber/v4l2/V4L2Grabber.cpp @@ -23,15 +23,16 @@ #define CLEAR(x) memset(&(x), 0, sizeof(x)) -V4L2Grabber::V4L2Grabber(const std::string & device, - int input, - VideoStandard videoStandard, - PixelFormat pixelFormat, - int width, - int height, - int frameDecimation, - int horizontalPixelDecimation, - int verticalPixelDecimation) +V4L2Grabber::V4L2Grabber(const std::string & device + , int input + , VideoStandard videoStandard + , PixelFormat pixelFormat + , int width + , int height + , int frameDecimation + , int horizontalPixelDecimation + , int verticalPixelDecimation + ) : _deviceName(device) , _input(input) , _videoStandard(videoStandard) @@ -53,6 +54,12 @@ V4L2Grabber::V4L2Grabber(const std::string & device, , _log(Logger::getInstance("V4L2:"+device)) , _initialized(false) , _deviceAutoDiscoverEnabled(false) + , _noSignalDetected(false) + , _x_frac_min(0.25) + , _y_frac_min(0.25) + , _x_frac_max(0.75) + , _y_frac_max(0.75) + { _imageResampler.setHorizontalPixelDecimation(std::max(1, horizontalPixelDecimation)); _imageResampler.setVerticalPixelDecimation(std::max(1, verticalPixelDecimation)); @@ -196,6 +203,24 @@ void V4L2Grabber::setSignalThreshold(double redSignalThreshold, double greenSign Info(_log, "Signal threshold set to: %s", ss.str().c_str() ); } +void V4L2Grabber::setSignalDetectionOffset(double horizontalMin, double verticalMin, double horizontalMax, double verticalMax) +{ + // rainbow 16 stripes 0.47 0.2 0.49 0.8 + // unicolor: 0.25 0.25 0.75 0.75 + + _x_frac_min = horizontalMin; + _y_frac_min = verticalMin; + _x_frac_max = horizontalMax; + _y_frac_max = verticalMax; + + Info(_log, "Signal detection area set to: %f,%f x %f,%f", _x_frac_min, _y_frac_min, _x_frac_max, _y_frac_max ); +} + +QRectF V4L2Grabber::getSignalDetectionOffset() +{ + return QRectF(_x_frac_min, _y_frac_min, _x_frac_max, _y_frac_max); +} + bool V4L2Grabber::start() { try @@ -787,16 +812,21 @@ void V4L2Grabber::process_image(const uint8_t * data) // check signal (only in center of the resulting image, because some grabbers have noise values along the borders) bool noSignal = true; - for (unsigned x = 0; noSignal && x < (image.width()>>1); ++x) + + // top left + unsigned xOffset = image.width() * _x_frac_min; + unsigned yOffset = image.height() * _y_frac_min; + + // bottom right + unsigned xMax = image.width() * _x_frac_max; + unsigned yMax = image.height() * _y_frac_max; + + + for (unsigned x = xOffset; noSignal && x < xMax; ++x) { - int xImage = (image.width()>>2) + x; - - for (unsigned y = 0; noSignal && y < (image.height()>>1); ++y) + for (unsigned y = yOffset; noSignal && y < yMax; ++y) { - int yImage = (image.height()>>2) + y; - - ColorRgb & rgb = image(xImage, yImage); - noSignal &= rgb <= _noSignalThresholdColor; + noSignal &= (ColorRgb&)image(x, y) <= _noSignalThresholdColor; } } @@ -808,6 +838,7 @@ void V4L2Grabber::process_image(const uint8_t * data) { if (_noSignalCounter >= _noSignalCounterThreshold) { + _noSignalDetected = true; Info(_log, "Signal detected"); } @@ -820,6 +851,7 @@ void V4L2Grabber::process_image(const uint8_t * data) } else if (_noSignalCounter == _noSignalCounterThreshold) { + _noSignalDetected = false; Info(_log, "Signal lost"); } } diff --git a/libsrc/grabber/v4l2/V4L2Wrapper.cpp b/libsrc/grabber/v4l2/V4L2Wrapper.cpp index ad183d18..7a1310fa 100644 --- a/libsrc/grabber/v4l2/V4L2Wrapper.cpp +++ b/libsrc/grabber/v4l2/V4L2Wrapper.cpp @@ -74,6 +74,12 @@ void V4L2Wrapper::setCropping(int cropLeft, int cropRight, int cropTop, int crop _grabber.setCropping(cropLeft, cropRight, cropTop, cropBottom); } +void V4L2Wrapper::setSignalDetectionOffset(double verticalMin, double horizontalMin, double verticalMax, double horizontalMax) +{ + _grabber.setSignalDetectionOffset(verticalMin, horizontalMin, verticalMax, horizontalMax); +} + + void V4L2Wrapper::set3D(VideoMode mode) { _grabber.set3D(mode); diff --git a/libsrc/hyperion/hyperion.schema.json b/libsrc/hyperion/hyperion.schema.json index e1ce0900..a860a414 100644 --- a/libsrc/hyperion/hyperion.schema.json +++ b/libsrc/hyperion/hyperion.schema.json @@ -540,7 +540,7 @@ "minimum" : 0.0, "maximum" : 1.0, "default" : 0.1, - "step" : 0.01, + "step" : 0.005, "append" : "edt_append_percent", "propertyOrder" : 16 }, @@ -551,7 +551,7 @@ "minimum" : 0.0, "maximum" : 1.0, "default" : 0.1, - "step" : 0.01, + "step" : 0.025, "append" : "edt_append_percent", "propertyOrder" : 17 }, @@ -562,9 +562,53 @@ "minimum" : 0.0, "maximum" : 1.0, "default" : 0.1, - "step" : 0.01, + "step" : 0.005, "append" : "edt_append_percent", "propertyOrder" : 18 + }, + "signalDetectionVerticalOffsetMin" : + { + "type" : "number", + "title" : "edt_conf_v4l2_signalDetectionVerticalOffsetMin_title", + "minimum" : 0.0, + "maximum" : 1.0, + "default" : 0.1, + "step" : 0.005, + "append" : "edt_append_percent", + "propertyOrder" : 19 + }, + "signalDetectionVerticalOffsetMax" : + { + "type" : "number", + "title" : "edt_conf_v4l2_signalDetectionVerticalOffsetMax_title", + "minimum" : 0.0, + "maximum" : 1.0, + "default" : 0.1, + "step" : 0.005, + "append" : "edt_append_percent", + "propertyOrder" : 20 + }, + "signalDetectionHorizontalOffsetMin" : + { + "type" : "number", + "title" : "edt_conf_v4l2_signalDetectionHorizontalOffsetMin_title", + "minimum" : 0.0, + "maximum" : 1.0, + "default" : 0.1, + "step" : 0.005, + "append" : "edt_append_percent", + "propertyOrder" : 21 + }, + "signalDetectionHorizontalOffsetMax" : + { + "type" : "number", + "title" : "edt_conf_v4l2_signalDetectionHorizontalOffsetMax_title", + "minimum" : 0.0, + "maximum" : 1.0, + "default" : 0.1, + "step" : 0.005, + "append" : "edt_append_percent", + "propertyOrder" : 22 } }, "additionalProperties" : false diff --git a/src/hyperion-v4l2/ScreenshotHandler.cpp b/src/hyperion-v4l2/ScreenshotHandler.cpp index a66a524e..e006fca9 100644 --- a/src/hyperion-v4l2/ScreenshotHandler.cpp +++ b/src/hyperion-v4l2/ScreenshotHandler.cpp @@ -5,8 +5,9 @@ // hyperion-v4l2 includes #include "ScreenshotHandler.h" -ScreenshotHandler::ScreenshotHandler(const QString & filename) : - _filename(filename) +ScreenshotHandler::ScreenshotHandler(const QString & filename, const QRectF & signalDetectionOffset) + : _filename(filename) + , _signalDetectionOffset(signalDetectionOffset) { } @@ -16,6 +17,41 @@ ScreenshotHandler::~ScreenshotHandler() void ScreenshotHandler::receiveImage(const Image & image) { + double x_frac_min = _signalDetectionOffset.x(); + double y_frac_min = _signalDetectionOffset.y(); + double x_frac_max = _signalDetectionOffset.width(); + double y_frac_max = _signalDetectionOffset.height(); + + int xOffset = image.width() * x_frac_min; + int yOffset = image.height() * y_frac_min; + int xMax = image.width() * x_frac_max; + int yMax = image.height() * y_frac_max; + + std::cout << std::endl << "Screenshot details" + << std::endl << "==================" + << std::endl << "dimension after decimation: " << image.width() << " x " << image.height() + << std::endl << "signal detection area : " << xOffset << "," << yOffset << " x " << xMax << "," << yMax << std::endl; + + ColorRgb noSignalThresholdColor = {0,0,0}; + + for (unsigned x = 0; x < (image.width()>>1); ++x) + { + int xImage = (image.width()>>2) + x; + + for (unsigned y = 0; y < (image.height()>>1); ++y) + { + int yImage = (image.height()>>2) + y; + + ColorRgb rgb = image(xImage, yImage); + if (rgb > noSignalThresholdColor) + { + noSignalThresholdColor = rgb; + } + } + } + std::cout << "signal threshold color : " << noSignalThresholdColor << std::endl; + std::cout << "signal threshold values: " << (float)noSignalThresholdColor.red/255.0f << ", "<< (float)noSignalThresholdColor.green/255.0f << ", " << (float)noSignalThresholdColor.blue/255.0f << std::endl; + // store as PNG QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888); pngImage.save(_filename); diff --git a/src/hyperion-v4l2/ScreenshotHandler.h b/src/hyperion-v4l2/ScreenshotHandler.h index 0b0059cf..5c447027 100644 --- a/src/hyperion-v4l2/ScreenshotHandler.h +++ b/src/hyperion-v4l2/ScreenshotHandler.h @@ -1,5 +1,6 @@ // Qt includes #include +#include // hyperionincludes #include @@ -11,7 +12,7 @@ class ScreenshotHandler : public QObject Q_OBJECT public: - ScreenshotHandler(const QString & filename); + ScreenshotHandler(const QString & filename, const QRectF & signalDetectionOffset); virtual ~ScreenshotHandler(); public slots: @@ -21,4 +22,5 @@ public slots: private: const QString _filename; + const QRectF _signalDetectionOffset; }; diff --git a/src/hyperion-v4l2/hyperion-v4l2.cpp b/src/hyperion-v4l2/hyperion-v4l2.cpp index 578575fa..ad8a4d3d 100644 --- a/src/hyperion-v4l2/hyperion-v4l2.cpp +++ b/src/hyperion-v4l2/hyperion-v4l2.cpp @@ -34,6 +34,7 @@ void saveScreenshot(QString filename, const Image & image) int main(int argc, char** argv) { + Logger *log = Logger::getInstance("V4L2GRABBER"); std::cout << "hyperion-v4l2:" << std::endl << "\tVersion : " << HYPERION_VERSION << " (" << HYPERION_BUILD_ID << ")" << std::endl @@ -68,10 +69,17 @@ int main(int argc, char** argv) IntOption & argSizeDecimation = parser.add ('s', "size-decimator", "Decimation factor for the output size [default=%1]", "1"); IntOption & argFrameDecimation = parser.add ('f', "frame-decimator", "Decimation factor for the video frames [default=%1]", "1"); BooleanOption & argScreenshot = parser.add(0x0, "screenshot", "Take a single screenshot, save it to file and quit"); + DoubleOption & argSignalThreshold = parser.add ('t', "signal-threshold", "The signal threshold for detecting the presence of a signal. Value should be between 0.0 and 1.0.", QString(), 0.0, 1.0); DoubleOption & argRedSignalThreshold = parser.add (0x0, "red-threshold", "The red signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)"); DoubleOption & argGreenSignalThreshold= parser.add (0x0, "green-threshold", "The green signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)"); DoubleOption & argBlueSignalThreshold = parser.add (0x0, "blue-threshold", "The blue signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)"); + + DoubleOption & argSignalHorizontalMin = parser.add (0x0, "signal-horizontal-min", "area for signal detection - horizontal minimum offset value. Values between 0.0 and 1.0"); + DoubleOption & argSignalVerticalMin = parser.add (0x0, "signal-vertical-min" , "area for signal detection - vertical minimum offset value. Values between 0.0 and 1.0"); + DoubleOption & argSignalHorizontalMax = parser.add (0x0, "signal-horizontal-max", "area for signal detection - horizontal maximum offset value. Values between 0.0 and 1.0"); + DoubleOption & argSignalVerticalMax = parser.add (0x0, "signal-vertical-max" , "area for signal detection - vertical maximum offset value. Values between 0.0 and 1.0"); + BooleanOption & arg3DSBS = parser.add(0x0, "3DSBS", "Interpret the incoming video stream as 3D side-by-side"); BooleanOption & arg3DTAB = parser.add(0x0, "3DTAB", "Interpret the incoming video stream as 3D top-and-bottom"); Option & argAddress = parser.add