diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..1adf024 --- /dev/null +++ b/.clang-format @@ -0,0 +1,36 @@ +# ************************************************************************* +# +# Copyright (c) 2024 Andrei Gramakov. All rights reserved. +# +# site: https://agramakov.me +# e-mail: mail@agramakov.me +# +# +# This file is a part of a template: +# - https://github.com/an-dr/hello_world_cpp +# +# Official reference: https://clang.llvm.org/docs/ClangFormatStyleOptions.html +# GUI configuration tool: https://clang-format-configurator.site +# ************************************************************************* + +Language: Cpp +BasedOnStyle: LLVM +SpacesBeforeTrailingComments: 2 +IndentWidth: 4 +AccessModifierOffset: -3 +SortIncludes: true +ColumnLimit: 80 +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 2 + - Regex: '^<.*\.hpp>' + Priority: 2 + - Regex: '^<.*>' + Priority: 1 + - Regex: '^".*\.h"' + Priority: 4 + - Regex: '^".*"' + Priority: 4 + - Regex: '.*' + Priority: 5 diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..6785298 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,3 @@ +Checks: 'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,modernize-*,-modernize-use-trailing-return-type' +FormatStyle: llvm + diff --git a/.cmake-format b/.cmake-format new file mode 100644 index 0000000..d18db97 --- /dev/null +++ b/.cmake-format @@ -0,0 +1,113 @@ +# ************************************************************************* +# +# Copyright (c) 2024 Andrei Gramakov. All rights reserved. +# +# site: https://agramakov.me +# e-mail: mail@agramakov.me +# +# +# This file is a part of a template: +# - https://github.com/an-dr/hello_world_cpp +# +# Official reference: +# https://cmake-format.readthedocs.io/en/latest/configuration.html +# ************************************************************************* + + +# ----------------------------- +# Options affecting formatting. +# ----------------------------- +with section("format"): + + # Disable formatting entirely, making cmake-format a no-op + disable = False + + # How wide to allow formatted cmake files + line_width = 80 + + # How many spaces to tab for indent + tab_size = 4 + + # If true, lines are indented using tab characters (utf-8 0x09) instead of + # space characters (utf-8 0x20). In cases where the layout would + # require a fractional tab character, the behavior of the fractional + # indentation is governed by + use_tabchars = False + + # If is True, then the value of this variable indicates how + # fractional indentions are handled during whitespace replacement. If set to + # 'use-space', fractional indentation is left as spaces (utf-8 0x20). If set + # to `round-up` fractional indentation is replaced with a single tab character + # (utf-8 0x09) effectively shifting the column to the next tabstop + fractional_tab_policy = 'use-space' + + # If an argument group contains more than this many sub-groups (parg or kwarg + # groups) then force it to a vertical layout. + max_subgroups_hwrap = 2 + + # If a positional argument group contains more than this many arguments, then + # force it to a vertical layout. + max_pargs_hwrap = 6 + + # If a cmdline positional group consumes more than this many lines without + # nesting, then invalidate the layout (and nest) + max_rows_cmdline = 2 + + # If true, separate flow control names from their parentheses with a space + separate_ctrl_name_with_space = False + + # If true, separate function names from parentheses with a space + separate_fn_name_with_space = False + + # If a statement is wrapped to more than one line, than dangle the closing + # parenthesis on its own line. + dangle_parens = True + + # If the trailing parenthesis must be 'dangled' on its on line, then align it + # to this reference: `prefix`: the start of the statement, `prefix-indent`: + # the start of the statement, plus one indentation level, `child`: align to + # the column of the arguments + dangle_align = 'prefix' + + # If the statement spelling length (including space and parenthesis) is + # smaller than this amount, then force reject nested layouts. + min_prefix_chars = 4 + + # If the statement spelling length (including space and parenthesis) is larger + # than the tab width by more than this amount, then force reject un-nested + # layouts. + max_prefix_chars = 10 + + # If a candidate layout is wrapped horizontally but it exceeds this many + # lines, then reject the layout. + max_lines_hwrap = 2 + + # What style line endings to use in the output. + line_ending = 'unix' + + # Format command names consistently as 'lower' or 'upper' case + command_case = 'canonical' + + # Format keywords consistently as 'lower' or 'upper' case + keyword_case = 'upper' + + # A list of command names which should always be wrapped + always_wrap = [] + + # If true, the argument lists which are known to be sortable will be sorted + # lexicographicall + enable_sort = True + + # If true, the parsers may infer whether or not an argument list is sortable + # (without annotation). + autosort = True + + # By default, if cmake-format cannot successfully fit everything into the + # desired linewidth it will apply the last, most agressive attempt that it + # made. If this flag is True, however, cmake-format will print error, exit + # with non-zero status code, and write-out nothing + require_valid_layout = False + + # A dictionary mapping layout nodes to a list of wrap decisions. See the + # documentation for more information. + layout_passes = {} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a2ad2ab..58ec9f0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,22 +50,3 @@ jobs: - name: 🔨 Build run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - - build-vremotion: - runs-on: ubuntu-latest - name: Build VisioneREmotion - - steps: - - uses: actions/checkout@v4 - with: - submodules: 'true' - token: ${{ secrets.GITHUB_TOKEN }} - - - name: 🤖 Install OpenCV - run: sudo apt-get install libopencv-dev libopencv-contrib-dev -y - - - name: 🔧 Configure CMake - run: cmake -B ${{github.workspace}}/build -S${{github.workspace}}/src/VisioneREmotion -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - - - name: 🔨 Build - run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} diff --git a/.gitmodules b/.gitmodules index 504e1eb..cc2da96 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,6 +4,6 @@ [submodule "src/common_components/microlog"] path = src/common_components/microlog url = https://github.com/an-dr/microlog.git -[submodule "src/VisioneREmotion/components/CppLinuxSerial"] - path = src/VisioneREmotion/components/CppLinuxSerial - url = https://github.com/gbmhunter/CppLinuxSerial.git +[submodule "src/common_components/eventpp"] + path = src/common_components/eventpp + url = https://github.com/wqking/eventpp.git diff --git a/README.md b/README.md index fdfeda2..c7b0d98 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ The project architecture is described [here](doc/architecture.md). - [VisioneR](#visioner) - [Table of Contents](#table-of-contents) - [Demo](#demo) + - [Requrements](#requrements) - [Implementation](#implementation) ## Demo @@ -19,6 +20,12 @@ Implementation using the [rEmotion](https://github.com/an-dr/rEmotion) platform: ![demo](doc/README/main_demo.gif) +## Requrements + +- opencv +- qt6-base-dev +- qt6-wayland + ## Implementation You can generate a Doxygen documentation by running the following command in the project root directory: diff --git a/VisioneR.code-workspace b/VisioneR.code-workspace index 2657d44..947e699 100644 --- a/VisioneR.code-workspace +++ b/VisioneR.code-workspace @@ -35,30 +35,6 @@ } ] }, - { - "name": "Debug - VisioneREmotion", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/install/VisioneREmotion/VisioneREmotion", - "miDebuggerPath": "gdb", - "args": [], - "stopAtEntry": false, - "cwd": "${workspaceFolder}/install/VisioneREmotion", - "preLaunchTask": "Install", - "setupCommands": [ - { // Display content in STL containers pretty - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ], - "environment": [ - { - "name": "GTK_PATH", - "value": "" - } - ] - }, { "name": "Debug - VisionerWebcam", "type": "cppdbg", @@ -116,7 +92,18 @@ }, "dependsOn": "Configure" }, - // Cmake build + { + "label": "compile_command.json", + "type": "shell", + "command": "cp", + "args": [ + "${workspaceFolder}/build/${input:Project}/compile_commands.json", + "${workspaceFolder}/build/compile_commands.json", + ], + "options": { + "cwd": "${workspaceFolder}", + }, + }, { "label": "Configure", "type": "shell", @@ -126,14 +113,17 @@ "Ninja", "-B", "${workspaceFolder}/build/${input:Project}", - "-DCMAKE_BUILD_TYPE=Debug" + "-DCMAKE_BUILD_TYPE=Debug", ], "group": { "kind": "build", "isDefault": true }, "options": { - "cwd": "${workspaceFolder}/src/${input:Project}" + "cwd": "${workspaceFolder}/src/${input:Project}", + "env": { + "ABCMAKE_EMOJI": "1" + } }, "problemMatcher": [], "presentation": { @@ -207,9 +197,6 @@ }, { "value": "VisionerWebcam", - }, - { - "value": "VisioneREmotion", } ] } diff --git a/ab.cmake b/ab.cmake index bacdc5b..06eda20 100644 --- a/ab.cmake +++ b/ab.cmake @@ -15,70 +15,342 @@ # Source Code: https://github.com/an-dr/abcmake # ************************************************************************* -set(ABCMAKE_VERSION_MAJOR 5) -set(ABCMAKE_VERSION_MINOR 2) +set(ABCMAKE_VERSION_MAJOR 6) +set(ABCMAKE_VERSION_MINOR 0) set(ABCMAKE_VERSION_PATCH 0) set(ABCMAKE_VERSION "${ABCMAKE_VERSION_MAJOR}.${ABCMAKE_VERSION_MINOR}.${ABCMAKE_VERSION_PATCH}") # Configure CMake +set(ABCMAKE ON) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) +# ---------------------------------------------------------------------------- +# Internal CMake modules +# ---------------------------------------------------------------------------- + +# ============================================================================== +# _abcmake_log.cmake.cmake ===================================================== + +set(__ABCMAKE_INDENTATION " ") + +if ($ENV{ABCMAKE_EMOJI}) + set(__ABCMAKE_COMPONENT "🔤") + set(__ABCMAKE_OK "✅") + set(__ABCMAKE_ERROR "❌") + set(__ABCMAKE_WARNING "🔶") + set(__ABCMAKE_NOTE "⬜") +else() + set(__ABCMAKE_COMPONENT "[ABCMAKE]") + set(__ABCMAKE_OK "[DONE]") + set(__ABCMAKE_ERROR "[ERROR]") + set(__ABCMAKE_WARNING "[WARNING]") + set(__ABCMAKE_NOTE "[INFO]") +endif() + +# Print a message with indentation +# @param INDENTATION The indentation level. If < 0, the message is not printed +# @param MESSAGE The message to print +function(_abcmake_log INDENTATION MESSAGE) + if(${INDENTATION} GREATER_EQUAL 0) + string(REPEAT ${__ABCMAKE_INDENTATION} ${INDENTATION} indentation) + message(STATUS "${indentation}${MESSAGE}") + endif() +endfunction() + +function(_abcmake_log_ok INDENTATION MESSAGE) + _abcmake_log(${INDENTATION} "${__ABCMAKE_OK} ${MESSAGE}") +endfunction() + +function(_abcmake_log_err INDENTATION MESSAGE) + _abcmake_log(${INDENTATION} "${__ABCMAKE_ERROR} ${MESSAGE}") +endfunction() + +function(_abcmake_log_warn INDENTATION MESSAGE) + _abcmake_log(${INDENTATION} "${__ABCMAKE_WARNING} ${MESSAGE}") +endfunction() + +function(_abcmake_log_note INDENTATION MESSAGE) + _abcmake_log(${INDENTATION} "${__ABCMAKE_NOTE} ${MESSAGE}") +endfunction() + +function(_abcmake_log_header INDENTATION MESSAGE) + _abcmake_log(${INDENTATION} "${__ABCMAKE_COMPONENT} ${MESSAGE}") +endfunction() + + +# _abcmake_log.cmake.cmake ===================================================== +# ============================================================================== + +# ============================================================================== +# abcmake_property.cmake ======================================================= + +# A change in any of these variables will cause a breaking change in the API! + +set(ABCMAKE_PROPERTY_PREFIX "ABCMAKE_") + +# Global properties: +set(ABCMAKE_PROP_ADDED_PROJECTS "ADDED_PROJECTS") # The list of projects that have been added to the solution +set(ABCMAKE_PROP_COMPONENT_REGISTRY "COPONENT_REGISTRY") # Component registry +set(_ABCMAKE_PROP_COMPONENTS_DIR "COMPONENTS_DIR") # The directory where the components are stored +set(_ABCMAKE_PROP_SRC_DIR "SRC_DIR") # The directory where the source files are stored +set(_ABCMAKE_PROP_INCLUDE_DIR "INCLUDE_DIR") # The directory where the include files are stored +set(_ABCMAKE_PROP_INSTALL_DIR "INSTALL_DIR") # The directory where the project will be installed + +# Directory-scope properties +set(ABCMAKE_DIRPROP_VERSION "VERSION") # The abcmake version of the component +set(ABCMAKE_DIRPROP_COMPONENT_NAME "COMPONENT_NAME") # The name of the component (local PROJECT_NAME) +set(ABCMAKE_DIRPROP_TARGETS "TARGETS") # The list of targets built by the component + +# Default values +set(_ABCMAKE_DEFAULT_COMPONENTS_DIR "components") +set(_ABCMAKE_DEFAULT_SRC_DIR "src") +set(_ABCMAKE_DEFAULT_INCLUDE_DIR "include") +set(_ABCMAKE_DEFAULT_INSTALL_DIR "${CMAKE_BINARY_DIR}/../install") + + +# Setters +# ======= + +function(_abcmake_set_prop PROPERTY_NAME PROPERTY_VALUE) + set_property(GLOBAL PROPERTY + ${ABCMAKE_PROPERTY_PREFIX}${PROPERTY_NAME} ${PROPERTY_VALUE}) +endfunction() + +function(_abcmake_append_prop PROPERTY_NAME PROPERTY_VALUE) + set_property(GLOBAL APPEND PROPERTY + ${ABCMAKE_PROPERTY_PREFIX}${PROPERTY_NAME} ${PROPERTY_VALUE}) +endfunction() + +function(_abcmake_set_prop_curdir PROPERTY_NAME PROPERTY_VALUE) + set_directory_properties(PROPERTIES + ${ABCMAKE_PROPERTY_PREFIX}${PROPERTY_NAME} ${PROPERTY_VALUE}) +endfunction() + +function(_abcmake_append_prop_curdir PROPERTY_NAME PROPERTY_VALUE) + set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + APPEND PROPERTY + ${ABCMAKE_PROPERTY_PREFIX}${PROPERTY_NAME} ${PROPERTY_VALUE}) +endfunction() + + +# Getters +# ======= + +# Get a global property of ABCMAKE (with the ABCMAKE_PROPERTY_PREFIX) +# @param PROPERTY_NAME - The name of the property to get +# @param OUT_VAR_NAME - The name of the variable to set with the result +# @param FALLBACK - Optional argument, if the property is not found, the value of FALLBACK will be used +function(_abcmake_get_prop PROPERTY_NAME OUT_VAR_NAME) + # optional argument FALLBACK + set(flags) + set(args) + set(listArgs FALLBACK) + cmake_parse_arguments(arg "${flags}" "${args}" "${listArgs}" ${ARGN}) + + # Getting the property + get_property(tmp_result GLOBAL PROPERTY + ${ABCMAKE_PROPERTY_PREFIX}${PROPERTY_NAME}) + + # If not found, try to use the fallback + if(NOT tmp_result AND arg_FALLBACK) + set(tmp_result ${arg_FALLBACK}) + endif() + + # Setting the result + set(${OUT_VAR_NAME} ${tmp_result} PARENT_SCOPE) +endfunction() + +function(_abcmake_get_prop_dir DIRECTORY PROPERTY_NAME OUT_VAR_NAME) + get_directory_property(tmp_result DIRECTORY ${DIRECTORY} + ${ABCMAKE_PROPERTY_PREFIX}${PROPERTY_NAME}) + set(${OUT_VAR_NAME} ${tmp_result} PARENT_SCOPE) +endfunction() + +# Specific Getters +# ================= + +function(_abcmake_get_components OUT_VAR_NAME) + _abcmake_get_prop(${_ABCMAKE_PROP_COMPONENTS_DIR} tmp_result + FALLBACK ${_ABCMAKE_DEFAULT_COMPONENTS_DIR}) + set(${OUT_VAR_NAME} ${tmp_result} PARENT_SCOPE) +endfunction() + +function(_abcmake_get_src OUT_VAR_NAME) + _abcmake_get_prop(${_ABCMAKE_PROP_SRC_DIR} tmp_result + FALLBACK ${_ABCMAKE_DEFAULT_SRC_DIR}) + set(${OUT_VAR_NAME} ${tmp_result} PARENT_SCOPE) +endfunction() + +function(_abcmake_get_include OUT_VAR_NAME) + _abcmake_get_prop(${_ABCMAKE_PROP_INCLUDE_DIR} tmp_result + FALLBACK ${_ABCMAKE_DEFAULT_INCLUDE_DIR}) + set(${OUT_VAR_NAME} ${tmp_result} PARENT_SCOPE) +endfunction() + +function(_abcmake_get_install OUT_VAR_NAME) + _abcmake_get_prop(${_ABCMAKE_PROP_INSTALL_DIR} tmp_result + FALLBACK ${_ABCMAKE_DEFAULT_INSTALL_DIR}) + set(${OUT_VAR_NAME} ${tmp_result} PARENT_SCOPE) +endfunction() + +# abcmake_property.cmake ======================================================= +# ============================================================================== + + +# ============================================================================== +# _abcmake_add_project.cmake ==================================================== + +# Add subdirectory to the project only if not added +function(_abcmake_add_subdirectory PATH) + + # ABCMAKE_ADDED_PROJECTS is an interface, it may break compatibility if changed! + _abcmake_get_prop(${ABCMAKE_PROP_ADDED_PROJECTS} projects) + message(DEBUG "Added projects: ${projects}") + + # Resolve relative path + get_filename_component(PATH "${PATH}" ABSOLUTE) + + if (NOT PATH IN_LIST projects) + # Add PATH to the global list + _abcmake_append_prop(${ABCMAKE_PROP_ADDED_PROJECTS} ${PATH}) + + # Use the last directory name for a binary directory name + get_filename_component(last_dir "${PATH}" NAME) + add_subdirectory(${PATH} abc_${last_dir}) + endif() + +endfunction() + +function(_abcmake_add_project PATH OUT_ABCMAKE_VER) + if (NOT EXISTS ${PATH}) + _abcmake_log_err(1 "Path \"${PATH}\" does not exist!") + return() + endif() + + if (NOT EXISTS ${PATH}/CMakeLists.txt) + _abcmake_log_note(1 "No CMakeLists.txt: ${PATH}. Skipping...") + return() + endif() + + message(DEBUG "Adding project ${PATH}") + _abcmake_add_subdirectory(${PATH}) + + _abcmake_get_prop_dir(${PATH} "VERSION" version) + set(${OUT_ABCMAKE_VER} ${version} PARENT_SCOPE) + if (NOT version) + _abcmake_log_warn(1 "Not abcmake: ${PATH}. Link it manually.") + endif() +endfunction() + +# _abcmake_add_project.cmake ==================================================== +# ============================================================================== + + +# ---------------------------------------------------------------------------- +# Public Functions +# ---------------------------------------------------------------------------- + # ============================================================================== # add_component.cmake ========================================================== include(CMakeParseArguments) +set(ABC_INSTALL_LIB_SUBDIR "lib") +set(ABC_INSTALL_EXE_SUBDIR ".") # Add all projects from the components subdirectory +# @param PROCESS_LEVEL - level of the recursion # @param TARGETNAME - name of the target to add components -function(_abc_AddComponents TARGETNAME) +function(_abcmake_add_components PROCESS_LEVEL TARGETNAME) + + # Get component directory + _abcmake_get_components(components) + # List of possible subprojects - file(GLOB children RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/components ${CMAKE_CURRENT_SOURCE_DIR}/components/*) + file(GLOB children RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/${components} ${CMAKE_CURRENT_SOURCE_DIR}/${components}/*) # Link all subprojects to the ${TARGETNAME} foreach(child ${children}) - if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/components/${child}) - target_link_component(${TARGETNAME} ${CMAKE_CURRENT_SOURCE_DIR}/components/${child}) + if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${components}/${child}) + _abcmake_target_link_components(${PROCESS_LEVEL} + ${TARGETNAME} + PATH ${CMAKE_CURRENT_SOURCE_DIR}/${components}/${child}) endif() endforeach() endfunction() +# Add all source files from the specified directory to the target +# @param TARGETNAME - name of the target to add sources +function(target_sources_directory TARGETNAME SOURCE_DIR) + file(GLOB_RECURSE SOURCES "${SOURCE_DIR}/*.cpp" "${SOURCE_DIR}/*.c") + message( DEBUG "${TARGETNAME} sources: ${SOURCES}") + target_sources(${TARGETNAME} PRIVATE ${SOURCES}) +endfunction() # Install the target near the build directory # @param TARGETNAME - name of the target to install # @param DESTINATION - path to the destination directory inside the install dir -function(_target_install_near_build TARGETNAME DESTINATION) +function(_abcmake_target_install TARGETNAME DESTINATION) # install directory - set (CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/../install" + _abcmake_get_install(install_dir) + set (CMAKE_INSTALL_PREFIX ${install_dir} CACHE PATH "default install path" FORCE) install(TARGETS ${TARGETNAME} DESTINATION ${DESTINATION}) endfunction() +function(_abcmake_count_parents OUT_PARENT_NUM) + set(PARENT_NUM 0) + get_directory_property(parent PARENT_DIRECTORY) + while (parent) + math(EXPR PARENT_NUM "${PARENT_NUM} + 1") + set(parent "") + get_directory_property(hasParent PARENT_DIRECTORY) + endwhile() + set(${OUT_PARENT_NUM} ${PARENT_NUM} PARENT_SCOPE) +endfunction() + # Add to the project all files from ./src, ./include, ./lib # @param TARGETNAME - name of the target to initialize # @param INCLUDE_DIR - path to the include directory # @param SOURCE_DIR - path to the source directory -function(_target_init_abcmake TARGETNAME INCLUDE_DIR SOURCE_DIR) +function(_abcmake_target_init TARGETNAME) + set(flags) + set(args) + set(listArgs INCLUDE_DIR SOURCE_DIR) + cmake_parse_arguments(arg "${flags}" "${args}" "${listArgs}" ${ARGN}) + + if (NOT arg_SOURCE_DIR) + set(arg_SOURCE_DIR "src") + endif() + + if (NOT arg_INCLUDE_DIR) + set(arg_INCLUDE_DIR "include") + endif() - get_directory_property(hasParent PARENT_DIRECTORY) + _abcmake_count_parents(parents_num) + set(process_level ${parents_num}) # if no parent, print the name of the target - if (NOT hasParent) - message(STATUS "🔤 ${TARGETNAME}") + if (parents_num EQUAL 0) + _abcmake_log_header(${process_level} "${TARGETNAME}") endif () # Report version - set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY - ABCMAKE_VERSION ${ABCMAKE_VERSION}) - + _abcmake_set_prop_curdir(${ABCMAKE_DIRPROP_VERSION} ${ABCMAKE_VERSION}) + + # Set name + _abcmake_set_prop_curdir(${ABCMAKE_DIRPROP_COMPONENT_NAME} ${PROJECT_NAME}) + # Add target to the target list - set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} APPEND PROPERTY - ABCMAKE_TARGETS ${TARGETNAME}) - - target_sources_directory(${TARGETNAME} ${SOURCE_DIR}) - target_include_directories(${TARGETNAME} PUBLIC ${INCLUDE_DIR}) - _abc_AddComponents(${TARGETNAME}) + _abcmake_append_prop_curdir(${ABCMAKE_DIRPROP_TARGETS} ${TARGETNAME}) + + foreach(s ${arg_SOURCE_DIR}) + target_sources_directory(${TARGETNAME} ${s}) + endforeach() + + target_include_directories(${TARGETNAME} PUBLIC ${arg_INCLUDE_DIR}) + _abcmake_add_components(${process_level} ${TARGETNAME}) endfunction() @@ -91,37 +363,41 @@ function(add_main_component TARGETNAME) set(args) set(listArgs INCLUDE_DIR SOURCE_DIR) cmake_parse_arguments(arg "${flags}" "${args}" "${listArgs}" ${ARGN}) + if (NOT arg_SOURCE_DIR) - set(arg_SOURCE_DIR "src") + _abcmake_get_src(arg_SOURCE_DIR) endif() if (NOT arg_INCLUDE_DIR) - set(arg_INCLUDE_DIR "include") + _abcmake_get_include(arg_INCLUDE_DIR) endif() add_executable(${TARGETNAME}) - _target_init_abcmake(${TARGETNAME} ${arg_INCLUDE_DIR} ${arg_SOURCE_DIR}) - _target_install_near_build(${TARGETNAME} ".") + _abcmake_target_init(${TARGETNAME} + INCLUDE_DIR ${arg_INCLUDE_DIR} + SOURCE_DIR ${arg_SOURCE_DIR}) + _abcmake_target_install(${TARGETNAME} ${ABC_INSTALL_EXE_SUBDIR}) endfunction() # Add a shared or static library component to the project # @param TARGETNAME - name of the target to add the component -# @param INCLUDE_DIR - path to the include directory -# @param SOURCE_DIR - path to the source directory +# @param INCLUDE_DIR - paths to the include directories +# @param SOURCE_DIR - paths to the source directories # @param SHARED - if set to TRUE, the library will be shared function(add_component TARGETNAME) set(flags SHARED) set(args) set(listArgs INCLUDE_DIR SOURCE_DIR) cmake_parse_arguments(arg "${flags}" "${args}" "${listArgs}" ${ARGN}) + message(DEBUG "add_component: ${TARGETNAME}") if (NOT arg_SOURCE_DIR) - set(arg_SOURCE_DIR "src") + _abcmake_get_src(arg_SOURCE_DIR) endif() if (NOT arg_INCLUDE_DIR) - set(arg_INCLUDE_DIR "include") + _abcmake_get_include(arg_INCLUDE_DIR) endif() if (arg_SHARED) @@ -130,100 +406,141 @@ function(add_component TARGETNAME) add_library(${TARGETNAME} STATIC) endif() - _target_init_abcmake(${TARGETNAME} ${arg_INCLUDE_DIR} ${arg_SOURCE_DIR}) - _target_install_near_build(${TARGETNAME} "lib") + _abcmake_target_init(${TARGETNAME} + INCLUDE_DIR ${arg_INCLUDE_DIR} + SOURCE_DIR ${arg_SOURCE_DIR}) + _abcmake_target_install(${TARGETNAME} ${ABC_INSTALL_LIB_SUBDIR}) endfunction() - # add_component.cmake ========================================================== # ============================================================================== # ============================================================================== -# target_sources_directory.cmake =============================================== - -# Add all source files from the specified directory to the target -# @param TARGETNAME - name of the target to add sources -function(target_sources_directory TARGETNAME SOURCE_DIR) - file(GLOB_RECURSE SOURCES "${SOURCE_DIR}/*.cpp" "${SOURCE_DIR}/*.c") - message( DEBUG "${TARGETNAME} sources: ${SOURCES}") - target_sources(${TARGETNAME} PRIVATE ${SOURCES}) -endfunction() - -# target_sources_directory.cmake =============================================== -# ============================================================================== +# register_components.cmake ==================================================== -# ============================================================================== -# target_link_component.cmake ================================================== +set(__ABCMAKE_COMPONENT_REGISTRY_SEPARATOR "::::") -# Add subdirectory to the project only if not added -function(_add_subdirectory PATH) +# Register a component by adding it to the registry +# @param PATH - list of paths to the components +function(register_components PATH) - # ABCMAKE_ADDED_PROJECTS is an interface, it may break compatibility if changed! - get_property(projects GLOBAL PROPERTY ABCMAKE_ADDED_PROJECTS) - - # Resolve relative path - get_filename_component(PATH "${PATH}" ABSOLUTE) + foreach(path ${ARGV}) + message(DEBUG " 📂 Path: ${path}") + _abcmake_add_project(${path} PROJECT_ABCMAKE_VER) + if(PROJECT_ABCMAKE_VER) + _abcmake_get_prop_dir(${path} ${ABCMAKE_DIRPROP_COMPONENT_NAME} component_name) + set(new_entry "${component_name}${__ABCMAKE_COMPONENT_REGISTRY_SEPARATOR}${path}") + _abcmake_append_prop(${ABCMAKE_PROP_COMPONENT_REGISTRY} ${new_entry}) + + _abcmake_log_header(0 "${component_name} (registered)") + endif() + endforeach() - if (NOT PATH IN_LIST projects) - # Add PATH to the global list - set_property(GLOBAL APPEND PROPERTY ABCMAKE_ADDED_PROJECTS ${PATH}) - - # Use the last directory name for a binary directory name - get_filename_component(last_dir "${PATH}" NAME) - add_subdirectory(${PATH} abc_${last_dir}) +endfunction() + +# Splits into COMPONENT_ENTRY into COMPONENT_NAME and COMPONENT_PATH +function (_split_component_entry COMPONENT_ENTRY OUT_NAME OUT_PATH) + string(FIND ${COMPONENT_ENTRY} ${__ABCMAKE_COMPONENT_REGISTRY_SEPARATOR} sep_pos) + if(sep_pos EQUAL -1) + message(FATAL_ERROR "Invalid component entry: ${COMPONENT_ENTRY}") endif() + string(REGEX MATCH "^(.+)${__ABCMAKE_COMPONENT_REGISTRY_SEPARATOR}(.+)" + ENTRY_MATCH ${COMPONENT_ENTRY}) + set(name ${CMAKE_MATCH_1}) + set(path ${CMAKE_MATCH_2}) + + set(${OUT_NAME} ${name} PARENT_SCOPE) + set(${OUT_PATH} ${path} PARENT_SCOPE) endfunction() -function(_abc_AddProject PATH OUT_ABCMAKE_VER) - if (EXISTS ${PATH}/CMakeLists.txt) - message(DEBUG "Adding project ${PATH}") - _add_subdirectory(${PATH}) - - get_directory_property(version DIRECTORY ${PATH} ABCMAKE_VERSION) - set(${OUT_ABCMAKE_VER} ${version} PARENT_SCOPE) - if (NOT version) - message (STATUS " 🔶 ${PATH} is not an ABCMAKE project. Link it manually.") +# Gets the path of a component from the registry. Returns null if not found. +function (_abcmake_get_from_registry COMPONENT_NAME OUT_PATH) + _abcmake_get_prop(${ABCMAKE_PROP_COMPONENT_REGISTRY} registry) + message(DEBUG "Get ${COMPONENT_NAME} from : ${registry}") + foreach(entry ${registry}) + _split_component_entry(${entry} name path) + if(name STREQUAL COMPONENT_NAME) + set(${OUT_PATH} ${path} PARENT_SCOPE) + return() endif() - - else() - message (STATUS " ❌ ${PATH} is not a CMake project") - endif() + endforeach() endfunction() + +# register_components.cmake ==================================================== +# ============================================================================== + + -# Link the component to the target -# DEPRECATED! Use target_link_components instead +# ============================================================================== +# target_link_components.cmake ================================================= + +# Link a component to the target # # @param TARGETNAME - name of the target for linking # @param COMPONENTPATH - path to the component to link -function (target_link_component TARGETNAME COMPONENTPATH) - _abc_AddProject(${COMPONENTPATH} ver) +function (_abcmake_target_link_single_component PROCESS_LEVEL TARGETNAME COMPONENTPATH) + + _abcmake_add_project(${COMPONENTPATH} ver) if (ver) - get_directory_property(to_link DIRECTORY ${COMPONENTPATH} ABCMAKE_TARGETS) - message (STATUS " ✅ Linking ${to_link} to ${TARGETNAME}") + # What to link? + _abcmake_get_prop_dir(${COMPONENTPATH} ${ABCMAKE_DIRPROP_TARGETS} to_link) + + # Link target_link_libraries(${TARGETNAME} PRIVATE ${to_link}) + _abcmake_log_ok(${PROCESS_LEVEL} "${TARGETNAME}: linked ${to_link}") endif() endfunction() + + # Link components to the target +# @param PROCESS_LEVEL - level of the process in the call stack (for logging) # @param TARGETNAME - name of the target for linking -# @param COMPONENTPATHS - path to the component to link -function (target_link_components TARGETNAME) +# @param PATH - paths to components to link +# @param NAME - names of components to link +function (_abcmake_target_link_components PROCESS_LEVEL TARGETNAME) + math(EXPR process_level "${PROCESS_LEVEL} + 1") + set(flags) set(args) - set(listArgs COMPONENTPATHS) + set(listArgs PATH NAME) cmake_parse_arguments(arg "${flags}" "${args}" "${listArgs}" ${ARGN}) - foreach(COMPONENTPATH ${COMPONENTPATHS}) - target_link_component(${TARGETNAME} ${COMPONENTPATH}) + message(DEBUG "_abcmake_target_link_components arg_PATH: ${arg_PATH}") + message(DEBUG "_abcmake_target_link_components arg_NAME: ${arg_NAME}") + + # Link components by path + foreach(PATH ${arg_PATH}) + _abcmake_target_link_single_component(${process_level} ${TARGETNAME} ${PATH}) endforeach() - foreach(COMPONENTPATH ${ARGN}) - target_link_component(${TARGETNAME} ${COMPONENTPATH}) + # Link components by name + foreach(NAME ${arg_NAME}) + set(reg_path "") # reset the variable + _abcmake_get_from_registry(${NAME} reg_path) + if (reg_path) + message ( DEBUG "Found component: ${NAME} -> ${reg_path}") + _abcmake_target_link_single_component(${process_level} ${TARGETNAME} ${reg_path}) + else() + _abcmake_log_err(${process_level} "${NAME} not found in the component registry!") + _abcmake_log(${process_level} "Use `register_components` to add it to the registry") + message (FATAL_ERROR "Component ${NAME} not found in the registry") + endif() endforeach() + + +endfunction() + +# Link components to the target +# @param TARGETNAME - name of the target for linking +# @param PATH - paths to components to link +# @param NAME - names of components to link +function (target_link_components TARGETNAME) + _abcmake_target_link_components(0 ${TARGETNAME} ${ARGN}) endfunction() -# target_link_component.cmake ================================================== +# target_link_components.cmake ================================================= # ============================================================================== diff --git a/doc/architecture.md b/doc/architecture.md index 771c899..29bc64f 100644 --- a/doc/architecture.md +++ b/doc/architecture.md @@ -53,6 +53,8 @@ The project is supposed to be tested by usage. ### 5.4 Software Structure + + ![classes](architecture/class.drawio.svg) ![dep](architecture/dep.drawio.svg) @@ -63,4 +65,6 @@ The project is supposed to be tested by usage. ### 5.6 Operational Logic +![data_exchange](architecture/communication.drawio.svg) + ![flow](architecture/flow.drawio.svg) diff --git a/doc/architecture/communication.drawio.svg b/doc/architecture/communication.drawio.svg new file mode 100644 index 0000000..4e1c6c8 --- /dev/null +++ b/doc/architecture/communication.drawio.svg @@ -0,0 +1,178 @@ + + + + + + + + +
+
+
+ Send Event +
+
+
+
+ + Send Event + +
+
+ + + + + + +
+
+
+ Emotion Core +
+
+
+
+ + Emotion Core + +
+
+ + + + +
+
+
+ Event Handler +
+
+
+
+ + Event Handler + +
+
+ + + + +
+
+
+ Face +
+
+
+
+ + Face + +
+
+ + + + + +
+
+
+ Send Command +
+
+
+
+ + Send Command + +
+
+ + + + + + +
+
+
+ Object Recognition App +
+
+
+
+ + Object Recognition App + +
+
+ + + + +
+
+
+ App +
+
+
+
+ + App + +
+
+ + + + + +
+
+
+ Input Objects +
+
+
+
+ + Input Objects + +
+
+ + + + + + + +
+
+
+ Input Scene +
+
+
+
+ + Input Scene + +
+
+ + +
+ + + + + Text is not SVG - cannot display + + + +
diff --git a/img/examples/scene_db.jpg b/img/unused/scene_db.jpg similarity index 100% rename from img/examples/scene_db.jpg rename to img/unused/scene_db.jpg diff --git a/img/examples/scene_hb.jpg b/img/unused/scene_hb.jpg similarity index 100% rename from img/examples/scene_hb.jpg rename to img/unused/scene_hb.jpg diff --git a/img/examples/scene_mb.jpg b/img/unused/scene_mb.jpg similarity index 100% rename from img/examples/scene_mb.jpg rename to img/unused/scene_mb.jpg diff --git a/src/VisioneREmotion/CMakeLists.txt b/src/VisioneREmotion/CMakeLists.txt deleted file mode 100644 index d7cc57c..0000000 --- a/src/VisioneREmotion/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -cmake_minimum_required(VERSION 3.15) -project(VisioneREmotion) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) - -# OpenCV -find_package(OpenCV REQUIRED) -include_directories(${OpenCV_INCLUDE_DIRS}) - -# Config: microlog -add_definitions(-DULOG_HIDE_FILE_STRING) -add_definitions(-DULOG_SHORT_LEVEL_STRINGS) -add_definitions(-DULOG_USE_COLOR) - -# Config: CppLinuxSerial -set(BUILD_TESTS OFF CACHE BOOL "Build tests") - -include(${CMAKE_CURRENT_LIST_DIR}/../../ab.cmake) - -add_main_component(${PROJECT_NAME}) -target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS}) -target_link_libraries(${PROJECT_NAME} PRIVATE CppLinuxSerial::CppLinuxSerial) -target_link_components(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/../common_components/SceneReaderWebcam - ${CMAKE_CURRENT_LIST_DIR}/../common_components/visioner_interfaces - ${CMAKE_CURRENT_LIST_DIR}/../common_components/object_finder - ${CMAKE_CURRENT_LIST_DIR}/../common_components/visioner_base - ${CMAKE_CURRENT_LIST_DIR}/../common_components/microlog - ) - -# Install -FILE(GLOB examples "${CMAKE_CURRENT_LIST_DIR}/../../img/examples/*") -install (FILES ${examples} DESTINATION ./input) diff --git a/src/VisioneREmotion/README.md b/src/VisioneREmotion/README.md deleted file mode 100644 index 46bb324..0000000 --- a/src/VisioneREmotion/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# VisioneREmotion - -Visioner implementation based on reading images from `input` folder and reading scene from a webcam. Expects images of following types: - -- `input/object_good_*` - image of an object for positive response -- `input/object_bad_*` - image of an object for negative response - -In theory, reads all major image formats, but tested only with `jpg` and `png`. diff --git a/src/VisioneREmotion/components/CppLinuxSerial b/src/VisioneREmotion/components/CppLinuxSerial deleted file mode 160000 index 6efc924..0000000 --- a/src/VisioneREmotion/components/CppLinuxSerial +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6efc924aac57df0cfad4b1d517d43153f271360d diff --git a/src/VisioneREmotion/src/AppVisioner.cpp b/src/VisioneREmotion/src/AppVisioner.cpp deleted file mode 100644 index 954b7f0..0000000 --- a/src/VisioneREmotion/src/AppVisioner.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// ************************************************************************* -// -// Copyright (c) 2024 Andrei Gramakov. All rights reserved. -// -// This file is licensed under the terms of the MIT license. -// For a copy, see: https://opensource.org/licenses/MIT -// -// site: https://agramakov.me -// e-mail: mail@agramakov.me -// -// ************************************************************************* - -#include -#include "FaceInterface.hpp" -#include "InputInterface.hpp" -#include "AppVisioner.hpp" - - -AppVisioner::AppVisioner(FaceInterface *face, InputInterface *input, InterfaceSceneReader *scene_input) - : App(face, input, scene_input) -{ -} - -void AppVisioner::Delay(int ms) -{ - cv::waitKey(ms); -} - -void AppVisioner::PreFindAction() -{ - cv::imshow("Scene", m_objectFinder.GetScene()); -} diff --git a/src/VisioneREmotion/src/AppVisioner.hpp b/src/VisioneREmotion/src/AppVisioner.hpp deleted file mode 100644 index 9119bf6..0000000 --- a/src/VisioneREmotion/src/AppVisioner.hpp +++ /dev/null @@ -1,21 +0,0 @@ -// ************************************************************************* -// -// Copyright (c) 2024 Andrei Gramakov. All rights reserved. -// -// site: https://agramakov.me -// e-mail: mail@agramakov.me -// -// ************************************************************************* - -#pragma once - -#include "App/App.hpp" - -class AppVisioner : public App -{ -public: - AppVisioner(FaceInterface *face, InputInterface *input, InterfaceSceneReader *scene_input); - void Delay(int ms) override; - void PreFindAction() override; - ~AppVisioner() = default; -}; diff --git a/src/VisioneREmotion/src/FaceRemotion.cpp b/src/VisioneREmotion/src/FaceRemotion.cpp deleted file mode 100644 index 8421948..0000000 --- a/src/VisioneREmotion/src/FaceRemotion.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// ************************************************************************* -// -// Copyright (c) 2024 Andrei Gramakov. All rights reserved. -// -// site: https://agramakov.me -// e-mail: mail@agramakov.me -// -// ************************************************************************* - -#include -#include -#include - -#include "FaceRemotion.hpp" - -#define CMD_CALM 0x30 -#define CMD_BLINK 0x31 -#define CMD_ANGRY 0x32 -#define CMD_HAPPY 0x33 -#define CMD_SAD 0x34 -#define CMD_DUNNO 0x35 -#define CMD_CONFUSED 0x36 -#define CMD_THINKING 0x37 - -using namespace mn::CppLinuxSerial; - -FaceRemotion::FaceRemotion(std::string port_name, int baudrate) : serialPort(port_name, - BaudRate::B_9600, - NumDataBits::EIGHT, - Parity::NONE, - NumStopBits::ONE) -{ - serialPort.SetTimeout(100); // Block for up to 100ms to receive data - serialPort.Open(); -} - -void FaceRemotion::ShowThinking() -{ - serialPort.Write("7"); -} - -void FaceRemotion::ShowBlink(int delay) -{ - // write(m_serial_port, "0", 1); - serialPort.Write("1"); - Delay(delay); - serialPort.Write("0"); -} - -void FaceRemotion::ShowCalm(int delay) -{ - serialPort.Write("0"); - Delay(delay); -} - -void FaceRemotion::ShowHappy(int delay) -{ - serialPort.Write("3"); - Delay(1000); -} - -void FaceRemotion::ShowSad(int delay) -{ - serialPort.Write("4"); - Delay(1000); -} - -void FaceRemotion::ShowDunno(int delay) -{ - serialPort.Write("5"); - Delay(delay); -} - -void FaceRemotion::ShowConfused(int delay) -{ - serialPort.Write("6"); - Delay(1000); -} - -void FaceRemotion::Delay(int ms) -{ - usleep(ms * 1000); -} - -FaceRemotion::~FaceRemotion() -{ - serialPort.Close(); -} diff --git a/src/VisioneREmotion/src/FaceRemotion.hpp b/src/VisioneREmotion/src/FaceRemotion.hpp deleted file mode 100644 index 207a758..0000000 --- a/src/VisioneREmotion/src/FaceRemotion.hpp +++ /dev/null @@ -1,32 +0,0 @@ -// ************************************************************************* -// -// Copyright (c) 2024 Andrei Gramakov. All rights reserved. -// -// site: https://agramakov.me -// e-mail: mail@agramakov.me -// -// ************************************************************************* - -#pragma once -#include - -#include "FaceInterface.hpp" -#include "CppLinuxSerial/SerialPort.hpp" - -class FaceRemotion : public FaceInterface -{ -public: - FaceRemotion(std::string port_name, int baudrate); - void ShowThinking() override; - void ShowBlink(int delay = 500) override; - void ShowCalm(int delay = 500) override; - void ShowHappy(int delay = 500) override; - void ShowSad(int delay = 500) override; - void ShowDunno(int delay = 500) override; - void ShowConfused(int delay = 500) override; - void Delay(int ms) override; - ~FaceRemotion(); - -private: - mn::CppLinuxSerial::SerialPort serialPort; -}; diff --git a/src/VisioneREmotion/src/main.cpp b/src/VisioneREmotion/src/main.cpp deleted file mode 100644 index 60ba29a..0000000 --- a/src/VisioneREmotion/src/main.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// ************************************************************************* -// -// Copyright (c) 2024 Andrei Gramakov. All rights reserved. -// -// This file is licensed under the terms of the MIT license. -// For a copy, see: https://opensource.org/licenses/MIT -// -// site: https://agramakov.me -// e-mail: mail@agramakov.me -// -// ************************************************************************* - -#include "AppVisioner.hpp" -#include "FaceRemotion.hpp" -#include "App/InputFiles.hpp" -#include "SceneReaderWebcam.hpp" -#include "ulog.h" - -int main(int argc, char **argv) -{ - - ulog_set_level(LOG_INFO); - InputFiles input; - FaceRemotion face("/dev/ttyUSB0", 9600); - SceneReaderWebcam scene_input; - - input.LoadFiles("input"); - - AppVisioner app(&face, &input, &scene_input); - app.Intro(); - - // Until the face is not exiting - int result = 0; - while(1) - { - result = app.RunOnce(true, true); - } - return 0; -} diff --git a/src/VisionerFile/CMakeLists.txt b/src/VisionerFile/CMakeLists.txt index 2e5aa8c..c4fe08d 100644 --- a/src/VisionerFile/CMakeLists.txt +++ b/src/VisionerFile/CMakeLists.txt @@ -2,8 +2,16 @@ cmake_minimum_required(VERSION 3.15) project(VisionerFile) set(CMAKE_CXX_STANDARD 17) +set(CMAKE_AUTOMOC ON) # for QT set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) +# Qt +find_package( + Qt6 + COMPONENTS Widgets + REQUIRED +) + # OpenCV find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) @@ -12,17 +20,32 @@ include_directories(${OpenCV_INCLUDE_DIRS}) add_definitions(-DULOG_HIDE_FILE_STRING) add_definitions(-DULOG_SHORT_LEVEL_STRINGS) add_definitions(-DULOG_USE_COLOR) -include(${CMAKE_CURRENT_LIST_DIR}/../../ab.cmake) + +# Add abcmake +set(ENV{ABCMAKE_PATH} ${CMAKE_CURRENT_LIST_DIR}/../../ab.cmake) +include($ENV{ABCMAKE_PATH}) add_main_component(${PROJECT_NAME}) -target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS}) -target_link_components(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/../common_components/visioner_interfaces - ${CMAKE_CURRENT_LIST_DIR}/../common_components/object_finder - ${CMAKE_CURRENT_LIST_DIR}/../common_components/visioner_base - ${CMAKE_CURRENT_LIST_DIR}/../common_components/microlog - ${CMAKE_CURRENT_LIST_DIR}/../common_components/FaceDesktop) -# Install examples -FILE(GLOB examples "${CMAKE_CURRENT_LIST_DIR}/../../img/examples/*") -install (FILES ${examples} DESTINATION ./input) +register_components( + ${CMAKE_CURRENT_LIST_DIR}/../common_components/microlog + ${CMAKE_CURRENT_LIST_DIR}/../common_components/gui + ${CMAKE_CURRENT_LIST_DIR}/../common_components/visioner_interfaces + ${CMAKE_CURRENT_LIST_DIR}/../common_components/visioner_app + ${CMAKE_CURRENT_LIST_DIR}/../common_components/FaceDesktop +) +target_link_components( + ${PROJECT_NAME} + NAME + visioner_interfaces + visioner_app + microlog + gui + FaceDesktop +) +target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS} Qt6::Widgets) + +# Install examples +file(GLOB examples "${CMAKE_CURRENT_LIST_DIR}/../../img/examples/*") +install(FILES ${examples} DESTINATION ./input) diff --git a/src/VisionerFile/src/AppVisioner.cpp b/src/VisionerFile/src/AppVisioner.cpp index a167e12..6d93a47 100644 --- a/src/VisionerFile/src/AppVisioner.cpp +++ b/src/VisionerFile/src/AppVisioner.cpp @@ -11,25 +11,19 @@ // ************************************************************************* #include +#include #include "FaceInterface.hpp" #include "InputInterface.hpp" #include "InterfaceSceneReader.hpp" #include "AppVisioner.hpp" +AppVisioner::AppVisioner(FaceInterface *face, InputInterface *input, Gui *gui, + InterfaceSceneReader *scene_input) + : App(face, input, gui, scene_input) {} -AppVisioner::AppVisioner(FaceInterface *face, InputInterface *input, InterfaceSceneReader *scene_input) - : App(face, input, scene_input) -{ -} - -void AppVisioner::Delay(int ms) -{ - cv::waitKey(ms); -} +void AppVisioner::Delay(int ms) { usleep(ms * 1000); } -void AppVisioner::PreFindAction() -{ - cv::imshow("Scene", m_objectFinder.GetScene()); - // Intro(); +void AppVisioner::PreFindAction() { + Show("", GetScene()); } diff --git a/src/VisionerFile/src/AppVisioner.hpp b/src/VisionerFile/src/AppVisioner.hpp index 33c4d8f..be34677 100644 --- a/src/VisionerFile/src/AppVisioner.hpp +++ b/src/VisionerFile/src/AppVisioner.hpp @@ -9,15 +9,15 @@ #pragma once -#include "App/App.hpp" +#include "App.hpp" #include "FaceInterface.hpp" #include "InputInterface.hpp" #include "InterfaceSceneReader.hpp" -class AppVisioner : public App -{ -public: - AppVisioner(FaceInterface *face, InputInterface *input, InterfaceSceneReader *scene_input); +class AppVisioner : public App { + public: + AppVisioner(FaceInterface *face, InputInterface *input, Gui *gui, + InterfaceSceneReader *scene_input); void Delay(int ms) override; void PreFindAction() override; ~AppVisioner() = default; diff --git a/src/VisionerFile/src/SceneReaderFileSystem.cpp b/src/VisionerFile/src/SceneReaderFileSystem.cpp index 38f6007..743a4c4 100644 --- a/src/VisionerFile/src/SceneReaderFileSystem.cpp +++ b/src/VisionerFile/src/SceneReaderFileSystem.cpp @@ -8,41 +8,36 @@ // ************************************************************************* #include + #include "SceneReaderFileSystem.hpp" -SceneReaderFileSystem::SceneReaderFileSystem() : - m_file_scanner(nullptr), m_path(""), m_scenes({}), m_scene_cursor(0) -{} +SceneReaderFileSystem::SceneReaderFileSystem() + : m_file_scanner(nullptr), m_path(""), m_scenes({}), m_scene_cursor(0) {} -SceneReaderFileSystem::~SceneReaderFileSystem() -{ - if (m_file_scanner != nullptr) - { +SceneReaderFileSystem::~SceneReaderFileSystem() { + if (m_file_scanner != nullptr) { delete m_file_scanner; } } -void SceneReaderFileSystem::SetPath(const std::string &path) -{ +void SceneReaderFileSystem::SetPath(const std::string &path) { // Set up m_path = path; - if (m_file_scanner != nullptr) - { + if (m_file_scanner != nullptr) { delete m_file_scanner; } m_file_scanner = new FileScanner(m_path); - + // Load pictures m_scenes.clear(); auto scenes = m_file_scanner->GetFiles("scene_"); - for (auto &scene: scenes) { + for (auto &scene : scenes) { m_scenes.push_back(cv::imread(scene)); } } -cv::Mat SceneReaderFileSystem::GetScene() -{ - if(m_scenes.size() == 0) { +cv::Mat SceneReaderFileSystem::GetScene() { + if (m_scenes.size() == 0) { return cv::Mat(); } m_scene_cursor = (m_scene_cursor + 1) % m_scenes.size(); diff --git a/src/VisionerFile/src/SceneReaderFileSystem.hpp b/src/VisionerFile/src/SceneReaderFileSystem.hpp index eda6c65..1cce340 100644 --- a/src/VisionerFile/src/SceneReaderFileSystem.hpp +++ b/src/VisionerFile/src/SceneReaderFileSystem.hpp @@ -12,18 +12,16 @@ #include "FileScanner.hpp" #include "InterfaceSceneReader.hpp" -class SceneReaderFileSystem : public InterfaceSceneReader -{ -public: +class SceneReaderFileSystem : public InterfaceSceneReader { + public: SceneReaderFileSystem(); ~SceneReaderFileSystem(); void SetPath(const std::string &path); cv::Mat GetScene() override; -private: - + + private: FileScanner *m_file_scanner; std::string m_path; std::vector m_scenes; int m_scene_cursor; - }; diff --git a/src/VisionerFile/src/main.cpp b/src/VisionerFile/src/main.cpp index 765e862..9fd0906 100644 --- a/src/VisionerFile/src/main.cpp +++ b/src/VisionerFile/src/main.cpp @@ -10,32 +10,58 @@ // // ************************************************************************* +#include // for handling abort +#include +#include +#include #include "AppVisioner.hpp" #include "FaceDesktop.hpp" -#include "App/InputFiles.hpp" +#include "Gui.hpp" +#include "InputFiles.hpp" #include "SceneReaderFileSystem.hpp" #include "ulog.h" -int main(int argc, char **argv) -{ +// void abort_handler(int) { +// std::cout << "Aborted" < +#include #include "FaceInterface.hpp" +#include "Gui.hpp" #include "InputInterface.hpp" -#include "AppVisioner.hpp" - -AppVisioner::AppVisioner(FaceInterface *face, InputInterface *input, InterfaceSceneReader *scene_input) - : App(face, input, scene_input) -{ -} +AppVisioner::AppVisioner(FaceInterface *face, InputInterface *input, Gui *gui, + InterfaceSceneReader *scene_input) + : App(face, input, gui, scene_input) {} -void AppVisioner::Delay(int ms) -{ - cv::waitKey(ms); -} +void AppVisioner::Delay(int ms) { usleep(ms * 1000); } -void AppVisioner::PreFindAction() -{ - cv::imshow("Scene", m_objectFinder.GetScene()); -} +void AppVisioner::PreFindAction() { Show("Scene", GetScene()); } diff --git a/src/VisionerWebcam/src/AppVisioner.hpp b/src/VisionerWebcam/src/AppVisioner.hpp index 9119bf6..be34677 100644 --- a/src/VisionerWebcam/src/AppVisioner.hpp +++ b/src/VisionerWebcam/src/AppVisioner.hpp @@ -9,12 +9,15 @@ #pragma once -#include "App/App.hpp" +#include "App.hpp" +#include "FaceInterface.hpp" +#include "InputInterface.hpp" +#include "InterfaceSceneReader.hpp" -class AppVisioner : public App -{ -public: - AppVisioner(FaceInterface *face, InputInterface *input, InterfaceSceneReader *scene_input); +class AppVisioner : public App { + public: + AppVisioner(FaceInterface *face, InputInterface *input, Gui *gui, + InterfaceSceneReader *scene_input); void Delay(int ms) override; void PreFindAction() override; ~AppVisioner() = default; diff --git a/src/VisionerWebcam/src/main.cpp b/src/VisionerWebcam/src/main.cpp index d67a631..e434e55 100644 --- a/src/VisionerWebcam/src/main.cpp +++ b/src/VisionerWebcam/src/main.cpp @@ -12,27 +12,28 @@ #include "AppVisioner.hpp" #include "FaceDesktop.hpp" -#include "App/InputFiles.hpp" +#include "Gui.hpp" +#include "InputFiles.hpp" #include "SceneReaderWebcam.hpp" #include "ulog.h" -int main(int argc, char **argv) -{ - +int main(int argc, char **argv) { + Gui gui; + gui.Start(); + ulog_set_level(LOG_INFO); InputFiles input; - FaceDesktop face; + FaceDesktop face(gui); SceneReaderWebcam scene_input; - + input.LoadFiles("input"); - AppVisioner app(&face, &input, &scene_input); - app.Intro(); - + AppVisioner app(&face, &input, &gui, &scene_input); + // app.Intro(); + // Until the face is not exiting int result = 0; - while(!face.IsExit()) - { + while (!face.IsExit()) { result = app.RunOnce(true, true); } return 0; diff --git a/src/common_components/FaceDesktop/CMakeLists.txt b/src/common_components/FaceDesktop/CMakeLists.txt index fa5307f..9989391 100644 --- a/src/common_components/FaceDesktop/CMakeLists.txt +++ b/src/common_components/FaceDesktop/CMakeLists.txt @@ -1,15 +1,22 @@ cmake_minimum_required(VERSION 3.5) project(FaceDesktop) +# QT +set(CMAKE_AUTOMOC ON) # for QT +find_package( + Qt6 + COMPONENTS Widgets + REQUIRED +) + # OpenCV find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) -include(${CMAKE_CURRENT_LIST_DIR}/../../../ab.cmake) +include($ENV{ABCMAKE_PATH}) add_component(${PROJECT_NAME}) -target_link_components(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/../visioner_interfaces) -target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS}) +target_link_components(${PROJECT_NAME} NAME visioner_interfaces gui) +target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS} Qt6::Widgets) - -FILE(GLOB faces "components/universal_faces/png/*") -install (FILES ${faces} DESTINATION ./faces) +file(GLOB faces "components/universal_faces/png/*") +install(FILES ${faces} DESTINATION ./faces) diff --git a/src/common_components/FaceDesktop/include/FaceDesktop.hpp b/src/common_components/FaceDesktop/include/FaceDesktop.hpp index 44f9581..4fc6601 100644 --- a/src/common_components/FaceDesktop/include/FaceDesktop.hpp +++ b/src/common_components/FaceDesktop/include/FaceDesktop.hpp @@ -9,16 +9,18 @@ #pragma once +#include +#include #include +#include #include #include -#include -#include "FaceInterface.hpp" +#include "Gui.hpp" -class FaceDesktop : public FaceInterface -{ +#include "FaceInterface.hpp" -public: +class FaceDesktop : public FaceInterface { + public: static const int WIN_SIZE_X = 500; static const int WIN_SIZE_Y = 256; static constexpr char WIN_NAME[] = "VisioneR"; @@ -31,9 +33,9 @@ class FaceDesktop : public FaceInterface {"happy", "faces/happy.png"}, {"sad", "faces/sad.png"}, {"dunno", "faces/dunno.png"}, - {"confused", "faces/confused.png"} }; + {"confused", "faces/confused.png"}}; - FaceDesktop(); + FaceDesktop(Gui &gui); void ShowThinking() override; void ShowBlink(int delay = 500) override; void ShowCalm(int delay = 500) override; @@ -43,12 +45,15 @@ class FaceDesktop : public FaceInterface void ShowConfused(int delay = 500) override; bool IsExit(); -private: - static const int WAIT_DELTA = 100; + private: + QPixmap ToQPixmap(const cv::Mat mat); void Delay(int delay) override; uint64_t GetTimeMs(); - std::map m_images; - bool m_exit = false; - int m_show_count = 0; + static const int WAIT_DELTA = 100; + + std::map m_images; + Gui *m_gui; + bool m_exit; + int m_show_count; }; diff --git a/src/common_components/FaceDesktop/src/FaceDesktop.cpp b/src/common_components/FaceDesktop/src/FaceDesktop.cpp index 61de185..e1c7167 100644 --- a/src/common_components/FaceDesktop/src/FaceDesktop.cpp +++ b/src/common_components/FaceDesktop/src/FaceDesktop.cpp @@ -7,107 +7,82 @@ // // ************************************************************************* #include -#include +#include #include #include -#include +#include +#include #include "FaceDesktop.hpp" using namespace cv; using namespace std::chrono; -FaceDesktop::FaceDesktop() -{ +FaceDesktop::FaceDesktop(Gui &gui) + : m_images({}), m_gui(&gui), m_exit(false), m_show_count(0) { // Load all images by the paths from m_img_paths - for (auto &img : m_img_paths) - { - m_images[img.first] = imread(img.second); - if (m_images[img.first].empty()) - { + for (auto &img : m_img_paths) { + m_images[img.first] = QImage(img.second.c_str()); + if (m_images[img.first].isNull()) { printf("Error: can't load image %s\n", img.second.c_str()); throw std::runtime_error("Can't load image"); } } - - // Create window - namedWindow(WIN_NAME, WINDOW_GUI_EXPANDED); - ShowCalm(1); - resizeWindow(WIN_NAME, WIN_SIZE_X, WIN_SIZE_Y); } -void FaceDesktop::ShowThinking() -{ +void FaceDesktop::ShowThinking() { int w_time = 350; - imshow(WIN_NAME, m_images["thinking1"]); + m_gui->SetImageLeft(m_images["thinking1"]); Delay(w_time); - imshow(WIN_NAME, m_images["thinking2"]); + m_gui->SetImageLeft(m_images["thinking2"]); Delay(w_time); - imshow(WIN_NAME, m_images["thinking3"]); + m_gui->SetImageLeft(m_images["thinking3"]); Delay(w_time); } -void FaceDesktop::ShowBlink(int delay) -{ - imshow(WIN_NAME, m_images["blink"]); +void FaceDesktop::ShowBlink(int delay) { + m_gui->SetImageLeft(m_images["blink"]); Delay(delay); } -void FaceDesktop::ShowCalm(int delay) -{ - imshow(WIN_NAME, m_images["calm"]); +void FaceDesktop::ShowCalm(int delay) { + m_gui->SetImageLeft(m_images["calm"]); Delay(delay); } -void FaceDesktop::ShowHappy(int delay) -{ - imshow(WIN_NAME, m_images["happy"]); +void FaceDesktop::ShowHappy(int delay) { + m_gui->SetImageLeft(m_images["happy"]); Delay(delay); } -void FaceDesktop::ShowSad(int delay) -{ - imshow(WIN_NAME, m_images["sad"]); +void FaceDesktop::ShowSad(int delay) { + m_gui->SetImageLeft(m_images["sad"]); Delay(delay); } -void FaceDesktop::ShowDunno(int delay) -{ - imshow(WIN_NAME, m_images["dunno"]); +void FaceDesktop::ShowDunno(int delay) { + m_gui->SetImageLeft(m_images["dunno"]); Delay(delay); } -void FaceDesktop::ShowConfused(int delay) -{ - imshow(WIN_NAME, m_images["confused"]); +void FaceDesktop::ShowConfused(int delay) { + m_gui->SetImageLeft(m_images["confused"]); Delay(delay); } -bool FaceDesktop::IsExit() -{ - return m_exit; +bool FaceDesktop::IsExit() { return m_exit; } + +QPixmap FaceDesktop::ToQPixmap(const cv::Mat mat) { + auto img = QImage((unsigned char *)mat.data, mat.cols, mat.rows, + QImage::Format_RGB888); + return QPixmap::fromImage(img); } -void FaceDesktop::Delay(int delay) -{ - uint64_t start = GetTimeMs(); - while (GetTimeMs() - start < delay) - { - // Check for ESC key - if (waitKey(WAIT_DELTA) == 27) // ESC - { - m_exit = true; - } - - // Stop Delaying if exiting - if (m_exit) - { - return; - } - } +void FaceDesktop::Delay(int delay) { + usleep(1000 * delay); } -uint64_t FaceDesktop::GetTimeMs() -{ - return duration_cast(system_clock::now().time_since_epoch()).count(); +uint64_t FaceDesktop::GetTimeMs() { + return duration_cast(system_clock::now().time_since_epoch()) + .count(); } diff --git a/src/common_components/SceneReaderWebcam/CMakeLists.txt b/src/common_components/SceneReaderWebcam/CMakeLists.txt index b357e57..e64b246 100644 --- a/src/common_components/SceneReaderWebcam/CMakeLists.txt +++ b/src/common_components/SceneReaderWebcam/CMakeLists.txt @@ -1,7 +1,8 @@ cmake_minimum_required(VERSION 3.15) project(SceneReaderWebcam) -include(${CMAKE_CURRENT_LIST_DIR}/../../../ab.cmake) -add_component(${PROJECT_NAME} SOURCE_DIR "." - INCLUDE_DIR ".") -target_link_components(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/../visioner_interfaces) +include($ENV{ABCMAKE_PATH}) +add_component(${PROJECT_NAME} SOURCE_DIR "." INCLUDE_DIR ".") +target_link_components( + ${PROJECT_NAME} PATH ${CMAKE_CURRENT_LIST_DIR}/../visioner_interfaces +) diff --git a/src/common_components/SceneReaderWebcam/SceneReaderWebcam.cpp b/src/common_components/SceneReaderWebcam/SceneReaderWebcam.cpp index 4f9b275..77a615c 100644 --- a/src/common_components/SceneReaderWebcam/SceneReaderWebcam.cpp +++ b/src/common_components/SceneReaderWebcam/SceneReaderWebcam.cpp @@ -7,16 +7,13 @@ // // ************************************************************************* -#include #include "SceneReaderWebcam.hpp" +#include -SceneReaderWebcam::SceneReaderWebcam() : cap(0) -{ -} +SceneReaderWebcam::SceneReaderWebcam() : cap(0) {} -cv::Mat SceneReaderWebcam::GetScene() -{ - if (!cap.isOpened()) // check if we succeeded +cv::Mat SceneReaderWebcam::GetScene() { + if (!cap.isOpened()) // check if we succeeded return cv::Mat(); cap >> m_scene; return m_scene; diff --git a/src/common_components/SceneReaderWebcam/SceneReaderWebcam.hpp b/src/common_components/SceneReaderWebcam/SceneReaderWebcam.hpp index a68f62f..a74f001 100644 --- a/src/common_components/SceneReaderWebcam/SceneReaderWebcam.hpp +++ b/src/common_components/SceneReaderWebcam/SceneReaderWebcam.hpp @@ -1,24 +1,23 @@ - // ************************************************************************* - // - // Copyright (c) 2024 Andrei Gramakov. All rights reserved. - // - // site: https://agramakov.me - // e-mail: mail@agramakov.me - // - // ************************************************************************* - - #pragma once - +// ************************************************************************* +// +// Copyright (c) 2024 Andrei Gramakov. All rights reserved. +// +// site: https://agramakov.me +// e-mail: mail@agramakov.me +// +// ************************************************************************* + +#pragma once + #include #include "InterfaceSceneReader.hpp" - -class SceneReaderWebcam : public InterfaceSceneReader -{ -public: +class SceneReaderWebcam : public InterfaceSceneReader { + public: SceneReaderWebcam(); cv::Mat GetScene() override; -private: + + private: cv::Mat m_scene; cv::VideoCapture cap; }; diff --git a/src/common_components/common_components.cmake b/src/common_components/common_components.cmake new file mode 100644 index 0000000..f587101 --- /dev/null +++ b/src/common_components/common_components.cmake @@ -0,0 +1,3 @@ +if(NOT ABCMAKE) + message(FATAL_ERROR "Please import ab.cmake") +endif() diff --git a/src/common_components/eventpp b/src/common_components/eventpp new file mode 160000 index 0000000..c472fb2 --- /dev/null +++ b/src/common_components/eventpp @@ -0,0 +1 @@ +Subproject commit c472fb22e71ead0e58ff7df89e12c66b0bdfb533 diff --git a/src/common_components/gui/CMakeLists.txt b/src/common_components/gui/CMakeLists.txt new file mode 100644 index 0000000..cc30442 --- /dev/null +++ b/src/common_components/gui/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.5) +project(gui) + +set(CMAKE_AUTOMOC ON) # for QT +find_package( + Qt6 + COMPONENTS Widgets + REQUIRED +) + +include($ENV{ABCMAKE_PATH}) +add_component(gui) + +# add headers to sources so CMAKE_AUTOMOC can see them +target_sources(${PROJECT_NAME} PRIVATE src/MainWindow.hpp) + +target_link_libraries(${PROJECT_NAME} Qt6::Widgets) diff --git a/src/common_components/gui/include/Gui.hpp b/src/common_components/gui/include/Gui.hpp new file mode 100644 index 0000000..bda3e82 --- /dev/null +++ b/src/common_components/gui/include/Gui.hpp @@ -0,0 +1,43 @@ +// ************************************************************************* +// +// Copyright (c) 2024 Andrei Gramakov. All rights reserved. +// +// site: https://agramakov.me +// e-mail: mail@agramakov.me +// +// ************************************************************************* + +#pragma once + +#include +#include +#include +#include + +class MainWindow; // Forward declaration +class QApplication; // Forward declaration + +class Gui { + public: + ~Gui(); + void Start(); + bool isReady(); + bool isClosed(); + + // Sets image. Thread safe. + void SetImageLeft(QPixmap &img); + + void SetImageLeft(QImage &img); + + // Sets image. Thread safe. + void SetImageRight(QPixmap &img); + void SetImageRight(QImage &img); + + private: + static void thread_func(Gui *self); + + QApplication *m_qapp; + MainWindow *m_window; + std::thread m_thread; + std::mutex m_mux; +}; diff --git a/src/common_components/gui/src/Gui.cpp b/src/common_components/gui/src/Gui.cpp new file mode 100644 index 0000000..32a9a99 --- /dev/null +++ b/src/common_components/gui/src/Gui.cpp @@ -0,0 +1,84 @@ +// ************************************************************************* +// +// Copyright (c) 2024 Andrei Gramakov. All rights reserved. +// +// This file is licensed under the terms of the MIT license. +// For a copy, see: https://opensource.org/licenses/MIT +// +// site: https://agramakov.me +// e-mail: mail@agramakov.me +// +// ************************************************************************* + +#include "Gui.hpp" + +#include +#include +#include +#include +#include "MainWindow.hpp" + +void Gui::Start() { + m_thread = std::thread(thread_func, this); + while (!isReady()) { + } +} + +Gui::~Gui() { m_thread.join(); } + +bool Gui::isReady() { + if (m_qapp == nullptr) { + return false; + } + return !(m_qapp->startingUp()); +} + +bool Gui::isClosed() { + if (m_window == nullptr) { + return true; + } + return m_window->isClosed(); +} + +void Gui::SetImageLeft(QPixmap &img) { + if (m_window != nullptr) { + m_mux.lock(); + m_window->SetImageLeft(img); + m_mux.unlock(); + } +} + +void Gui::SetImageLeft(QImage &img) { + int w = img.width(); + QPixmap pixmap; + pixmap.convertFromImage(img); + w = pixmap.width(); + SetImageLeft(pixmap); +} + +void Gui::SetImageRight(QImage &img) { + QPixmap pixmap; + pixmap.convertFromImage(img); + SetImageRight(pixmap); +} + +void Gui::SetImageRight(QPixmap &img) { + if (m_window != nullptr) { + m_mux.lock(); + m_window->SetImageRight(img); + m_mux.unlock(); + } +} + +void Gui::thread_func(Gui *self) { + int argc = 0; + char **argv = {}; + // Name the thread + pthread_setname_np(pthread_self(), "Gui"); + + self->m_qapp = new QApplication(argc, argv); + self->m_window = new MainWindow; + self->m_window->show(); + self->m_qapp->exec(); + std::cout << "Gui Closed" << std::endl; +} diff --git a/src/common_components/gui/src/MainWindow.cpp b/src/common_components/gui/src/MainWindow.cpp new file mode 100644 index 0000000..1f4c88f --- /dev/null +++ b/src/common_components/gui/src/MainWindow.cpp @@ -0,0 +1,76 @@ +// ************************************************************************* +// +// Copyright (c) 2024 Andrei Gramakov. All rights reserved. +// +// site: https://agramakov.me +// e-mail: mail@agramakov.me +// +// ************************************************************************* + +#include "MainWindow.hpp" +#include +#include +#include +#include +#include +#include + +MainWindow::MainWindow() + : m_imageLeft(nullptr), m_imageRight(nullptr), m_closed(false) { + // Create QLabel widgets for the images + m_imageLeft = new QLabel(this); + m_imageRight = new QLabel(this); + + // Set the label positions and sizes + m_imageLeft->setGeometry(10, 10, LEFT_W, LEFT_H); + m_imageRight->setGeometry(20 + RIGHT_W, 10, RIGHT_W, RIGHT_H); + + // Set the main window properties + setCentralWidget(m_imageLeft); // Set imageLabel1 as central widget + setWindowTitle("VisioneR GUI"); + resize(2 * 20 + LEFT_W + RIGHT_W, RIGHT_H + 20); // Set the window size + + // Load the images (replace with actual file paths) + SetImageLeft("faces/calm.png"); + SetImageRight("faces/blink.png"); +} + +void MainWindow::SetImageLeft(std::string path) { + QPixmap img(path.c_str()); + SetImageLeft(img); +} + +void MainWindow::SetImageRight(std::string path) { + QPixmap img(path.c_str()); + SetImageRight(img); +} + +void MainWindow::SetImageLeft(const QPixmap &img) { + // Resize and set + QPixmap resizedImg = img.scaled(LEFT_W, LEFT_H, Qt::KeepAspectRatio); + m_imageLeft->setPixmap(resizedImg); +} + +void MainWindow::SetImageRight(const QPixmap &img) { + // Resize and set + QPixmap resizedImg = img.scaled(RIGHT_W, RIGHT_H, Qt::KeepAspectRatio); + m_imageRight->setPixmap(resizedImg); +} + +bool MainWindow::isClosed() { return m_closed; } + +MainWindow::~MainWindow() { + delete m_imageLeft; + delete m_imageRight; +} + +void MainWindow::closeEvent(QCloseEvent *event) { + m_closed = true; + std::cout << "Bye" << std::endl; +} + +void MainWindow::keyPressEvent(QKeyEvent *event) { + if (event->key() == Qt::Key_Escape) { + close(); + } +} diff --git a/src/common_components/gui/src/MainWindow.hpp b/src/common_components/gui/src/MainWindow.hpp new file mode 100644 index 0000000..9a20f06 --- /dev/null +++ b/src/common_components/gui/src/MainWindow.hpp @@ -0,0 +1,44 @@ +// ************************************************************************* +// +// Copyright (c) 2024 Andrei Gramakov. All rights reserved. +// +// site: https://agramakov.me +// e-mail: mail@agramakov.me +// +// ************************************************************************* + +#pragma once + +#include +#include + +// Forward declarations +class QLabel; +class QPixmap; + +class MainWindow : public QMainWindow { + Q_OBJECT + + public: + MainWindow(); + void SetImageLeft(std::string path); + void SetImageLeft(const QPixmap &img); + void SetImageRight(std::string path); + void SetImageRight(const QPixmap &img); + bool isClosed(); + ~MainWindow(); + + protected: + static const int LEFT_W = 640; + static const int LEFT_H = 480; + static const int RIGHT_W = 640; + static const int RIGHT_H = 480; + + void closeEvent(QCloseEvent *event); + + private: + QLabel *m_imageLeft; + QLabel *m_imageRight; + bool m_closed; + void keyPressEvent(QKeyEvent *event) override; +}; diff --git a/src/common_components/microlog b/src/common_components/microlog index 44f4dba..4b2d00f 160000 --- a/src/common_components/microlog +++ b/src/common_components/microlog @@ -1 +1 @@ -Subproject commit 44f4dbaf927aea391d0fd1e1668be7330c8aa9ce +Subproject commit 4b2d00ffa8094372860107de8ade26e00f0a97b0 diff --git a/src/common_components/object_finder/src/Quadrilateral.cpp b/src/common_components/object_finder/src/Quadrilateral.cpp deleted file mode 100644 index 5ae9dfe..0000000 --- a/src/common_components/object_finder/src/Quadrilateral.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include "Quadrilateral.hpp" - -Quadrilateral::Quadrilateral(Point2f p1, Point2f p2, Point2f p3, Point2f p4) - : arr({p1, p2, p3, p4}) -{ -} - -Point2f Quadrilateral::GetCenter() -{ - return (arr[0] + arr[1] + arr[2] + arr[3]) / 4; -} - -array Quadrilateral::GetSides() -{ - - return {_GetDistance(arr[0], arr[1]), - _GetDistance(arr[1], arr[2]), - _GetDistance(arr[2], arr[3]), - _GetDistance(arr[3], arr[0])}; -} - -float Quadrilateral::GetArea() -{ - array s = GetSides(); - float semip = (s[0] + s[1] + s[2] + s[3]) / 2; - float result = sqrt((semip - s[0]) * (semip - s[1]) * (semip - s[2]) * (semip - s[3])); - return isnan(result) ? 0 : result; -} - -Point2f &Quadrilateral::operator[](int i) -{ - return arr[i]; -} - -const Point2f &Quadrilateral::operator[](int i) const -{ - return arr[i]; -} - -float Quadrilateral::GetPerimeter() -{ - array sides = GetSides(); - return sides[0] + sides[1] + sides[2] + sides[3]; -} - -vector Quadrilateral::GetIntegerPoints() -{ - vector res; - for (auto p : arr) - { - res.push_back(p); - } - return res; -} - -float Quadrilateral::_GetDistance(Point2f &p_a, Point2f &p_b) -{ - return sqrt((p_a.x - p_b.x) * (p_a.x - p_b.x) + - (p_a.y - p_b.y) * (p_a.y - p_b.y)); -} diff --git a/src/common_components/visioner_app/CMakeLists.txt b/src/common_components/visioner_app/CMakeLists.txt new file mode 100644 index 0000000..9eb1029 --- /dev/null +++ b/src/common_components/visioner_app/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.5) +project(visioner_app) + +set(CMAKE_AUTOMOC ON) # for QT +find_package( + Qt6 + COMPONENTS Widgets + REQUIRED +) + +include($ENV{ABCMAKE_PATH}) +add_component(visioner_app) + +target_link_components(visioner_app NAME gui microlog visioner_interfaces) +target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets) diff --git a/src/common_components/visioner_base/README.md b/src/common_components/visioner_app/README.md similarity index 100% rename from src/common_components/visioner_base/README.md rename to src/common_components/visioner_app/README.md diff --git a/src/common_components/object_finder/CMakeLists.txt b/src/common_components/visioner_app/components/object_finder/CMakeLists.txt similarity index 64% rename from src/common_components/object_finder/CMakeLists.txt rename to src/common_components/visioner_app/components/object_finder/CMakeLists.txt index 17bdc70..86cbaf1 100644 --- a/src/common_components/object_finder/CMakeLists.txt +++ b/src/common_components/visioner_app/components/object_finder/CMakeLists.txt @@ -5,7 +5,7 @@ project(object_finder) find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) -include(${CMAKE_CURRENT_LIST_DIR}/../../../ab.cmake) +include($ENV{ABCMAKE_PATH}) add_component(${PROJECT_NAME}) -target_link_component(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}/../microlog) +target_link_components(${PROJECT_NAME} NAME microlog) target_link_libraries(${PROJECT_NAME} PRIVATE ${OpenCV_LIBS}) diff --git a/src/common_components/object_finder/include/ObjectFinder.hpp b/src/common_components/visioner_app/components/object_finder/include/ObjectFinder.hpp similarity index 67% rename from src/common_components/object_finder/include/ObjectFinder.hpp rename to src/common_components/visioner_app/components/object_finder/include/ObjectFinder.hpp index 82e7c55..bd5b8df 100644 --- a/src/common_components/object_finder/include/ObjectFinder.hpp +++ b/src/common_components/visioner_app/components/object_finder/include/ObjectFinder.hpp @@ -15,31 +15,26 @@ #include "Quadrilateral.hpp" -class ObjectFinder -{ -public: +class ObjectFinder { + public: Quadrilateral Find(Mat &objectImg); const cv::Mat &GetScene() const { return m_sceneImg; } bool SetScene(cv::Mat &sceneImg); -private: - bool _DetectKeypoints(std::string image_name, - cv::Mat &img, + private: + bool _DetectKeypoints(std::string image_name, cv::Mat &img, std::vector &keypoints, bool show = false); - bool _ComputeDescriptors(std::string image_name, - cv::Mat &img, + bool _ComputeDescriptors(std::string image_name, cv::Mat &img, std::vector &keypoints, cv::Mat &descriptors); - bool _MatchDescriptors(cv::Mat &results, - cv::Mat &dists, + bool _MatchDescriptors(cv::Mat &results, cv::Mat &dists, std::vector> &matches, bool useBFMatcher = false); - bool _FindGoodMatches(cv::Mat &results, - cv::Mat &dists, + bool _FindGoodMatches(cv::Mat &results, cv::Mat &dists, std::vector> &matches, std::vector &src_points, std::vector &dst_points, @@ -50,17 +45,16 @@ class ObjectFinder bool _FindHomography(std::vector &src_points, std::vector &dst_points, - std::vector &outlier_mask, - cv::Mat &H, + std::vector &outlier_mask, cv::Mat &H, unsigned int minInliers = 8); - Quadrilateral _GetObjectRectangle(cv::Mat &objectImg, - cv::Mat &sceneImg, - cv::Mat &H); - - bool _ValidateObjectQuadrilateral(Quadrilateral &sceneObjectQuadrilateral, - cv::Mat &origObjectImg, int a2p_ratio = VALIDATION_OBJA2P_VS_SCENEA2P); + Quadrilateral _GetObjectRectangle(cv::Mat &objectImg, cv::Mat &sceneImg, + cv::Mat &H); + bool + _ValidateObjectQuadrilateral(Quadrilateral &sceneObjectQuadrilateral, + cv::Mat &origObjectImg, + int a2p_ratio = VALIDATION_OBJA2P_VS_SCENEA2P); static const int VALIDATION_OBJA2P_VS_SCENEA2P = 5; std::vector m_objectKeypoints; diff --git a/src/common_components/object_finder/include/Quadrilateral.hpp b/src/common_components/visioner_app/components/object_finder/include/Quadrilateral.hpp similarity index 86% rename from src/common_components/object_finder/include/Quadrilateral.hpp rename to src/common_components/visioner_app/components/object_finder/include/Quadrilateral.hpp index 9ac0456..f44e6ca 100644 --- a/src/common_components/object_finder/include/Quadrilateral.hpp +++ b/src/common_components/visioner_app/components/object_finder/include/Quadrilateral.hpp @@ -8,31 +8,29 @@ // ************************************************************************* #pragma once -#include #include #include +#include using namespace cv; using namespace std; -class Quadrilateral -{ -public: - Quadrilateral() = default; +class Quadrilateral { + public: + Quadrilateral() = default; Quadrilateral(Point2f p1, Point2f p2, Point2f p3, Point2f p4); Point2f GetCenter(); - arrayGetSides(); + array GetSides(); float GetArea(); float GetPerimeter(); vector GetIntegerPoints(); - + // overload operator [] Point2f &operator[](int i); const Point2f &operator[](int i) const; array arr; - -private: + + private: float _GetDistance(Point2f &p_a, Point2f &p_b); - }; diff --git a/src/common_components/object_finder/include/Visualizer.hpp b/src/common_components/visioner_app/components/object_finder/include/Visualizer.hpp similarity index 68% rename from src/common_components/object_finder/include/Visualizer.hpp rename to src/common_components/visioner_app/components/object_finder/include/Visualizer.hpp index 0701848..75e677b 100644 --- a/src/common_components/object_finder/include/Visualizer.hpp +++ b/src/common_components/visioner_app/components/object_finder/include/Visualizer.hpp @@ -12,24 +12,21 @@ #include #include "Quadrilateral.hpp" -class Visualizer -{ -public: +class Visualizer { + public: Visualizer() = default; void SetImg(cv::Mat img); cv::Mat SelectAndDismiss(Quadrilateral selection); - cv::Mat & GetSceneWithSelection(); - cv::Mat & GetSceneWithoutSelectedObjects(); + cv::Mat &GetSceneWithSelection(); + cv::Mat &GetSceneWithoutSelectedObjects(); -private: + private: cv::Mat m_img_orig; cv::Mat m_img_selection; cv::Mat m_img_dismissed; - static void DrawQuadrilateral(cv::Mat &img, - Quadrilateral selection, + static void DrawQuadrilateral(cv::Mat &img, Quadrilateral selection, bool crossed, cv::Scalar color = Scalar(0, 255, 0), int thickness = 2); - static void ClearQuadrilateral(cv::Mat &img, - Quadrilateral selection); + static void ClearQuadrilateral(cv::Mat &img, Quadrilateral selection); }; diff --git a/src/common_components/object_finder/src/ObjectFinder.cpp b/src/common_components/visioner_app/components/object_finder/src/ObjectFinder.cpp similarity index 58% rename from src/common_components/object_finder/src/ObjectFinder.cpp rename to src/common_components/visioner_app/components/object_finder/src/ObjectFinder.cpp index 4ad18fb..b9fa292 100644 --- a/src/common_components/object_finder/src/ObjectFinder.cpp +++ b/src/common_components/visioner_app/components/object_finder/src/ObjectFinder.cpp @@ -10,12 +10,12 @@ // // ************************************************************************* -#include // for homography +#include // for homography #include #include #include #include -#include // for wrapPerspective +#include // for wrapPerspective #include #include @@ -28,18 +28,17 @@ using namespace cv; using namespace std; -bool ObjectFinder::_ValidateObjectQuadrilateral(Quadrilateral &sceneObjectQuadrilateral, - cv::Mat &origObjectImg, int a2p_ratio) -{ +bool ObjectFinder::_ValidateObjectQuadrilateral( + Quadrilateral &sceneObjectQuadrilateral, cv::Mat &origObjectImg, + int a2p_ratio) { // Validate object quadrilateral is in the scene - for (auto p : sceneObjectQuadrilateral.arr) - { - if (p.x < 0 || p.y < 0 || p.x > m_sceneImg.cols || p.y > m_sceneImg.rows) - { + for (auto p : sceneObjectQuadrilateral.arr) { + if (p.x < 0 || p.y < 0 || p.x > m_sceneImg.cols || + p.y > m_sceneImg.rows) { return false; } } - + // Object A2P float origObjArea = origObjectImg.rows * origObjectImg.cols; float origObjPerimeter = 2 * (origObjectImg.rows + origObjectImg.cols); @@ -49,42 +48,42 @@ bool ObjectFinder::_ValidateObjectQuadrilateral(Quadrilateral &sceneObjectQuadri sceneObjPerimeter = isnan(sceneObjPerimeter) ? 0 : sceneObjPerimeter; auto obj_area = sceneObjectQuadrilateral.GetArea(); obj_area = isnan(obj_area) ? 0 : obj_area; - + // Scene A2P - float sceneObjA2P = sceneObjPerimeter == 0 ? 0 : obj_area / sceneObjPerimeter; + float sceneObjA2P = + sceneObjPerimeter == 0 ? 0 : obj_area / sceneObjPerimeter; - // log_debug("Validation orig A2P vs scene A2P: %f | %f", origA2P, sceneObjA2P); + // log_debug("Validation orig A2P vs scene A2P: %f | %f", origA2P, + // sceneObjA2P); log_debug("Validation orig A2P / scene A2P: %f", origA2P / sceneObjA2P); - if (origA2P / sceneObjA2P > a2p_ratio) - { + if (origA2P / sceneObjA2P > a2p_ratio) { return false; } - + // Obj size auto scene_area = m_sceneImg.rows * m_sceneImg.cols; auto obj_area_ratio = scene_area / obj_area; - if (obj_area_ratio > 10) - { + if (obj_area_ratio > 10) { return false; } return true; } -Quadrilateral ObjectFinder::Find(Mat &objectImg) -{ +Quadrilateral ObjectFinder::Find(Mat &objectImg) { m_objectImg = objectImg; - if (m_objectImg.empty() || m_sceneImg.empty()) - { + if (m_objectImg.empty() || m_sceneImg.empty()) { log_error("Empty images"); return Quadrilateral(); } _DetectKeypoints("Object", m_objectImg, m_objectKeypoints, false); - _ComputeDescriptors("Object", m_objectImg, m_objectKeypoints, m_objectDescriptors); + _ComputeDescriptors("Object", m_objectImg, m_objectKeypoints, + m_objectDescriptors); _DetectKeypoints("Scene", m_sceneImg, m_sceneKeypoints); - _ComputeDescriptors("Scene", m_sceneImg, m_sceneKeypoints, m_sceneDescriptors); + _ComputeDescriptors("Scene", m_sceneImg, m_sceneKeypoints, + m_sceneDescriptors); bool useBFMatcher = true; @@ -97,35 +96,34 @@ Quadrilateral ObjectFinder::Find(Mat &objectImg) vector src_points, dst_points; vector src_point_idxs, dst_point_idxs; vector outlier_mask; - _FindGoodMatches(results, dists, matches, - src_points, dst_points, src_point_idxs, dst_point_idxs, - outlier_mask, useBFMatcher); + _FindGoodMatches(results, dists, matches, src_points, dst_points, + src_point_idxs, dst_point_idxs, outlier_mask, + useBFMatcher); // Find homography Mat H; bool result = false; result = _FindHomography(src_points, dst_points, outlier_mask, H, 20); - if (!result) - { + if (!result) { log_debug("homography not found"); return Quadrilateral(); } // Get result - Quadrilateral found_object = _GetObjectRectangle(m_objectImg, m_sceneImg, H); + Quadrilateral found_object = + _GetObjectRectangle(m_objectImg, m_sceneImg, H); // Check - if (!_ValidateObjectQuadrilateral(found_object, m_objectImg, ObjectFinder::VALIDATION_OBJA2P_VS_SCENEA2P)) - { + if (!_ValidateObjectQuadrilateral( + found_object, m_objectImg, + ObjectFinder::VALIDATION_OBJA2P_VS_SCENEA2P)) { return Quadrilateral(); } return found_object; } -bool ObjectFinder::SetScene(cv::Mat &sceneImg) -{ - if (sceneImg.empty()) - { +bool ObjectFinder::SetScene(cv::Mat &sceneImg) { + if (sceneImg.empty()) { log_error("Empty/no image"); return false; } @@ -133,23 +131,19 @@ bool ObjectFinder::SetScene(cv::Mat &sceneImg) return true; } -bool ObjectFinder::_DetectKeypoints(string image_name, - Mat &img, - vector &keypoints, - bool show) -{ +bool ObjectFinder::_DetectKeypoints(string image_name, Mat &img, + vector &keypoints, bool show) { Ptr detector = getFeatureDetector(); detector->detect(img, keypoints); log_debug("[%s] %d keypoints detected", image_name.c_str(), (int)keypoints.size()); - if (show) - { + if (show) { // Draw keypoints Mat img_keypoints = img.clone(); - drawKeypoints(img_keypoints, keypoints, img_keypoints, - Scalar::all(-1), DrawMatchesFlags::DRAW_RICH_KEYPOINTS); + drawKeypoints(img_keypoints, keypoints, img_keypoints, Scalar::all(-1), + DrawMatchesFlags::DRAW_RICH_KEYPOINTS); // show imshow("Keypoints", img_keypoints); waitKey(1500); @@ -157,41 +151,35 @@ bool ObjectFinder::_DetectKeypoints(string image_name, return true; } -bool ObjectFinder::_ComputeDescriptors(string image_name, - Mat &img, +bool ObjectFinder::_ComputeDescriptors(string image_name, Mat &img, vector &keypoints, - Mat &descriptors) -{ - if (keypoints.size() == 0) - { + Mat &descriptors) { + if (keypoints.size() == 0) { log_error("[%s]: no keypoints", image_name.c_str()); return false; } Ptr extractor = getDescriptorExtractor(); extractor->compute(img, keypoints, descriptors); - log_debug("[%s] %d descriptors extracted", - image_name.c_str(), + log_debug("[%s] %d descriptors extracted", image_name.c_str(), descriptors.rows); return true; } bool ObjectFinder::_MatchDescriptors(Mat &results, Mat &dists, - vector> &matches, bool useBFMatcher) -{ - int k = 2; // find the 2 nearest neighbors - if (m_objectDescriptors.type() == CV_8U) - { + vector> &matches, + bool useBFMatcher) { + int k = 2; // find the 2 nearest neighbors + if (m_objectDescriptors.type() == CV_8U) { // Binary descriptors detected (from ORB, Brief, BRISK, FREAK) log_trace("Binary descriptors detected..."); - if (useBFMatcher) - { - // use NORM_HAMMING2 for ORB descriptor with WTA_K == 3 or 4 (see ORB constructor) + if (useBFMatcher) { + // use NORM_HAMMING2 for ORB descriptor with WTA_K == 3 or 4 (see + // ORB constructor) BFMatcher matcher(NORM_HAMMING); - matcher.knnMatch(m_objectDescriptors, m_sceneDescriptors, matches, k); - } - else - { + matcher.knnMatch(m_objectDescriptors, m_sceneDescriptors, matches, + k); + } else { // Create Flann LSH index flann::Index flannIndex(m_sceneDescriptors, flann::LshIndexParams(12, 20, 2), @@ -199,20 +187,17 @@ bool ObjectFinder::_MatchDescriptors(Mat &results, Mat &dists, log_debug("Creating FLANN LSH index is done"); // search (nearest neighbor) - flannIndex.knnSearch(m_objectDescriptors, results, dists, k, flann::SearchParams()); + flannIndex.knnSearch(m_objectDescriptors, results, dists, k, + flann::SearchParams()); } - } - else - { + } else { // assume it is CV_32F log_trace("Float descriptors detected..."); - if (useBFMatcher) - { + if (useBFMatcher) { BFMatcher matcher(NORM_L2); - matcher.knnMatch(m_objectDescriptors, m_sceneDescriptors, matches, k); - } - else - { + matcher.knnMatch(m_objectDescriptors, m_sceneDescriptors, matches, + k); + } else { // Create Flann KDTree index flann::Index flannIndex(m_sceneDescriptors, flann::KDTreeIndexParams(), @@ -227,8 +212,7 @@ bool ObjectFinder::_MatchDescriptors(Mat &results, Mat &dists, log_trace("Time nearest neighbor search = %lld ms", 0LL); // Conversion to CV_32F if needed - if (dists.type() == CV_32S) - { + if (dists.type() == CV_32S) { Mat temp; dists.convertTo(temp, CV_32F); dists = temp; @@ -236,50 +220,44 @@ bool ObjectFinder::_MatchDescriptors(Mat &results, Mat &dists, return true; } -bool ObjectFinder::_FindGoodMatches(Mat &results, - Mat &dists, - vector> &matches, - vector &src_points, - vector &dst_points, - vector &src_point_idxs, - vector &dst_point_idxs, - vector &outlier_mask, - bool useBFMatcher) -{ +bool ObjectFinder::_FindGoodMatches( + Mat &results, Mat &dists, vector> &matches, + vector &src_points, vector &dst_points, + vector &src_point_idxs, vector &dst_point_idxs, + vector &outlier_mask, bool useBFMatcher) { // Find correspondences by NNDR (Nearest Neighbor Distance Ratio) float nndrRatio = 0.8f; // Check if this descriptor matches with those of the objects - if (!useBFMatcher) - { - for (int i = 0; i < m_objectDescriptors.rows; ++i) - { + if (!useBFMatcher) { + for (int i = 0; i < m_objectDescriptors.rows; ++i) { // Apply NNDR - log_trace("q=%d dist1=%f dist2=%f", i, dists.at(i, 0), dists.at(i, 1)); - if (results.at(i, 0) >= 0 && - results.at(i, 1) >= 0 && - dists.at(i, 0) <= nndrRatio * dists.at(i, 1)) - { + log_trace("q=%d dist1=%f dist2=%f", i, dists.at(i, 0), + dists.at(i, 1)); + if (results.at(i, 0) >= 0 && results.at(i, 1) >= 0 && + dists.at(i, 0) <= nndrRatio * dists.at(i, 1)) { src_points.push_back(m_objectKeypoints.at(i).pt); src_point_idxs.push_back(i); - dst_points.push_back(m_sceneKeypoints.at(results.at(i, 0)).pt); + dst_points.push_back( + m_sceneKeypoints.at(results.at(i, 0)).pt); dst_point_idxs.push_back(results.at(i, 0)); } } - } - else - { - for (unsigned int i = 0; i < matches.size(); ++i) - { + } else { + for (unsigned int i = 0; i < matches.size(); ++i) { // Apply NNDR - log_trace("q=%d dist1=%f dist2=%f", matches.at(i).at(0).queryIdx, matches.at(i).at(0).distance, matches.at(i).at(1).distance); + log_trace("q=%d dist1=%f dist2=%f", matches.at(i).at(0).queryIdx, + matches.at(i).at(0).distance, + matches.at(i).at(1).distance); if (matches.at(i).size() == 2 && - matches.at(i).at(0).distance <= nndrRatio * matches.at(i).at(1).distance) - { - src_points.push_back(m_objectKeypoints.at(matches.at(i).at(0).queryIdx).pt); + matches.at(i).at(0).distance <= + nndrRatio * matches.at(i).at(1).distance) { + src_points.push_back( + m_objectKeypoints.at(matches.at(i).at(0).queryIdx).pt); src_point_idxs.push_back(matches.at(i).at(0).queryIdx); - dst_points.push_back(m_sceneKeypoints.at(matches.at(i).at(0).trainIdx).pt); + dst_points.push_back( + m_sceneKeypoints.at(matches.at(i).at(0).trainIdx).pt); dst_point_idxs.push_back(matches.at(i).at(0).trainIdx); } } @@ -290,64 +268,50 @@ bool ObjectFinder::_FindGoodMatches(Mat &results, bool ObjectFinder::_FindHomography(vector &src_points, vector &dst_points, - vector &outlier_mask, - Mat &H, - unsigned int minInliers) -{ + vector &outlier_mask, Mat &H, + unsigned int minInliers) { bool result = false; - if (src_points.size() >= minInliers) - { - H = findHomography(src_points, - dst_points, - RANSAC, - 1.0, - outlier_mask); + if (src_points.size() >= minInliers) { + H = findHomography(src_points, dst_points, RANSAC, 1.0, outlier_mask); int inliers = 0, outliers = 0; - for (unsigned int k = 0; k < src_points.size(); ++k) - { - if (outlier_mask.at(k)) - { + for (unsigned int k = 0; k < src_points.size(); ++k) { + if (outlier_mask.at(k)) { ++inliers; - } - else - { + } else { ++outliers; } } log_debug("Inliers=%d Outliers=%d", inliers, outliers); // TODO: only if there is H - //log_trace("H[0][0]=%f \tH[0][1]=%f \tH[0][2]=%f", H.at(0, 0), H.at(0, 1), H.at(0, 2)); - //log_trace("H[1][0]=%f \tH[1][1]=%f \tH[1][2]=%f", H.at(1, 0), H.at(1, 1), H.at(1, 2)); - // log_trace("H[2][0]=%f \tH[2][1]=%f \tH[2][2]=%f", H.at(2, 0), H.at(2, 1), H.at(2, 2)); + // log_trace("H[0][0]=%f \tH[0][1]=%f \tH[0][2]=%f", H.at(0, 0), + // H.at(0, 1), H.at(0, 2)); log_trace("H[1][0]=%f + // \tH[1][1]=%f \tH[1][2]=%f", H.at(1, 0), H.at(1, 1), + // H.at(1, 2)); + // log_trace("H[2][0]=%f \tH[2][1]=%f \tH[2][2]=%f", H.at(2, 0), + // H.at(2, 1), H.at(2, 2)); result = true; - } - else - { - log_debug("Not enough matches (%d) for homography...", (int)src_points.size()); + } else { + log_debug("Not enough matches (%d) for homography...", + (int)src_points.size()); } return result; } Quadrilateral ObjectFinder::_GetObjectRectangle(cv::Mat &objectImg, - cv::Mat &sceneImg, - cv::Mat &H) -{ + cv::Mat &sceneImg, cv::Mat &H) { //-- Get the corners from the image_1 ( the object to be "detected" ) - Quadrilateral obj_corners(Point2f(0, 0), - Point2f((float)objectImg.cols, 0), - Point2f((float)objectImg.cols, (float)objectImg.rows), - Point2f(0, (float)objectImg.rows)); + Quadrilateral obj_corners( + Point2f(0, 0), Point2f((float)objectImg.cols, 0), + Point2f((float)objectImg.cols, (float)objectImg.rows), + Point2f(0, (float)objectImg.rows)); Quadrilateral scene_corners; // Catch exception if transformation is not possible - try - { + try { perspectiveTransform(obj_corners.arr, scene_corners.arr, H); - } - catch (...) - { + } catch (...) { return Quadrilateral(); } diff --git a/src/common_components/visioner_app/components/object_finder/src/Quadrilateral.cpp b/src/common_components/visioner_app/components/object_finder/src/Quadrilateral.cpp new file mode 100644 index 0000000..573bcf1 --- /dev/null +++ b/src/common_components/visioner_app/components/object_finder/src/Quadrilateral.cpp @@ -0,0 +1,45 @@ +#include "Quadrilateral.hpp" +#include + +Quadrilateral::Quadrilateral(Point2f p1, Point2f p2, Point2f p3, Point2f p4) + : arr({p1, p2, p3, p4}) {} + +Point2f Quadrilateral::GetCenter() { + return (arr[0] + arr[1] + arr[2] + arr[3]) / 4; +} + +array Quadrilateral::GetSides() { + + return {_GetDistance(arr[0], arr[1]), _GetDistance(arr[1], arr[2]), + _GetDistance(arr[2], arr[3]), _GetDistance(arr[3], arr[0])}; +} + +float Quadrilateral::GetArea() { + array s = GetSides(); + float semip = (s[0] + s[1] + s[2] + s[3]) / 2; + float result = + sqrt((semip - s[0]) * (semip - s[1]) * (semip - s[2]) * (semip - s[3])); + return isnan(result) ? 0 : result; +} + +Point2f &Quadrilateral::operator[](int i) { return arr[i]; } + +const Point2f &Quadrilateral::operator[](int i) const { return arr[i]; } + +float Quadrilateral::GetPerimeter() { + array sides = GetSides(); + return sides[0] + sides[1] + sides[2] + sides[3]; +} + +vector Quadrilateral::GetIntegerPoints() { + vector res; + for (auto p : arr) { + res.push_back(p); + } + return res; +} + +float Quadrilateral::_GetDistance(Point2f &p_a, Point2f &p_b) { + return sqrt((p_a.x - p_b.x) * (p_a.x - p_b.x) + + (p_a.y - p_b.y) * (p_a.y - p_b.y)); +} diff --git a/src/common_components/object_finder/src/Visualizer.cpp b/src/common_components/visioner_app/components/object_finder/src/Visualizer.cpp similarity index 63% rename from src/common_components/object_finder/src/Visualizer.cpp rename to src/common_components/visioner_app/components/object_finder/src/Visualizer.cpp index 41dd408..fc21ce1 100644 --- a/src/common_components/object_finder/src/Visualizer.cpp +++ b/src/common_components/visioner_app/components/object_finder/src/Visualizer.cpp @@ -7,53 +7,41 @@ // // ************************************************************************* -#include #include "Visualizer.hpp" +#include -void Visualizer::SetImg(cv::Mat img) -{ +void Visualizer::SetImg(cv::Mat img) { m_img_orig = img.clone(); m_img_selection = img.clone(); m_img_dismissed = img.clone(); } -cv::Mat Visualizer::SelectAndDismiss(Quadrilateral selection) -{ +cv::Mat Visualizer::SelectAndDismiss(Quadrilateral selection) { DrawQuadrilateral(m_img_selection, selection, true); ClearQuadrilateral(m_img_dismissed, selection); return m_img_dismissed; } -cv::Mat &Visualizer::GetSceneWithSelection() -{ - return m_img_selection; -} +cv::Mat &Visualizer::GetSceneWithSelection() { return m_img_selection; } -cv::Mat &Visualizer::GetSceneWithoutSelectedObjects() -{ +cv::Mat &Visualizer::GetSceneWithoutSelectedObjects() { return m_img_dismissed; } -void Visualizer::DrawQuadrilateral(cv::Mat &img, - Quadrilateral selection, - bool crossed, - cv::Scalar color, - int thickness) -{ +void Visualizer::DrawQuadrilateral(cv::Mat &img, Quadrilateral selection, + bool crossed, cv::Scalar color, + int thickness) { cv::line(img, selection[0], selection[1], color, thickness); cv::line(img, selection[1], selection[2], color, thickness); cv::line(img, selection[2], selection[3], color, thickness); cv::line(img, selection[3], selection[0], color, thickness); - if (crossed) - { + if (crossed) { cv::line(img, selection[0], selection[2], color, thickness); cv::line(img, selection[1], selection[3], color, thickness); } } -void Visualizer::ClearQuadrilateral(cv::Mat &img, Quadrilateral selection) -{ - cv::fillPoly(img, selection.GetIntegerPoints(),Scalar(128)); - +void Visualizer::ClearQuadrilateral(cv::Mat &img, Quadrilateral selection) { + cv::fillPoly(img, selection.GetIntegerPoints(), Scalar(128)); } diff --git a/src/common_components/object_finder/src/opencv_tools.cpp b/src/common_components/visioner_app/components/object_finder/src/opencv_tools.cpp similarity index 90% rename from src/common_components/object_finder/src/opencv_tools.cpp rename to src/common_components/visioner_app/components/object_finder/src/opencv_tools.cpp index fb0ad14..0a1ce72 100644 --- a/src/common_components/object_finder/src/opencv_tools.cpp +++ b/src/common_components/visioner_app/components/object_finder/src/opencv_tools.cpp @@ -1,7 +1,6 @@ #include "opencv_tools.hpp" -Ptr getDescriptorExtractor() -{ +Ptr getDescriptorExtractor() { Ptr extractor; #if CV_MAJOR_VERSION == 2 // The extractor can be any of (see OpenCV features2d.hpp): @@ -13,14 +12,13 @@ Ptr getDescriptorExtractor() // extractor = Ptr(new FREAK()); #elif CV_MAJOR_VERSION < 4 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION < 3) extractor = xfeatures2d::SIFT::create(); -#else // >= 4.3.0 +#else // >= 4.3.0 extractor = SIFT::create(); #endif return extractor; } -Ptr getFeatureDetector() -{ +Ptr getFeatureDetector() { Ptr detector; #if CV_MAJOR_VERSION == 2 // detector = Ptr(new DenseFeatureDetector()); @@ -34,7 +32,7 @@ Ptr getFeatureDetector() // detector = Ptr(new BRISK()); #elif CV_MAJOR_VERSION < 4 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION < 3) detector = xfeatures2d::SIFT::create(); -#else // >= 4.3.0 +#else // >= 4.3.0 detector = SIFT::create(); #endif diff --git a/src/common_components/object_finder/src/opencv_tools.hpp b/src/common_components/visioner_app/components/object_finder/src/opencv_tools.hpp similarity index 100% rename from src/common_components/object_finder/src/opencv_tools.hpp rename to src/common_components/visioner_app/components/object_finder/src/opencv_tools.hpp diff --git a/src/common_components/visioner_base/include/App/App.hpp b/src/common_components/visioner_app/include/App.hpp similarity index 55% rename from src/common_components/visioner_base/include/App/App.hpp rename to src/common_components/visioner_app/include/App.hpp index 134897f..c6be0a2 100644 --- a/src/common_components/visioner_base/include/App/App.hpp +++ b/src/common_components/visioner_app/include/App.hpp @@ -9,31 +9,41 @@ #pragma once -#include "ObjectFinder.hpp" +#include +#include #include "FaceInterface.hpp" #include "InputInterface.hpp" #include "InterfaceSceneReader.hpp" -#include "Visualizer.hpp" -class App -{ -public: - App(FaceInterface *face, InputInterface *input, InterfaceSceneReader *scene_input = nullptr); +// Forward declaration +class ObjectFinder; +class Visualizer; +class Gui; + +class App { + public: + App(FaceInterface *face, InputInterface *input, Gui *gui, + InterfaceSceneReader *scene_input = nullptr); virtual int RunOnce(bool show_result = true, bool less_confused = false); virtual void Intro(); virtual void Delay(int ms) = 0; ~App() = default; -protected: - ObjectFinder m_objectFinder; + protected: + cv::Mat GetScene(); + QImage ToQImage(cv::Mat &cv_mat); + void Show(std::string title, cv::Mat cv_img); + + ObjectFinder *m_objectFinder; + Visualizer *m_vis; FaceInterface *m_face; InputInterface *m_input; InterfaceSceneReader *m_scene_input; + Gui *m_gui; cv::Mat m_current_scene; - Visualizer m_vis; - -private: - virtual int FindObjects(std::vector objects, bool show_result = true); - virtual void PreFindAction(); + private: + virtual int FindObjects(std::vector objects, + bool show_result = true); + virtual void PreFindAction(); }; diff --git a/src/common_components/visioner_base/include/FileScanner.hpp b/src/common_components/visioner_app/include/FileScanner.hpp similarity index 92% rename from src/common_components/visioner_base/include/FileScanner.hpp rename to src/common_components/visioner_app/include/FileScanner.hpp index c6b1b9b..0cb42df 100644 --- a/src/common_components/visioner_base/include/FileScanner.hpp +++ b/src/common_components/visioner_app/include/FileScanner.hpp @@ -12,14 +12,13 @@ #include #include -class FileScanner -{ -public: +class FileScanner { + public: FileScanner(const std::string &path); // Get all files in the directory by pattern std::vector GetFiles(const std::string &pattern); - -private: + + private: std::string m_path; }; diff --git a/src/common_components/visioner_base/include/App/InputFiles.hpp b/src/common_components/visioner_app/include/InputFiles.hpp similarity index 80% rename from src/common_components/visioner_base/include/App/InputFiles.hpp rename to src/common_components/visioner_app/include/InputFiles.hpp index ba23ccf..0fe9857 100644 --- a/src/common_components/visioner_base/include/App/InputFiles.hpp +++ b/src/common_components/visioner_app/include/InputFiles.hpp @@ -13,21 +13,19 @@ #include "FileScanner.hpp" #include "InputInterface.hpp" -class InputFiles : public InputInterface -{ -public: +class InputFiles : public InputInterface { + public: InputFiles(); - std::vector& GetGoodObjects() override; - std::vector& GetBadObjects() override; + std::vector &GetGoodObjects() override; + std::vector &GetBadObjects() override; void LoadFiles(const std::string &path); ~InputFiles(); -private: + private: FileScanner *m_file_scanner; std::string m_path; std::vector m_objects_good; std::vector m_objects_bad; std::vector m_objects_good_names; std::vector m_objects_bad_names; - }; diff --git a/src/common_components/visioner_base/src/App.cpp b/src/common_components/visioner_app/src/App.cpp similarity index 55% rename from src/common_components/visioner_base/src/App.cpp rename to src/common_components/visioner_app/src/App.cpp index 9377cd4..ef3f2dd 100644 --- a/src/common_components/visioner_base/src/App.cpp +++ b/src/common_components/visioner_app/src/App.cpp @@ -7,21 +7,25 @@ // // ************************************************************************* -#include -#include "ulog.h" +#include +#include "FaceInterface.hpp" +#include "Gui.hpp" +#include "InputInterface.hpp" #include "InterfaceSceneReader.hpp" -#include "App/App.hpp" +#include "ObjectFinder.hpp" #include "Visualizer.hpp" +#include "ulog.h" + +#include "App.hpp" using namespace cv; -App::App(FaceInterface *face, InputInterface *input, InterfaceSceneReader *scene_reader) - : m_face(face), m_input(input), m_scene_input(scene_reader), m_objectFinder() -{ -} +App::App(FaceInterface *face, InputInterface *input, Gui *gui, + InterfaceSceneReader *scene_reader) + : m_face(face), m_input(input), m_scene_input(scene_reader), m_gui(gui), + m_objectFinder(new ObjectFinder), m_vis(new Visualizer) {} -void App::Intro() -{ +void App::Intro() { m_face->ShowCalm(1000); m_face->ShowBlink(200); m_face->ShowCalm(1000); @@ -29,27 +33,39 @@ void App::Intro() m_face->ShowCalm(1000); } -int App::FindObjects(std::vector objects, bool show_result) -{ +cv::Mat App::GetScene() { return m_objectFinder->GetScene(); } + +QImage App::ToQImage(cv::Mat &cv_mat) { + // cv::Mat temp; + // cv_mat.copyTo(temp); + // cv::cvtColor(temp, temp, cv::COLOR_BGR2RGB); + return QImage((unsigned char *)cv_mat.data, cv_mat.cols, cv_mat.rows, + QImage::Format_RGB888); +} + +void App::Show(std::string title, cv::Mat cv_img) { + // m_gui->SetTitle(title); + auto qimg = ToQImage(cv_img); + m_gui->SetImageRight(qimg); +} + +int App::FindObjects(std::vector objects, bool show_result) { int found_objects = 0; - for (auto &object : objects) - { + for (auto &object : objects) { int obj_num = 0; - Quadrilateral obj = m_objectFinder.Find(object); - if (obj.GetPerimeter() > 0) - { + Quadrilateral obj = m_objectFinder->Find(object); + if (obj.GetPerimeter() > 0) { found_objects++; // Remove the object from the scene and update the scene - m_current_scene = m_vis.SelectAndDismiss(obj); - + m_current_scene = m_vis->SelectAndDismiss(obj); + // Logging Point2f center = obj.GetCenter(); auto area = obj.GetArea(); auto perimeter = obj.GetPerimeter(); float a2p = area / perimeter; log_info("Object %d! Center: %f-%f. Area:%f. Area/Perimeter: %f", - obj_num, center.x, center.y, area, a2p); - + obj_num, center.x, center.y, area, a2p); } obj_num++; } @@ -58,65 +74,53 @@ int App::FindObjects(std::vector objects, bool show_result) void App::PreFindAction() {} -int App::RunOnce(bool show_result, bool less_confused) -{ +int App::RunOnce(bool show_result, bool less_confused) { // Set the new scene m_current_scene = m_scene_input->GetScene(); - m_objectFinder.SetScene(m_current_scene); - m_vis.SetImg(m_current_scene); + m_objectFinder->SetScene(m_current_scene); + m_vis->SetImg(m_current_scene); PreFindAction(); // Find good objects int good_objects = FindObjects(m_input->GetGoodObjects(), show_result); - if (good_objects){ + if (good_objects) { log_info("👍 Good objects found: %d", good_objects); - } - else { + } else { log_info("No good objects found"); } - + // Find bad objects int bad_objects = FindObjects(m_input->GetBadObjects(), show_result); - if (bad_objects){ + if (bad_objects) { log_info("👎 Bad objects found: %d", bad_objects); - } - else { + } else { log_info("No bad objects found"); } - + // Show - if (show_result){ - imshow("Scene", m_vis.GetSceneWithSelection()); + if (show_result) { + Show("Scene", m_vis->GetSceneWithSelection()); } // Reaction - if (good_objects == 0 && bad_objects == 0) - { - if (less_confused) - { + if (good_objects == 0 && bad_objects == 0) { + if (less_confused) { m_face->ShowCalm(1); - } - else - { + } else { m_face->ShowDunno(1); } return -1; } - if (good_objects > bad_objects) - { + if (good_objects > bad_objects) { m_face->ShowHappy(1); return 1; - } - else if (good_objects < bad_objects) - { + } else if (good_objects < bad_objects) { m_face->ShowSad(1); return 2; - } - else - { + } else { m_face->ShowConfused(1); return 0; } diff --git a/src/common_components/visioner_base/src/FileScanner.cpp b/src/common_components/visioner_app/src/FileScanner.cpp similarity index 91% rename from src/common_components/visioner_base/src/FileScanner.cpp rename to src/common_components/visioner_app/src/FileScanner.cpp index df98149..20cef54 100644 --- a/src/common_components/visioner_base/src/FileScanner.cpp +++ b/src/common_components/visioner_app/src/FileScanner.cpp @@ -1,17 +1,14 @@ -#include #include "FileScanner.hpp" +#include FileScanner::FileScanner(const std::string &path) : m_path(path) {} -std::vector FileScanner::GetFiles(const std::string &pattern) -{ +std::vector FileScanner::GetFiles(const std::string &pattern) { std::vector files; - for (const auto &entry : std::filesystem::directory_iterator(m_path)) - { + for (const auto &entry : std::filesystem::directory_iterator(m_path)) { if (entry.is_regular_file() && - entry.path().string().find(pattern) != std::string::npos) - { + entry.path().string().find(pattern) != std::string::npos) { files.push_back(entry.path().string()); } } diff --git a/src/common_components/visioner_base/src/InputFiles.cpp b/src/common_components/visioner_app/src/InputFiles.cpp similarity index 63% rename from src/common_components/visioner_base/src/InputFiles.cpp rename to src/common_components/visioner_app/src/InputFiles.cpp index 5cc15ab..ecdc640 100644 --- a/src/common_components/visioner_base/src/InputFiles.cpp +++ b/src/common_components/visioner_app/src/InputFiles.cpp @@ -7,45 +7,32 @@ // // ************************************************************************* -#include +#include "InputFiles.hpp" #include +#include #include "FileScanner.hpp" -#include "App/InputFiles.hpp" +InputFiles::InputFiles() {} -InputFiles::InputFiles() -{ - -} +std::vector &InputFiles::GetGoodObjects() { return m_objects_good; } -std::vector& InputFiles::GetGoodObjects() -{ - return m_objects_good; -} +std::vector &InputFiles::GetBadObjects() { return m_objects_bad; } -std::vector &InputFiles::GetBadObjects() -{ - return m_objects_bad; -} - -void InputFiles::LoadFiles(const std::string &path) -{ +void InputFiles::LoadFiles(const std::string &path) { m_path = path; m_file_scanner = new FileScanner(m_path); - + m_objects_good.clear(); m_objects_good_names = m_file_scanner->GetFiles("object_good_"); - for (auto &obj: m_objects_good_names) { + for (auto &obj : m_objects_good_names) { m_objects_good.push_back(cv::imread(obj)); } - + m_objects_bad.clear(); m_objects_bad_names = m_file_scanner->GetFiles("object_bad_"); - for (auto &obj: m_objects_bad_names) { + for (auto &obj : m_objects_bad_names) { m_objects_bad.push_back(cv::imread(obj)); } } -InputFiles::~InputFiles() { - delete m_file_scanner; -} +InputFiles::~InputFiles() { delete m_file_scanner; } diff --git a/src/common_components/visioner_base/CMakeLists.txt b/src/common_components/visioner_base/CMakeLists.txt deleted file mode 100644 index 16b9219..0000000 --- a/src/common_components/visioner_base/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -cmake_minimum_required(VERSION 3.5) -project(visioner_base) - -include(${CMAKE_CURRENT_LIST_DIR}/../../../ab.cmake) -add_component(visioner_base) -target_link_components(visioner_base ${CMAKE_CURRENT_LIST_DIR}/../microlog - ${CMAKE_CURRENT_LIST_DIR}/../object_finder - ${CMAKE_CURRENT_LIST_DIR}/../visioner_interfaces) diff --git a/src/common_components/visioner_interfaces/CMakeLists.txt b/src/common_components/visioner_interfaces/CMakeLists.txt index 8d69cf3..06d4c44 100644 --- a/src/common_components/visioner_interfaces/CMakeLists.txt +++ b/src/common_components/visioner_interfaces/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.5) project(visioner_interfaces) -include(${CMAKE_CURRENT_LIST_DIR}/../../../ab.cmake) +include($ENV{ABCMAKE_PATH}) add_component(visioner_interfaces) diff --git a/src/common_components/visioner_interfaces/include/FaceInterface.hpp b/src/common_components/visioner_interfaces/include/FaceInterface.hpp index 520c533..aee256f 100644 --- a/src/common_components/visioner_interfaces/include/FaceInterface.hpp +++ b/src/common_components/visioner_interfaces/include/FaceInterface.hpp @@ -10,7 +10,7 @@ #pragma once class FaceInterface { -public: + public: virtual void ShowThinking() = 0; virtual void ShowBlink(int delay = 500) = 0; virtual void ShowCalm(int delay = 500) = 0; diff --git a/src/common_components/visioner_interfaces/include/InputInterface.hpp b/src/common_components/visioner_interfaces/include/InputInterface.hpp index ca06c4c..360aad3 100644 --- a/src/common_components/visioner_interfaces/include/InputInterface.hpp +++ b/src/common_components/visioner_interfaces/include/InputInterface.hpp @@ -9,13 +9,12 @@ #pragma once -#include -#include #include +#include +#include -class InputInterface -{ -public: +class InputInterface { + public: InputInterface() = default; virtual std::vector &GetGoodObjects() = 0; virtual std::vector &GetBadObjects() = 0; diff --git a/src/common_components/visioner_interfaces/include/InterfaceSceneReader.hpp b/src/common_components/visioner_interfaces/include/InterfaceSceneReader.hpp index 7e6c9eb..ced9054 100644 --- a/src/common_components/visioner_interfaces/include/InterfaceSceneReader.hpp +++ b/src/common_components/visioner_interfaces/include/InterfaceSceneReader.hpp @@ -9,13 +9,12 @@ #pragma once -#include -#include #include +#include +#include -class InterfaceSceneReader -{ -public: +class InterfaceSceneReader { + public: InterfaceSceneReader() = default; virtual cv::Mat GetScene() = 0; }; diff --git a/src/common_components/visioner_interfaces/src/visioner_interfaces.cpp b/src/common_components/visioner_interfaces/src/visioner_interfaces.cpp index c80a45a..9122de0 100644 --- a/src/common_components/visioner_interfaces/src/visioner_interfaces.cpp +++ b/src/common_components/visioner_interfaces/src/visioner_interfaces.cpp @@ -1,4 +1,3 @@ -void visioner_interfaces() -{ +void visioner_interfaces() { // To make build systems happy. This function is not used. }