#include #include #include #include #include #include #include "hyperiongrabber.h" #include "HyperionProcessor.h" #include "LedColorMapping.h" // ANSI escape code to clear the screen const QString ANSI_RESET = "\033[0m"; // Function to get a printable block with a specific background color QString getAnsiColorBlock(const QColor& color) { if (!color.isValid()) { return " "; } // Use 24-bit color ANSI escape codes return QString("\033[48;2;%1;%2;%3m ").arg(color.red()).arg(color.green()).arg(color.blue()); } void printLedColorsAsBoxes(const QVector& ledColors) { QTextStream cout(stdout); for (const QColor& color : ledColors) { cout << getAnsiColorBlock(color); } cout << ANSI_RESET << "\n"; cout.flush(); } static HyperionGrabber *grabber = nullptr; static QApplication *app = nullptr; static HyperionProcessor *processor = nullptr; void quit(int) { if (grabber != nullptr) { delete grabber; } if (processor != nullptr) { delete processor; } if (app != nullptr) { app->quit(); } } class GrabberConfigurator : public QObject { Q_OBJECT public: GrabberConfigurator(const QHash &opts, const LedLayout& layout, const QJsonObject& config, QObject *parent = nullptr) : QObject(parent), _layout(layout) { grabber = new HyperionGrabber(opts); processor = new HyperionProcessor(layout, config); connect(grabber, &HyperionGrabber::imageReady, this, &GrabberConfigurator::processFrame); } public slots: void processFrame(const QImage &image) { qDebug() << "GrabberConfigurator::processFrame called."; if (image.isNull()) return; // Process the image with HyperionProcessor QVector ledColors = processor->process(image); // Debugging: Print some sample LED colors if (!ledColors.isEmpty()) { qDebug() << "Sample LED Colors:"; qDebug() << " LED 0:" << ledColors.at(0).name(); if (ledColors.size() > 1) qDebug() << " LED 1:" << ledColors.at(1).name(); if (ledColors.size() > _layout.bottom) qDebug() << " LED (bottom+1):" << ledColors.at(_layout.bottom).name(); if (ledColors.size() > _layout.bottom + _layout.right) qDebug() << " LED (bottom+right+1):" << ledColors.at(_layout.bottom + _layout.right).name(); } // Get the processed image dimensions and border info QSize processedImageSize = processor->getLastImageSize(); BlackBorder border = processor->getLastBorder(); // Calculate the content rectangle int xOffset = border.verticalSize; int yOffset = border.horizontalSize; int contentWidth = processedImageSize.width() - (2 * border.verticalSize); int contentHeight = processedImageSize.height() - (2 * border.horizontalSize); if (contentWidth > 0 && contentHeight > 0) { // QImage croppedImage = image.copy(xOffset, yOffset, contentWidth, contentHeight); // Debugging: Print ledMap details const QVector>& ledMap = processor->getLedMap(); qDebug() << "ledMap size:" << ledMap.size(); for (int i = 0; i < ledColors.size(); ++i) { const QColor& color = ledColors.at(i); const QVector& pixels = ledMap.at(i); qDebug() << " LED" << i << "pixels size:" << pixels.size(); // Debugging: Print rectangle dimensions (if needed, can be re-enabled) // int minX = image.width(); int minY = image.height(); int maxX = 0; int maxY = 0; // for (const QPoint& p : pixels) { minX = qMin(minX, p.x()); minY = qMin(minY, p.y()); maxX = qMax(maxX, p.x()); maxY = qMax(maxY, p.y()); } // int rectMinX = minX - xOffset; int rectMinY = minY - yOffset; // int rectWidth = qMax(1, maxX - minX + 1); int rectHeight = qMax(1, maxY - minY + 1); // qDebug() << "LED" << i << ": Rect(" << rectMinX << "," << rectMinY << "," << rectWidth << "," << rectHeight << ") Color:" << color.name(); } // Print LED colors as a line of boxes in the terminal printLedColorsAsBoxes(ledColors); } else { qDebug() << "No content to process after black border removal."; } } private: LedLayout _layout; // Still needed for HyperionProcessor constructor }; int main(int argc, char *argv[]) { app = new QApplication(argc, argv); signal(SIGINT, quit); signal(SIGTERM, quit); QApplication::setApplicationName("GrabberConfigurator"); QApplication::setApplicationVersion("0.2"); QCommandLineParser parser; parser.setApplicationDescription("A tool to test the Hyperion processing pipeline."); parser.addHelpOption(); parser.addVersionOption(); // Add options for HyperionGrabber (scale, frameskip, etc.) parser.addOption(QCommandLineOption(QStringList() << "s" << "scale", "Divisor used to scale your screen resolution (e.g., 8).", "scale", "8")); parser.addOption(QCommandLineOption(QStringList() << "f" << "frameskip", "Number of frames to skip between captures (e.g., 1).", "frameskip", "0")); // Add options for the LED layout parser.addOption(QCommandLineOption(QStringList() << "leds-bottom", "Number of LEDs on the bottom edge.", "count", "70")); parser.addOption(QCommandLineOption(QStringList() << "leds-right", "Number of LEDs on the right edge.", "count", "20")); parser.addOption(QCommandLineOption(QStringList() << "leds-top", "Number of LEDs on the top edge.", "count", "70")); parser.addOption(QCommandLineOption(QStringList() << "leds-left", "Number of LEDs on the left edge.", "count", "20")); // Add options for the processor parser.addOption(QCommandLineOption(QStringList() << "bbt", "Black border threshold (0.0 to 1.0).", "threshold", "0.1")); parser.process(*app); QHash grabberOpts; grabberOpts.insert("scale", parser.value("scale")); grabberOpts.insert("frameskip", parser.value("frameskip")); LedLayout layout; layout.bottom = parser.value("leds-bottom").toInt(); layout.right = parser.value("leds-right").toInt(); layout.top = parser.value("leds-top").toInt(); layout.left = parser.value("leds-left").toInt(); QJsonObject processorConfig; processorConfig["blackBorderThreshold"] = parser.value("bbt").toDouble(); // No QLabel or QWidget needed for this visualization // QWidget window; // QLabel label; // label.setParent(&window); // label.setScaledContents(true); // window.show(); GrabberConfigurator configurator(grabberOpts, layout, processorConfig); qInfo() << "Starting GrabberConfigurator. A line of colored boxes should appear in the terminal. Press Ctrl+C to exit."; return app->exec(); } #include "grabberconfigurator.moc"