// Qt includes #include #include #include #include // hyperion-v4l2 includes #include "ScreenshotHandler.h" ScreenshotHandler::ScreenshotHandler(const QString & filename, const QRectF & signalDetectionOffset) : _filename(filename) , _signalDetectionOffset(signalDetectionOffset) { } ScreenshotHandler::~ScreenshotHandler() { } void ScreenshotHandler::receiveImage(const Image & image) { 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); // 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; }