feat: Refactor main application to use HyperionProcessor and WledClient with environment variable configuration

This commit is contained in:
Tobias J. Endres 2025-08-16 05:40:47 +02:00
parent d81fe64cc1
commit c46fade6b0
20 changed files with 799 additions and 165 deletions

View File

@ -1,11 +1,5 @@
set(__QT_DEPLOY_TARGET_Hyperion_Grabber_Wayland_QT_FILE /home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/Hyperion_Grabber_Wayland_QT)
set(__QT_DEPLOY_TARGET_Hyperion_Grabber_Wayland_QT_TYPE EXECUTABLE)
set(__QT_DEPLOY_TARGET_wled_config_tool_FILE /home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/wled_config_tool)
set(__QT_DEPLOY_TARGET_wled_config_tool_TYPE EXECUTABLE)
set(__QT_DEPLOY_TARGET_grabberconfigurator_FILE /home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/grabberconfigurator)
set(__QT_DEPLOY_TARGET_grabberconfigurator_TYPE EXECUTABLE)
set(__QT_DEPLOY_TARGET_test_hyperion_processor_FILE /home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/test_hyperion_processor)
set(__QT_DEPLOY_TARGET_test_hyperion_processor_TYPE EXECUTABLE)
set(__QT_DEPLOY_TARGET_hyperion-mock_FILE /home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/hyperion-mock)
set(__QT_DEPLOY_TARGET_hyperion-mock_TYPE EXECUTABLE)
set(__QT_DEPLOY_TARGET_screen_capture_test_FILE /home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/screen_capture_test)

View File

@ -27,6 +27,7 @@ add_executable(Hyperion_Grabber_Wayland_QT
LedColorMapping.cpp
BlackBorderDetector.cpp
HyperionProcessor.cpp
LinearColorSmoothing.cpp
)
target_link_libraries(Hyperion_Grabber_Wayland_QT
@ -41,67 +42,6 @@ target_link_libraries(Hyperion_Grabber_Wayland_QT
${PIPEWIRE_LIBRARIES}
)
add_executable(wled_config_tool
wled_config_tool.cpp
wledconfigclient.cpp
wledclient.cpp
)
target_link_libraries(wled_config_tool
Qt6::Core
Qt6::Network
Qt6::Gui
)
target_compile_definitions(wled_config_tool PRIVATE WLED_CONFIG_TOOL_BUILD)
add_executable(grabberconfigurator
grabberconfigurator.cpp
hyperiongrabber.cpp
wledclient.cpp
debugclient.cpp
WaylandGrabber.cpp
wledconfigclient.cpp
LedColorMapping.cpp
BlackBorderDetector.cpp
HyperionProcessor.cpp
)
target_link_libraries(grabberconfigurator
Qt6::Core
Qt6::Gui
Qt6::WaylandClient
Qt6::Multimedia
Qt6::Widgets
Qt6::MultimediaWidgets
Qt6::Network
Qt6::OpenGL
${PIPEWIRE_LIBRARIES}
)
add_executable(test_hyperion_processor
test_hyperion_processor.cpp
hyperiongrabber.cpp
wledclient.cpp
debugclient.cpp
WaylandGrabber.cpp
wledconfigclient.cpp
LedColorMapping.cpp
BlackBorderDetector.cpp
HyperionProcessor.cpp
)
target_link_libraries(test_hyperion_processor
Qt6::Core
Qt6::Gui
Qt6::WaylandClient
Qt6::Multimedia
Qt6::Widgets
Qt6::MultimediaWidgets
Qt6::Network
Qt6::OpenGL
${PIPEWIRE_LIBRARIES}
)
add_executable(hyperion-mock
hyperion-mock.cpp
)

View File

@ -1,12 +1,14 @@
#include "HyperionProcessor.h"
#include <QDebug>
#include <QtMath>
HyperionProcessor::HyperionProcessor(const LedLayout &layout, const QJsonObject &config, QObject *parent)
: QObject(parent),
_layout(layout),
_config(config),
_borderDetector(config.value("blackBorderThreshold").toDouble(0.1)),
_lastImageSize(0, 0)
_lastImageSize(0, 0),
_colorSmoother(config.value("smoothingFactor").toDouble(0.1)) // Initialize color smoother
{
}
@ -34,7 +36,10 @@ QVector<QColor> HyperionProcessor::process(const QImage &image)
}
// 3. Calculate the colors
return calculateLedColors(image);
QVector<QColor> calculatedColors = calculateLedColors(image);
// 4. Apply smoothing
return _colorSmoother.smooth(calculatedColors);
}
void HyperionProcessor::buildLedMap(int imageWidth, int imageHeight, const BlackBorder &border)
@ -147,7 +152,8 @@ QVector<QColor> HyperionProcessor::calculateLedColors(const QImage &image)
ledColors.reserve(_ledMap.size());
for (const auto &pixelList : _ledMap) {
ledColors.append(getAverageColor(image, pixelList));
// Use getMeanSqrtLedColor for more vibrant colors
ledColors.append(getMeanSqrtLedColor(image, pixelList));
}
return ledColors;
@ -169,3 +175,22 @@ QColor HyperionProcessor::getAverageColor(const QImage &image, const QVector<QPo
return QColor(r / pixels.size(), g / pixels.size(), b / pixels.size());
}
QColor HyperionProcessor::getMeanSqrtLedColor(const QImage &image, const QVector<QPoint> &pixels) const
{
if (pixels.isEmpty()) {
return Qt::black;
}
quint64 r_sq = 0, g_sq = 0, b_sq = 0;
for (const QPoint &pt : pixels) {
QColor color = image.pixelColor(pt);
r_sq += color.red() * color.red();
g_sq += color.green() * color.green();
b_sq += color.blue() * color.blue();
}
return QColor(static_cast<int>(qSqrt(static_cast<double>(r_sq / pixels.size()))),
static_cast<int>(qSqrt(static_cast<double>(g_sq / pixels.size()))),
static_cast<int>(qSqrt(static_cast<double>(b_sq / pixels.size()))));
}

View File

@ -8,6 +8,7 @@
#include <QJsonObject>
#include "LedColorMapping.h" // We can reuse the LedLayout struct
#include "BlackBorderDetector.h"
#include "LinearColorSmoothing.h"
class HyperionProcessor : public QObject
{
@ -22,6 +23,7 @@ private:
void buildLedMap(int imageWidth, int imageHeight, const BlackBorder &border);
QVector<QColor> calculateLedColors(const QImage &image);
QColor getAverageColor(const QImage &image, const QVector<QPoint> &pixels) const;
QColor getMeanSqrtLedColor(const QImage &image, const QVector<QPoint> &pixels) const;
LedLayout _layout;
QJsonObject _config;
@ -32,6 +34,8 @@ private:
QVector<QVector<QPoint>> _ledMap;
LinearColorSmoothing _colorSmoother;
public:
QSize getLastImageSize() const { return _lastImageSize; }
BlackBorder getLastBorder() const { return _lastBorder; }

Binary file not shown.

View File

@ -0,0 +1,90 @@
/****************************************************************************
** Meta object code from reading C++ file 'HyperionProcessor.h'
**
** Created by: The Qt Meta Object Compiler version 69 (Qt 6.9.1)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#include "../../HyperionProcessor.h"
#include <QtCore/qmetatype.h>
#include <QtCore/qtmochelpers.h>
#include <memory>
#include <QtCore/qxptype_traits.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'HyperionProcessor.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 69
#error "This file was generated using the moc from 6.9.1. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif
#ifndef Q_CONSTINIT
#define Q_CONSTINIT
#endif
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
QT_WARNING_DISABLE_GCC("-Wuseless-cast")
namespace {
struct qt_meta_tag_ZN17HyperionProcessorE_t {};
} // unnamed namespace
template <> constexpr inline auto HyperionProcessor::qt_create_metaobjectdata<qt_meta_tag_ZN17HyperionProcessorE_t>()
{
namespace QMC = QtMocConstants;
QtMocHelpers::StringRefStorage qt_stringData {
"HyperionProcessor"
};
QtMocHelpers::UintData qt_methods {
};
QtMocHelpers::UintData qt_properties {
};
QtMocHelpers::UintData qt_enums {
};
return QtMocHelpers::metaObjectData<HyperionProcessor, qt_meta_tag_ZN17HyperionProcessorE_t>(QMC::MetaObjectFlag{}, qt_stringData,
qt_methods, qt_properties, qt_enums);
}
Q_CONSTINIT const QMetaObject HyperionProcessor::staticMetaObject = { {
QMetaObject::SuperData::link<QObject::staticMetaObject>(),
qt_staticMetaObjectStaticContent<qt_meta_tag_ZN17HyperionProcessorE_t>.stringdata,
qt_staticMetaObjectStaticContent<qt_meta_tag_ZN17HyperionProcessorE_t>.data,
qt_static_metacall,
nullptr,
qt_staticMetaObjectRelocatingContent<qt_meta_tag_ZN17HyperionProcessorE_t>.metaTypes,
nullptr
} };
void HyperionProcessor::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
auto *_t = static_cast<HyperionProcessor *>(_o);
(void)_t;
(void)_c;
(void)_id;
(void)_a;
}
const QMetaObject *HyperionProcessor::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
void *HyperionProcessor::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_staticMetaObjectStaticContent<qt_meta_tag_ZN17HyperionProcessorE_t>.strings))
return static_cast<void*>(this);
return QObject::qt_metacast(_clname);
}
int HyperionProcessor::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
return _id;
}
QT_WARNING_POP

View File

@ -0,0 +1,435 @@
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/Hyperion_Grabber_Wayland_QT_autogen/EWIEGA46WW/moc_HyperionProcessor.cpp: /home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/HyperionProcessor.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/Hyperion_Grabber_Wayland_QT_autogen/moc_predefs.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/BlackBorderDetector.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LedColorMapping.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LinearColorSmoothing.h \
/usr/include/alloca.h \
/usr/include/asm-generic/bitsperlong.h \
/usr/include/asm-generic/errno-base.h \
/usr/include/asm-generic/errno.h \
/usr/include/asm-generic/int-ll64.h \
/usr/include/asm-generic/posix_types.h \
/usr/include/asm-generic/types.h \
/usr/include/asm/bitsperlong.h \
/usr/include/asm/errno.h \
/usr/include/asm/posix_types.h \
/usr/include/asm/posix_types_64.h \
/usr/include/asm/types.h \
/usr/include/assert.h \
/usr/include/bits/atomic_wide_counter.h \
/usr/include/bits/byteswap.h \
/usr/include/bits/cpu-set.h \
/usr/include/bits/endian.h \
/usr/include/bits/endianness.h \
/usr/include/bits/errno.h \
/usr/include/bits/floatn-common.h \
/usr/include/bits/floatn.h \
/usr/include/bits/libc-header-start.h \
/usr/include/bits/local_lim.h \
/usr/include/bits/locale.h \
/usr/include/bits/long-double.h \
/usr/include/bits/posix1_lim.h \
/usr/include/bits/posix2_lim.h \
/usr/include/bits/pthread_stack_min-dynamic.h \
/usr/include/bits/pthreadtypes-arch.h \
/usr/include/bits/pthreadtypes.h \
/usr/include/bits/sched.h \
/usr/include/bits/select.h \
/usr/include/bits/setjmp.h \
/usr/include/bits/stdint-intn.h \
/usr/include/bits/stdio_lim.h \
/usr/include/bits/stdlib-float.h \
/usr/include/bits/struct_mutex.h \
/usr/include/bits/struct_rwlock.h \
/usr/include/bits/thread-shared-types.h \
/usr/include/bits/time.h \
/usr/include/bits/time64.h \
/usr/include/bits/timesize.h \
/usr/include/bits/timex.h \
/usr/include/bits/types.h \
/usr/include/bits/types/FILE.h \
/usr/include/bits/types/__FILE.h \
/usr/include/bits/types/__fpos64_t.h \
/usr/include/bits/types/__fpos_t.h \
/usr/include/bits/types/__locale_t.h \
/usr/include/bits/types/__mbstate_t.h \
/usr/include/bits/types/__sigset_t.h \
/usr/include/bits/types/clock_t.h \
/usr/include/bits/types/clockid_t.h \
/usr/include/bits/types/cookie_io_functions_t.h \
/usr/include/bits/types/error_t.h \
/usr/include/bits/types/locale_t.h \
/usr/include/bits/types/mbstate_t.h \
/usr/include/bits/types/sigset_t.h \
/usr/include/bits/types/struct_FILE.h \
/usr/include/bits/types/struct___jmp_buf_tag.h \
/usr/include/bits/types/struct_itimerspec.h \
/usr/include/bits/types/struct_sched_param.h \
/usr/include/bits/types/struct_timespec.h \
/usr/include/bits/types/struct_timeval.h \
/usr/include/bits/types/struct_tm.h \
/usr/include/bits/types/time_t.h \
/usr/include/bits/types/timer_t.h \
/usr/include/bits/types/wint_t.h \
/usr/include/bits/typesizes.h \
/usr/include/bits/uintn-identity.h \
/usr/include/bits/uio_lim.h \
/usr/include/bits/waitflags.h \
/usr/include/bits/waitstatus.h \
/usr/include/bits/wchar.h \
/usr/include/bits/wordsize.h \
/usr/include/bits/xopen_lim.h \
/usr/include/c++/15.2.1/algorithm \
/usr/include/c++/15.2.1/array \
/usr/include/c++/15.2.1/atomic \
/usr/include/c++/15.2.1/backward/auto_ptr.h \
/usr/include/c++/15.2.1/backward/binders.h \
/usr/include/c++/15.2.1/bit \
/usr/include/c++/15.2.1/bits/algorithmfwd.h \
/usr/include/c++/15.2.1/bits/align.h \
/usr/include/c++/15.2.1/bits/alloc_traits.h \
/usr/include/c++/15.2.1/bits/allocated_ptr.h \
/usr/include/c++/15.2.1/bits/allocator.h \
/usr/include/c++/15.2.1/bits/atomic_base.h \
/usr/include/c++/15.2.1/bits/atomic_lockfree_defines.h \
/usr/include/c++/15.2.1/bits/basic_string.h \
/usr/include/c++/15.2.1/bits/basic_string.tcc \
/usr/include/c++/15.2.1/bits/char_traits.h \
/usr/include/c++/15.2.1/bits/charconv.h \
/usr/include/c++/15.2.1/bits/chrono.h \
/usr/include/c++/15.2.1/bits/concept_check.h \
/usr/include/c++/15.2.1/bits/cpp_type_traits.h \
/usr/include/c++/15.2.1/bits/cxxabi_forced.h \
/usr/include/c++/15.2.1/bits/cxxabi_init_exception.h \
/usr/include/c++/15.2.1/bits/enable_special_members.h \
/usr/include/c++/15.2.1/bits/erase_if.h \
/usr/include/c++/15.2.1/bits/exception.h \
/usr/include/c++/15.2.1/bits/exception_defines.h \
/usr/include/c++/15.2.1/bits/exception_ptr.h \
/usr/include/c++/15.2.1/bits/functexcept.h \
/usr/include/c++/15.2.1/bits/functional_hash.h \
/usr/include/c++/15.2.1/bits/hash_bytes.h \
/usr/include/c++/15.2.1/bits/hashtable.h \
/usr/include/c++/15.2.1/bits/hashtable_policy.h \
/usr/include/c++/15.2.1/bits/invoke.h \
/usr/include/c++/15.2.1/bits/ios_base.h \
/usr/include/c++/15.2.1/bits/list.tcc \
/usr/include/c++/15.2.1/bits/locale_classes.h \
/usr/include/c++/15.2.1/bits/locale_classes.tcc \
/usr/include/c++/15.2.1/bits/localefwd.h \
/usr/include/c++/15.2.1/bits/memory_resource.h \
/usr/include/c++/15.2.1/bits/memoryfwd.h \
/usr/include/c++/15.2.1/bits/move.h \
/usr/include/c++/15.2.1/bits/nested_exception.h \
/usr/include/c++/15.2.1/bits/new_allocator.h \
/usr/include/c++/15.2.1/bits/node_handle.h \
/usr/include/c++/15.2.1/bits/ostream_insert.h \
/usr/include/c++/15.2.1/bits/parse_numbers.h \
/usr/include/c++/15.2.1/bits/postypes.h \
/usr/include/c++/15.2.1/bits/predefined_ops.h \
/usr/include/c++/15.2.1/bits/ptr_traits.h \
/usr/include/c++/15.2.1/bits/range_access.h \
/usr/include/c++/15.2.1/bits/refwrap.h \
/usr/include/c++/15.2.1/bits/requires_hosted.h \
/usr/include/c++/15.2.1/bits/shared_ptr.h \
/usr/include/c++/15.2.1/bits/shared_ptr_atomic.h \
/usr/include/c++/15.2.1/bits/shared_ptr_base.h \
/usr/include/c++/15.2.1/bits/specfun.h \
/usr/include/c++/15.2.1/bits/std_abs.h \
/usr/include/c++/15.2.1/bits/std_function.h \
/usr/include/c++/15.2.1/bits/stl_algo.h \
/usr/include/c++/15.2.1/bits/stl_algobase.h \
/usr/include/c++/15.2.1/bits/stl_bvector.h \
/usr/include/c++/15.2.1/bits/stl_construct.h \
/usr/include/c++/15.2.1/bits/stl_function.h \
/usr/include/c++/15.2.1/bits/stl_heap.h \
/usr/include/c++/15.2.1/bits/stl_iterator.h \
/usr/include/c++/15.2.1/bits/stl_iterator_base_funcs.h \
/usr/include/c++/15.2.1/bits/stl_iterator_base_types.h \
/usr/include/c++/15.2.1/bits/stl_list.h \
/usr/include/c++/15.2.1/bits/stl_map.h \
/usr/include/c++/15.2.1/bits/stl_multimap.h \
/usr/include/c++/15.2.1/bits/stl_multiset.h \
/usr/include/c++/15.2.1/bits/stl_numeric.h \
/usr/include/c++/15.2.1/bits/stl_pair.h \
/usr/include/c++/15.2.1/bits/stl_raw_storage_iter.h \
/usr/include/c++/15.2.1/bits/stl_relops.h \
/usr/include/c++/15.2.1/bits/stl_set.h \
/usr/include/c++/15.2.1/bits/stl_tempbuf.h \
/usr/include/c++/15.2.1/bits/stl_tree.h \
/usr/include/c++/15.2.1/bits/stl_uninitialized.h \
/usr/include/c++/15.2.1/bits/stl_vector.h \
/usr/include/c++/15.2.1/bits/stream_iterator.h \
/usr/include/c++/15.2.1/bits/streambuf.tcc \
/usr/include/c++/15.2.1/bits/streambuf_iterator.h \
/usr/include/c++/15.2.1/bits/string_view.tcc \
/usr/include/c++/15.2.1/bits/stringfwd.h \
/usr/include/c++/15.2.1/bits/uniform_int_dist.h \
/usr/include/c++/15.2.1/bits/unique_ptr.h \
/usr/include/c++/15.2.1/bits/unordered_map.h \
/usr/include/c++/15.2.1/bits/unordered_set.h \
/usr/include/c++/15.2.1/bits/uses_allocator.h \
/usr/include/c++/15.2.1/bits/uses_allocator_args.h \
/usr/include/c++/15.2.1/bits/utility.h \
/usr/include/c++/15.2.1/bits/vector.tcc \
/usr/include/c++/15.2.1/bits/version.h \
/usr/include/c++/15.2.1/cassert \
/usr/include/c++/15.2.1/cctype \
/usr/include/c++/15.2.1/cerrno \
/usr/include/c++/15.2.1/chrono \
/usr/include/c++/15.2.1/climits \
/usr/include/c++/15.2.1/clocale \
/usr/include/c++/15.2.1/cmath \
/usr/include/c++/15.2.1/compare \
/usr/include/c++/15.2.1/concepts \
/usr/include/c++/15.2.1/cstddef \
/usr/include/c++/15.2.1/cstdint \
/usr/include/c++/15.2.1/cstdio \
/usr/include/c++/15.2.1/cstdlib \
/usr/include/c++/15.2.1/cstring \
/usr/include/c++/15.2.1/ctime \
/usr/include/c++/15.2.1/cwchar \
/usr/include/c++/15.2.1/debug/assertions.h \
/usr/include/c++/15.2.1/debug/debug.h \
/usr/include/c++/15.2.1/exception \
/usr/include/c++/15.2.1/ext/aligned_buffer.h \
/usr/include/c++/15.2.1/ext/alloc_traits.h \
/usr/include/c++/15.2.1/ext/atomicity.h \
/usr/include/c++/15.2.1/ext/concurrence.h \
/usr/include/c++/15.2.1/ext/numeric_traits.h \
/usr/include/c++/15.2.1/ext/string_conversions.h \
/usr/include/c++/15.2.1/ext/type_traits.h \
/usr/include/c++/15.2.1/functional \
/usr/include/c++/15.2.1/initializer_list \
/usr/include/c++/15.2.1/iosfwd \
/usr/include/c++/15.2.1/iterator \
/usr/include/c++/15.2.1/limits \
/usr/include/c++/15.2.1/list \
/usr/include/c++/15.2.1/map \
/usr/include/c++/15.2.1/memory \
/usr/include/c++/15.2.1/new \
/usr/include/c++/15.2.1/numeric \
/usr/include/c++/15.2.1/optional \
/usr/include/c++/15.2.1/pstl/execution_defs.h \
/usr/include/c++/15.2.1/pstl/glue_numeric_defs.h \
/usr/include/c++/15.2.1/ratio \
/usr/include/c++/15.2.1/set \
/usr/include/c++/15.2.1/stdexcept \
/usr/include/c++/15.2.1/streambuf \
/usr/include/c++/15.2.1/string \
/usr/include/c++/15.2.1/string_view \
/usr/include/c++/15.2.1/system_error \
/usr/include/c++/15.2.1/tr1/bessel_function.tcc \
/usr/include/c++/15.2.1/tr1/beta_function.tcc \
/usr/include/c++/15.2.1/tr1/ell_integral.tcc \
/usr/include/c++/15.2.1/tr1/exp_integral.tcc \
/usr/include/c++/15.2.1/tr1/gamma.tcc \
/usr/include/c++/15.2.1/tr1/hypergeometric.tcc \
/usr/include/c++/15.2.1/tr1/legendre_function.tcc \
/usr/include/c++/15.2.1/tr1/modified_bessel_func.tcc \
/usr/include/c++/15.2.1/tr1/poly_hermite.tcc \
/usr/include/c++/15.2.1/tr1/poly_laguerre.tcc \
/usr/include/c++/15.2.1/tr1/riemann_zeta.tcc \
/usr/include/c++/15.2.1/tr1/special_function_util.h \
/usr/include/c++/15.2.1/tuple \
/usr/include/c++/15.2.1/type_traits \
/usr/include/c++/15.2.1/typeinfo \
/usr/include/c++/15.2.1/unordered_map \
/usr/include/c++/15.2.1/unordered_set \
/usr/include/c++/15.2.1/utility \
/usr/include/c++/15.2.1/variant \
/usr/include/c++/15.2.1/vector \
/usr/include/c++/15.2.1/x86_64-pc-linux-gnu/bits/atomic_word.h \
/usr/include/c++/15.2.1/x86_64-pc-linux-gnu/bits/c++allocator.h \
/usr/include/c++/15.2.1/x86_64-pc-linux-gnu/bits/c++config.h \
/usr/include/c++/15.2.1/x86_64-pc-linux-gnu/bits/c++locale.h \
/usr/include/c++/15.2.1/x86_64-pc-linux-gnu/bits/cpu_defines.h \
/usr/include/c++/15.2.1/x86_64-pc-linux-gnu/bits/error_constants.h \
/usr/include/c++/15.2.1/x86_64-pc-linux-gnu/bits/gthr-default.h \
/usr/include/c++/15.2.1/x86_64-pc-linux-gnu/bits/gthr.h \
/usr/include/c++/15.2.1/x86_64-pc-linux-gnu/bits/os_defines.h \
/usr/include/ctype.h \
/usr/include/endian.h \
/usr/include/errno.h \
/usr/include/features-time64.h \
/usr/include/features.h \
/usr/include/gnu/stubs-64.h \
/usr/include/gnu/stubs.h \
/usr/include/limits.h \
/usr/include/linux/errno.h \
/usr/include/linux/limits.h \
/usr/include/linux/posix_types.h \
/usr/include/linux/stddef.h \
/usr/include/linux/types.h \
/usr/include/locale.h \
/usr/include/pthread.h \
/usr/include/qt6/QtCore/QJsonObject \
/usr/include/qt6/QtCore/QObject \
/usr/include/qt6/QtCore/QVector \
/usr/include/qt6/QtCore/q17memory.h \
/usr/include/qt6/QtCore/q20functional.h \
/usr/include/qt6/QtCore/q20iterator.h \
/usr/include/qt6/QtCore/q20memory.h \
/usr/include/qt6/QtCore/q20type_traits.h \
/usr/include/qt6/QtCore/q20utility.h \
/usr/include/qt6/QtCore/q23utility.h \
/usr/include/qt6/QtCore/qalgorithms.h \
/usr/include/qt6/QtCore/qanystringview.h \
/usr/include/qt6/QtCore/qarraydata.h \
/usr/include/qt6/QtCore/qarraydataops.h \
/usr/include/qt6/QtCore/qarraydatapointer.h \
/usr/include/qt6/QtCore/qassert.h \
/usr/include/qt6/QtCore/qatomic.h \
/usr/include/qt6/QtCore/qatomic_cxx11.h \
/usr/include/qt6/QtCore/qbasicatomic.h \
/usr/include/qt6/QtCore/qbindingstorage.h \
/usr/include/qt6/QtCore/qbytearray.h \
/usr/include/qt6/QtCore/qbytearrayalgorithms.h \
/usr/include/qt6/QtCore/qbytearraylist.h \
/usr/include/qt6/QtCore/qbytearrayview.h \
/usr/include/qt6/QtCore/qcalendar.h \
/usr/include/qt6/QtCore/qcborcommon.h \
/usr/include/qt6/QtCore/qcborvalue.h \
/usr/include/qt6/QtCore/qchar.h \
/usr/include/qt6/QtCore/qcompare.h \
/usr/include/qt6/QtCore/qcompare_impl.h \
/usr/include/qt6/QtCore/qcomparehelpers.h \
/usr/include/qt6/QtCore/qcompilerdetection.h \
/usr/include/qt6/QtCore/qconfig.h \
/usr/include/qt6/QtCore/qconstructormacros.h \
/usr/include/qt6/QtCore/qcontainerfwd.h \
/usr/include/qt6/QtCore/qcontainerinfo.h \
/usr/include/qt6/QtCore/qcontainertools_impl.h \
/usr/include/qt6/QtCore/qcontiguouscache.h \
/usr/include/qt6/QtCore/qdarwinhelpers.h \
/usr/include/qt6/QtCore/qdatastream.h \
/usr/include/qt6/QtCore/qdatetime.h \
/usr/include/qt6/QtCore/qdebug.h \
/usr/include/qt6/QtCore/qendian.h \
/usr/include/qt6/QtCore/qexceptionhandling.h \
/usr/include/qt6/QtCore/qflags.h \
/usr/include/qt6/QtCore/qfloat16.h \
/usr/include/qt6/QtCore/qforeach.h \
/usr/include/qt6/QtCore/qfunctionaltools_impl.h \
/usr/include/qt6/QtCore/qfunctionpointer.h \
/usr/include/qt6/QtCore/qgenericatomic.h \
/usr/include/qt6/QtCore/qglobal.h \
/usr/include/qt6/QtCore/qglobalstatic.h \
/usr/include/qt6/QtCore/qhash.h \
/usr/include/qt6/QtCore/qhashfunctions.h \
/usr/include/qt6/QtCore/qiodevicebase.h \
/usr/include/qt6/QtCore/qiterable.h \
/usr/include/qt6/QtCore/qiterator.h \
/usr/include/qt6/QtCore/qjsondocument.h \
/usr/include/qt6/QtCore/qjsonobject.h \
/usr/include/qt6/QtCore/qjsonparseerror.h \
/usr/include/qt6/QtCore/qjsonvalue.h \
/usr/include/qt6/QtCore/qlatin1stringview.h \
/usr/include/qt6/QtCore/qline.h \
/usr/include/qt6/QtCore/qlist.h \
/usr/include/qt6/QtCore/qlocale.h \
/usr/include/qt6/QtCore/qlogging.h \
/usr/include/qt6/QtCore/qmalloc.h \
/usr/include/qt6/QtCore/qmap.h \
/usr/include/qt6/QtCore/qmargins.h \
/usr/include/qt6/QtCore/qmath.h \
/usr/include/qt6/QtCore/qmetacontainer.h \
/usr/include/qt6/QtCore/qmetatype.h \
/usr/include/qt6/QtCore/qminmax.h \
/usr/include/qt6/QtCore/qnamespace.h \
/usr/include/qt6/QtCore/qnumeric.h \
/usr/include/qt6/QtCore/qobject.h \
/usr/include/qt6/QtCore/qobject_impl.h \
/usr/include/qt6/QtCore/qobjectdefs.h \
/usr/include/qt6/QtCore/qobjectdefs_impl.h \
/usr/include/qt6/QtCore/qoverload.h \
/usr/include/qt6/QtCore/qpair.h \
/usr/include/qt6/QtCore/qpoint.h \
/usr/include/qt6/QtCore/qprocessordetection.h \
/usr/include/qt6/QtCore/qrect.h \
/usr/include/qt6/QtCore/qrefcount.h \
/usr/include/qt6/QtCore/qregularexpression.h \
/usr/include/qt6/QtCore/qscopedpointer.h \
/usr/include/qt6/QtCore/qscopeguard.h \
/usr/include/qt6/QtCore/qset.h \
/usr/include/qt6/QtCore/qshareddata.h \
/usr/include/qt6/QtCore/qshareddata_impl.h \
/usr/include/qt6/QtCore/qsharedpointer.h \
/usr/include/qt6/QtCore/qsharedpointer_impl.h \
/usr/include/qt6/QtCore/qsize.h \
/usr/include/qt6/QtCore/qspan.h \
/usr/include/qt6/QtCore/qstdlibdetection.h \
/usr/include/qt6/QtCore/qstring.h \
/usr/include/qt6/QtCore/qstringalgorithms.h \
/usr/include/qt6/QtCore/qstringbuilder.h \
/usr/include/qt6/QtCore/qstringconverter.h \
/usr/include/qt6/QtCore/qstringconverter_base.h \
/usr/include/qt6/QtCore/qstringfwd.h \
/usr/include/qt6/QtCore/qstringlist.h \
/usr/include/qt6/QtCore/qstringliteral.h \
/usr/include/qt6/QtCore/qstringmatcher.h \
/usr/include/qt6/QtCore/qstringtokenizer.h \
/usr/include/qt6/QtCore/qstringview.h \
/usr/include/qt6/QtCore/qswap.h \
/usr/include/qt6/QtCore/qsysinfo.h \
/usr/include/qt6/QtCore/qsystemdetection.h \
/usr/include/qt6/QtCore/qtaggedpointer.h \
/usr/include/qt6/QtCore/qtclasshelpermacros.h \
/usr/include/qt6/QtCore/qtconfiginclude.h \
/usr/include/qt6/QtCore/qtconfigmacros.h \
/usr/include/qt6/QtCore/qtcore-config.h \
/usr/include/qt6/QtCore/qtcoreexports.h \
/usr/include/qt6/QtCore/qtcoreglobal.h \
/usr/include/qt6/QtCore/qtdeprecationdefinitions.h \
/usr/include/qt6/QtCore/qtdeprecationmarkers.h \
/usr/include/qt6/QtCore/qtenvironmentvariables.h \
/usr/include/qt6/QtCore/qtextstream.h \
/usr/include/qt6/QtCore/qtformat_impl.h \
/usr/include/qt6/QtCore/qtmetamacros.h \
/usr/include/qt6/QtCore/qtnoop.h \
/usr/include/qt6/QtCore/qtpreprocessorsupport.h \
/usr/include/qt6/QtCore/qtresource.h \
/usr/include/qt6/QtCore/qttranslation.h \
/usr/include/qt6/QtCore/qttypetraits.h \
/usr/include/qt6/QtCore/qtversion.h \
/usr/include/qt6/QtCore/qtversionchecks.h \
/usr/include/qt6/QtCore/qtypeinfo.h \
/usr/include/qt6/QtCore/qtypes.h \
/usr/include/qt6/QtCore/qurl.h \
/usr/include/qt6/QtCore/qutf8stringview.h \
/usr/include/qt6/QtCore/quuid.h \
/usr/include/qt6/QtCore/qvariant.h \
/usr/include/qt6/QtCore/qvarlengtharray.h \
/usr/include/qt6/QtCore/qvector.h \
/usr/include/qt6/QtCore/qversiontagging.h \
/usr/include/qt6/QtCore/qxptype_traits.h \
/usr/include/qt6/QtCore/qyieldcpu.h \
/usr/include/qt6/QtGui/QColor \
/usr/include/qt6/QtGui/QImage \
/usr/include/qt6/QtGui/qcolor.h \
/usr/include/qt6/QtGui/qimage.h \
/usr/include/qt6/QtGui/qpaintdevice.h \
/usr/include/qt6/QtGui/qpixelformat.h \
/usr/include/qt6/QtGui/qpolygon.h \
/usr/include/qt6/QtGui/qregion.h \
/usr/include/qt6/QtGui/qrgb.h \
/usr/include/qt6/QtGui/qrgba64.h \
/usr/include/qt6/QtGui/qtgui-config.h \
/usr/include/qt6/QtGui/qtguiexports.h \
/usr/include/qt6/QtGui/qtguiglobal.h \
/usr/include/qt6/QtGui/qtransform.h \
/usr/include/qt6/QtGui/qwindowdefs.h \
/usr/include/sched.h \
/usr/include/stdc-predef.h \
/usr/include/stdio.h \
/usr/include/stdlib.h \
/usr/include/string.h \
/usr/include/strings.h \
/usr/include/sys/cdefs.h \
/usr/include/sys/select.h \
/usr/include/sys/types.h \
/usr/include/time.h \
/usr/include/wchar.h \
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include/stdarg.h \
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include/stdbool.h \
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include/stddef.h

View File

@ -39,16 +39,22 @@ template <> constexpr inline auto HyperionGrabber::qt_create_metaobjectdata<qt_m
namespace QMC = QtMocConstants;
QtMocHelpers::StringRefStorage qt_stringData {
"HyperionGrabber",
"_processFrame",
"imageReady",
"",
"image",
"_processFrame",
"QVideoFrame",
"frame"
};
QtMocHelpers::UintData qt_methods {
// Signal 'imageReady'
QtMocHelpers::SignalData<void(const QImage &)>(1, 2, QMC::AccessPublic, QMetaType::Void, {{
{ QMetaType::QImage, 3 },
}}),
// Slot '_processFrame'
QtMocHelpers::SlotData<void(const QVideoFrame &)>(1, 2, QMC::AccessPrivate, QMetaType::Void, {{
{ 0x80000000 | 3, 4 },
QtMocHelpers::SlotData<void(const QVideoFrame &)>(4, 2, QMC::AccessPrivate, QMetaType::Void, {{
{ 0x80000000 | 5, 6 },
}}),
};
QtMocHelpers::UintData qt_properties {
@ -73,14 +79,15 @@ void HyperionGrabber::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int
auto *_t = static_cast<HyperionGrabber *>(_o);
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: _t->_processFrame((*reinterpret_cast< std::add_pointer_t<QVideoFrame>>(_a[1]))); break;
case 0: _t->imageReady((*reinterpret_cast< std::add_pointer_t<QImage>>(_a[1]))); break;
case 1: _t->_processFrame((*reinterpret_cast< std::add_pointer_t<QVideoFrame>>(_a[1]))); break;
default: ;
}
}
if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
switch (_id) {
default: *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType(); break;
case 0:
case 1:
switch (*reinterpret_cast<int*>(_a[1])) {
default: *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType(); break;
case 0:
@ -89,6 +96,10 @@ void HyperionGrabber::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int
break;
}
}
if (_c == QMetaObject::IndexOfMethod) {
if (QtMocHelpers::indexOfMethod<void (HyperionGrabber::*)(const QImage & )>(_a, &HyperionGrabber::imageReady, 0))
return;
}
}
const QMetaObject *HyperionGrabber::metaObject() const
@ -110,15 +121,21 @@ int HyperionGrabber::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
if (_id < 1)
if (_id < 2)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
_id -= 2;
}
if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
if (_id < 1)
if (_id < 2)
qt_static_metacall(this, _c, _id, _a);
_id -= 1;
_id -= 2;
}
return _id;
}
// SIGNAL 0
void HyperionGrabber::imageReady(const QImage & _t1)
{
QMetaObject::activate<void>(this, &staticMetaObject, 0, nullptr, _t1);
}
QT_WARNING_POP

View File

@ -1,9 +1,17 @@
Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/BlackBorderDetector.cpp \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/BlackBorderDetector.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/CMakeFiles/4.0.3-dirty/CMakeCCompiler.cmake \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/CMakeFiles/4.0.3-dirty/CMakeCXXCompiler.cmake \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/CMakeFiles/4.0.3-dirty/CMakeSystem.cmake \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/CMakeLists.txt \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/HyperionProcessor.cpp \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/HyperionProcessor.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/Hyperion_Grabber_Wayland_QT_autogen/moc_predefs.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LedColorMapping.cpp \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LedColorMapping.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LinearColorSmoothing.cpp \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LinearColorSmoothing.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/WaylandGrabber.cpp \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/WaylandGrabber.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/debugclient.cpp \
@ -294,6 +302,7 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/include/qt6/QtCore/QTimer \
/usr/include/qt6/QtCore/QUrl \
/usr/include/qt6/QtCore/QVariant \
/usr/include/qt6/QtCore/QVector \
/usr/include/qt6/QtCore/q17memory.h \
/usr/include/qt6/QtCore/q20functional.h \
/usr/include/qt6/QtCore/q20iterator.h \
@ -442,9 +451,11 @@ Hyperion_Grabber_Wayland_QT_autogen/timestamp: \
/usr/include/qt6/QtCore/quuid.h \
/usr/include/qt6/QtCore/qvariant.h \
/usr/include/qt6/QtCore/qvarlengtharray.h \
/usr/include/qt6/QtCore/qvector.h \
/usr/include/qt6/QtCore/qversiontagging.h \
/usr/include/qt6/QtCore/qxptype_traits.h \
/usr/include/qt6/QtCore/qyieldcpu.h \
/usr/include/qt6/QtGui/QColor \
/usr/include/qt6/QtGui/QImage \
/usr/include/qt6/QtGui/QScreen \
/usr/include/qt6/QtGui/QTransform \

View File

@ -1,4 +1,5 @@
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_HyperionProcessor.cpp"
#include "EWIEGA46WW/moc_WaylandGrabber.cpp"
#include "EWIEGA46WW/moc_debugclient.cpp"
#include "EWIEGA46WW/moc_hyperiongrabber.cpp"

36
LinearColorSmoothing.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "LinearColorSmoothing.h"
#include <QDebug>
LinearColorSmoothing::LinearColorSmoothing(double smoothingFactor)
: _smoothingFactor(qBound(0.0, smoothingFactor, 1.0))
{
}
QVector<QColor> LinearColorSmoothing::smooth(const QVector<QColor>& newColors)
{
if (newColors.isEmpty()) {
_previousColors.clear();
return newColors;
}
if (_previousColors.isEmpty() || _previousColors.size() != newColors.size()) {
_previousColors = newColors;
return newColors;
}
QVector<QColor> smoothedColors(newColors.size());
for (int i = 0; i < newColors.size(); ++i) {
const QColor& newColor = newColors.at(i);
const QColor& prevColor = _previousColors.at(i);
int r = static_cast<int>(newColor.red() * (1.0 - _smoothingFactor) + prevColor.red() * _smoothingFactor);
int g = static_cast<int>(newColor.green() * (1.0 - _smoothingFactor) + prevColor.green() * _smoothingFactor);
int b = static_cast<int>(newColor.blue() * (1.0 - _smoothingFactor) + prevColor.blue() * _smoothingFactor);
smoothedColors[i] = QColor(r, g, b);
}
_previousColors = smoothedColors;
return smoothedColors;
}

19
LinearColorSmoothing.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef LINEARCOLORSMOOTHING_H
#define LINEARCOLORSMOOTHING_H
#include <QVector>
#include <QColor>
class LinearColorSmoothing
{
public:
explicit LinearColorSmoothing(double smoothingFactor = 0.1);
QVector<QColor> smooth(const QVector<QColor>& newColors);
private:
double _smoothingFactor;
QVector<QColor> _previousColors;
};
#endif // LINEARCOLORSMOOTHING_H

Binary file not shown.

View File

@ -90,7 +90,8 @@ static QApplication *app = nullptr;
static HyperionProcessor *processor = nullptr;
static WledClient *wledClient = nullptr;
void quit(int) {
void quit(int)
{
if (grabber != nullptr) {
delete grabber;
}
@ -115,8 +116,6 @@ public:
{
grabber = new HyperionGrabber(opts);
processor = new HyperionProcessor(layout, config);
wledClient = new WledClient(wledAddress, wledPort, this);
// Connect grabber to a new slot that will trigger the timer
connect(grabber, &HyperionGrabber::imageReady, this, &GrabberConfigurator::onImageReady);
@ -124,6 +123,8 @@ public:
_timer->setInterval(1000); // 1 second
connect(_timer, &QTimer::timeout, this, &GrabberConfigurator::processCurrentFrame);
_timer->start();
wledClient = new WledClient(wledAddress, wledPort, this);
}
public slots:
@ -156,8 +157,8 @@ public slots:
if (ledColors.size() > _layout.bottom + _layout.right) qDebug() << " LED (bottom+right+1):" << ledColors.at(_layout.bottom + _layout.right).name();
}
// Remove terminal visualization
// printAsciiLayout(ledColors, _layout);
// Print LED colors as a rectangular layout in the terminal
printAsciiLayout(ledColors, _layout);
}
private:
@ -192,6 +193,7 @@ int main(int argc, char *argv[])
// Add options for the processor
parser.addOption(QCommandLineOption(QStringList() << "bbt", "Black border threshold (0.0 to 1.0).", "threshold", "0.2")); // Increased threshold
parser.addOption(QCommandLineOption(QStringList() << "sf", "Smoothing factor (0.0 to 1.0).", "factor", "0.1")); // Smoothing factor
// Add WLED options
parser.addOption(QCommandLineOption(QStringList() << "a" << "address", "IP address of the WLED device.", "address"));
@ -220,6 +222,7 @@ int main(int argc, char *argv[])
QJsonObject processorConfig;
processorConfig["blackBorderThreshold"] = parser.value("bbt").toDouble();
processorConfig["smoothingFactor"] = parser.value("sf").toDouble();
GrabberConfigurator configurator(grabberOpts, layout, processorConfig, wledAddress, wledPort);
@ -228,4 +231,4 @@ int main(int argc, char *argv[])
return app->exec();
}
#include "grabberconfigurator.moc"
#include "grabberconfigurator.moc"

View File

@ -2,6 +2,7 @@
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/grabberconfigurator_autogen/moc_predefs.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/BlackBorderDetector.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LedColorMapping.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LinearColorSmoothing.h \
/usr/include/alloca.h \
/usr/include/asm-generic/bitsperlong.h \
/usr/include/asm-generic/errno-base.h \

View File

@ -9,6 +9,8 @@ grabberconfigurator_autogen/timestamp: \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/HyperionProcessor.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LedColorMapping.cpp \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LedColorMapping.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LinearColorSmoothing.cpp \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LinearColorSmoothing.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/WaylandGrabber.cpp \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/WaylandGrabber.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/debugclient.cpp \

View File

@ -3,6 +3,7 @@
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/BlackBorderDetector.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/HyperionProcessor.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LedColorMapping.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/LinearColorSmoothing.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/WaylandGrabber.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/hyperiongrabber.h \
/home/tobi/Projects/hyperion/Hyperion_Grabber_X11_QT/wledclient.h \

View File

@ -35,7 +35,7 @@ HyperionGrabber::HyperionGrabber(QHash<QString, QString> opts)
}
}
_client_p = new WledClient(addr, port, this);
// _client_p = new WledClient(addr, port, this); // Removed as client is now handled by GrabberConfigurator
_waylandGrabber_p = new WaylandGrabber(this);
connect(_waylandGrabber_p, &WaylandGrabber::frameReady, this, &HyperionGrabber::_processFrame);
@ -55,7 +55,7 @@ HyperionGrabber::~HyperionGrabber()
_timer_p->stop();
delete _timer_p;
}
delete _client_p;
// delete _client_p; // Removed as client is now handled by GrabberConfigurator
}
// private slots
@ -92,5 +92,25 @@ void HyperionGrabber::_processFrame(const QVideoFrame &frame)
scaledImage = scaledImage.convertToFormat(QImage::Format_RGB888);
}
// Calculate image difference
if (!_lastScaledImage_m.isNull() && scaledImage.size() == _lastScaledImage_m.size()) {
quint64 diff = 0;
for (int y = 0; y < scaledImage.height(); ++y) {
QRgb *line = reinterpret_cast<QRgb*>(scaledImage.scanLine(y));
QRgb *lastLine = reinterpret_cast<QRgb*>(_lastScaledImage_m.scanLine(y));
for (int x = 0; x < scaledImage.width(); ++x) {
diff += qAbs(qRed(line[x]) - qRed(lastLine[x]));
diff += qAbs(qGreen(line[x]) - qGreen(lastLine[x]));
diff += qAbs(qBlue(line[x]) - qBlue(lastLine[x]));
}
}
if (diff < _changeThreshold_m) {
// Image has not changed significantly, do not emit
return;
}
}
_lastScaledImage_m = scaledImage; // Store the current image for next comparison
emit imageReady(scaledImage);
}
}

View File

@ -58,6 +58,13 @@ This document captures key insights, challenges, and solutions encountered durin
* **Solution:** Added `WledClient` instance, command-line options for WLED address/port, and called `setLedsColor` with calculated LED colors. This sets up the pipeline for sending data directly to the WLED device.
* **Lesson:** Modular design allows for easy integration of different components. The `grabberconfigurator` now serves as a complete testbed for the entire Ambilight pipeline, from screen capture to WLED output.
## 10. Main Application Refactoring and Environment Variable Configuration
* **Challenge:** Consolidating the screen grabbing, Hyperion processing, and WLED communication into the main `Hyperion_Grabber_Wayland_QT` application and configuring it via environment variables.
* **Solution:** Refactored `main.cpp` to remove command-line parsing and instead read all configuration parameters (WLED address/port, LED layout, Hyperion algorithm parameters, grabber settings) from environment variables. Implemented a `QTimer` to control the frame processing rate.
* **Lesson:** Centralizing configuration via environment variables provides flexibility and simplifies deployment. Using a timer for frame processing ensures a consistent update rate for the LEDs, independent of the grabber's frame rate.
[Commit: e31f154] - feat: Implement and verify HyperionProcessor with live visualization
[Commit: 478828b] - docs: Add lesson learned about KWin script interference
[Commit: 60bcfb0] - feat: Integrate WledClient into grabberconfigurator for direct WLED communication
[Commit: <CURRENT_COMMIT_HASH>] - feat: Refactor main application for environment variable configuration

182
main.cpp
View File

@ -5,24 +5,26 @@
#include <QDateTime>
#include <QJsonDocument>
#include <QJsonObject>
#ifdef WLED_CONFIG_TOOL_BUILD
#include <QCoreApplication>
#include "wledconfigclient.h"
#else
#include <QApplication>
#include <QTimer>
#include <QApplication> // Added for QApplication
#include "hyperiongrabber.h"
#endif
#include "HyperionProcessor.h"
#include "wledclient.h"
#include "LedColorMapping.h"
#include "LinearColorSmoothing.h"
// Global pointers for cleanup
static HyperionGrabber *grabber = nullptr;
static QApplication *qapp = nullptr;
static HyperionProcessor *processor = nullptr;
static WledClient *wledClient = nullptr;
static QTimer *processTimer = nullptr;
static QImage currentImage; // Store the latest captured image
#ifndef WLED_CONFIG_TOOL_BUILD
static HyperionGrabber *grab;
static QApplication *qapp;
#endif
// Custom message handler for logging to file
static QFile *logFile = nullptr;
void customMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QByteArray localMsg = msg.toLocal8Bit();
@ -62,68 +64,69 @@ void customMessageOutput(QtMsgType type, const QMessageLogContext &context, cons
}
}
#ifndef WLED_CONFIG_TOOL_BUILD
// Signal handler for graceful shutdown
static void quit(int)
{
if (grab != nullptr) {
delete grab;
if (processTimer) {
processTimer->stop();
delete processTimer;
processTimer = nullptr;
}
if (grabber != nullptr) {
delete grabber;
grabber = nullptr;
}
if (processor != nullptr) {
delete processor;
processor = nullptr;
}
if (wledClient != nullptr) {
delete wledClient;
wledClient = nullptr;
}
if (logFile) {
logFile->close();
delete logFile;
logFile = nullptr;
}
qapp->exit();
if (qapp != nullptr) {
qapp->exit();
}
}
#endif
#ifdef WLED_CONFIG_TOOL_BUILD
int main(int argc, char *argv[])
// Slot to receive and store the latest image from HyperionGrabber
void onImageReady(const QImage &image)
{
QCoreApplication app(argc, argv);
currentImage = image;
}
QCommandLineParser parser;
parser.setApplicationDescription("WLED Configuration Tool");
parser.addHelpOption();
parser.addOption(QCommandLineOption({"a", "address"}, "IP address of the WLED device.", "address"));
parser.process(app);
if (!parser.isSet("address")) {
qWarning() << "Error: WLED IP address not provided. Use -a or --address.";
parser.showHelp(1);
// Slot to process the current image and send to WLED (triggered by timer)
void processCurrentFrame()
{
if (currentImage.isNull()) {
qDebug() << "No image available yet for processing.";
return;
}
QString wledIp = parser.value("address");
// Process the image with HyperionProcessor
QVector<QColor> ledColors = processor->process(currentImage);
WledConfigClient client(wledIp);
// Send colors to WLED
wledClient->setLedsColor(ledColors);
QObject::connect(&client, &WledConfigClient::infoReceived, [&](const QJsonObject &info) {
QJsonDocument doc(info);
qDebug() << "WLED Configuration Info:\n" << doc.toJson(QJsonDocument::Indented);
app.quit();
});
QObject::connect(&client, &WledConfigClient::error, [&](const QString &message) {
qWarning() << "Error retrieving WLED info:" << message;
app.quit();
});
client.getInfo();
return app.exec();
qDebug() << "Processed frame and sent to WLED.";
}
#else
int main(int argc, char *argv[])
{
// Initialize logging to file
logFile = new QFile("output.log");
if (!logFile->open(QFile::WriteOnly | QFile::Text | QFile::Truncate)) {
fprintf(stderr, "Warning: Could not open log file output.log for writing.\n");
delete logFile;
logFile = nullptr;
}
qInstallMessageHandler(customMessageOutput);
qapp = new QApplication(argc, argv);
signal(SIGINT, quit);
@ -131,35 +134,60 @@ int main(int argc, char *argv[])
QApplication::setApplicationName("HyperionGrabber");
QApplication::setApplicationVersion("0.2");
QCommandLineParser parser;
parser.setApplicationDescription("Hyperion grabber for Wayland using Qt");
parser.addHelpOption();
parser.addVersionOption();
parser.addOption(QCommandLineOption({"a", "address"}, "Address to the hyperion json server. (ex. 127.0.0.1)", "address"));
parser.addOption(QCommandLineOption({"p", "port"}, "Port for the hyperion json server. (ex. 19444)", "port"));
parser.addOption(QCommandLineOption({"s", "scale"}, "Divisor used to scale your screen resolution (ex. 8 ; if your screen is 1920x1080, the result image sent to hyperion is 240x135", "scale"));
parser.addOption(QCommandLineOption({"f", "frameskip"}, "Number of frames to skip between captures (ex. 1 ; 0 means no frames are skipped)", "frameskip"));
parser.addOption(QCommandLineOption({"i", "inactive"}, "How many seconds after the screen is inactive to turn off the LED's. Set to 0 to disable.", "seonds"));
parser.addOption(QCommandLineOption({"r", "redadjust"}, "Adjustment of the LED's red color (requires 3 space seperated values between 0 and 255) (ex. \"255,10,0\")", "value"));
parser.addOption(QCommandLineOption({"g", "greenadjust"}, "Adjustment of the LED's green color (requires 3 space seperated values between 0 and 255) (ex. \"75,210,0\")", "value"));
parser.addOption(QCommandLineOption({"b", "blueadjust"}, "Adjustment of the LED's blue color (requires 3 space seperated values between 0 and 255) (ex. \"0,10,160\")", "value"));
parser.addOption(QCommandLineOption({"t", "temperature"}, "Adjustment of the LED's color temperature (requires 3 space seperated values between 0 and 255) (ex. \"255,255,250\")", "value"));
parser.addOption(QCommandLineOption({"d", "threshold"}, "Set the threshold of the LED's (requires 3 space seperated values between 0.0 and 1.0) (ex. \"0.0025,0.005,0.01\")", "value"));
parser.addOption(QCommandLineOption({"l", "transform"}, "Adjusts the luminance / saturation of the LED's values are in this order: luminanceGain, luminanceMin, saturationL (requires 3 space seperated values between 0.0 and 1.0) (ex. \"1.0,0.01,1.0\")", "value"));
parser.process(*qapp);
QHash<QString, QString> opts;
for (const auto &optName : parser.optionNames()) {
if (parser.isSet(optName)) {
opts.insert(optName, parser.value(optName));
}
// Read configuration from environment variables
QString wledAddress = qgetenv("HYPERION_GRABBER_WLED_ADDRESS");
if (wledAddress.isEmpty()) {
qCritical() << "Error: HYPERION_GRABBER_WLED_ADDRESS environment variable not set.";
return 1;
}
grab = new HyperionGrabber(opts);
quint16 wledPort = qgetenv("HYPERION_GRABBER_WLED_PORT").toUShort();
if (wledPort == 0) wledPort = 21324; // Default WLED UDP Realtime port
QHash<QString, QString> grabberOpts;
grabberOpts.insert("scale", QString::number(qgetenv("HYPERION_GRABBER_SCALE").toInt()));
grabberOpts.insert("frameskip", QString::number(qgetenv("HYPERION_GRABBER_FRAMESKIP").toInt()));
grabberOpts.insert("changeThreshold", QString::number(qgetenv("HYPERION_GRABBER_CHANGE_THRESHOLD").toInt()));
LedLayout layout;
layout.bottom = qgetenv("HYPERION_GRABBER_LEDS_BOTTOM").toInt();
layout.right = qgetenv("HYPERION_GRABBER_LEDS_RIGHT").toInt();
layout.top = qgetenv("HYPERION_GRABBER_LEDS_TOP").toInt();
layout.left = qgetenv("HYPERION_GRABBER_LEDS_LEFT").toInt();
QJsonObject processorConfig;
processorConfig["blackBorderThreshold"] = qgetenv("HYPERION_GRABBER_BLACK_BORDER_THRESHOLD").toDouble();
processorConfig["smoothingFactor"] = qgetenv("HYPERION_GRABBER_SMOOTHING_FACTOR").toDouble();
// Apply default values if environment variables are not set or invalid
if (grabberOpts["scale"].isEmpty()) grabberOpts["scale"] = "8";
if (grabberOpts["frameskip"].isEmpty()) grabberOpts["frameskip"] = "0";
if (grabberOpts["changeThreshold"].isEmpty()) grabberOpts["changeThreshold"] = "100";
if (layout.bottom == 0) layout.bottom = 70;
if (layout.right == 0) layout.right = 20;
if (layout.top == 0) layout.top = 70;
if (layout.left == 0) layout.left = 20;
if (!processorConfig.contains("blackBorderThreshold")) processorConfig["blackBorderThreshold"] = 0.2;
if (!processorConfig.contains("smoothingFactor")) processorConfig["smoothingFactor"] = 0.1;
// Instantiate components
grabber = new HyperionGrabber(grabberOpts);
processor = new HyperionProcessor(layout, processorConfig);
wledClient = new WledClient(wledAddress, wledPort);
// Connect grabber to image receiver slot
QObject::connect(grabber, &HyperionGrabber::imageReady, &onImageReady);
// Setup timer for processing frames
processTimer = new QTimer();
processTimer->setInterval(1000); // Process every 1 second
QObject::connect(processTimer, &QTimer::timeout, &processCurrentFrame);
processTimer->start();
qInfo() << "HyperionGrabber started. Sending LED colors to WLED device:" << wledAddress << ":" << wledPort;
return qapp->exec();
}
#endif