diff --git a/CMakeLists.txt b/CMakeLists.txt index a1a4216..f8943d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,4 +78,8 @@ add_executable(CurvesExample examples/curves.cpp) target_include_directories(CurvesExample PRIVATE ".") target_link_libraries(CurvesExample RemoteCapturyStatic Threads::Threads) -add_custom_target(Examples DEPENDS PollingExample CallbackExample CurvesExample) +add_executable(SearchExample examples/search.cpp) +target_include_directories(SearchExample PRIVATE ".") +target_link_libraries(SearchExample RemoteCapturyStatic Threads::Threads) + +add_custom_target(Examples DEPENDS PollingExample CallbackExample CurvesExample SearchExample) diff --git a/examples/curves.cpp b/examples/curves.cpp index da56d9f..d53e5b9 100644 --- a/examples/curves.cpp +++ b/examples/curves.cpp @@ -41,17 +41,37 @@ int main(int argc, char** argv) // Here we stream angle data rather than pose data. This can be easier to process, e.g. in biofeedback applications. // Additional flags should be added as required. uint16_t angles[] = {CAPTURY_LEFT_KNEE_FLEXION_EXTENSION, CAPTURY_RIGHT_KNEE_FLEXION_EXTENSION}; - Captury_startStreamingImagesAndAngles(CAPTURY_STREAM_ANGLES, /*camera*/-1, 2, angles); + Captury_startStreamingImagesAndAngles(CAPTURY_STREAM_POSES | CAPTURY_STREAM_ANGLES, /*camera*/-1, 2, angles); #ifdef WIN32 Sleep(100000); #else - usleep(100000*1000); + usleep(10000*1000); #endif // instead of the callback approach you can also use polling like this: - // int numAngles; - // CapturyAngleData* angles = Captury_getCurrentAngles(actorId, &numAngles); + uint64_t lastTimestamp = 0; + while (true) { + // get list of actors - otherwise we won't know whom to poll + const CapturyActor* actors; + int numActors = Captury_getActors(&actors); + + for (int i = 0; i < numActors; ++i) { + int numAngles; + CapturyAngleData* angles = Captury_getCurrentAngles(actors[i].id, &numAngles); + if (angles == NULL) + continue; + + for (int n = 0; n < numAngles; ++n) + Captury_log(CAPTURY_LOG_INFO, "actor %x has new angle %d: %g\n", actors[i].id, angles[n].type, angles[n].value); + } + + #ifdef WIN32 + Sleep(20); + #else + usleep(20*1000); + #endif + } Captury_stopStreaming(); diff --git a/examples/search.cpp b/examples/search.cpp new file mode 100644 index 0000000..a1ea65d --- /dev/null +++ b/examples/search.cpp @@ -0,0 +1,116 @@ +#include +#include "RemoteCaptury.h" +#ifndef WIN32 +#include +#endif + +// This example uses the callback interface to get the current pose of all actors from CapturyLive + + + +// This callback is called every time a new pose becomes available. +// Make sure this callback is quick. Otherwise frames may get dropped. +void newPoseCallback(CapturyActor* actor, CapturyPose* pose, int trackingQuality) +{ + Captury_log(CAPTURY_LOG_INFO, "actor %x has a new pose now\n", actor->id); +} + +// this is called whenever an actor changes state (starts or stops tracking or finishes scaling or is deleted). +// Make sure this callback is quick. Otherwise frames may get dropped. +void actorChangedCallback(int actorId, int mode) +{ + Captury_log(CAPTURY_LOG_INFO, "actor %x has state %s now\n", actorId, CapturyActorStatusString[mode]); + + switch (mode) { + case ACTOR_SCALING: + break; + case ACTOR_TRACKING: + break; + case ACTOR_STOPPED: + break; + case ACTOR_DELETED: + break; + case ACTOR_UNKNOWN: + break; + } + + const CapturyActor* actor = Captury_getActor(actorId); + // do something with it +} + +int main(int argc, char** argv) +{ + // This is cheating a little as we're not connecting to a remote machine + // but you can change the IP. There is also a more advanced version of Captury_connect() that gives you more options + // to control ports or to enable asynchronous connect mode. + int ret = Captury_connect("127.0.0.1", 2101); + if (ret == 0) + return -1; + + // This is optional but sometimes it's quite useful to know the exact time on the CapturyLive machine. + // The accuracy of the synchronization depends primarily on your OS and the network topology between + // the CapturyLive machine and this machine. On a LAN running Windows on the target machine you can + // expect about 100us accuracy. + Captury_startTimeSynchronizationLoop(); + + // register callback that is called in a different thread whenever a new pose becomes available + ret = Captury_registerNewPoseCallback(newPoseCallback); + if (ret == 0) + return -1; + + ret = Captury_registerActorChangedCallback(actorChangedCallback); + if (ret == 0) + return -1; + + // start streaming + // The recommended features are CAPTURY_STREAM_POSES and CAPTURY_STREAM_COMPRESSED. + // Additional flags should be added as required. + Captury_startStreaming(CAPTURY_STREAM_POSES | CAPTURY_STREAM_COMPRESSED); + + while (true) { + // get list of actors - otherwise we won't know whom to poll + const CapturyActor* actors; + int numActors = Captury_getActors(&actors); + + // check whether there is a person being tracked already + bool anyAlive = false; + for (int i = 0; i < numActors; ++i) { + int status = Captury_getActorStatus(actors[i].id); + + switch (status) { + case ACTOR_SCALING: + case ACTOR_TRACKING: + anyAlive = true; + break; + case ACTOR_STOPPED: + // keep the list of actors clean + Captury_deleteActor(actors[i].id); + break; + case ACTOR_DELETED: + case ACTOR_UNKNOWN: + break; + } + if (anyAlive) + break; + } + + // if there is no person being tracked, try to find a new one + if (!anyAlive) { + // try to find a new actor at the location (1m, 1m) with any orientation (500 > 360deg) + Captury_snapActor(-1000.0f, 0.0f, 500.0f); + } + + // sleep 1 second + #ifdef WIN32 + Sleep(1000); + #else + usleep(1000*1000); + #endif + } + + Captury_stopStreaming(); + + Captury_disconnect(); + + return 0; +}