Browse Source

initial commit

master
cailean 3 months ago
commit
98afb8ebf6
  1. 90
      .gitignore
  2. 181
      .vscode/c_cpp_properties.json
  3. 72
      .vscode/launch.json
  4. 133
      .vscode/tasks.json
  5. 13
      Makefile
  6. 2
      addons.make
  7. 142
      config.make
  8. 107
      onnx-test.code-workspace
  9. 69
      onnx-test.qbs
  10. 1
      readme.md
  11. 287
      src/Onnx.cpp
  12. 57
      src/Onnx.h
  13. 55
      src/Player.cpp
  14. 39
      src/Player.h
  15. 155
      src/Yolo.cpp
  16. 81
      src/Yolo.h
  17. 17
      src/main.cpp
  18. 210
      src/ofApp.cpp
  19. 49
      src/ofApp.h

90
.gitignore

@ -0,0 +1,90 @@
#.gitignore is a file which makes git ignore files which should
# not go into version control in the first place
# Questions? See
# http://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository#Ignoring-Files
# http://git-scm.com/docs/gitignore
###########################
# ignore generated binaries
# but not the data folder
###########################
/bin/*
#########
# general
#########
[Bb]uild/
[Oo]bj/
*.o
[Dd]ebug*/
[Rr]elease*/
*.mode*
*.app/
*.pyc
.svn/
*.log
########################
# IDE files which should
# be ignored
########################
# XCode
*.pbxuser
*.perspective
*.perspectivev3
*.mode1v3
*.mode2v3
# XCode 4
*.xccheckout
xcuserdata/
# Visual Studio
*.sdf
*.opensdf
*.suo
*.pdb
*.ilk
*.aps
ipch/
# Eclipse
.metadata
local.properties
.externalToolBuilders
# Android Studio
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
##################
# operating system
##################
# Linux
*~
# KDE
.directory
.AppleDouble
# OSX
.DS_Store
*.swp
*~.nib
# Thumbnails
._*
# Windows
# Image file caches
Thumbs.db
# Folder config file
Desktop.ini
# Android
.csettings
/bin/data/

181
.vscode/c_cpp_properties.json

@ -0,0 +1,181 @@
{
"configurations": [
{
"name": "Mac",
"includePath": [
"/usr/include",
"/usr/local/include",
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/",
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1",
"${workspaceRoot}/../../../libs/openFrameworks",
"${workspaceRoot}/../../../libs/openFrameworks/3d",
"${workspaceRoot}/../../../libs/openFrameworks/app",
"${workspaceRoot}/../../../libs/openFrameworks/communication",
"${workspaceRoot}/../../../libs/openFrameworks/events",
"${workspaceRoot}/../../../libs/openFrameworks/gl",
"${workspaceRoot}/../../../libs/openFrameworks/graphics",
"${workspaceRoot}/../../../libs/openFrameworks/math",
"${workspaceRoot}/../../../libs/openFrameworks/sound",
"${workspaceRoot}/../../../libs/openFrameworks/types",
"${workspaceRoot}/../../../libs/openFrameworks/utils",
"${workspaceRoot}/../../../libs/openFrameworks/video",
"${workspaceRoot}/../../../libs/boost/include",
"${workspaceRoot}/../../../libs/cairo/include",
"${workspaceRoot}/../../../libs/curl/include",
"${workspaceRoot}/../../../libs/fmod/include",
"${workspaceRoot}/../../../libs/FreeImage/include",
"${workspaceRoot}/../../../libs/freetype/include",
"${workspaceRoot}/../../../libs/glew/include",
"${workspaceRoot}/../../../libs/glfw/include",
"${workspaceRoot}/../../../libs/glm/include",
"${workspaceRoot}/../../../libs/json/include",
"${workspaceRoot}/../../../libs/pugixml/include",
"${workspaceRoot}/../../../libs/rtAudio/include",
"${workspaceRoot}/../../../libs/tess2/include",
"${workspaceRoot}/../../../libs/uriparser/include",
"${workspaceRoot}/../../../libs/utf8/include"
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "${workspaceRoot}/.vscode/browse.db",
"path": [
"/usr/include",
"/usr/local/include",
"/System/Library/Frameworks",
"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/",
"${workspaceRoot}/../../../libs",
"${workspaceRoot}/../../../addons",
"${workspaceRoot}/../../../libs/openFrameworks"
]
},
"intelliSenseMode": "clang-x64",
"macFrameworkPath": [
"/System/Library/Frameworks",
"/Library/Frameworks"
],
"compilerPath": "/usr/local/bin/gcc-8",
"cStandard": "c11",
"cppStandard": "c++17"
},
{
"name": "Linux",
"includePath": [
"/usr/include",
"/usr/local/include",
"/usr/include/c++/5",
"/usr/include/c++/5/backward",
"/usr/lib/gcc/x86_64-linux-gnu/5/include",
"/usr/lib/x86_64-linux-gnu/glib-2.0/include",
"/usr/lib/x86_64-linux-gnu/gstreamer-1.0/include",
"/usr/local/include",
"/usr/lib/gcc/x86_64-linux-gnu/5/include-fixed",
"/usr/include/x86_64-linux-gnu",
"${workspaceRoot}/../../../libs/openFrameworks",
"${workspaceRoot}/../../../libs/openFrameworks/3d",
"${workspaceRoot}/../../../libs/openFrameworks/app",
"${workspaceRoot}/../../../libs/openFrameworks/communication",
"${workspaceRoot}/../../../libs/openFrameworks/events",
"${workspaceRoot}/../../../libs/openFrameworks/gl",
"${workspaceRoot}/../../../libs/openFrameworks/graphics",
"${workspaceRoot}/../../../libs/openFrameworks/math",
"${workspaceRoot}/../../../libs/openFrameworks/sound",
"${workspaceRoot}/../../../libs/openFrameworks/types",
"${workspaceRoot}/../../../libs/openFrameworks/utils",
"${workspaceRoot}/../../../libs/openFrameworks/video",
"${workspaceRoot}/../../../libs/boost/include",
"${workspaceRoot}/../../../libs/cairo/include",
"${workspaceRoot}/../../../libs/curl/include",
"${workspaceRoot}/../../../libs/fmod/include",
"${workspaceRoot}/../../../libs/FreeImage/include",
"${workspaceRoot}/../../../libs/freetype/include",
"${workspaceRoot}/../../../libs/glew/include",
"${workspaceRoot}/../../../libs/glfw/include",
"${workspaceRoot}/../../../libs/glm/include",
"${workspaceRoot}/../../../libs/json/include",
"${workspaceRoot}/../../../libs/pugixml/include",
"${workspaceRoot}/../../../libs/rtAudio/include",
"${workspaceRoot}/../../../libs/tess2/include",
"${workspaceRoot}/../../../libs/uriparser/include",
"${workspaceRoot}/../../../libs/utf8/include",
"${workspaceRoot}/../../../libs/poco/include",
"${workspaceRoot}/../../../libs/kiss/include",
"/usr/include/x86_64-linux-gnu/c++/5",
"/usr/include/pulse",
"/usr/include/cairo",
"/usr/include/gstreamer-1.0",
"/usr/include/glib-2.0",
"${workspaceRoot}",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxOpenCv/src",
"/usr/local/onnxruntime-linux-x64-gpu-1.19.2/include",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxOpenCv/libs/opencv/include/opencv4"
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "",
"path": [
"/usr/include",
"/usr/local/include",
"${workspaceRoot}/../../../libs",
"${workspaceRoot}/../../../addons",
"${workspaceRoot}/../../../libs/openFrameworks",
"/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/addons/ofxOpenCv/src",
"/usr/local/onnxruntime-linux-x64-gpu-1.19.2/include"
]
},
"intelliSenseMode": "clang-x64",
"compilerPath": "/usr/bin/g++",
"cStandard": "c17",
"cppStandard": "c++17"
},
{
"name": "Win32",
"includePath": [
"C:/msys64/mingw32/include/c++/7.4.0",
"C:/msys64/mingw32/i686-w64-mingw32/include",
"${workspaceRoot}/../../../libs",
"${workspaceRoot}/../../../addons",
"${workspaceRoot}/../../../libs/openFrameworks",
"${workspaceRoot}/../../../libs/openFrameworks/3d",
"${workspaceRoot}/../../../libs/openFrameworks/app",
"${workspaceRoot}/../../../libs/openFrameworks/communication",
"${workspaceRoot}/../../../libs/openFrameworks/events",
"${workspaceRoot}/../../../libs/openFrameworks/gl",
"${workspaceRoot}/../../../libs/openFrameworks/graphics",
"${workspaceRoot}/../../../libs/openFrameworks/math",
"${workspaceRoot}/../../../libs/openFrameworks/sound",
"${workspaceRoot}/../../../libs/openFrameworks/types",
"${workspaceRoot}/../../../libs/openFrameworks/utils",
"${workspaceRoot}/../../../libs/openFrameworks/video",
"${workspaceRoot}/../../../libs/boost/include",
"${workspaceRoot}/../../../libs/cairo/include",
"${workspaceRoot}/../../../libs/curl/include",
"${workspaceRoot}/../../../libs/fmod/include",
"${workspaceRoot}/../../../libs/FreeImage/include",
"${workspaceRoot}/../../../libs/freetype/include",
"${workspaceRoot}/../../../libs/glew/include",
"${workspaceRoot}/../../../libs/glfw/include",
"${workspaceRoot}/../../../libs/glm/include",
"${workspaceRoot}/../../../libs/json/include",
"${workspaceRoot}/../../../libs/pugixml/include",
"${workspaceRoot}/../../../libs/rtAudio/include",
"${workspaceRoot}/../../../libs/tess2/include",
"${workspaceRoot}/../../../libs/uriparser/include",
"${workspaceRoot}/../../../libs/utf8/include"
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": "",
"path": [
"${workspaceRoot}/../../../libs",
"${workspaceRoot}/../../../addons",
"${workspaceRoot}/../../../libs/openFrameworks"
]
},
"intelliSenseMode": "clang-x64",
"compilerPath": "C:/msys64/mingw32/bin/g++.exe",
"cStandard": "c11",
"cppStandard": "c++17"
}
],
"version": 4
}

72
.vscode/launch.json

@ -0,0 +1,72 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "C++ Launch",
"type": "cppdbg",
"request": "launch",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": false,
"linux": {
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"program": "${workspaceRoot}/bin/${workspaceFolderBasename}_debug"
},
"osx": {
"MIMode": "lldb",
"program": "${workspaceRoot}/bin/${workspaceFolderBasename}_debug.app/Contents/MacOS/${workspaceFolderBasename}_debug"
},
"windows": {
"MIMode": "gdb",
"miDebuggerPath": "gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"program": "${workspaceRoot}/bin/${workspaceFolderBasename}_debug"
}
},
{
"name": "C++ Attach",
"type": "cppdbg",
"request": "attach",
"program": "enter program name, for example ${workspaceRoot}/a.out",
"processId": "${command:pickProcess}",
"linux": {
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
},
"osx": {
"MIMode": "lldb"
},
"windows": {
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
}
]
}

133
.vscode/tasks.json

@ -0,0 +1,133 @@
{
"version": "2.0.0",
"shell":{
"task": true
},
"tasks": [
{
"type": "shell",
"label": "Build RELEASE",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"command": "make -j -s 2>&1 && make RunRelease",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"type": "shell",
"label": "Build DEBUG",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"command": "make Debug -j -s 2>&1 || exit 1",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"type": "shell",
"label": "Clean DEBUG",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"command": "make CleanDebug",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"type": "shell",
"label": "Clean RELEASE",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"command": "make CleanRelease",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"type": "shell",
"label": "Clean ALL",
"presentation": {
"reveal": "always",
"panel": "shared"
},
"command": "make clean",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
}
]
}

13
Makefile

@ -0,0 +1,13 @@
# Attempt to load a config.make file.
# If none is found, project defaults in config.project.make will be used.
ifneq ($(wildcard config.make),)
include config.make
endif
# make sure the the OF_ROOT location is defined
ifndef OF_ROOT
OF_ROOT=$(realpath ../../..)
endif
# call the project makefile!
include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk

2
addons.make

@ -0,0 +1,2 @@
ofxOpenCv
ofxOpenCv

142
config.make

@ -0,0 +1,142 @@
################################################################################
# CONFIGURE PROJECT MAKEFILE (optional)
# This file is where we make project specific configurations.
################################################################################
################################################################################
# OF ROOT
# The location of your root openFrameworks installation
# (default) OF_ROOT = ../../..
################################################################################
OF_ROOT = ../../..
################################################################################
# PROJECT ROOT
# The location of the project - a starting place for searching for files
# (default) PROJECT_ROOT = . (this directory)
#
################################################################################
# PROJECT_ROOT = .
################################################################################
# PROJECT SPECIFIC CHECKS
# This is a project defined section to create internal makefile flags to
# conditionally enable or disable the addition of various features within
# this makefile. For instance, if you want to make changes based on whether
# GTK is installed, one might test that here and create a variable to check.
################################################################################
# None
################################################################################
# PROJECT EXTERNAL SOURCE PATHS
# These are fully qualified paths that are not within the PROJECT_ROOT folder.
# Like source folders in the PROJECT_ROOT, these paths are subject to
# exlclusion via the PROJECT_EXLCUSIONS list.
#
# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank)
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_EXTERNAL_SOURCE_PATHS =
################################################################################
# PROJECT EXCLUSIONS
# These makefiles assume that all folders in your current project directory
# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations
# to look for source code. The any folders or files that match any of the
# items in the PROJECT_EXCLUSIONS list below will be ignored.
#
# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete
# string unless teh user adds a wildcard (%) operator to match subdirectories.
# GNU make only allows one wildcard for matching. The second wildcard (%) is
# treated literally.
#
# (default) PROJECT_EXCLUSIONS = (blank)
#
# Will automatically exclude the following:
#
# $(PROJECT_ROOT)/bin%
# $(PROJECT_ROOT)/obj%
# $(PROJECT_ROOT)/%.xcodeproj
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_EXCLUSIONS =
################################################################################
# PROJECT LINKER FLAGS
# These flags will be sent to the linker when compiling the executable.
#
# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# Currently, shared libraries that are needed are copied to the
# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to
# add a runtime path to search for those shared libraries, since they aren't
# incorporated directly into the final executable application binary.
# TODO: should this be a default setting?
# PROJECT_LDFLAGS=-Wl,-rpath=./libs
################################################################################
# PROJECT DEFINES
# Create a space-delimited list of DEFINES. The list will be converted into
# CFLAGS with the "-D" flag later in the makefile.
#
# (default) PROJECT_DEFINES = (blank)
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_DEFINES =
################################################################################
# PROJECT CFLAGS
# This is a list of fully qualified CFLAGS required when compiling for this
# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS
# defined in your platform specific core configuration files. These flags are
# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below.
#
# (default) PROJECT_CFLAGS = (blank)
#
# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in
# your platform specific configuration file will be applied by default and
# further flags here may not be needed.
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_CFLAGS =
################################################################################
# PROJECT OPTIMIZATION CFLAGS
# These are lists of CFLAGS that are target-specific. While any flags could
# be conditionally added, they are usually limited to optimization flags.
# These flags are added BEFORE the PROJECT_CFLAGS.
#
# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.
#
# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)
#
# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.
#
# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)
#
# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the
# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration
# file will be applied by default and further optimization flags here may not
# be needed.
#
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_OPTIMIZATION_CFLAGS_RELEASE =
# PROJECT_OPTIMIZATION_CFLAGS_DEBUG =
################################################################################
# PROJECT COMPILERS
# Custom compilers can be set for CC and CXX
# (default) PROJECT_CXX = (blank)
# (default) PROJECT_CC = (blank)
# Note: Leave a leading space when adding list items with the += operator
################################################################################
# PROJECT_CXX =
# PROJECT_CC =

107
onnx-test.code-workspace

@ -0,0 +1,107 @@
{
"folders": [
{
"path": "."
},
{
"path": "${workspaceRoot}/../../../../libs/openFrameworks"
},
{
"path": "${workspaceRoot}/../../../../addons"
}
],
"settings": {
"files.associations": {
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"any": "cpp",
"array": "cpp",
"atomic": "cpp",
"strstream": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cfenv": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"expected": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"source_location": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp",
"format": "cpp",
"stdfloat": "cpp",
"__nullptr": "cpp",
"*.ipp": "cpp",
"__bit_reference": "cpp",
"__hash_table": "cpp",
"__split_buffer": "cpp",
"__tree": "cpp",
"filesystem": "cpp"
}
}
}

69
onnx-test.qbs

@ -0,0 +1,69 @@
import qbs
import qbs.Process
import qbs.File
import qbs.FileInfo
import qbs.TextFile
import "../../../libs/openFrameworksCompiled/project/qtcreator/ofApp.qbs" as ofApp
Project{
property string of_root: "../../.."
ofApp {
name: { return FileInfo.baseName(sourceDirectory) }
files: [
'src/main.cpp',
'src/ofApp.cpp',
'src/ofApp.h',
]
of.addons: [
'ofxOpenCv',
'ofxOpenCv',
]
// additional flags for the project. the of module sets some
// flags by default to add the core libraries, search paths...
// this flags can be augmented through the following properties:
of.pkgConfigs: [] // list of additional system pkgs to include
of.includePaths: [] // include search paths
of.cFlags: [] // flags passed to the c compiler
of.cxxFlags: [] // flags passed to the c++ compiler
of.linkerFlags: [] // flags passed to the linker
of.defines: [] // defines are passed as -D to the compiler
// and can be checked with #ifdef or #if in the code
of.frameworks: [] // osx only, additional frameworks to link with the project
of.staticLibraries: [] // static libraries
of.dynamicLibraries: [] // dynamic libraries
// other flags can be set through the cpp module: http://doc.qt.io/qbs/cpp-module.html
// eg: this will enable ccache when compiling
//
// cpp.compilerWrapper: 'ccache'
Depends{
name: "cpp"
}
// common rules that parse the include search paths, core libraries...
Depends{
name: "of"
}
// dependency with the OF library
Depends{
name: "openFrameworks"
}
}
property bool makeOF: true // use makfiles to compile the OF library
// will compile OF only once for all your projects
// otherwise compiled per project with qbs
property bool precompileOfMain: false // precompile ofMain.h
// faster to recompile when including ofMain.h
// but might use a lot of space per project
references: [FileInfo.joinPaths(of_root, "/libs/openFrameworksCompiled/project/qtcreator/openFrameworks.qbs")]
}

1
readme.md

@ -0,0 +1 @@
## Affection Mapping Beta ##

287
src/Onnx.cpp

@ -0,0 +1,287 @@
#include "Onnx.h"
// Setups the model. CUDA is enabled by default
void Onnx::Setup(ORTCHAR_T* modelPath, bool isLog, bool useCuda){
session_options.SetIntraOpNumThreads(1);
session_options.SetIntraOpNumThreads(1);
session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL);
log = isLog;
// cuda setup
if(useCuda){
OrtCUDAProviderOptions opts;
opts.device_id = 0;
opts.cudnn_conv_algo_search = OrtCudnnConvAlgoSearchExhaustive;
opts.do_copy_in_default_stream = 0;
opts.arena_extend_strategy = 0;
session_options.AppendExecutionProvider_CUDA(opts);
}
ort_session = std::make_shared<Ort::Session>(ort_env, modelPath, session_options);
Ort::AllocatorWithDefaultOptions allocator;
for (std::size_t i = 0; i < ort_session->GetInputCount(); i++) {
input_node_names.emplace_back(ort_session->GetInputNameAllocated(i, allocator).get());
input_node_dims = ort_session->GetInputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape();
if(log)
std::cout << "\t" << input_node_names.at(i) << " : " << PrintShape(input_node_dims) << std::endl;
}
// some models might have negative shape values to indicate dynamic shape, e.g., for variable batch size.
for (auto& s : input_node_dims) {
if (s < 0) {
s = 1;
if(log)
std::cout << "transfromed!" << std::endl;
}
}
if(log)
std::cout << "Output Node Name/Shape (" << output_node_names.size() << "):" << std::endl;
for (std::size_t i = 0; i < ort_session->GetOutputCount(); i++) {
output_node_names.emplace_back(ort_session->GetOutputNameAllocated(i, allocator).get());
auto output_shapes = ort_session->GetOutputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape();
if(log)
std::cout << "\t" << output_node_names.at(i) << " : " << PrintShape(output_shapes) << std::endl;
}
}
// Runs the model, given an image
std::vector<Ort::Value> Onnx::Run(ofImage &img){
auto start = std::chrono::high_resolution_clock::now();
TransformImage(img);
size_t input_tensor_size = image_array.total();
std::vector<Ort::Value> input_tensors;
Ort::MemoryInfo mem_info = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault);
input_tensors.emplace_back(Ort::Value::CreateTensor<float>(mem_info, (float*)image_array.data,
input_tensor_size, input_node_dims.data(), input_node_dims.size()));
// double-check the dimensions of the input tensor
assert(input_tensors[0].IsTensor() && input_tensors[0].GetTensorTypeAndShapeInfo().GetShape() == input_node_dims);
//std::cout << "\ninput_tensor shape: " << PrintShape(input_tensors[0].GetTensorTypeAndShapeInfo().GetShape()) << std::endl;
// pass data through model
std::vector<const char*> input_names_char(input_node_names.size(), nullptr);
std::transform(std::begin(input_node_names), std::end(input_node_names), std::begin(input_names_char),
[&](const std::string& str) { return str.c_str(); });
std::vector<const char*> output_names_char(output_node_names.size(), nullptr);
std::transform(std::begin(output_node_names), std::end(output_node_names), std::begin(output_names_char),
[&](const std::string& str) { return str.c_str(); });
std::cout << "Running model... ";
try {
auto output_tensors = ort_session->Run(Ort::RunOptions{nullptr}, input_names_char.data(), input_tensors.data(),
input_names_char.size(), output_names_char.data(), output_names_char.size());
std::cout << "Done!" << std::endl;
if (timeStamp) {
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end - start;
std::cout << "Update loop took " << elapsed.count() << " ms" << std::endl;
}
return output_tensors;
} catch (const Ort::Exception& exception) {
std::cout << "ERROR running model inference: " << exception.what() << std::endl;
return input_tensors;
}
}
/*
Runs a model, with a batch of images as input (emotion.onnx)
(1) Creates a 1-dim float array based on the batch * channels * width * height)
(2) Transforms each image into a cv::Mat, and appends it to the array
(3) Sends that information to the model to be processed.
*/
std::vector<Ort::Value> Onnx::RunBatch(std::vector<ofImage>& images){
auto start = std::chrono::high_resolution_clock::now();
// Number of images in the batch
size_t batchSize = images.size();
std::vector<int64_t> batch_node_dims = {static_cast<int64_t>(batchSize), 3, 260, 260};
std::vector<float> batch_image_array(static_cast<int64_t>(batchSize) * 3 * 260 * 260);
for(size_t i = 0; i < batchSize; i++){
TransformImage(images[i]);
// Copy the image data into the batch_image_array
std::memcpy(
batch_image_array.data() + i * 3 * 260 * 260, // Destination: starting point for this image in the batch array
image_array.data, // Source: pixel data in the cv::Mat
3 * 260 * 260 * sizeof(float) // Size: number of bytes to copy (3 channels * 260 * 260 pixels)
);
}
size_t input_tensor_size = batch_image_array.size();
std::vector<Ort::Value> input_tensors;
Ort::MemoryInfo mem_info = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault);
input_tensors.emplace_back(Ort::Value::CreateTensor<float>(mem_info, batch_image_array.data(),
input_tensor_size, batch_node_dims.data(), batch_node_dims.size()));
// double-check the dimensions of the input tensor
assert(input_tensors[0].IsTensor() && input_tensors[0].GetTensorTypeAndShapeInfo().GetShape() == batch_node_dims);
std::cout << "\ninput_tensor shape: " << PrintShape(input_tensors[0].GetTensorTypeAndShapeInfo().GetShape()) << std::endl;
// pass data through model
std::vector<const char*> input_names_char(input_node_names.size(), nullptr);
std::transform(std::begin(input_node_names), std::end(input_node_names), std::begin(input_names_char),
[&](const std::string& str) { return str.c_str(); });
std::vector<const char*> output_names_char(output_node_names.size(), nullptr);
std::transform(std::begin(output_node_names), std::end(output_node_names), std::begin(output_names_char),
[&](const std::string& str) { return str.c_str(); });
std::cout << "Running model... ";
try {
auto output_tensors = ort_session->Run(Ort::RunOptions{nullptr}, input_names_char.data(), input_tensors.data(),
input_names_char.size(), output_names_char.data(), output_names_char.size());
std::cout << "Done!" << std::endl;
if (timeStamp) {
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = end - start;
std::cout << "Update loop took " << elapsed.count() << " ms" << std::endl;
}
return output_tensors;
} catch (const Ort::Exception& exception) {
std::cout << "ERROR running model inference: " << exception.what() << std::endl;
return input_tensors;
}
}
// Transforms an ofImage into a cv::ImageArray
void Onnx::TransformImage(ofImage &img){
// Convert ofImage to cv::Mat
ofPixels &pixels = img.getPixels(); // Get pixels from ofImage
int width = img.getWidth();
int height = img.getHeight();
int channels = img.getPixels().getNumChannels();
// Create a cv::Mat from the pixel data
cv::Mat cvImg = cv::Mat(height, width, (channels == 3) ? CV_8UC3 : CV_8UC1, pixels.getData());
// Convert cv::Mat to cv::InputArray
cv::InputArray inputArray(cvImg);
image_array = cv::dnn::blobFromImage(inputArray, 1 / 255.0, cv::Size(input_node_dims[2] , input_node_dims[3] ), (0, 0, 0), false, false);
}
/* Generates a random 1 dimensional float array, creating values between 0->255.
Returns a tensor. */
Ort::Value Onnx::GenerateTensor(){
std::vector<float> random_input_tensor_values(CalculateProduct(input_node_dims));
std::generate(random_input_tensor_values.begin(), random_input_tensor_values.end(), [&] { return rand() % 255; });
return VectorToTensor(random_input_tensor_values, input_node_dims);
}
// Calculates the product of the vector, how many values.
int Onnx::CalculateProduct(const std::vector<std::int64_t>& v){
int total = 1;
for (auto& i : v) total *= i;
return total;
}
// Creates a tensor from a given vector input.
Ort::Value Onnx::VectorToTensor(std::vector<float>& data, const std::vector<std::int64_t>& shape){
Ort::MemoryInfo mem_info = Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault);
auto tensor = Ort::Value::CreateTensor<float>(mem_info, data.data(), data.size(), shape.data(), shape.size());
return tensor;
}
// Prints the shape of the given tensor (ex. input: (1, 1, 512, 512))
std::string Onnx::PrintShape(const std::vector<std::int64_t>& v){
std::stringstream ss("");
for (std::size_t i = 0; i < v.size() - 1; i++) ss << v[i] << "x";
ss << v[v.size() - 1];
return ss.str();
}
// Function to calculate the minimum value in an array
float Onnx::ReduceMin(const float* data, size_t size) {
return *std::min_element(data, data + size);
}
// Function to calculate the maximum value in an array
float Onnx::ReduceMax(const float* data, size_t size) {
return *std::max_element(data, data + size);
}
// Function to normalize an array between 0 and 1
void Onnx::Normalize(float* data, size_t size, float min_value, float max_value) {
for (size_t i = 0; i < size; ++i) {
data[i] = (data[i] - min_value) / (max_value - min_value);
}
}
// Coverts the output tensor data to a texture of a given ofFbo.
void Onnx::DataToFbo(const float* data, size_t width, size_t height, ofFbo& fbo){
// Convert data into opencv mat
cv::Mat inputMat(height, width, CV_32FC1, const_cast<float*>(data));
// Convert to 8-bit grayscale Mat
cv::Mat inputMat8U;
inputMat.convertTo(inputMat8U, CV_8UC1, 255.0); // Convert float to 8-bit grayscale
// Resize the image using OpenCV
cv::Mat resizedMat;
cv::resize(inputMat8U, resizedMat, cv::Size(fbo.getWidth(), fbo.getHeight()), 0, 0, cv::INTER_LINEAR);
// Convert OpenCV Mat to ofPixels
ofPixels pixels;
pixels.allocate(fbo.getWidth(), fbo.getHeight(), OF_PIXELS_GRAY);
// Copy data from resizedMat to ofPixels
for (size_t y = 0; y < fbo.getHeight(); ++y) {
for (size_t x = 0; x < fbo.getWidth(); ++x) {
unsigned char value = resizedMat.at<uchar>(y, x);
pixels.setColor(x, y, ofColor(value));
}
}
// Update FBO with new pixels
fbo.begin();
ofTexture& texture = fbo.getTexture();
texture.loadData(pixels);
fbo.end();
}
void Onnx::Softmax(float* data, size_t size) {
std::vector<float> logits(data, data + size);
std::vector<float> expValues(size);
float maxLogit = *std::max_element(logits.begin(), logits.end());
// Calculate exp(logit - maxLogit) for numerical stability
std::transform(logits.begin(), logits.end(), expValues.begin(),
[maxLogit](float logit) { return std::exp(logit - maxLogit); });
float sumExp = std::accumulate(expValues.begin(), expValues.end(), 0.0f);
// Normalize to get probabilities
std::transform(expValues.begin(), expValues.end(), data,
[sumExp](float expValue) { return expValue / sumExp; });
}

57
src/Onnx.h

@ -0,0 +1,57 @@
#ifndef ONNX
#define ONNX
#include <onnxruntime_cxx_api.h>
#include <algorithm> // std::generate
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <cstdlib> // For std::rand and std::srand
#include "ofMain.h"
#include "ofxOpenCv.h"
#include <numeric>
#include <cmath>
class Onnx {
public:
Onnx() {}
void Setup(ORTCHAR_T* modelPath, bool isLog, bool useCuda);
std::vector<Ort::Value> Run(ofImage &img);
std::vector<Ort::Value> RunBatch(std::vector<ofImage> &images);
std::string PrintShape(const std::vector<std::int64_t>& v);
Ort::Value VectorToTensor(std::vector<float>& data, const std::vector<std::int64_t>& shape);
Ort::Value GenerateTensor();
int CalculateProduct(const std::vector<std::int64_t>& v);
void TransformImage(ofImage &img);
float ReduceMin(const float* data, size_t size);
float ReduceMax(const float* data, size_t size);
void Normalize(float* data, size_t size, float min_value, float max_value);
void DataToFbo(const float* data, size_t width, size_t height, ofFbo& fbo);
void Softmax(float* data, size_t size);
bool timeStamp = true;
bool log = false;
protected:
Ort::Env ort_env;
Ort::SessionOptions session_options;
cv::Mat image_array;
std::shared_ptr<Ort::Session> ort_session;
std::vector<std::string> input_node_names;
std::vector<int64_t> input_node_dims; // 1 input only.
std::size_t input_tensor_size = 1;
std::vector<float> input_values_handler;
Ort::MemoryInfo memory_info_handler = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
std::vector<std::string> output_node_names;
std::vector<std::vector<int64_t>> output_node_dims; // >=1 outputs
std::vector<Ort::Value> output_values;
Ort::Value dummy_tensor{ nullptr };
std::vector<ofImage> imageBatch;
int num_outputs = 1;
};
#endif

55
src/Player.cpp

@ -0,0 +1,55 @@
#include "Player.h"
Player::Player(){
hasVideo = false;
}
/* Basic ofVideoPlayer setup */
void Player::Setup(){
videoPlayer.setLoopState(OF_LOOP_NONE);
videoPlayer.setVolume(0);
}
/* Updated the video player:
(1) Allocates the required W x H for the model input
(2) Updates the video texture, and sets the current frame value */
void Player::Update(ofImage &img){
if(!img.isAllocated() || img.getWidth() != videoPlayer.getWidth() || img.getHeight() != videoPlayer.getHeight()){
img.allocate(videoPlayer.getWidth(), videoPlayer.getHeight(), OF_IMAGE_COLOR);
std::cout << "allocating new ofImage" << std::endl;
}
if(videoPlayer.isLoaded()){
hasVideo = true;
playerCurrentFrame = videoPlayer.getCurrentFrame();
videoPlayer.update();
videoPlayer.play();
}
}
void Player::Draw(){
if(videoPlayer.isLoaded()){
videoPlayer.draw(0, 0);
}
}
ofPixels Player::GetVideoPixels(){
return videoPlayer.getPixels();
}
/* Loads the video from path:
(1) Sets the frame
(2) Allocates the fbo dims for final render */
void Player::SetVideo(std::string path, ofFbo &fbo){
videoPlayer.load(path);
videoPlayer.setFrame(800);
fbo.allocate(videoPlayer.getWidth(), videoPlayer.getHeight(), GL_RGB);
}
// Sets a random frame in the active video
void Player::SetRandomFrame(){
int randomFrame = ofRandom(0, videoPlayer.getTotalNumFrames());
std::cout << "setting frame: " << randomFrame << std::endl;
videoPlayer.setFrame(randomFrame);
}

39
src/Player.h

@ -0,0 +1,39 @@
#ifndef _PLAYER
#define _PLAYER
#include "ofMain.h"
class Player {
public:
void Setup();
void Update(ofImage &img);
void Draw();
void SetVideo(std::string path, ofFbo &fbo);
ofPixels GetVideoPixels();
void SetVideoPosition();
void SetRandomFrame();
void SetupGUI();
void UpdateGUI();
void UpdateVector();
void CheckNewFrame();
void GetCurrentFrame();
ofVideoPlayer videoPlayer;
int playerCurrentFrame;
int playerTotalFrameNum;
int playerVideoIndex;
std::string videoPath;
bool hasVideo;
glm::vec2 centerPosition;
ofFbo fbo;
Player();
};
#endif

155
src/Yolo.cpp

@ -0,0 +1,155 @@
#include "Yolo.h"
// Takes output tensor data, processes that data, and returns an array of BoxfWithLandmarks (detected_faces)
void Yolo::ParseOutput(float* &output_tensors, std::vector<types::BoxfWithLandmarks> &sorted_faces, unsigned int num_anchors) {
std::vector<types::BoxfWithLandmarks> detected_faces;
for (unsigned int i = 0; i < num_anchors; ++i) {
const float *row_ptr = output_tensors + i * 16; // Each row contains 16 values
float obj_conf = row_ptr[4]; // Objectness confidence
if (obj_conf < 0.5) continue; // Filter out low-confidence detections
// Extract bounding box, confidence, and landmarks
float cx = row_ptr[0];
float cy = row_ptr[1];
float w = row_ptr[2];
float h = row_ptr[3];
float cls_conf = row_ptr[15]; // Face confidence score
if (cls_conf < 0.5) continue; // Filter by class confidence
types::BoxfWithLandmarks face;
face.box.x1 = cx - w / 2;
face.box.y1 = cy - h / 2;
face.box.x2 = cx + w / 2;
face.box.y2 = cy + h / 2;
face.box.score = cls_conf;
face.box.label_text = "face";
// Extract landmarks
for (int j = 0; j < 10; j += 2) {
face.landmarks.points.push_back(cv::Point2f(row_ptr[5 + j], row_ptr[5 + j + 1]));
}
detected_faces.push_back(face); // Store the detected face with landmarks
}
// Apply NMS to detected faces list to remove any overlapping bounding boxes.
NonMaximumSuppression(detected_faces, sorted_faces, 0.5);
// Sort faces based on confidence value
SortDetectedFaces(sorted_faces);
}
// Simple helper for drawing boxes given x1, y1, x2, y2 coordinates.
void Yolo::DrawBox(std::vector<types::BoxfWithLandmarks> &detected_faces){
for (const auto &face : detected_faces) {
ofNoFill();
ofDrawRectangle(face.box.x1, face.box.y1, face.box.x2 - face.box.x1, face.box.y2 - face.box.y1);
}
}
// Simple helper to draw boxes at the center of the detected face.
void Yolo::DrawCenter(std::vector<types::BoxfWithLandmarks> &detected_faces){
ofNoFill();
ofDrawCircle(detected_faces[0].box.center, 5);
}
// Applies NMS to an array of BoxfWithLandmarks.face.boxes, to remove any overlapping bounding boxes.
void Yolo::NonMaximumSuppression(std::vector<types::BoxfWithLandmarks> &input_faces, std::vector<types::BoxfWithLandmarks> &output_faces, float iou_threshold)
{
// Sort the boxes by their confidence scores (highest to lowest)
std::sort(input_faces.begin(), input_faces.end(),
[](const types::BoxfWithLandmarks &a, const types::BoxfWithLandmarks &b) {
return a.box.score > b.box.score;
});
std::vector<int> suppressed(input_faces.size(), 0); // Suppression mask
// Iterate through the boxes
for (size_t i = 0; i < input_faces.size(); ++i) {
if (suppressed[i]) continue; // Skip already suppressed boxes
// Add this box to the output
output_faces.push_back(input_faces[i]);
for (size_t j = i + 1; j < input_faces.size(); ++j) {
if (suppressed[j]) continue;
// Calculate IoU between box i and box j
float iou = input_faces[i].box.iou_of(input_faces[j].box);
// Suppress box j if IoU is greater than the threshold
if (iou > iou_threshold) {
suppressed[j] = 1;
}
}
}
}
// Scales the coordinates of detected faces from the model output dimensions -> the original input image dimensions.
void Yolo::ConvertBoxCoordsToOriginalSize(std::vector<types::BoxfWithLandmarks> &detected_faces, size_t original_width, size_t original_height){
float width_scale = static_cast<float>(original_width) / modelSize;
float height_scale = static_cast<float>(original_height) / modelSize;
for (auto &face : detected_faces) {
// Convert bounding box coordinates
face.box.x1 *= width_scale;
face.box.y1 *= height_scale;
face.box.x2 *= width_scale;
face.box.y2 *= height_scale;
face.box.UpdateCenter();
// Convert landmarks
for (size_t j = 0; j < face.landmarks.points.size(); ++j) {
face.landmarks.points[j].x *= width_scale;
face.landmarks.points[j].y *= height_scale;
}
}
}
void Yolo::CropFaceToImage(ofImage &inputImage, types::BoxfWithLandmarks &face, ofxCvColorImage &colorImage){
colorImage.resetROI();
// Calculate the coordinates and dimensions of the face box
float x1 = face.box.x1;
float y1 = face.box.y1;
float x2 = face.box.x2;
float y2 = face.box.y2;
// Ensure coordinates are within the input image bounds
x1 = ofClamp(x1, 0.0f, (float)inputImage.getWidth());
y1 = ofClamp(y1, 0.0f, (float)inputImage.getHeight());
x2 = ofClamp(x2, 0.0f, (float)inputImage.getWidth());
y2 = ofClamp(y2, 0.0f, (float)inputImage.getHeight());
// Calculate width and height of the cropped area
float cropWidth = x2 - x1;
float cropHeight = y2 - y1;
// Create cropped section, defined by the box coords
ofFbo tempFbo;
tempFbo.allocate(cropWidth, cropHeight, GL_RGB);
tempFbo.begin();
ofClear(0);
inputImage.getTexture().drawSubsection(0, 0, cropWidth, cropHeight, x1, y1);
tempFbo.end();
ofFloatPixels pix;
tempFbo.readToPixels(pix);
colorImage.setFromPixels(pix);
colorImage.resize(260, 260);
}
void Yolo::SortDetectedFaces(std::vector<types::BoxfWithLandmarks> &detectedFaces){
std::sort(detectedFaces.begin(), detectedFaces.end(),
[](const types::BoxfWithLandmarks &a, const types::BoxfWithLandmarks &b) {
return a.box.score > b.box.score; // Sort in descending order
});
}

81
src/Yolo.h

@ -0,0 +1,81 @@
#ifndef YOLO
#define YOLO
#include "ofMain.h"
#include "ofxOpenCv.h"
#include <onnxruntime_cxx_api.h>
#include <algorithm>
struct Emotef{
float emotions[7];
};
namespace types {
/*
Struct for storing information about detetced faces.
*/
struct Boxf {
float x1, y1, x2, y2; // Coordinates of the bounding box
float score; // Confidence score
glm::vec2 center;
int label; // Class label (e.g., "face")
std::string label_text;
Emotef emotional_state;
// Calculate Intersection over Union (IoU) with another box
float iou_of(const Boxf &other) const {
float intersection_x1 = std::max(x1, other.x1);
float intersection_y1 = std::max(y1, other.y1);
float intersection_x2 = std::min(x2, other.x2);
float intersection_y2 = std::min(y2, other.y2);
float intersection_area = std::max(0.0f, intersection_x2 - intersection_x1) *
std::max(0.0f, intersection_y2 - intersection_y1);
float this_area = (x2 - x1) * (y2 - y1);
float other_area = (other.x2 - other.x1) * (other.y2 - other.y1);
float union_area = this_area + other_area - intersection_area;
return intersection_area / union_area;
}
void UpdateCenter(){
center.x = (x1 + x2) / 2;
center.y = (y1 + y2) / 2;
}
void SetEmotionState(float* emotional_data){
std::copy(emotional_data, emotional_data + 7, emotional_state.emotions);
}
};
struct Landmarks {
std::vector<cv::Point2f> points; // Facial landmarks points (e.g., eyes, nose, mouth)
bool flag = false; // Indicator if landmarks are available
};
struct BoxfWithLandmarks {
Boxf box; // Bounding box for the face
Landmarks landmarks; // Landmark points for the face
bool flag = false; // Indicator if this detection is valid
};
}
class Yolo{
public:
Yolo(){};
void ParseOutput(float* &out_ptr, std::vector<types::BoxfWithLandmarks> &sorted_faces, unsigned int num_anchors);
void DrawBox(std::vector<types::BoxfWithLandmarks> &detected_faces);
void DrawCenter(std::vector<types::BoxfWithLandmarks> &detected_faces);
void NonMaximumSuppression(std::vector<types::BoxfWithLandmarks> &input_faces, std::vector<types::BoxfWithLandmarks> &output_faces, float iou_threshold);
void ConvertBoxCoordsToOriginalSize(std::vector<types::BoxfWithLandmarks> &detected_faces, size_t original_width, size_t original_height);
void CropFaceToImage(ofImage &inputImage, types::BoxfWithLandmarks &face, ofxCvColorImage &colorImage);
void SortDetectedFaces(std::vector<types::BoxfWithLandmarks> &detectedFaces);
private:
// Input dimenions of the model -- used for coordinate scaling.
size_t modelSize = 640;
};
#endif

17
src/main.cpp

@ -0,0 +1,17 @@
#include "ofMain.h"
#include "ofApp.h"
//========================================================================
int main( ){
//Use ofGLFWWindowSettings for more options like multi-monitor fullscreen
ofGLWindowSettings settings;
settings.setSize(1280, 720);
settings.windowMode = OF_WINDOW; //can also be OF_FULLSCREEN
auto window = ofCreateWindow(settings);
ofRunApp(window, make_shared<ofApp>());
ofRunMainLoop();
}

210
src/ofApp.cpp

@ -0,0 +1,210 @@
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
ofSetFrameRate(24);
ofSetVerticalSync(true);
player.Setup();
player.SetVideo("videos/demo.mp4", fbo);
emoteImage.allocate(260, 260);
tempImage.allocate(emoteImage.getWidth(), emoteImage.getHeight(), OF_IMAGE_COLOR);
ORTCHAR_T* modelPath = "/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/apps/myApps/onnx-test/bin/data/depth_anything_v2_vitb.onnx";
ORTCHAR_T* modelPath2 = "/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/apps/myApps/onnx-test/bin/data/yolov5s-face.onnx";
ORTCHAR_T* modelPath3 = "/home/cailean/Desktop/openframeworks/of_v0.12.0_linux64gcc6_release/apps/myApps/onnx-test/bin/data/rgb_emotion.onnx";
/* Setup Models (modelPath, log, useCuda) */
yolo.Setup(modelPath2, false, true);
depth.Setup(modelPath, false, true);
emotion.Setup(modelPath3, false, true);
}
//--------------------------------------------------------------
void ofApp::update(){
/* Check to see if the application has moved to the first frame
As the models need to load first, as the first inference is quite slow */
if(ofGetFrameNum() > 0)
firstRun = false;
/* Clear detetced face list */
detected_faces.clear();
/* Setup model input using ofImage */
player.Update(img);
img.setFromPixels(player.GetVideoPixels());
/* Run Models */
try{
auto output_tensors = depth.Run(img);
float* output_ptr = output_tensors.front().GetTensorMutableData<float>();
size_t num_elements = output_tensors.front().GetTensorTypeAndShapeInfo().GetElementCount();
float min_value = depth.ReduceMin(output_ptr, num_elements);
float max_value = depth.ReduceMax(output_ptr, num_elements);
depth.Normalize(output_ptr, num_elements, min_value, max_value);
depth.DataToFbo(output_ptr, 518, 518, fbo);
auto output_tensors_face = yolo.Run(img);
auto output_faces = output_tensors_face.front().GetTensorTypeAndShapeInfo().GetShape();
unsigned int num_anchors = output_faces[1]; // Number of anchors
float* output_face_ptr = output_tensors_face.front().GetTensorMutableData<float>();
faceDetector.ParseOutput(output_face_ptr, detected_faces, num_anchors);
faceDetector.ConvertBoxCoordsToOriginalSize(detected_faces, fbo.getWidth(), fbo.getHeight());
/* As no input is generated for the emotion recognition model, run a dummy vector through the model
So it can load */
if(firstRun){
/*
Create a dummy initial input of batch_size = 5, as
when initialising the model, it will attempt to create a space in memory for this array.
If the batch_size does change it will completely slow down inference, due to how the cudnn_search_algo is set.
None of the other search alogithms bar EXHAUSTIVE will work.. no idead why.
*/
for(int i = 0; i < emotionImageMaxBatchSize; i++){
tempImage.setFromPixels(emoteImage.getPixels());
croppedFaces.push_back(tempImage);
}
// Run model to warmup
auto emotion_output_tensor = emotion.RunBatch(croppedFaces);
} else {
inferEmotionalState();
}
/* Run emotion inference */
//inferEmotionalState();
} catch (exception e){
std::cout << "Model did not run" << std::endl;
}
}
//--------------------------------------------------------------
void ofApp::draw(){
fbo.draw(0, 0);
if(!firstRun){
faceDetector.DrawBox(detected_faces);
faceDetector.DrawCenter(detected_faces);
}
// emoteImage.draw(640, 0);
// for(auto& face : detected_faces){
// ofDrawBitmapString(std::to_string(face.box.emotional_state.emotions[0]), 700, 300);
// }
}
//--------------------------------------------------------------
void ofApp::inferEmotionalState(){
/*
Max faces to process with the model (5)
*/
int max_faces_to_process = std::min(emotionImageMaxBatchSize, static_cast<int>(detected_faces.size()));
/*
For the detetced faces, set the cropped image to a location in the image batch array
*/
for (size_t i = 0; i < max_faces_to_process; i++){
auto& face = detected_faces[i];
faceDetector.CropFaceToImage(img, face, emoteImage);
tempImage.setFromPixels(emoteImage.getPixels());
croppedFaces[i] = tempImage;
}
auto emotion_output_tensor = emotion.RunBatch(croppedFaces);
auto& output_tensor = emotion_output_tensor.front();
auto output_shap = output_tensor.GetTensorTypeAndShapeInfo().GetShape();
size_t batch_size = output_shap[0]; // Number of images in the batch
size_t num_classes = output_shap[1]; // Number of emotion classes
std::cout << batch_size << " : " << num_classes << std::endl;
// for(int i = 0; i < max_faces_to_process; ++i){
// auto& face = detected_faces[i];
// faceDetector.CropFaceToImage(img, face, emoteImage);
// tempImage.setFromPixels(emoteImage.getPixels());
// auto emotion_output_tensor = emotion.Run(tempImage);
// float* emotional_data = emotion_output_tensor.front().GetTensorMutableData<float>();
// emotion.Softmax(emotional_data, 7);
// face.box.SetEmotionState(emotional_data);
// }
std::cout << croppedFaces.size() << std::endl;
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key){
if (key=OF_KEY_LEFT){
player.SetRandomFrame();
}
}
//--------------------------------------------------------------
void ofApp::keyReleased(int key){
}
//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){
}
//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){
}
//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){
}
//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){
}
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}
//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){
}
//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){
}

49
src/ofApp.h

@ -0,0 +1,49 @@
#pragma once
#include "ofMain.h"
#include <onnxruntime_cxx_api.h>
#include "ofxOpenCv.h"
#include "Onnx.h"
#include "Yolo.h"
#include <vector>
#include "Player.h"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y );
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
void inferEmotionalState();
ofImage img;
ofFbo fbo;
cv::Mat cvImg;
ofVideoGrabber webcam;
Player player;
bool firstRun = true;
Onnx depth;
Onnx yolo;
Onnx emotion;
ofxCvColorImage emoteImage;
ofImage tempImage;
std::vector<ofImage> croppedFaces;
int emotionImageMaxBatchSize = 5;
Emotef emo;
Yolo faceDetector;
std::vector<types::BoxfWithLandmarks> detected_faces;
};
Loading…
Cancel
Save