diff --git a/libsrc/jsonserver/JsonSchemas.qrc b/libsrc/jsonserver/JsonSchemas.qrc index 1e5c00eb..c9575da5 100644 --- a/libsrc/jsonserver/JsonSchemas.qrc +++ b/libsrc/jsonserver/JsonSchemas.qrc @@ -7,8 +7,6 @@ schema/schema-clear.json schema/schema-clearall.json schema/schema-transform.json - schema/schema-correction.json - schema/schema-temperature.json schema/schema-adjustment.json schema/schema-effect.json schema/schema-create-effect.json diff --git a/libsrc/jsonserver/schema/schema-correction.json b/libsrc/jsonserver/schema/schema-correction.json deleted file mode 100644 index b3f92e40..00000000 --- a/libsrc/jsonserver/schema/schema-correction.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "type":"object", - "required":true, - "properties":{ - "command": { - "type" : "string", - "required" : true, - "enum" : ["correction"] - }, - "tan" : { - "type" : "integer" - }, - "correction": { - "type": "object", - "required": true, - "properties": { - "id" : { - "type" : "string", - "required" : false - }, - "correctionValues" : { - "type": "array", - "required": false, - "items" : { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "minItems": 3, - "maxItems": 3 - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false -} diff --git a/libsrc/jsonserver/schema/schema-temperature.json b/libsrc/jsonserver/schema/schema-temperature.json deleted file mode 100644 index 8af7f6d7..00000000 --- a/libsrc/jsonserver/schema/schema-temperature.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "type":"object", - "required":true, - "properties":{ - "command": { - "type" : "string", - "required" : true, - "enum" : ["temperature"] - }, - "tan" : { - "type" : "integer" - }, - "temperature": { - "type": "object", - "required": true, - "properties": { - "id" : { - "type" : "string", - "required" : false - }, - "correctionValues" : { - "type": "array", - "required": false, - "items" : { - "type": "integer", - "minimum": 0, - "maximum": 255 - }, - "minItems": 3, - "maxItems": 3 - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false -} diff --git a/libsrc/jsonserver/schema/schema.json b/libsrc/jsonserver/schema/schema.json index 740f34e7..fdeb9f93 100644 --- a/libsrc/jsonserver/schema/schema.json +++ b/libsrc/jsonserver/schema/schema.json @@ -5,7 +5,7 @@ "command": { "type" : "string", "required" : true, - "enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "transform", "correction", "temperature", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging"] + "enum" : ["color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "transform", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging"] } } } diff --git a/libsrc/utils/HslTransform.cpp b/libsrc/utils/HslTransform.cpp index 535e1676..33af7561 100644 --- a/libsrc/utils/HslTransform.cpp +++ b/libsrc/utils/HslTransform.cpp @@ -2,10 +2,10 @@ #include #include -HslTransform::HslTransform() : - _saturationGain(1.0), - _luminanceGain(1.0), - _luminanceMinimum(0.0) +HslTransform::HslTransform() + : _saturationGain(1.0) + , _luminanceGain(1.0) + , _luminanceMinimum(0.0) { } @@ -57,12 +57,9 @@ void HslTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue) con uint16_t hue; float saturation, luminance; rgb2hsl(red, green, blue, hue, saturation, luminance); - + float s = saturation * _saturationGain; - if (s > 1.0f) - saturation = 1.0f; - else - saturation = s; + saturation = std::min(s, 1.0f); float l = luminance * _luminanceGain; if (l < _luminanceMinimum) @@ -70,39 +67,36 @@ void HslTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue) con saturation = 0; l = _luminanceMinimum; } - if (l > 1.0f) - luminance = 1.0f; - else - luminance = l; - + luminance = std::min(l, 1.0f); + hsl2rgb(hue, saturation, luminance, red, green, blue); } } void HslTransform::rgb2hsl(uint8_t red, uint8_t green, uint8_t blue, uint16_t & hue, float & saturation, float & luminance) { - float r = red / 255.0f; - float g = green / 255.0f; - float b = blue / 255.0f; + float r = (float)red / 255.0f; + float g = (float)green / 255.0f; + float b = (float)blue / 255.0f; - float rgbMin = r < g ? (r < b ? r : b) : (g < b ? g : b); - float rgbMax = r > g ? (r > b ? r : b) : (g > b ? g : b); + float rgbMin = std::min(r,std::min(g,b)); + float rgbMax = std::max(r,std::max(g,b)); float diff = rgbMax - rgbMin; //luminance luminance = (rgbMin + rgbMax) / 2.0f; - if (diff == 0.0f) { + if (diff == 0.0f) + { saturation = 0.0f; - hue = 0; + hue = 0; return; - } + } //saturation - if (luminance < 0.5f) - saturation = diff / (rgbMin + rgbMax); - else - saturation = diff / (2.0f - rgbMin - rgbMax); + saturation = (luminance < 0.5f) + ? (diff / (rgbMin + rgbMax)) + : (diff / (2.0f - rgbMin - rgbMax)); if (rgbMax == r) { @@ -125,30 +119,29 @@ void HslTransform::rgb2hsl(uint8_t red, uint8_t green, uint8_t blue, uint16_t & void HslTransform::hsl2rgb(uint16_t hue, float saturation, float luminance, uint8_t & red, uint8_t & green, uint8_t & blue) { - if (saturation == 0.0f){ - red = (uint8_t)(luminance * 255.0f); + if (saturation == 0.0f) + { + red = (uint8_t)(luminance * 255.0f); green = (uint8_t)(luminance * 255.0f); - blue = (uint8_t)(luminance * 255.0f); + blue = (uint8_t)(luminance * 255.0f); return; } - - float q; - - if (luminance < 0.5f) - q = luminance * (1.0f + saturation); - else - q = (luminance + saturation) - (luminance * saturation); - + + float q = (luminance < 0.5f) + ? luminance * (1.0f + saturation) + : (luminance + saturation) - (luminance * saturation); + float p = (2.0f * luminance) - q; float h = hue / 360.0f; - + float t[3]; t[0] = h + (1.0f / 3.0f); t[1] = h; t[2] = h - (1.0f / 3.0f); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) + { if (t[i] < 0.0f) t[i] += 1.0f; if (t[i] > 1.0f) @@ -157,7 +150,8 @@ void HslTransform::hsl2rgb(uint16_t hue, float saturation, float luminance, uint float out[3]; - for (int i = 0; i < 3; i++) { + for (int i = 0; i < 3; i++) + { if (t[i] * 6.0f < 1.0f) out[i] = p + (q - p) * 6.0f * t[i]; else if (t[i] * 2.0f < 1.0f) @@ -168,8 +162,8 @@ void HslTransform::hsl2rgb(uint16_t hue, float saturation, float luminance, uint } //convert back to 0...255 range - red = (uint8_t)(out[0] * 255.0f); + red = (uint8_t)(out[0] * 255.0f); green = (uint8_t)(out[1] * 255.0f); - blue = (uint8_t)(out[2] * 255.0f); + blue = (uint8_t)(out[2] * 255.0f); } diff --git a/libsrc/utils/HsvTransform.cpp b/libsrc/utils/HsvTransform.cpp index 14554fa9..8ff2ae7b 100644 --- a/libsrc/utils/HsvTransform.cpp +++ b/libsrc/utils/HsvTransform.cpp @@ -1,9 +1,9 @@ #include #include -HsvTransform::HsvTransform() : - _saturationGain(1.0), - _valueGain(1.0) +HsvTransform::HsvTransform() + : _saturationGain(1.0) + , _valueGain(1.0) { } diff --git a/src/hyperion-v4l2/ScreenshotHandler.cpp b/src/hyperion-v4l2/ScreenshotHandler.cpp index e006fca9..d12f9479 100644 --- a/src/hyperion-v4l2/ScreenshotHandler.cpp +++ b/src/hyperion-v4l2/ScreenshotHandler.cpp @@ -1,6 +1,8 @@ // Qt includes #include #include +#include +#include // hyperion-v4l2 includes #include "ScreenshotHandler.h" @@ -17,41 +19,7 @@ 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; - + findNoSignalSettings(image); // store as PNG QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888); pngImage.save(_filename); @@ -59,3 +27,220 @@ void ScreenshotHandler::receiveImage(const Image & image) // Quit the application after the first image QCoreApplication::quit(); } + +bool ScreenshotHandler::findNoSignalSettings(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(); + + unsigned xOffset = image.width() * x_frac_min; + unsigned yOffset = image.height() * y_frac_min; + unsigned xMax = image.width() * x_frac_max; + unsigned yMax = image.height() * y_frac_max; + + ColorRgb noSignalThresholdColor = {0,0,0}; + + unsigned yMid = (yMax+yOffset) / 2; + ColorRgb redThresoldColor = {255,75,75}; + ColorRgb greenThresoldColor = {75,255,75}; + ColorRgb blueThresoldColor = {75,75,255}; + + QVector redOffsets; + QVector redCounts; + QVector greenOffsets; + QVector greenCounts; + QVector blueOffsets; + QVector blueCounts; + + unsigned currentColor = 255; + for (unsigned x = xOffset; x < xMax; ++x) + { + ColorRgb rgb = image(x, yMid); + if (rgb <= redThresoldColor) + { + if ( currentColor != 0) + { + redOffsets.append(x); + redCounts.append(1); + } + else + { + redCounts[redCounts.size()-1]++; + } + currentColor = 0; + } + if (rgb <= greenThresoldColor){ + if ( currentColor != 1) + { + greenOffsets.append(x); + greenCounts.append(1); + } + else + { + greenCounts[greenCounts.size()-1]++; + } + currentColor = 1; + } + if (rgb <= blueThresoldColor) + { + if ( currentColor != 2) + { + blueOffsets.append(x); + blueCounts.append(1); + } + else + { + blueCounts[blueCounts.size()-1]++; + } + currentColor = 2; + } + } + + auto itR = std::max_element(std::begin(redCounts), std::end(redCounts)); + auto itG = std::max_element(std::begin(greenCounts), std::end(greenCounts)); + auto itB = std::max_element(std::begin(blueCounts), std::end(blueCounts)); + + //std::cout << *itR << " " << *itG << " " << *itB << std::endl; + double xOffsetSuggested = xOffset; + double yOffsetSuggested = yOffset; + double xMaxSuggested = xMax; + double yMaxSuggested = yMax; + bool noSignalBlack = false; + + noSignalThresholdColor = {0,0,0}; + if (*itR >= *itG && *itR >= *itB && *itR > 1) + { + xOffsetSuggested = redOffsets[redCounts.indexOf(*itR)]; + xMaxSuggested = xOffsetSuggested + *itR; + noSignalThresholdColor = redThresoldColor; + } + else if (*itG >= *itR && *itG >= *itB && *itG > 1 ) + { + xOffsetSuggested = greenOffsets[greenCounts.indexOf(*itG)]; + xMaxSuggested = xOffsetSuggested + *itG; + noSignalThresholdColor = greenThresoldColor; + } + else if ( *itB > 1 ) + { + xOffsetSuggested = blueOffsets[blueCounts.indexOf(*itB)]; + xMaxSuggested = xOffsetSuggested + *itB; + noSignalThresholdColor = blueThresoldColor; + } + else + { + noSignalThresholdColor = {75,75,75}; + noSignalBlack = true; + } + + // serach vertical max + if (!noSignalBlack) + { + unsigned xMid = (xMaxSuggested + xOffsetSuggested) / 2; + for (unsigned y = yMid; y >= yOffset && yOffsetSuggested != y; --y) + { + ColorRgb rgb = image(xMid, y); + if (rgb <= noSignalThresholdColor) + { + yOffsetSuggested = y; + } + } + + for (unsigned y = yMid; y <= yMax && yMaxSuggested != y; ++y) + { + ColorRgb rgb = image(xMid, y); + if (rgb <= noSignalThresholdColor) + { + yMaxSuggested = y; + } + } + } + + // optimize thresold color + noSignalThresholdColor = {0,0,0}; + for (unsigned x = xOffsetSuggested; x < xMaxSuggested; ++x) + { + for (unsigned y = yOffsetSuggested; y < yMaxSuggested; ++y) + { + ColorRgb rgb = image(x, y); + if (rgb >= noSignalThresholdColor) + { + noSignalThresholdColor = rgb; + } + } + } + + // calculate fractional values + xOffsetSuggested = (int)(((float)xOffsetSuggested/image.width())*100+0.5)/100.0; + xMaxSuggested = (int)(((float)xMaxSuggested/image.width())*100)/100.0; + yOffsetSuggested = (int)(((float)yOffsetSuggested/image.height())*100+0.5)/100.0; + yMaxSuggested = (int)(((float)yMaxSuggested/image.height())*100)/100.0; + double thresholdRed = (int)(((float)noSignalThresholdColor.red/255.0f)*100+0.5)/100.0; + double thresholdGreen = (int)(((float)noSignalThresholdColor.green/255.0f)*100+0.5)/100.0; + double thresholdBlue = (int)(((float)noSignalThresholdColor.blue/255.0f)*100+0.5)/100.0; + thresholdRed = (thresholdRed<0.1f) ?0.1f : thresholdRed; + thresholdGreen = (thresholdGreen<0.1f)?0.1f : thresholdGreen; + thresholdBlue = (thresholdBlue<0.1f) ?0.1f : thresholdBlue; + + std::cout << std::endl << "Signal detection informations" + << std::endl << "=============================" + << std::endl << "dimension after decimation: " << image.width() << " x " << image.height() + << std::endl << "signal detection area : " << xOffset << "," << yOffset << " x " << xMax << "," << yMax << std::endl << std::endl; + + // check if values make sense + if (thresholdRed < 0.5 && thresholdGreen < 0.5 && thresholdBlue < 0.5 && thresholdRed > 0.15 && thresholdGreen > 0.15 && thresholdBlue > 0.15) + { + std::cout << "WARNING \"no signal image\" is to dark, signal detection is not relaiable." << std::endl; + } + + if (thresholdRed > 0.5 && thresholdGreen > 0.5 && thresholdBlue > 0.5) + { + std::cout << "WARNING \"no signal image\" is to bright, signal detection is not relaiable." << std::endl; + } + + if (thresholdRed > thresholdGreen && thresholdRed > thresholdBlue && ((thresholdRed-thresholdGreen) <= 0.5 || (thresholdRed-thresholdBlue) <= 0.5)) + { + std::cout << "WARNING difference between threshold color and the other color components is to small, signal detection might have problems." << std::endl; + } + + if (thresholdGreen > thresholdRed && thresholdGreen > thresholdBlue && ((thresholdGreen-thresholdRed) <= 0.5 || (thresholdGreen-thresholdBlue) <= 0.5)) + { + std::cout << "WARNING difference between threshold color and the other color components is to small, signal detection might have problems." << std::endl; + } + + if (thresholdBlue > thresholdGreen && thresholdBlue > thresholdRed && ((thresholdBlue-thresholdGreen) <= 0.5 || (thresholdBlue-thresholdRed) <= 0.5)) + { + std::cout << "WARNING difference between threshold color and the other color components is to small, signal detection might have problems." << std::endl; + } + + if (noSignalBlack) + { + std::cout << "WARNING no red, green or blue \"no signal area\" detected, signal detection might have problems." << std::endl; + } + + if (xOffsetSuggested >= xMaxSuggested || (xMaxSuggested - xOffsetSuggested) < 0.029 ) + { + std::cout << "WARNING horizontal values of signal detection are invalid or detection area is to small, signal detection is not relaiable." << std::endl; + } + + if (yOffsetSuggested >= yMaxSuggested || (yMaxSuggested - yOffsetSuggested) < 0.029 ) + { + std::cout << "WARNING horizontal values of signal detection are invalid or detection area is to small, signal detection is not relaiable." << std::endl; + } + + std::cout << std::endl + << "suggested config values for signal detection:" << std::endl + << "\t\"redSignalThreshold\" : " << thresholdRed << "," << std::endl + << "\t\"greenSignalThreshold\" : " << thresholdGreen << "," << std::endl + << "\t\"blueSignalThreshold\" : " << thresholdBlue << "," << std::endl + << "\t\"signalDetectionHorizontalOffsetMin\" : " << xOffsetSuggested << "," << std::endl + << "\t\"signalDetectionVerticalOffsetMin\" : " << yOffsetSuggested << "," << std::endl + << "\t\"signalDetectionHorizontalOffsetMax\" : " << xMaxSuggested << "," << std::endl + << "\t\"signalDetectionVerticalOffsetMax\" : " << yMaxSuggested << std::endl; + + return true; +} + + + diff --git a/src/hyperion-v4l2/ScreenshotHandler.h b/src/hyperion-v4l2/ScreenshotHandler.h index 5c447027..9db02756 100644 --- a/src/hyperion-v4l2/ScreenshotHandler.h +++ b/src/hyperion-v4l2/ScreenshotHandler.h @@ -21,6 +21,8 @@ public slots: void receiveImage(const Image & image); private: + bool findNoSignalSettings(const Image & image); + const QString _filename; const QRectF _signalDetectionOffset; }; diff --git a/src/hyperion-v4l2/hyperion-v4l2.cpp b/src/hyperion-v4l2/hyperion-v4l2.cpp index ad8a4d3d..e5d5578f 100644 --- a/src/hyperion-v4l2/hyperion-v4l2.cpp +++ b/src/hyperion-v4l2/hyperion-v4l2.cpp @@ -35,6 +35,8 @@ void saveScreenshot(QString filename, const Image & image) int main(int argc, char** argv) { Logger *log = Logger::getInstance("V4L2GRABBER"); + Logger::setLogLevel(Logger::WARNING); + std::cout << "hyperion-v4l2:" << std::endl << "\tVersion : " << HYPERION_VERSION << " (" << HYPERION_BUILD_ID << ")" << std::endl