diff --git a/.qt/QtDeployTargets.cmake b/.qt/QtDeployTargets.cmake index eca9367..fcd8a89 100644 --- a/.qt/QtDeployTargets.cmake +++ b/.qt/QtDeployTargets.cmake @@ -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) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce0e329..523dc08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ) diff --git a/HyperionProcessor.cpp b/HyperionProcessor.cpp index a27f44f..6c83c88 100644 --- a/HyperionProcessor.cpp +++ b/HyperionProcessor.cpp @@ -1,12 +1,14 @@ #include "HyperionProcessor.h" #include +#include 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 HyperionProcessor::process(const QImage &image) } // 3. Calculate the colors - return calculateLedColors(image); + QVector 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 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 &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(qSqrt(static_cast(r_sq / pixels.size()))), + static_cast(qSqrt(static_cast(g_sq / pixels.size()))), + static_cast(qSqrt(static_cast(b_sq / pixels.size())))); +} diff --git a/HyperionProcessor.h b/HyperionProcessor.h index 4d07a77..db4ca98 100644 --- a/HyperionProcessor.h +++ b/HyperionProcessor.h @@ -8,6 +8,7 @@ #include #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 calculateLedColors(const QImage &image); QColor getAverageColor(const QImage &image, const QVector &pixels) const; + QColor getMeanSqrtLedColor(const QImage &image, const QVector &pixels) const; LedLayout _layout; QJsonObject _config; @@ -32,6 +34,8 @@ private: QVector> _ledMap; + LinearColorSmoothing _colorSmoother; + public: QSize getLastImageSize() const { return _lastImageSize; } BlackBorder getLastBorder() const { return _lastBorder; } diff --git a/Hyperion_Grabber_Wayland_QT b/Hyperion_Grabber_Wayland_QT index 6af3468..b4d7708 100755 Binary files a/Hyperion_Grabber_Wayland_QT and b/Hyperion_Grabber_Wayland_QT differ diff --git a/Hyperion_Grabber_Wayland_QT_autogen/EWIEGA46WW/moc_HyperionProcessor.cpp b/Hyperion_Grabber_Wayland_QT_autogen/EWIEGA46WW/moc_HyperionProcessor.cpp new file mode 100644 index 0000000..815c14a --- /dev/null +++ b/Hyperion_Grabber_Wayland_QT_autogen/EWIEGA46WW/moc_HyperionProcessor.cpp @@ -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 + +#include + +#include + + +#include +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'HyperionProcessor.h' doesn't include ." +#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() +{ + namespace QMC = QtMocConstants; + QtMocHelpers::StringRefStorage qt_stringData { + "HyperionProcessor" + }; + + QtMocHelpers::UintData qt_methods { + }; + QtMocHelpers::UintData qt_properties { + }; + QtMocHelpers::UintData qt_enums { + }; + return QtMocHelpers::metaObjectData(QMC::MetaObjectFlag{}, qt_stringData, + qt_methods, qt_properties, qt_enums); +} +Q_CONSTINIT const QMetaObject HyperionProcessor::staticMetaObject = { { + QMetaObject::SuperData::link(), + qt_staticMetaObjectStaticContent.stringdata, + qt_staticMetaObjectStaticContent.data, + qt_static_metacall, + nullptr, + qt_staticMetaObjectRelocatingContent.metaTypes, + nullptr +} }; + +void HyperionProcessor::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + auto *_t = static_cast(_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.strings)) + return static_cast(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 diff --git a/Hyperion_Grabber_Wayland_QT_autogen/EWIEGA46WW/moc_HyperionProcessor.cpp.d b/Hyperion_Grabber_Wayland_QT_autogen/EWIEGA46WW/moc_HyperionProcessor.cpp.d new file mode 100644 index 0000000..11d07d7 --- /dev/null +++ b/Hyperion_Grabber_Wayland_QT_autogen/EWIEGA46WW/moc_HyperionProcessor.cpp.d @@ -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 diff --git a/Hyperion_Grabber_Wayland_QT_autogen/EWIEGA46WW/moc_hyperiongrabber.cpp b/Hyperion_Grabber_Wayland_QT_autogen/EWIEGA46WW/moc_hyperiongrabber.cpp index aba4bc2..cc21bda 100644 --- a/Hyperion_Grabber_Wayland_QT_autogen/EWIEGA46WW/moc_hyperiongrabber.cpp +++ b/Hyperion_Grabber_Wayland_QT_autogen/EWIEGA46WW/moc_hyperiongrabber.cpp @@ -39,16 +39,22 @@ template <> constexpr inline auto HyperionGrabber::qt_create_metaobjectdata(1, 2, QMC::AccessPublic, QMetaType::Void, {{ + { QMetaType::QImage, 3 }, + }}), // Slot '_processFrame' - QtMocHelpers::SlotData(1, 2, QMC::AccessPrivate, QMetaType::Void, {{ - { 0x80000000 | 3, 4 }, + QtMocHelpers::SlotData(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(_o); if (_c == QMetaObject::InvokeMetaMethod) { switch (_id) { - case 0: _t->_processFrame((*reinterpret_cast< std::add_pointer_t>(_a[1]))); break; + case 0: _t->imageReady((*reinterpret_cast< std::add_pointer_t>(_a[1]))); break; + case 1: _t->_processFrame((*reinterpret_cast< std::add_pointer_t>(_a[1]))); break; default: ; } } if (_c == QMetaObject::RegisterMethodArgumentMetaType) { switch (_id) { default: *reinterpret_cast(_a[0]) = QMetaType(); break; - case 0: + case 1: switch (*reinterpret_cast(_a[1])) { default: *reinterpret_cast(_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(_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(this, &staticMetaObject, 0, nullptr, _t1); +} QT_WARNING_POP diff --git a/Hyperion_Grabber_Wayland_QT_autogen/deps b/Hyperion_Grabber_Wayland_QT_autogen/deps index 3b66ce4..8b9c760 100644 --- a/Hyperion_Grabber_Wayland_QT_autogen/deps +++ b/Hyperion_Grabber_Wayland_QT_autogen/deps @@ -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 \ diff --git a/Hyperion_Grabber_Wayland_QT_autogen/mocs_compilation.cpp b/Hyperion_Grabber_Wayland_QT_autogen/mocs_compilation.cpp index 22cccf3..46f3ab3 100644 --- a/Hyperion_Grabber_Wayland_QT_autogen/mocs_compilation.cpp +++ b/Hyperion_Grabber_Wayland_QT_autogen/mocs_compilation.cpp @@ -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" diff --git a/LinearColorSmoothing.cpp b/LinearColorSmoothing.cpp new file mode 100644 index 0000000..ecb931c --- /dev/null +++ b/LinearColorSmoothing.cpp @@ -0,0 +1,36 @@ +#include "LinearColorSmoothing.h" +#include + +LinearColorSmoothing::LinearColorSmoothing(double smoothingFactor) + : _smoothingFactor(qBound(0.0, smoothingFactor, 1.0)) +{ +} + +QVector LinearColorSmoothing::smooth(const QVector& newColors) +{ + if (newColors.isEmpty()) { + _previousColors.clear(); + return newColors; + } + + if (_previousColors.isEmpty() || _previousColors.size() != newColors.size()) { + _previousColors = newColors; + return newColors; + } + + QVector 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(newColor.red() * (1.0 - _smoothingFactor) + prevColor.red() * _smoothingFactor); + int g = static_cast(newColor.green() * (1.0 - _smoothingFactor) + prevColor.green() * _smoothingFactor); + int b = static_cast(newColor.blue() * (1.0 - _smoothingFactor) + prevColor.blue() * _smoothingFactor); + + smoothedColors[i] = QColor(r, g, b); + } + + _previousColors = smoothedColors; + return smoothedColors; +} diff --git a/LinearColorSmoothing.h b/LinearColorSmoothing.h new file mode 100644 index 0000000..863dbc2 --- /dev/null +++ b/LinearColorSmoothing.h @@ -0,0 +1,19 @@ +#ifndef LINEARCOLORSMOOTHING_H +#define LINEARCOLORSMOOTHING_H + +#include +#include + +class LinearColorSmoothing +{ +public: + explicit LinearColorSmoothing(double smoothingFactor = 0.1); + + QVector smooth(const QVector& newColors); + +private: + double _smoothingFactor; + QVector _previousColors; +}; + +#endif // LINEARCOLORSMOOTHING_H diff --git a/grabberconfigurator b/grabberconfigurator index be76fad..73e9355 100755 Binary files a/grabberconfigurator and b/grabberconfigurator differ diff --git a/grabberconfigurator.cpp b/grabberconfigurator.cpp index 4f70e00..d3c4650 100644 --- a/grabberconfigurator.cpp +++ b/grabberconfigurator.cpp @@ -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" \ No newline at end of file diff --git a/grabberconfigurator_autogen/EWIEGA46WW/moc_HyperionProcessor.cpp.d b/grabberconfigurator_autogen/EWIEGA46WW/moc_HyperionProcessor.cpp.d index 4cb9468..eb2892b 100644 --- a/grabberconfigurator_autogen/EWIEGA46WW/moc_HyperionProcessor.cpp.d +++ b/grabberconfigurator_autogen/EWIEGA46WW/moc_HyperionProcessor.cpp.d @@ -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 \ diff --git a/grabberconfigurator_autogen/deps b/grabberconfigurator_autogen/deps index 5140e5c..202074a 100644 --- a/grabberconfigurator_autogen/deps +++ b/grabberconfigurator_autogen/deps @@ -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 \ diff --git a/grabberconfigurator_autogen/include/grabberconfigurator.moc.d b/grabberconfigurator_autogen/include/grabberconfigurator.moc.d index 0438e42..1a0f3d3 100644 --- a/grabberconfigurator_autogen/include/grabberconfigurator.moc.d +++ b/grabberconfigurator_autogen/include/grabberconfigurator.moc.d @@ -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 \ diff --git a/hyperiongrabber.cpp b/hyperiongrabber.cpp index 938124e..3eecde6 100644 --- a/hyperiongrabber.cpp +++ b/hyperiongrabber.cpp @@ -35,7 +35,7 @@ HyperionGrabber::HyperionGrabber(QHash 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(scaledImage.scanLine(y)); + QRgb *lastLine = reinterpret_cast(_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); -} +} \ No newline at end of file diff --git a/lessons_learned.md b/lessons_learned.md index a9923d4..0a2067b 100644 --- a/lessons_learned.md +++ b/lessons_learned.md @@ -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: ] - feat: Refactor main application for environment variable configuration \ No newline at end of file diff --git a/main.cpp b/main.cpp index 0e9dd86..c1b83d0 100644 --- a/main.cpp +++ b/main.cpp @@ -5,24 +5,26 @@ #include #include #include - - - -#ifdef WLED_CONFIG_TOOL_BUILD #include -#include "wledconfigclient.h" -#else -#include +#include +#include // 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 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 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 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