mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
v4l: make suggestions for all no signal values (#339)
* on v4l screenshot, print out nosignal threshold values * separate fractional parameters for no signal detection * fully implement handling for "rainbow grabber" * hyperion-v4l2 --screenshot can also evaluate best reagion and color for no signal detection * tune output of no signal detection * v4l outputs warninsg only, todo: make it adyustable * typo * v4l signal detection, now with validation checks * remove obsolete schema files * fix code style * fix text typos * code style
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
// Qt includes
|
||||
#include <QImage>
|
||||
#include <QCoreApplication>
|
||||
#include <QVector>
|
||||
#include <algorithm>
|
||||
|
||||
// hyperion-v4l2 includes
|
||||
#include "ScreenshotHandler.h"
|
||||
@@ -17,41 +19,7 @@ ScreenshotHandler::~ScreenshotHandler()
|
||||
|
||||
void ScreenshotHandler::receiveImage(const Image<ColorRgb> & 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<ColorRgb> & image)
|
||||
// Quit the application after the first image
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
|
||||
bool ScreenshotHandler::findNoSignalSettings(const Image<ColorRgb> & 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<unsigned> redOffsets;
|
||||
QVector<unsigned> redCounts;
|
||||
QVector<unsigned> greenOffsets;
|
||||
QVector<unsigned> greenCounts;
|
||||
QVector<unsigned> blueOffsets;
|
||||
QVector<unsigned> 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@@ -21,6 +21,8 @@ public slots:
|
||||
void receiveImage(const Image<ColorRgb> & image);
|
||||
|
||||
private:
|
||||
bool findNoSignalSettings(const Image<ColorRgb> & image);
|
||||
|
||||
const QString _filename;
|
||||
const QRectF _signalDetectionOffset;
|
||||
};
|
||||
|
@@ -35,6 +35,8 @@ void saveScreenshot(QString filename, const Image<ColorRgb> & 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
|
||||
|
Reference in New Issue
Block a user