camenduru's picture
thanks to openpose ❤
7fc5a59
#ifndef OPENPOSE_WRAPPER_WRAPPER_HPP
#define OPENPOSE_WRAPPER_WRAPPER_HPP
#include <openpose/core/common.hpp>
#include <openpose/thread/headers.hpp>
#include <openpose/wrapper/enumClasses.hpp>
#include <openpose/wrapper/wrapperStructExtra.hpp>
#include <openpose/wrapper/wrapperStructFace.hpp>
#include <openpose/wrapper/wrapperStructGui.hpp>
#include <openpose/wrapper/wrapperStructHand.hpp>
#include <openpose/wrapper/wrapperStructInput.hpp>
#include <openpose/wrapper/wrapperStructOutput.hpp>
#include <openpose/wrapper/wrapperStructPose.hpp>
namespace op
{
/**
* WrapperT: OpenPose all-in-one wrapper template class. Simplified into Wrapper for WrapperT<std::vector<Datum>>
* WrapperT allows the user to set up the input (video, webcam, custom input, etc.), pose, face and/or hands
* estimation and rendering, and output (integrated small GUI, custom output, etc.).
*
* This function can be used in 2 ways:
* - Synchronous mode: call the full constructor with your desired input and output workers.
* - Asynchronous mode: call the empty constructor WrapperT() + use the emplace and pop functions to push the
* original frames and retrieve the processed ones.
* - Mix of them:
* - Synchronous input + asynchronous output: call the constructor WrapperT(ThreadManagerMode::Synchronous,
* workersInput, {}, true)
* - Asynchronous input + synchronous output: call the constructor
* WrapperT(ThreadManagerMode::Synchronous, nullptr, workersOutput, irrelevantBoolean, true)
*/
template<typename TDatum = BASE_DATUM,
typename TDatums = std::vector<std::shared_ptr<TDatum>>,
typename TDatumsSP = std::shared_ptr<TDatums>,
typename TWorker = std::shared_ptr<Worker<TDatumsSP>>>
class WrapperT
{
public:
/**
* Constructor.
* @param threadManagerMode Thread synchronization mode. If set to ThreadManagerMode::Synchronous, everything
* will run inside the WrapperT. If ThreadManagerMode::Synchronous(In/Out), then input (frames producer) and/or
* output (GUI, writing results, etc.) will be controlled outside the WrapperT class by the user. See
* ThreadManagerMode for a detailed explanation of when to use each one.
*/
explicit WrapperT(const ThreadManagerMode threadManagerMode = ThreadManagerMode::Synchronous);
/**
* Destructor.
* It automatically frees resources.
*/
virtual ~WrapperT();
/**
* Disable multi-threading.
* Useful for debugging and logging, all the Workers will run in the same thread.
* Note that workerOnNewThread (argument for setWorker function) will not make any effect.
*/
void disableMultiThreading();
/**
* Add an user-defined extra Worker for a desired task (input, output, ...).
* @param workerType WorkerType to configure (e.g., Input, PreProcessing, PostProcessing, Output).
* @param worker TWorker to be added.
* @param workerOnNewThread Whether to add this TWorker on a new thread (if it is computationally demanding) or
* simply reuse existing threads (for light functions). Set to true if the performance time is unknown.
*/
void setWorker(const WorkerType workerType, const TWorker& worker, const bool workerOnNewThread = true);
/**
* It configures the pose parameters. Do not call for default values.
*/
void configure(const WrapperStructPose& wrapperStructPose);
/**
* Analogous to configure(WrapperStructPose) but applied to face (WrapperStructFace)
*/
void configure(const WrapperStructFace& wrapperStructFace);
/**
* Analogous to configure() but applied to hand (WrapperStructHand)
*/
void configure(const WrapperStructHand& wrapperStructHand);
/**
* Analogous to configure() but applied to the extra options (WrapperStructExtra)
*/
void configure(const WrapperStructExtra& wrapperStructExtra);
/**
* Analogous to configure() but applied to the input (WrapperStructInput)
*/
void configure(const WrapperStructInput& wrapperStructInput);
/**
* Analogous to configure() but applied to the output (WrapperStructOutput)
*/
void configure(const WrapperStructOutput& wrapperStructOutput);
/**
* Analogous to configure() but applied to the GUI (WrapperStructGui)
*/
void configure(const WrapperStructGui& wrapperStructGui);
/**
* Function to start multi-threading.
* Similar to start(), but exec() blocks the thread that calls the function (it saves 1 thread). Use exec()
* instead of start() if the calling thread will otherwise be waiting for the WrapperT to end.
*/
void exec();
/**
* Function to start multi-threading.
* Similar to exec(), but start() does not block the thread that calls the function. It just opens new threads,
* so it lets the user perform other tasks meanwhile on the calling thread.
* VERY IMPORTANT NOTE: if the GUI is selected and OpenCV is compiled with Qt support, this option will not
* work. Qt needs the main thread to plot visual results, so the final GUI (which uses OpenCV) would return an
* exception similar to: `QMetaMethod::invoke: Unable to invoke methods with return values in queued
* connections`. Use exec() in that case.
*/
void start();
/**
* Function to stop multi-threading.
* It can be called internally or externally.
*/
void stop();
/**
* Whether the WrapperT is running.
* It will return true after exec() or start() and before stop(), and false otherwise.
* @return Boolean specifying whether the WrapperT is running.
*/
bool isRunning() const;
/**
* It sets the maximum number of elements in the queue.
* For maximum speed, set to a very large number, but the trade-off would be:
* - Latency will hugely increase.
* - The program might go out of RAM memory (so the computer might freeze).
* For minimum latency while keeping an optimal speed, set to -1, that will automatically
* detect the ideal number based on how many elements are connected to that queue.
* @param defaultMaxSizeQueues long long element with the maximum number of elements on the queue.
*/
void setDefaultMaxSizeQueues(const long long defaultMaxSizeQueues = -1);
/**
* Emplace (move) an element on the first (input) queue.
* Only valid if ThreadManagerMode::Asynchronous or ThreadManagerMode::AsynchronousIn.
* If the input queue is full or the WrapperT was stopped, it will return false and not emplace it.
* @param tDatums TDatumsSP element to be emplaced.
* @return Boolean specifying whether the tDatums could be emplaced.
*/
bool tryEmplace(TDatumsSP& tDatums);
/**
* Emplace (move) an element on the first (input) queue.
* Similar to tryEmplace.
* However, if the input queue is full, it will wait until it can emplace it.
* If the WrapperT class is stopped before adding the element, it will return false and not emplace it.
* @param tDatums TDatumsSP element to be emplaced.
* @return Boolean specifying whether the tDatums could be emplaced.
*/
bool waitAndEmplace(TDatumsSP& tDatums);
/**
* Similar to waitAndEmplace(const TDatumsSP& tDatums), but it takes a Matrix as input.
* @param matrix Matrix with the image to be processed.
* @return Boolean specifying whether the tDatums could be emplaced.
*/
bool waitAndEmplace(Matrix& matrix);
/**
* Push (copy) an element on the first (input) queue.
* Same as tryEmplace, but it copies the data instead of moving it.
* @param tDatums TDatumsSP element to be pushed.
* @return Boolean specifying whether the tDatums could be pushed.
*/
bool tryPush(const TDatumsSP& tDatums);
/**
* Push (copy) an element on the first (input) queue.
* Same as waitAndEmplace, but it copies the data instead of moving it.
* @param tDatums TDatumsSP element to be pushed.
* @return Boolean specifying whether the tDatums could be pushed.
*/
bool waitAndPush(const TDatumsSP& tDatums);
/**
* Similar to waitAndPush(const TDatumsSP& tDatums), but it takes a Matrix as input.
* @param matrix Matrix with the image to be processed.
* @return Boolean specifying whether the tDatums could be pushed.
*/
bool waitAndPush(const Matrix& matrix);
/**
* Pop (retrieve) an element from the last (output) queue.
* Only valid if ThreadManagerMode::Asynchronous or ThreadManagerMode::AsynchronousOut.
* If the output queue is empty or the WrapperT was stopped, it will return false and not retrieve it.
* @param tDatums TDatumsSP element where the retrieved element will be placed.
* @return Boolean specifying whether the tDatums could be retrieved.
*/
bool tryPop(TDatumsSP& tDatums);
/**
* Pop (retrieve) an element from the last (output) queue.
* Similar to tryPop.
* However, if the output queue is empty, it will wait until it can pop an element.
* If the WrapperT class is stopped before popping the element, it will return false and not retrieve it.
* @param tDatums TDatumsSP element where the retrieved element will be placed.
* @return Boolean specifying whether the tDatums could be retrieved.
*/
bool waitAndPop(TDatumsSP& tDatums);
/**
* Runs both waitAndEmplace and waitAndPop.
* @param tDatums TDatumsSP element where the retrieved element will be placed.
* @return Boolean specifying whether the tDatums could be retrieved.
*/
bool emplaceAndPop(TDatumsSP& tDatums);
/**
* Similar to emplaceAndPop(TDatumsSP& tDatums), but it takes a Matrix as input.
* @param matrix Matrix with the image to be processed.
* @return TDatumsSP element where the processed information will be placed.
*/
TDatumsSP emplaceAndPop(const Matrix& matrix);
private:
const ThreadManagerMode mThreadManagerMode;
ThreadManager<TDatumsSP> mThreadManager;
bool mMultiThreadEnabled;
// Configuration
WrapperStructPose mWrapperStructPose;
WrapperStructFace mWrapperStructFace;
WrapperStructHand mWrapperStructHand;
WrapperStructExtra mWrapperStructExtra;
WrapperStructInput mWrapperStructInput;
WrapperStructOutput mWrapperStructOutput;
WrapperStructGui mWrapperStructGui;
// User configurable workers
std::array<bool, int(WorkerType::Size)> mUserWsOnNewThread;
std::array<std::vector<TWorker>, int(WorkerType::Size)> mUserWs;
DELETE_COPY(WrapperT);
};
// Type
typedef WrapperT<BASE_DATUM> Wrapper;
}
// Implementation
#include <openpose/wrapper/wrapperAuxiliary.hpp>
namespace op
{
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::WrapperT(const ThreadManagerMode threadManagerMode) :
mThreadManagerMode{threadManagerMode},
mThreadManager{threadManagerMode},
mMultiThreadEnabled{true}
{
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::~WrapperT()
{
try
{
stop();
// Reset mThreadManager
mThreadManager.reset();
// Reset user workers
for (auto& userW : mUserWs)
userW.clear();
}
catch (const std::exception& e)
{
errorDestructor(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::disableMultiThreading()
{
try
{
mMultiThreadEnabled = false;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::setWorker(
const WorkerType workerType, const TWorker& worker, const bool workerOnNewThread)
{
try
{
// Sanity check
if (worker == nullptr)
error("Your worker is a nullptr.", __LINE__, __FILE__, __FUNCTION__);
// Add worker
mUserWs[int(workerType)].clear();
mUserWs[int(workerType)].emplace_back(worker);
mUserWsOnNewThread[int(workerType)] = workerOnNewThread;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::configure(const WrapperStructPose& wrapperStructPose)
{
try
{
mWrapperStructPose = wrapperStructPose;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::configure(const WrapperStructFace& wrapperStructFace)
{
try
{
mWrapperStructFace = wrapperStructFace;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::configure(const WrapperStructHand& wrapperStructHand)
{
try
{
mWrapperStructHand = wrapperStructHand;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::configure(const WrapperStructExtra& wrapperStructExtra)
{
try
{
mWrapperStructExtra = wrapperStructExtra;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::configure(const WrapperStructInput& wrapperStructInput)
{
try
{
mWrapperStructInput = wrapperStructInput;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::configure(const WrapperStructOutput& wrapperStructOutput)
{
try
{
mWrapperStructOutput = wrapperStructOutput;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::configure(const WrapperStructGui& wrapperStructGui)
{
try
{
mWrapperStructGui = wrapperStructGui;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::exec()
{
try
{
configureThreadManager<TDatum, TDatums, TDatumsSP, TWorker>(
mThreadManager, mMultiThreadEnabled, mThreadManagerMode, mWrapperStructPose, mWrapperStructFace,
mWrapperStructHand, mWrapperStructExtra, mWrapperStructInput, mWrapperStructOutput, mWrapperStructGui,
mUserWs, mUserWsOnNewThread);
opLog("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
mThreadManager.exec();
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::start()
{
try
{
configureThreadManager<TDatum, TDatums, TDatumsSP, TWorker>(
mThreadManager, mMultiThreadEnabled, mThreadManagerMode, mWrapperStructPose, mWrapperStructFace,
mWrapperStructHand, mWrapperStructExtra, mWrapperStructInput, mWrapperStructOutput, mWrapperStructGui,
mUserWs, mUserWsOnNewThread);
opLog("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
mThreadManager.start();
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::stop()
{
try
{
mThreadManager.stop();
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
bool WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::isRunning() const
{
try
{
return mThreadManager.isRunning();
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return false;
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
void WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::setDefaultMaxSizeQueues(const long long defaultMaxSizeQueues)
{
try
{
mThreadManager.setDefaultMaxSizeQueues(defaultMaxSizeQueues);
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
bool WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::tryEmplace(TDatumsSP& tDatums)
{
try
{
if (!mUserWs[int(WorkerType::Input)].empty())
error("Emplace cannot be called if an input worker was already selected.",
__LINE__, __FUNCTION__, __FILE__);
// tryEmplace for 1 camera
if (tDatums->size() < 2)
{
return mThreadManager.tryEmplace(tDatums);
}
// tryEmplace for multiview
else
{
bool successfulEmplace = true;
for (auto datumIndex = 0u; datumIndex < tDatums->size(); ++datumIndex)
{
auto tDatumsSingle = std::make_shared<TDatums>(TDatums({ tDatums->at(datumIndex) }));
if (!tryEmplace(tDatumsSingle))
{
successfulEmplace = false;
break;
}
}
return successfulEmplace;
}
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return false;
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
bool WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::waitAndEmplace(TDatumsSP& tDatums)
{
try
{
if (!mUserWs[int(WorkerType::Input)].empty())
error("Emplace cannot be called if an input worker was already selected.",
__LINE__, __FUNCTION__, __FILE__);
// waitAndEmplace for 1 camera
if (tDatums->size() < 2)
{
return mThreadManager.waitAndEmplace(tDatums);
}
// waitAndEmplace for multiview
else
{
bool successfulEmplace = true;
for (auto datumIndex = 0u ; datumIndex < tDatums->size() ; ++datumIndex)
{
auto tDatumsSingle = std::make_shared<TDatums>(TDatums({tDatums->at(datumIndex)}));
if (!waitAndEmplace(tDatumsSingle))
{
successfulEmplace = false;
opLog("Waiting to emplace for multi-camera failed.",
Priority::High, __LINE__, __FUNCTION__, __FILE__);
break;
}
}
return successfulEmplace;
}
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return false;
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
bool WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::waitAndEmplace(Matrix& matrix)
{
try
{
// Create new datum
auto datumsPtr = std::make_shared<std::vector<std::shared_ptr<TDatum>>>();
datumsPtr->emplace_back();
auto& tDatumPtr = datumsPtr->at(0);
tDatumPtr = std::make_shared<TDatum>();
// Fill datum
std::swap(tDatumPtr->cvInputData, matrix);
// Return result
return waitAndEmplace(datumsPtr);
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return false;
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
bool WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::tryPush(const TDatumsSP& tDatums)
{
try
{
if (!mUserWs[int(WorkerType::Input)].empty())
error("Push cannot be called if an input worker was already selected.",
__LINE__, __FUNCTION__, __FILE__);
return mThreadManager.tryPush(tDatums);
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return false;
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
bool WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::waitAndPush(const TDatumsSP& tDatums)
{
try
{
if (!mUserWs[int(WorkerType::Input)].empty())
error("Push cannot be called if an input worker was already selected.",
__LINE__, __FUNCTION__, __FILE__);
return mThreadManager.waitAndPush(tDatums);
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return false;
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
bool WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::waitAndPush(const Matrix& matrix)
{
try
{
// Create new datum
auto datumsPtr = std::make_shared<std::vector<std::shared_ptr<TDatum>>>();
datumsPtr->emplace_back();
auto& tDatumPtr = datumsPtr->at(0);
tDatumPtr = std::make_shared<TDatum>();
// Fill datum
tDatumPtr->cvInputData = matrix.clone();
// Return result
return waitAndEmplace(datumsPtr);
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return false;
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
bool WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::tryPop(TDatumsSP& tDatums)
{
try
{
if (!mUserWs[int(WorkerType::Output)].empty())
error("Pop cannot be called if an output worker was already selected.",
__LINE__, __FUNCTION__, __FILE__);
return mThreadManager.tryPop(tDatums);
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return false;
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
bool WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::waitAndPop(TDatumsSP& tDatums)
{
try
{
if (!mUserWs[int(WorkerType::Output)].empty())
error("Pop cannot be called if an output worker was already selected.",
__LINE__, __FUNCTION__, __FILE__);
return mThreadManager.waitAndPop(tDatums);
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return false;
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
bool WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::emplaceAndPop(TDatumsSP& tDatums)
{
try
{
// Run waitAndEmplace + waitAndPop
if (waitAndEmplace(tDatums))
return waitAndPop(tDatums);
return false;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return false;
}
}
template<typename TDatum, typename TDatums, typename TDatumsSP, typename TWorker>
TDatumsSP WrapperT<TDatum, TDatums, TDatumsSP, TWorker>::emplaceAndPop(const Matrix& matrix)
{
try
{
// Create new datum
auto datumsPtr = std::make_shared<std::vector<std::shared_ptr<TDatum>>>();
datumsPtr->emplace_back();
auto& tDatumPtr = datumsPtr->at(0);
tDatumPtr = std::make_shared<TDatum>();
// Fill datum
tDatumPtr->cvInputData = matrix;
// Emplace and pop
emplaceAndPop(datumsPtr);
// Return result
return datumsPtr;
}
catch (const std::exception& e)
{
error(e.what(), __LINE__, __FUNCTION__, __FILE__);
return TDatumsSP{};
}
}
extern template class WrapperT<BASE_DATUM>;
}
#endif // OPENPOSE_WRAPPER_WRAPPER_HPP