From cd19355e536df1bf6294a20646ef69510e72c8a9 Mon Sep 17 00:00:00 2001 From: Travis CI Date: Thu, 18 Jan 2018 22:24:14 +0000 Subject: [PATCH] Deploy code docs to GitHub Pages Travis build: 128 Commit: 9fc452e7fd1c190ac478e9af51768cb57f1362ce --- doxygen.log | 2 +- html/wrapper_8hpp_source.html | 1607 +++++++++++++++++---------------- 2 files changed, 810 insertions(+), 799 deletions(-) diff --git a/doxygen.log b/doxygen.log index 58f40b22..caf3e0d5 100644 --- a/doxygen.log +++ b/doxygen.log @@ -901,5 +901,5 @@ Generating file index... Generating file member index... Generating example index... finalizing index lists... -lookup cache used 2782/65536 hits=16690 misses=2975 +lookup cache used 2781/65536 hits=16676 misses=2974 finished... diff --git a/html/wrapper_8hpp_source.html b/html/wrapper_8hpp_source.html index 4c6da109..c23615b2 100644 --- a/html/wrapper_8hpp_source.html +++ b/html/wrapper_8hpp_source.html @@ -506,803 +506,814 @@ $(document).ready(function(){initNavTree('wrapper_8hpp_source.html','');});
531  error("Body keypoint detection must be enabled in order to run hand keypoint detection.",
532  __LINE__, __FUNCTION__, __FILE__);
533  }
-
534 
-
535  // Get number GPUs
-
536  auto gpuNumber = wrapperStructPose.gpuNumber;
-
537  const auto gpuNumberStart = wrapperStructPose.gpuNumberStart;
-
538  // If number GPU < 0 --> set it to all the available GPUs
-
539  if (gpuNumber < 0)
-
540  {
-
541  // Get total number GPUs
-
542  const auto totalGpuNumber = getGpuNumber();
-
543  if (totalGpuNumber <= gpuNumberStart)
-
544  error("Number of initial GPUs (`--number_gpu_start`) must be lower than the total number of used"
-
545  " GPUs (`--number_gpu`)", __LINE__, __FUNCTION__, __FILE__);
-
546  gpuNumber = totalGpuNumber - gpuNumberStart;
-
547  // Reset initial GPU to 0 (we want them all)
-
548  // Logging message
-
549  log("Auto-detecting all available GPUs... Detected " + std::to_string(totalGpuNumber)
-
550  + " GPU(s), using " + std::to_string(gpuNumber) + " of them starting at GPU "
-
551  + std::to_string(gpuNumberStart) + ".", Priority::High);
-
552  }
-
553 
-
554  // Proper format
-
555  const auto writeImagesCleaned = formatAsDirectory(wrapperStructOutput.writeImages);
-
556  const auto writeKeypointCleaned = formatAsDirectory(wrapperStructOutput.writeKeypoint);
-
557  const auto writeJsonCleaned = formatAsDirectory(wrapperStructOutput.writeJson);
-
558  const auto writeHeatMapsCleaned = formatAsDirectory(wrapperStructOutput.writeHeatMaps);
-
559  const auto modelFolder = formatAsDirectory(wrapperStructPose.modelFolder);
-
560 
-
561  // Common parameters
-
562  auto finalOutputSize = wrapperStructPose.outputSize;
-
563  Point<int> producerSize{-1,-1};
-
564  if (wrapperStructInput.producerSharedPtr != nullptr)
-
565  {
-
566  // 1. Set producer properties
-
567  const auto displayProducerFpsMode = (wrapperStructInput.realTimeProcessing
-
568  ? ProducerFpsMode::OriginalFps : ProducerFpsMode::RetrievalFps);
-
569  wrapperStructInput.producerSharedPtr->setProducerFpsMode(displayProducerFpsMode);
-
570  wrapperStructInput.producerSharedPtr->set(ProducerProperty::Flip, wrapperStructInput.frameFlip);
-
571  wrapperStructInput.producerSharedPtr->set(ProducerProperty::Rotation, wrapperStructInput.frameRotate);
-
572  wrapperStructInput.producerSharedPtr->set(ProducerProperty::AutoRepeat,
-
573  wrapperStructInput.framesRepeat);
-
574  // 2. Set finalOutputSize
-
575  producerSize = Point<int>{(int)wrapperStructInput.producerSharedPtr->get(CV_CAP_PROP_FRAME_WIDTH),
-
576  (int)wrapperStructInput.producerSharedPtr->get(CV_CAP_PROP_FRAME_HEIGHT)};
-
577  // Set finalOutputSize to input size if desired
-
578  if (finalOutputSize.x == -1 || finalOutputSize.y == -1)
-
579  finalOutputSize = producerSize;
-
580  }
-
581 
-
582  // Producer
-
583  if (wrapperStructInput.producerSharedPtr != nullptr)
-
584  {
-
585  const auto datumProducer = std::make_shared<DatumProducer<TDatums>>(
-
586  wrapperStructInput.producerSharedPtr, wrapperStructInput.frameFirst, wrapperStructInput.frameLast,
-
587  spVideoSeek
-
588  );
-
589  wDatumProducer = std::make_shared<WDatumProducer<TDatumsPtr, TDatums>>(datumProducer);
-
590  }
-
591  else
-
592  wDatumProducer = nullptr;
-
593 
-
594  std::vector<std::shared_ptr<PoseExtractor>> poseExtractors;
-
595  std::vector<std::shared_ptr<PoseGpuRenderer>> poseGpuRenderers;
-
596  std::shared_ptr<PoseCpuRenderer> poseCpuRenderer;
-
597  if (gpuNumber > 0)
-
598  {
-
599  // Get input scales and sizes
-
600  const auto scaleAndSizeExtractor = std::make_shared<ScaleAndSizeExtractor>(
-
601  wrapperStructPose.netInputSize, finalOutputSize, wrapperStructPose.scalesNumber,
-
602  wrapperStructPose.scaleGap
-
603  );
-
604  spWScaleAndSizeExtractor = std::make_shared<WScaleAndSizeExtractor<TDatumsPtr>>(scaleAndSizeExtractor);
-
605 
-
606  // Input cvMat to OpenPose input & output format
-
607  const auto cvMatToOpInput = std::make_shared<CvMatToOpInput>();
-
608  spWCvMatToOpInput = std::make_shared<WCvMatToOpInput<TDatumsPtr>>(cvMatToOpInput);
-
609  if (renderOutput)
-
610  {
-
611  const auto cvMatToOpOutput = std::make_shared<CvMatToOpOutput>();
-
612  spWCvMatToOpOutput = std::make_shared<WCvMatToOpOutput<TDatumsPtr>>(cvMatToOpOutput);
-
613  }
-
614 
-
615  // Pose estimators & renderers
-
616  std::vector<TWorker> cpuRenderers;
-
617  spWPoses.clear();
-
618  spWPoses.resize(gpuNumber);
-
619  if (wrapperStructPose.enable)
-
620  {
-
621  // Pose estimators
-
622  for (auto gpuId = 0; gpuId < gpuNumber; gpuId++)
-
623  poseExtractors.emplace_back(std::make_shared<PoseExtractorCaffe>(
-
624  wrapperStructPose.poseModel, modelFolder, gpuId + gpuNumberStart,
-
625  wrapperStructPose.heatMapTypes, wrapperStructPose.heatMapScale,
-
626  wrapperStructPose.addPartCandidates, wrapperStructPose.enableGoogleLogging
-
627  ));
-
628 
-
629  // Pose renderers
-
630  if (renderOutputGpu || wrapperStructPose.renderMode == RenderMode::Cpu)
-
631  {
-
632  // If wrapperStructPose.renderMode != RenderMode::Gpu but renderOutput, then we create an
-
633  // alpha = 0 pose renderer in order to keep the removing background option
-
634  const auto alphaKeypoint = (wrapperStructPose.renderMode != RenderMode::None
-
635  ? wrapperStructPose.alphaKeypoint : 0.f);
-
636  const auto alphaHeatMap = (wrapperStructPose.renderMode != RenderMode::None
-
637  ? wrapperStructPose.alphaHeatMap : 0.f);
-
638  // GPU rendering
-
639  if (renderOutputGpu)
-
640  {
-
641  for (const auto& poseExtractor : poseExtractors)
-
642  {
-
643  poseGpuRenderers.emplace_back(std::make_shared<PoseGpuRenderer>(
-
644  wrapperStructPose.poseModel, poseExtractor, wrapperStructPose.renderThreshold,
-
645  wrapperStructPose.blendOriginalFrame, alphaKeypoint,
-
646  alphaHeatMap, wrapperStructPose.defaultPartToRender
-
647  ));
-
648  }
-
649  }
-
650  // CPU rendering
-
651  if (wrapperStructPose.renderMode == RenderMode::Cpu)
-
652  {
-
653  poseCpuRenderer = std::make_shared<PoseCpuRenderer>(wrapperStructPose.poseModel,
-
654  wrapperStructPose.renderThreshold,
-
655  wrapperStructPose.blendOriginalFrame);
-
656  cpuRenderers.emplace_back(std::make_shared<WPoseRenderer<TDatumsPtr>>(poseCpuRenderer));
-
657  }
-
658  }
-
659  log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
-
660 
-
661  // Pose extractor(s)
-
662  spWPoses.resize(poseExtractors.size());
-
663  for (auto i = 0u; i < spWPoses.size(); i++)
-
664  spWPoses.at(i) = {std::make_shared<WPoseExtractor<TDatumsPtr>>(poseExtractors.at(i))};
-
665  }
-
666 
-
667 
-
668  // Face extractor(s)
-
669  if (wrapperStructFace.enable)
-
670  {
-
671  // Face detector
-
672  // OpenPose face detector
-
673  if (wrapperStructPose.enable)
-
674  {
-
675  const auto faceDetector = std::make_shared<FaceDetector>(wrapperStructPose.poseModel);
-
676  for (auto gpu = 0u; gpu < spWPoses.size(); gpu++)
-
677  spWPoses.at(gpu).emplace_back(std::make_shared<WFaceDetector<TDatumsPtr>>(faceDetector));
-
678  }
-
679  // OpenCV face detector
-
680  else
-
681  {
-
682  log("Body keypoint detection is disabled. Hence, using OpenCV face detector (much less"
-
683  " accurate but faster).", Priority::High);
-
684  for (auto gpu = 0u; gpu < spWPoses.size(); gpu++)
-
685  {
-
686  // 1 FaceDetectorOpenCV per thread, OpenCV face detector is not thread-safe
-
687  const auto faceDetectorOpenCV = std::make_shared<FaceDetectorOpenCV>(modelFolder);
-
688  spWPoses.at(gpu).emplace_back(
-
689  std::make_shared<WFaceDetectorOpenCV<TDatumsPtr>>(faceDetectorOpenCV)
-
690  );
-
691  }
-
692  }
-
693  // Face keypoint extractor
-
694  for (auto gpu = 0u; gpu < spWPoses.size(); gpu++)
-
695  {
-
696  // Face keypoint extractor
-
697  const auto netOutputSize = wrapperStructFace.netInputSize;
-
698  const auto faceExtractor = std::make_shared<FaceExtractorCaffe>(
-
699  wrapperStructFace.netInputSize, netOutputSize, modelFolder,
-
700  gpu + gpuNumberStart, wrapperStructPose.heatMapTypes, wrapperStructPose.heatMapScale,
-
701  wrapperStructPose.enableGoogleLogging
-
702  );
-
703  spWPoses.at(gpu).emplace_back(std::make_shared<WFaceExtractor<TDatumsPtr>>(faceExtractor));
-
704  }
-
705  }
-
706 
-
707  // Hand extractor(s)
-
708  if (wrapperStructHand.enable)
-
709  {
-
710  const auto handDetector = std::make_shared<HandDetector>(wrapperStructPose.poseModel);
-
711  for (auto gpu = 0u; gpu < spWPoses.size(); gpu++)
-
712  {
-
713  // Hand detector
-
714  // If tracking
-
715  if (wrapperStructHand.tracking)
-
716  spWPoses.at(gpu).emplace_back(
-
717  std::make_shared<WHandDetectorTracking<TDatumsPtr>>(handDetector)
-
718  );
-
719  // If detection
-
720  else
-
721  spWPoses.at(gpu).emplace_back(std::make_shared<WHandDetector<TDatumsPtr>>(handDetector));
-
722  // Hand keypoint extractor
-
723  const auto netOutputSize = wrapperStructHand.netInputSize;
-
724  const auto handExtractor = std::make_shared<HandExtractorCaffe>(
-
725  wrapperStructHand.netInputSize, netOutputSize, modelFolder,
-
726  gpu + gpuNumberStart, wrapperStructHand.scalesNumber, wrapperStructHand.scaleRange,
-
727  wrapperStructPose.heatMapTypes, wrapperStructPose.heatMapScale,
-
728  wrapperStructPose.enableGoogleLogging
-
729  );
-
730  spWPoses.at(gpu).emplace_back(
-
731  std::make_shared<WHandExtractor<TDatumsPtr>>(handExtractor)
-
732  );
-
733  // If tracking
-
734  if (wrapperStructHand.tracking)
-
735  spWPoses.at(gpu).emplace_back(
-
736  std::make_shared<WHandDetectorUpdate<TDatumsPtr>>(handDetector)
-
737  );
-
738  }
-
739  }
-
740 
-
741  // Pose renderer(s)
-
742  if (!poseGpuRenderers.empty())
-
743  for (auto i = 0u; i < spWPoses.size(); i++)
-
744  spWPoses.at(i).emplace_back(std::make_shared<WPoseRenderer<TDatumsPtr>>(
-
745  poseGpuRenderers.at(i)
-
746  ));
-
747 
-
748  // Face renderer(s)
-
749  if (renderFace)
-
750  {
-
751  // CPU rendering
-
752  if (wrapperStructFace.renderMode == RenderMode::Cpu)
-
753  {
-
754  // Construct face renderer
-
755  const auto faceRenderer = std::make_shared<FaceCpuRenderer>(wrapperStructFace.renderThreshold,
-
756  wrapperStructFace.alphaKeypoint,
-
757  wrapperStructFace.alphaHeatMap);
-
758  // Add worker
-
759  cpuRenderers.emplace_back(std::make_shared<WFaceRenderer<TDatumsPtr>>(faceRenderer));
-
760  }
-
761  // GPU rendering
-
762  else if (wrapperStructFace.renderMode == RenderMode::Gpu)
-
763  {
-
764  for (auto i = 0u; i < spWPoses.size(); i++)
-
765  {
-
766  // Construct face renderer
-
767  const auto faceRenderer = std::make_shared<FaceGpuRenderer>(
-
768  wrapperStructFace.renderThreshold, wrapperStructFace.alphaKeypoint,
-
769  wrapperStructFace.alphaHeatMap
-
770  );
-
771  // Performance boost -> share spGpuMemory for all renderers
-
772  if (!poseGpuRenderers.empty())
-
773  {
-
774  const bool isLastRenderer = !renderHandGpu;
-
775  const auto renderer = std::static_pointer_cast<PoseGpuRenderer>(
-
776  poseGpuRenderers.at(i)
-
777  );
-
778  faceRenderer->setSharedParametersAndIfLast(renderer->getSharedParameters(),
-
779  isLastRenderer);
-
780  }
-
781  // Add worker
-
782  spWPoses.at(i).emplace_back(std::make_shared<WFaceRenderer<TDatumsPtr>>(faceRenderer));
-
783  }
-
784  }
-
785  else
-
786  error("Unknown RenderMode.", __LINE__, __FUNCTION__, __FILE__);
-
787  }
-
788 
-
789  // Hand renderer(s)
-
790  if (renderHand)
-
791  {
-
792  // CPU rendering
-
793  if (wrapperStructHand.renderMode == RenderMode::Cpu)
-
794  {
-
795  // Construct hand renderer
-
796  const auto handRenderer = std::make_shared<HandCpuRenderer>(wrapperStructHand.renderThreshold,
-
797  wrapperStructHand.alphaKeypoint,
-
798  wrapperStructHand.alphaHeatMap);
-
799  // Add worker
-
800  cpuRenderers.emplace_back(std::make_shared<WHandRenderer<TDatumsPtr>>(handRenderer));
-
801  }
-
802  // GPU rendering
-
803  else if (wrapperStructHand.renderMode == RenderMode::Gpu)
-
804  {
-
805  for (auto i = 0u; i < spWPoses.size(); i++)
-
806  {
-
807  // Construct hands renderer
-
808  const auto handRenderer = std::make_shared<HandGpuRenderer>(
-
809  wrapperStructHand.renderThreshold, wrapperStructHand.alphaKeypoint,
-
810  wrapperStructHand.alphaHeatMap
-
811  );
-
812  // Performance boost -> share spGpuMemory for all renderers
-
813  if (!poseGpuRenderers.empty())
-
814  {
-
815  const bool isLastRenderer = true;
-
816  const auto renderer = std::static_pointer_cast<PoseGpuRenderer>(
-
817  poseGpuRenderers.at(i)
-
818  );
-
819  handRenderer->setSharedParametersAndIfLast(renderer->getSharedParameters(),
-
820  isLastRenderer);
-
821  }
-
822  // Add worker
-
823  spWPoses.at(i).emplace_back(std::make_shared<WHandRenderer<TDatumsPtr>>(handRenderer));
-
824  }
-
825  }
-
826  else
-
827  error("Unknown RenderMode.", __LINE__, __FUNCTION__, __FILE__);
-
828  }
-
829 
-
830  // Itermediate workers (e.g. OpenPose format to cv::Mat, json & frames recorder, ...)
-
831  mPostProcessingWs.clear();
-
832  // Frame buffer and ordering
-
833  if (spWPoses.size() > 1u)
-
834  mPostProcessingWs.emplace_back(std::make_shared<WQueueOrderer<TDatumsPtr>>());
-
835  // Person ID identification
-
836  if (wrapperStructPose.identification)
-
837  {
-
838  const auto personIdExtractor = std::make_shared<PersonIdExtractor>();
-
839  mPostProcessingWs.emplace_back(
-
840  std::make_shared<WPersonIdExtractor<TDatumsPtr>>(personIdExtractor)
-
841  );
-
842  }
-
843  // Frames processor (OpenPose format -> cv::Mat format)
-
844  if (renderOutput)
-
845  {
-
846  mPostProcessingWs = mergeVectors(mPostProcessingWs, cpuRenderers);
-
847  const auto opOutputToCvMat = std::make_shared<OpOutputToCvMat>();
-
848  mPostProcessingWs.emplace_back(std::make_shared<WOpOutputToCvMat<TDatumsPtr>>(opOutputToCvMat));
-
849  }
-
850  // Re-scale pose if desired
-
851  // If desired scale is not the current input
-
852  if (wrapperStructPose.keypointScale != ScaleMode::InputResolution
-
853  // and desired scale is not output when size(input) = size(output)
-
854  && !(wrapperStructPose.keypointScale == ScaleMode::OutputResolution &&
-
855  (finalOutputSize == producerSize || finalOutputSize.x <= 0 || finalOutputSize.y <= 0))
-
856  // and desired scale is not net output when size(input) = size(net output)
-
857  && !(wrapperStructPose.keypointScale == ScaleMode::NetOutputResolution
-
858  && producerSize == wrapperStructPose.netInputSize))
-
859  {
-
860  // Then we must rescale the keypoints
-
861  auto keypointScaler = std::make_shared<KeypointScaler>(wrapperStructPose.keypointScale);
-
862  mPostProcessingWs.emplace_back(std::make_shared<WKeypointScaler<TDatumsPtr>>(keypointScaler));
-
863  }
-
864  }
-
865 
-
866  mOutputWs.clear();
-
867  // Write people pose data on disk (json for OpenCV >= 3, xml, yml...)
-
868  if (!writeKeypointCleaned.empty())
-
869  {
-
870  const auto keypointSaver = std::make_shared<KeypointSaver>(writeKeypointCleaned,
-
871  wrapperStructOutput.writeKeypointFormat);
-
872  mOutputWs.emplace_back(std::make_shared<WPoseSaver<TDatumsPtr>>(keypointSaver));
-
873  if (wrapperStructFace.enable)
-
874  mOutputWs.emplace_back(std::make_shared<WFaceSaver<TDatumsPtr>>(keypointSaver));
-
875  if (wrapperStructHand.enable)
-
876  mOutputWs.emplace_back(std::make_shared<WHandSaver<TDatumsPtr>>(keypointSaver));
-
877  }
-
878  // Write OpenPose output data on disk in json format (body/hand/face keypoints, body part locations if
-
879  // enabled, etc.)
-
880  if (!writeJsonCleaned.empty())
-
881  {
-
882  const auto peopleJsonSaver = std::make_shared<PeopleJsonSaver>(writeJsonCleaned);
-
883  mOutputWs.emplace_back(std::make_shared<WPeopleJsonSaver<TDatumsPtr>>(peopleJsonSaver));
-
884  }
-
885  // Write people pose data on disk (COCO validation json format)
-
886  if (!wrapperStructOutput.writeCocoJson.empty())
-
887  {
-
888  // If humanFormat: bigger size (& maybe slower to process), but easier for user to read it
-
889  const auto humanFormat = true;
-
890  const auto cocoJsonSaver = std::make_shared<CocoJsonSaver>(wrapperStructOutput.writeCocoJson,
-
891  humanFormat);
-
892  mOutputWs.emplace_back(std::make_shared<WCocoJsonSaver<TDatumsPtr>>(cocoJsonSaver));
-
893  }
-
894  // Write frames as desired image format on hard disk
-
895  if (!writeImagesCleaned.empty())
-
896  {
-
897  const auto imageSaver = std::make_shared<ImageSaver>(writeImagesCleaned,
-
898  wrapperStructOutput.writeImagesFormat);
-
899  mOutputWs.emplace_back(std::make_shared<WImageSaver<TDatumsPtr>>(imageSaver));
-
900  }
-
901  // Write frames as *.avi video on hard disk
-
902  if (!wrapperStructOutput.writeVideo.empty() && wrapperStructInput.producerSharedPtr != nullptr)
-
903  {
-
904  if (finalOutputSize.x <= 0 || finalOutputSize.y <= 0)
-
905  error("Video can only be recorded if outputSize is fixed (e.g. video, webcam, IP camera),"
-
906  "but not for a image directory.", __LINE__, __FUNCTION__, __FILE__);
-
907  const auto originalVideoFps = (wrapperStructInput.producerSharedPtr->get(CV_CAP_PROP_FPS) > 0.
-
908  ? wrapperStructInput.producerSharedPtr->get(CV_CAP_PROP_FPS) : 30.);
-
909  const auto videoSaver = std::make_shared<VideoSaver>(
-
910  wrapperStructOutput.writeVideo, CV_FOURCC('M','J','P','G'), originalVideoFps, finalOutputSize
-
911  );
-
912  mOutputWs.emplace_back(std::make_shared<WVideoSaver<TDatumsPtr>>(videoSaver));
-
913  }
-
914  // Write heat maps as desired image format on hard disk
-
915  if (!writeHeatMapsCleaned.empty())
-
916  {
-
917  const auto heatMapSaver = std::make_shared<HeatMapSaver>(writeHeatMapsCleaned,
-
918  wrapperStructOutput.writeHeatMapsFormat);
-
919  mOutputWs.emplace_back(std::make_shared<WHeatMapSaver<TDatumsPtr>>(heatMapSaver));
-
920  }
-
921  // Add frame information for GUI
-
922  // If this WGuiInfoAdder instance is placed before the WImageSaver or WVideoSaver, then the resulting
-
923  // recorded frames will look exactly as the final displayed image by the GUI
-
924  if (wrapperStructOutput.guiVerbose && (wrapperStructOutput.displayGui || !mUserOutputWs.empty()
-
925  || mThreadManagerMode == ThreadManagerMode::Asynchronous
-
926  || mThreadManagerMode == ThreadManagerMode::AsynchronousOut))
+
534  #ifdef CPU_ONLY
+
535  if (wrapperStructPose.gpuNumber > 0)
+
536  error("GPU number must be negative or 0 if CPU_ONLY is enabled.", __LINE__, __FUNCTION__, __FILE__);
+
537  #endif
+
538 
+
539  // Get number threads
+
540  // CPU --> 1 thread or no pose extraction
+
541  #ifdef CPU_ONLY
+
542  const auto numberThreads = (wrapperStructPose.gpuNumber == 0 ? 0 : 1);
+
543  const auto gpuNumberStart = 0;
+
544  // GPU --> user picks (<= #GPUs)
+
545  #else
+
546  auto numberThreads = wrapperStructPose.gpuNumber;
+
547  const auto gpuNumberStart = wrapperStructPose.gpuNumberStart;
+
548  // If number GPU < 0 --> set it to all the available GPUs
+
549  if (numberThreads < 0)
+
550  {
+
551  // Get total number GPUs
+
552  const auto totalGpuNumber = getGpuNumber();
+
553  if (totalGpuNumber <= gpuNumberStart)
+
554  error("Number of initial GPUs (`--number_gpu_start`) must be lower than the total number of used"
+
555  " GPUs (`--number_gpu`)", __LINE__, __FUNCTION__, __FILE__);
+
556  numberThreads = totalGpuNumber - gpuNumberStart;
+
557  // Reset initial GPU to 0 (we want them all)
+
558  // Logging message
+
559  log("Auto-detecting all available GPUs... Detected " + std::to_string(totalGpuNumber)
+
560  + " GPU(s), using " + std::to_string(numberThreads) + " of them starting at GPU "
+
561  + std::to_string(gpuNumberStart) + ".", Priority::High);
+
562  }
+
563  #endif
+
564 
+
565  // Proper format
+
566  const auto writeImagesCleaned = formatAsDirectory(wrapperStructOutput.writeImages);
+
567  const auto writeKeypointCleaned = formatAsDirectory(wrapperStructOutput.writeKeypoint);
+
568  const auto writeJsonCleaned = formatAsDirectory(wrapperStructOutput.writeJson);
+
569  const auto writeHeatMapsCleaned = formatAsDirectory(wrapperStructOutput.writeHeatMaps);
+
570  const auto modelFolder = formatAsDirectory(wrapperStructPose.modelFolder);
+
571 
+
572  // Common parameters
+
573  auto finalOutputSize = wrapperStructPose.outputSize;
+
574  Point<int> producerSize{-1,-1};
+
575  if (wrapperStructInput.producerSharedPtr != nullptr)
+
576  {
+
577  // 1. Set producer properties
+
578  const auto displayProducerFpsMode = (wrapperStructInput.realTimeProcessing
+
579  ? ProducerFpsMode::OriginalFps : ProducerFpsMode::RetrievalFps);
+
580  wrapperStructInput.producerSharedPtr->setProducerFpsMode(displayProducerFpsMode);
+
581  wrapperStructInput.producerSharedPtr->set(ProducerProperty::Flip, wrapperStructInput.frameFlip);
+
582  wrapperStructInput.producerSharedPtr->set(ProducerProperty::Rotation, wrapperStructInput.frameRotate);
+
583  wrapperStructInput.producerSharedPtr->set(ProducerProperty::AutoRepeat,
+
584  wrapperStructInput.framesRepeat);
+
585  // 2. Set finalOutputSize
+
586  producerSize = Point<int>{(int)wrapperStructInput.producerSharedPtr->get(CV_CAP_PROP_FRAME_WIDTH),
+
587  (int)wrapperStructInput.producerSharedPtr->get(CV_CAP_PROP_FRAME_HEIGHT)};
+
588  // Set finalOutputSize to input size if desired
+
589  if (finalOutputSize.x == -1 || finalOutputSize.y == -1)
+
590  finalOutputSize = producerSize;
+
591  }
+
592 
+
593  // Producer
+
594  if (wrapperStructInput.producerSharedPtr != nullptr)
+
595  {
+
596  const auto datumProducer = std::make_shared<DatumProducer<TDatums>>(
+
597  wrapperStructInput.producerSharedPtr, wrapperStructInput.frameFirst, wrapperStructInput.frameLast,
+
598  spVideoSeek
+
599  );
+
600  wDatumProducer = std::make_shared<WDatumProducer<TDatumsPtr, TDatums>>(datumProducer);
+
601  }
+
602  else
+
603  wDatumProducer = nullptr;
+
604 
+
605  std::vector<std::shared_ptr<PoseExtractor>> poseExtractors;
+
606  std::vector<std::shared_ptr<PoseGpuRenderer>> poseGpuRenderers;
+
607  std::shared_ptr<PoseCpuRenderer> poseCpuRenderer;
+
608  if (numberThreads > 0)
+
609  {
+
610  // Get input scales and sizes
+
611  const auto scaleAndSizeExtractor = std::make_shared<ScaleAndSizeExtractor>(
+
612  wrapperStructPose.netInputSize, finalOutputSize, wrapperStructPose.scalesNumber,
+
613  wrapperStructPose.scaleGap
+
614  );
+
615  spWScaleAndSizeExtractor = std::make_shared<WScaleAndSizeExtractor<TDatumsPtr>>(scaleAndSizeExtractor);
+
616 
+
617  // Input cvMat to OpenPose input & output format
+
618  const auto cvMatToOpInput = std::make_shared<CvMatToOpInput>();
+
619  spWCvMatToOpInput = std::make_shared<WCvMatToOpInput<TDatumsPtr>>(cvMatToOpInput);
+
620  if (renderOutput)
+
621  {
+
622  const auto cvMatToOpOutput = std::make_shared<CvMatToOpOutput>();
+
623  spWCvMatToOpOutput = std::make_shared<WCvMatToOpOutput<TDatumsPtr>>(cvMatToOpOutput);
+
624  }
+
625 
+
626  // Pose estimators & renderers
+
627  std::vector<TWorker> cpuRenderers;
+
628  spWPoses.clear();
+
629  spWPoses.resize(numberThreads);
+
630  if (wrapperStructPose.enable)
+
631  {
+
632  // Pose estimators
+
633  for (auto gpuId = 0; gpuId < numberThreads; gpuId++)
+
634  poseExtractors.emplace_back(std::make_shared<PoseExtractorCaffe>(
+
635  wrapperStructPose.poseModel, modelFolder, gpuId + gpuNumberStart,
+
636  wrapperStructPose.heatMapTypes, wrapperStructPose.heatMapScale,
+
637  wrapperStructPose.addPartCandidates, wrapperStructPose.enableGoogleLogging
+
638  ));
+
639 
+
640  // Pose renderers
+
641  if (renderOutputGpu || wrapperStructPose.renderMode == RenderMode::Cpu)
+
642  {
+
643  // If wrapperStructPose.renderMode != RenderMode::Gpu but renderOutput, then we create an
+
644  // alpha = 0 pose renderer in order to keep the removing background option
+
645  const auto alphaKeypoint = (wrapperStructPose.renderMode != RenderMode::None
+
646  ? wrapperStructPose.alphaKeypoint : 0.f);
+
647  const auto alphaHeatMap = (wrapperStructPose.renderMode != RenderMode::None
+
648  ? wrapperStructPose.alphaHeatMap : 0.f);
+
649  // GPU rendering
+
650  if (renderOutputGpu)
+
651  {
+
652  for (const auto& poseExtractor : poseExtractors)
+
653  {
+
654  poseGpuRenderers.emplace_back(std::make_shared<PoseGpuRenderer>(
+
655  wrapperStructPose.poseModel, poseExtractor, wrapperStructPose.renderThreshold,
+
656  wrapperStructPose.blendOriginalFrame, alphaKeypoint,
+
657  alphaHeatMap, wrapperStructPose.defaultPartToRender
+
658  ));
+
659  }
+
660  }
+
661  // CPU rendering
+
662  if (wrapperStructPose.renderMode == RenderMode::Cpu)
+
663  {
+
664  poseCpuRenderer = std::make_shared<PoseCpuRenderer>(wrapperStructPose.poseModel,
+
665  wrapperStructPose.renderThreshold,
+
666  wrapperStructPose.blendOriginalFrame);
+
667  cpuRenderers.emplace_back(std::make_shared<WPoseRenderer<TDatumsPtr>>(poseCpuRenderer));
+
668  }
+
669  }
+
670  log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
+
671 
+
672  // Pose extractor(s)
+
673  spWPoses.resize(poseExtractors.size());
+
674  for (auto i = 0u; i < spWPoses.size(); i++)
+
675  spWPoses.at(i) = {std::make_shared<WPoseExtractor<TDatumsPtr>>(poseExtractors.at(i))};
+
676  }
+
677 
+
678 
+
679  // Face extractor(s)
+
680  if (wrapperStructFace.enable)
+
681  {
+
682  // Face detector
+
683  // OpenPose face detector
+
684  if (wrapperStructPose.enable)
+
685  {
+
686  const auto faceDetector = std::make_shared<FaceDetector>(wrapperStructPose.poseModel);
+
687  for (auto gpu = 0u; gpu < spWPoses.size(); gpu++)
+
688  spWPoses.at(gpu).emplace_back(std::make_shared<WFaceDetector<TDatumsPtr>>(faceDetector));
+
689  }
+
690  // OpenCV face detector
+
691  else
+
692  {
+
693  log("Body keypoint detection is disabled. Hence, using OpenCV face detector (much less"
+
694  " accurate but faster).", Priority::High);
+
695  for (auto gpu = 0u; gpu < spWPoses.size(); gpu++)
+
696  {
+
697  // 1 FaceDetectorOpenCV per thread, OpenCV face detector is not thread-safe
+
698  const auto faceDetectorOpenCV = std::make_shared<FaceDetectorOpenCV>(modelFolder);
+
699  spWPoses.at(gpu).emplace_back(
+
700  std::make_shared<WFaceDetectorOpenCV<TDatumsPtr>>(faceDetectorOpenCV)
+
701  );
+
702  }
+
703  }
+
704  // Face keypoint extractor
+
705  for (auto gpu = 0u; gpu < spWPoses.size(); gpu++)
+
706  {
+
707  // Face keypoint extractor
+
708  const auto netOutputSize = wrapperStructFace.netInputSize;
+
709  const auto faceExtractor = std::make_shared<FaceExtractorCaffe>(
+
710  wrapperStructFace.netInputSize, netOutputSize, modelFolder,
+
711  gpu + gpuNumberStart, wrapperStructPose.heatMapTypes, wrapperStructPose.heatMapScale,
+
712  wrapperStructPose.enableGoogleLogging
+
713  );
+
714  spWPoses.at(gpu).emplace_back(std::make_shared<WFaceExtractor<TDatumsPtr>>(faceExtractor));
+
715  }
+
716  }
+
717 
+
718  // Hand extractor(s)
+
719  if (wrapperStructHand.enable)
+
720  {
+
721  const auto handDetector = std::make_shared<HandDetector>(wrapperStructPose.poseModel);
+
722  for (auto gpu = 0u; gpu < spWPoses.size(); gpu++)
+
723  {
+
724  // Hand detector
+
725  // If tracking
+
726  if (wrapperStructHand.tracking)
+
727  spWPoses.at(gpu).emplace_back(
+
728  std::make_shared<WHandDetectorTracking<TDatumsPtr>>(handDetector)
+
729  );
+
730  // If detection
+
731  else
+
732  spWPoses.at(gpu).emplace_back(std::make_shared<WHandDetector<TDatumsPtr>>(handDetector));
+
733  // Hand keypoint extractor
+
734  const auto netOutputSize = wrapperStructHand.netInputSize;
+
735  const auto handExtractor = std::make_shared<HandExtractorCaffe>(
+
736  wrapperStructHand.netInputSize, netOutputSize, modelFolder,
+
737  gpu + gpuNumberStart, wrapperStructHand.scalesNumber, wrapperStructHand.scaleRange,
+
738  wrapperStructPose.heatMapTypes, wrapperStructPose.heatMapScale,
+
739  wrapperStructPose.enableGoogleLogging
+
740  );
+
741  spWPoses.at(gpu).emplace_back(
+
742  std::make_shared<WHandExtractor<TDatumsPtr>>(handExtractor)
+
743  );
+
744  // If tracking
+
745  if (wrapperStructHand.tracking)
+
746  spWPoses.at(gpu).emplace_back(
+
747  std::make_shared<WHandDetectorUpdate<TDatumsPtr>>(handDetector)
+
748  );
+
749  }
+
750  }
+
751 
+
752  // Pose renderer(s)
+
753  if (!poseGpuRenderers.empty())
+
754  for (auto i = 0u; i < spWPoses.size(); i++)
+
755  spWPoses.at(i).emplace_back(std::make_shared<WPoseRenderer<TDatumsPtr>>(
+
756  poseGpuRenderers.at(i)
+
757  ));
+
758 
+
759  // Face renderer(s)
+
760  if (renderFace)
+
761  {
+
762  // CPU rendering
+
763  if (wrapperStructFace.renderMode == RenderMode::Cpu)
+
764  {
+
765  // Construct face renderer
+
766  const auto faceRenderer = std::make_shared<FaceCpuRenderer>(wrapperStructFace.renderThreshold,
+
767  wrapperStructFace.alphaKeypoint,
+
768  wrapperStructFace.alphaHeatMap);
+
769  // Add worker
+
770  cpuRenderers.emplace_back(std::make_shared<WFaceRenderer<TDatumsPtr>>(faceRenderer));
+
771  }
+
772  // GPU rendering
+
773  else if (wrapperStructFace.renderMode == RenderMode::Gpu)
+
774  {
+
775  for (auto i = 0u; i < spWPoses.size(); i++)
+
776  {
+
777  // Construct face renderer
+
778  const auto faceRenderer = std::make_shared<FaceGpuRenderer>(
+
779  wrapperStructFace.renderThreshold, wrapperStructFace.alphaKeypoint,
+
780  wrapperStructFace.alphaHeatMap
+
781  );
+
782  // Performance boost -> share spGpuMemory for all renderers
+
783  if (!poseGpuRenderers.empty())
+
784  {
+
785  const bool isLastRenderer = !renderHandGpu;
+
786  const auto renderer = std::static_pointer_cast<PoseGpuRenderer>(
+
787  poseGpuRenderers.at(i)
+
788  );
+
789  faceRenderer->setSharedParametersAndIfLast(renderer->getSharedParameters(),
+
790  isLastRenderer);
+
791  }
+
792  // Add worker
+
793  spWPoses.at(i).emplace_back(std::make_shared<WFaceRenderer<TDatumsPtr>>(faceRenderer));
+
794  }
+
795  }
+
796  else
+
797  error("Unknown RenderMode.", __LINE__, __FUNCTION__, __FILE__);
+
798  }
+
799 
+
800  // Hand renderer(s)
+
801  if (renderHand)
+
802  {
+
803  // CPU rendering
+
804  if (wrapperStructHand.renderMode == RenderMode::Cpu)
+
805  {
+
806  // Construct hand renderer
+
807  const auto handRenderer = std::make_shared<HandCpuRenderer>(wrapperStructHand.renderThreshold,
+
808  wrapperStructHand.alphaKeypoint,
+
809  wrapperStructHand.alphaHeatMap);
+
810  // Add worker
+
811  cpuRenderers.emplace_back(std::make_shared<WHandRenderer<TDatumsPtr>>(handRenderer));
+
812  }
+
813  // GPU rendering
+
814  else if (wrapperStructHand.renderMode == RenderMode::Gpu)
+
815  {
+
816  for (auto i = 0u; i < spWPoses.size(); i++)
+
817  {
+
818  // Construct hands renderer
+
819  const auto handRenderer = std::make_shared<HandGpuRenderer>(
+
820  wrapperStructHand.renderThreshold, wrapperStructHand.alphaKeypoint,
+
821  wrapperStructHand.alphaHeatMap
+
822  );
+
823  // Performance boost -> share spGpuMemory for all renderers
+
824  if (!poseGpuRenderers.empty())
+
825  {
+
826  const bool isLastRenderer = true;
+
827  const auto renderer = std::static_pointer_cast<PoseGpuRenderer>(
+
828  poseGpuRenderers.at(i)
+
829  );
+
830  handRenderer->setSharedParametersAndIfLast(renderer->getSharedParameters(),
+
831  isLastRenderer);
+
832  }
+
833  // Add worker
+
834  spWPoses.at(i).emplace_back(std::make_shared<WHandRenderer<TDatumsPtr>>(handRenderer));
+
835  }
+
836  }
+
837  else
+
838  error("Unknown RenderMode.", __LINE__, __FUNCTION__, __FILE__);
+
839  }
+
840 
+
841  // Itermediate workers (e.g. OpenPose format to cv::Mat, json & frames recorder, ...)
+
842  mPostProcessingWs.clear();
+
843  // Frame buffer and ordering
+
844  if (spWPoses.size() > 1u)
+
845  mPostProcessingWs.emplace_back(std::make_shared<WQueueOrderer<TDatumsPtr>>());
+
846  // Person ID identification
+
847  if (wrapperStructPose.identification)
+
848  {
+
849  const auto personIdExtractor = std::make_shared<PersonIdExtractor>();
+
850  mPostProcessingWs.emplace_back(
+
851  std::make_shared<WPersonIdExtractor<TDatumsPtr>>(personIdExtractor)
+
852  );
+
853  }
+
854  // Frames processor (OpenPose format -> cv::Mat format)
+
855  if (renderOutput)
+
856  {
+
857  mPostProcessingWs = mergeVectors(mPostProcessingWs, cpuRenderers);
+
858  const auto opOutputToCvMat = std::make_shared<OpOutputToCvMat>();
+
859  mPostProcessingWs.emplace_back(std::make_shared<WOpOutputToCvMat<TDatumsPtr>>(opOutputToCvMat));
+
860  }
+
861  // Re-scale pose if desired
+
862  // If desired scale is not the current input
+
863  if (wrapperStructPose.keypointScale != ScaleMode::InputResolution
+
864  // and desired scale is not output when size(input) = size(output)
+
865  && !(wrapperStructPose.keypointScale == ScaleMode::OutputResolution &&
+
866  (finalOutputSize == producerSize || finalOutputSize.x <= 0 || finalOutputSize.y <= 0))
+
867  // and desired scale is not net output when size(input) = size(net output)
+
868  && !(wrapperStructPose.keypointScale == ScaleMode::NetOutputResolution
+
869  && producerSize == wrapperStructPose.netInputSize))
+
870  {
+
871  // Then we must rescale the keypoints
+
872  auto keypointScaler = std::make_shared<KeypointScaler>(wrapperStructPose.keypointScale);
+
873  mPostProcessingWs.emplace_back(std::make_shared<WKeypointScaler<TDatumsPtr>>(keypointScaler));
+
874  }
+
875  }
+
876 
+
877  mOutputWs.clear();
+
878  // Write people pose data on disk (json for OpenCV >= 3, xml, yml...)
+
879  if (!writeKeypointCleaned.empty())
+
880  {
+
881  const auto keypointSaver = std::make_shared<KeypointSaver>(writeKeypointCleaned,
+
882  wrapperStructOutput.writeKeypointFormat);
+
883  mOutputWs.emplace_back(std::make_shared<WPoseSaver<TDatumsPtr>>(keypointSaver));
+
884  if (wrapperStructFace.enable)
+
885  mOutputWs.emplace_back(std::make_shared<WFaceSaver<TDatumsPtr>>(keypointSaver));
+
886  if (wrapperStructHand.enable)
+
887  mOutputWs.emplace_back(std::make_shared<WHandSaver<TDatumsPtr>>(keypointSaver));
+
888  }
+
889  // Write OpenPose output data on disk in json format (body/hand/face keypoints, body part locations if
+
890  // enabled, etc.)
+
891  if (!writeJsonCleaned.empty())
+
892  {
+
893  const auto peopleJsonSaver = std::make_shared<PeopleJsonSaver>(writeJsonCleaned);
+
894  mOutputWs.emplace_back(std::make_shared<WPeopleJsonSaver<TDatumsPtr>>(peopleJsonSaver));
+
895  }
+
896  // Write people pose data on disk (COCO validation json format)
+
897  if (!wrapperStructOutput.writeCocoJson.empty())
+
898  {
+
899  // If humanFormat: bigger size (& maybe slower to process), but easier for user to read it
+
900  const auto humanFormat = true;
+
901  const auto cocoJsonSaver = std::make_shared<CocoJsonSaver>(wrapperStructOutput.writeCocoJson,
+
902  humanFormat);
+
903  mOutputWs.emplace_back(std::make_shared<WCocoJsonSaver<TDatumsPtr>>(cocoJsonSaver));
+
904  }
+
905  // Write frames as desired image format on hard disk
+
906  if (!writeImagesCleaned.empty())
+
907  {
+
908  const auto imageSaver = std::make_shared<ImageSaver>(writeImagesCleaned,
+
909  wrapperStructOutput.writeImagesFormat);
+
910  mOutputWs.emplace_back(std::make_shared<WImageSaver<TDatumsPtr>>(imageSaver));
+
911  }
+
912  // Write frames as *.avi video on hard disk
+
913  if (!wrapperStructOutput.writeVideo.empty() && wrapperStructInput.producerSharedPtr != nullptr)
+
914  {
+
915  if (finalOutputSize.x <= 0 || finalOutputSize.y <= 0)
+
916  error("Video can only be recorded if outputSize is fixed (e.g. video, webcam, IP camera),"
+
917  "but not for a image directory.", __LINE__, __FUNCTION__, __FILE__);
+
918  const auto originalVideoFps = (wrapperStructInput.producerSharedPtr->get(CV_CAP_PROP_FPS) > 0.
+
919  ? wrapperStructInput.producerSharedPtr->get(CV_CAP_PROP_FPS) : 30.);
+
920  const auto videoSaver = std::make_shared<VideoSaver>(
+
921  wrapperStructOutput.writeVideo, CV_FOURCC('M','J','P','G'), originalVideoFps, finalOutputSize
+
922  );
+
923  mOutputWs.emplace_back(std::make_shared<WVideoSaver<TDatumsPtr>>(videoSaver));
+
924  }
+
925  // Write heat maps as desired image format on hard disk
+
926  if (!writeHeatMapsCleaned.empty())
927  {
-
928  const auto guiInfoAdder = std::make_shared<GuiInfoAdder>(gpuNumber, wrapperStructOutput.displayGui);
-
929  mOutputWs.emplace_back(std::make_shared<WGuiInfoAdder<TDatumsPtr>>(guiInfoAdder));
-
930  }
-
931  // Minimal graphical user interface (GUI)
-
932  spWGui = nullptr;
-
933  if (wrapperStructOutput.displayGui)
-
934  {
-
935  // PoseRenderers to Renderers
-
936  std::vector<std::shared_ptr<Renderer>> renderers;
-
937  if (wrapperStructPose.renderMode == RenderMode::Cpu)
-
938  renderers.emplace_back(std::static_pointer_cast<Renderer>(poseCpuRenderer));
-
939  else
-
940  for (const auto& poseGpuRenderer : poseGpuRenderers)
-
941  renderers.emplace_back(std::static_pointer_cast<Renderer>(poseGpuRenderer));
-
942  // Gui
-
943  const auto gui = std::make_shared<Gui>(
-
944  finalOutputSize, wrapperStructOutput.fullScreen, mThreadManager.getIsRunningSharedPtr(),
-
945  spVideoSeek, poseExtractors, renderers
-
946  );
-
947  // WGui
-
948  spWGui = {std::make_shared<WGui<TDatumsPtr>>(gui)};
-
949  }
-
950  // Set wrapper as configured
-
951  mConfigured = true;
-
952  log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
-
953  }
-
954  catch (const std::exception& e)
-
955  {
-
956  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
957  }
-
958  }
-
959 
-
960  template<typename TDatums, typename TWorker, typename TQueue>
-
961  void Wrapper<TDatums, TWorker, TQueue>::exec()
-
962  {
-
963  try
-
964  {
-
965  configureThreadManager();
-
966  log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
-
967  mThreadManager.exec();
+
928  const auto heatMapSaver = std::make_shared<HeatMapSaver>(writeHeatMapsCleaned,
+
929  wrapperStructOutput.writeHeatMapsFormat);
+
930  mOutputWs.emplace_back(std::make_shared<WHeatMapSaver<TDatumsPtr>>(heatMapSaver));
+
931  }
+
932  // Add frame information for GUI
+
933  // If this WGuiInfoAdder instance is placed before the WImageSaver or WVideoSaver, then the resulting
+
934  // recorded frames will look exactly as the final displayed image by the GUI
+
935  if (wrapperStructOutput.guiVerbose && (wrapperStructOutput.displayGui || !mUserOutputWs.empty()
+
936  || mThreadManagerMode == ThreadManagerMode::Asynchronous
+
937  || mThreadManagerMode == ThreadManagerMode::AsynchronousOut))
+
938  {
+
939  const auto guiInfoAdder = std::make_shared<GuiInfoAdder>(numberThreads, wrapperStructOutput.displayGui);
+
940  mOutputWs.emplace_back(std::make_shared<WGuiInfoAdder<TDatumsPtr>>(guiInfoAdder));
+
941  }
+
942  // Minimal graphical user interface (GUI)
+
943  spWGui = nullptr;
+
944  if (wrapperStructOutput.displayGui)
+
945  {
+
946  // PoseRenderers to Renderers
+
947  std::vector<std::shared_ptr<Renderer>> renderers;
+
948  if (wrapperStructPose.renderMode == RenderMode::Cpu)
+
949  renderers.emplace_back(std::static_pointer_cast<Renderer>(poseCpuRenderer));
+
950  else
+
951  for (const auto& poseGpuRenderer : poseGpuRenderers)
+
952  renderers.emplace_back(std::static_pointer_cast<Renderer>(poseGpuRenderer));
+
953  // Gui
+
954  const auto gui = std::make_shared<Gui>(
+
955  finalOutputSize, wrapperStructOutput.fullScreen, mThreadManager.getIsRunningSharedPtr(),
+
956  spVideoSeek, poseExtractors, renderers
+
957  );
+
958  // WGui
+
959  spWGui = {std::make_shared<WGui<TDatumsPtr>>(gui)};
+
960  }
+
961  // Set wrapper as configured
+
962  mConfigured = true;
+
963  log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
+
964  }
+
965  catch (const std::exception& e)
+
966  {
+
967  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
968  }
-
969  catch (const std::exception& e)
-
970  {
-
971  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
972  }
-
973  }
-
974 
-
975  template<typename TDatums, typename TWorker, typename TQueue>
-
976  void Wrapper<TDatums, TWorker, TQueue>::start()
-
977  {
-
978  try
-
979  {
-
980  configureThreadManager();
-
981  log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
-
982  mThreadManager.start();
+
969  }
+
970 
+
971  template<typename TDatums, typename TWorker, typename TQueue>
+
972  void Wrapper<TDatums, TWorker, TQueue>::exec()
+
973  {
+
974  try
+
975  {
+
976  configureThreadManager();
+
977  log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
+
978  mThreadManager.exec();
+
979  }
+
980  catch (const std::exception& e)
+
981  {
+
982  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
983  }
-
984  catch (const std::exception& e)
-
985  {
-
986  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
987  }
-
988  }
-
989 
-
990  template<typename TDatums, typename TWorker, typename TQueue>
-
991  void Wrapper<TDatums, TWorker, TQueue>::stop()
-
992  {
-
993  try
-
994  {
-
995  mThreadManager.stop();
-
996  }
-
997  catch (const std::exception& e)
-
998  {
-
999  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
1000  }
-
1001  }
-
1002 
-
1003  template<typename TDatums, typename TWorker, typename TQueue>
-
1004  bool Wrapper<TDatums, TWorker, TQueue>::isRunning() const
-
1005  {
-
1006  try
-
1007  {
-
1008  return mThreadManager.isRunning();
-
1009  }
-
1010  catch (const std::exception& e)
-
1011  {
-
1012  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
1013  return false;
-
1014  }
-
1015  }
-
1016 
-
1017  template<typename TDatums, typename TWorker, typename TQueue>
-
1018  bool Wrapper<TDatums, TWorker, TQueue>::tryEmplace(std::shared_ptr<TDatums>& tDatums)
-
1019  {
-
1020  try
-
1021  {
-
1022  if (!mUserInputWs.empty())
-
1023  error("Emplace cannot be called if an input worker was already selected.",
-
1024  __LINE__, __FUNCTION__, __FILE__);
-
1025  return mThreadManager.tryEmplace(tDatums);
-
1026  }
-
1027  catch (const std::exception& e)
-
1028  {
-
1029  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
1030  return false;
-
1031  }
-
1032  }
-
1033 
-
1034  template<typename TDatums, typename TWorker, typename TQueue>
-
1035  bool Wrapper<TDatums, TWorker, TQueue>::waitAndEmplace(std::shared_ptr<TDatums>& tDatums)
-
1036  {
-
1037  try
-
1038  {
-
1039  if (!mUserInputWs.empty())
-
1040  error("Emplace cannot be called if an input worker was already selected.",
-
1041  __LINE__, __FUNCTION__, __FILE__);
-
1042  return mThreadManager.waitAndEmplace(tDatums);
-
1043  }
-
1044  catch (const std::exception& e)
-
1045  {
-
1046  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
1047  return false;
-
1048  }
-
1049  }
-
1050 
-
1051  template<typename TDatums, typename TWorker, typename TQueue>
-
1052  bool Wrapper<TDatums, TWorker, TQueue>::tryPush(const std::shared_ptr<TDatums>& tDatums)
-
1053  {
-
1054  try
-
1055  {
-
1056  if (!mUserInputWs.empty())
-
1057  error("Push cannot be called if an input worker was already selected.",
-
1058  __LINE__, __FUNCTION__, __FILE__);
-
1059  return mThreadManager.tryPush(tDatums);
-
1060  }
-
1061  catch (const std::exception& e)
-
1062  {
-
1063  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
1064  return false;
-
1065  }
-
1066  }
-
1067 
-
1068  template<typename TDatums, typename TWorker, typename TQueue>
-
1069  bool Wrapper<TDatums, TWorker, TQueue>::waitAndPush(const std::shared_ptr<TDatums>& tDatums)
-
1070  {
-
1071  try
-
1072  {
-
1073  if (!mUserInputWs.empty())
-
1074  error("Push cannot be called if an input worker was already selected.",
-
1075  __LINE__, __FUNCTION__, __FILE__);
-
1076  return mThreadManager.waitAndPush(tDatums);
-
1077  }
-
1078  catch (const std::exception& e)
-
1079  {
-
1080  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
1081  return false;
-
1082  }
-
1083  }
-
1084 
-
1085  template<typename TDatums, typename TWorker, typename TQueue>
-
1086  bool Wrapper<TDatums, TWorker, TQueue>::tryPop(std::shared_ptr<TDatums>& tDatums)
-
1087  {
-
1088  try
-
1089  {
-
1090  if (!mUserOutputWs.empty())
-
1091  error("Pop cannot be called if an output worker was already selected.",
-
1092  __LINE__, __FUNCTION__, __FILE__);
-
1093  return mThreadManager.tryPop(tDatums);
-
1094  }
-
1095  catch (const std::exception& e)
-
1096  {
-
1097  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
1098  return false;
-
1099  }
-
1100  }
-
1101 
-
1102  template<typename TDatums, typename TWorker, typename TQueue>
-
1103  bool Wrapper<TDatums, TWorker, TQueue>::waitAndPop(std::shared_ptr<TDatums>& tDatums)
-
1104  {
-
1105  try
-
1106  {
-
1107  if (!mUserOutputWs.empty())
-
1108  error("Pop cannot be called if an output worker was already selected.",
-
1109  __LINE__, __FUNCTION__, __FILE__);
-
1110  return mThreadManager.waitAndPop(tDatums);
-
1111  }
-
1112  catch (const std::exception& e)
-
1113  {
-
1114  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
1115  return false;
-
1116  }
-
1117  }
-
1118 
-
1119  template<typename TDatums, typename TWorker, typename TQueue>
-
1120  void Wrapper<TDatums, TWorker, TQueue>::reset()
-
1121  {
-
1122  try
-
1123  {
-
1124  mConfigured = false;
-
1125  mThreadManager.reset();
-
1126  mThreadId = 0ull;
-
1127  // Reset
-
1128  mUserInputWs.clear();
-
1129  wDatumProducer = nullptr;
-
1130  spWScaleAndSizeExtractor = nullptr;
-
1131  spWCvMatToOpInput = nullptr;
-
1132  spWCvMatToOpOutput = nullptr;
-
1133  spWPoses.clear();
-
1134  mPostProcessingWs.clear();
-
1135  mUserPostProcessingWs.clear();
-
1136  mOutputWs.clear();
-
1137  spWGui = nullptr;
-
1138  mUserOutputWs.clear();
-
1139  }
-
1140  catch (const std::exception& e)
-
1141  {
-
1142  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
1143  }
-
1144  }
-
1145 
-
1146  template<typename TDatums, typename TWorker, typename TQueue>
-
1147  void Wrapper<TDatums, TWorker, TQueue>::configureThreadManager()
-
1148  {
-
1149  try
-
1150  {
-
1151  // The less number of queues -> the less lag
-
1152 
-
1153  // Security checks
-
1154  if (!mConfigured)
-
1155  error("Configure the Wrapper class before calling `start()`.", __LINE__, __FUNCTION__, __FILE__);
-
1156  if ((wDatumProducer == nullptr) == (mUserInputWs.empty())
-
1157  && mThreadManagerMode != ThreadManagerMode::Asynchronous
-
1158  && mThreadManagerMode != ThreadManagerMode::AsynchronousIn)
-
1159  {
-
1160  const auto message = "You need to have 1 and only 1 producer selected. You can introduce your own"
-
1161  " producer by using setWorkerInput() or use the OpenPose default producer by"
-
1162  " configuring it in the configure function) or use the"
-
1163  " ThreadManagerMode::Asynchronous(In) mode.";
-
1164  error(message, __LINE__, __FUNCTION__, __FILE__);
-
1165  }
-
1166  if (mOutputWs.empty() && mUserOutputWs.empty() && spWGui == nullptr
-
1167  && mThreadManagerMode != ThreadManagerMode::Asynchronous
-
1168  && mThreadManagerMode != ThreadManagerMode::AsynchronousOut)
-
1169  {
-
1170  error("No output selected.", __LINE__, __FUNCTION__, __FILE__);
-
1171  }
-
1172 
-
1173  // Thread Manager:
-
1174  // Clean previous thread manager (avoid configure to crash the program if used more than once)
-
1175  mThreadManager.reset();
-
1176  mThreadId = 0ull;
-
1177  auto queueIn = 0ull;
-
1178  auto queueOut = 1ull;
-
1179  // If custom user Worker and uses its own thread
-
1180  spWIdGenerator = std::make_shared<WIdGenerator<std::shared_ptr<TDatums>>>();
-
1181  if (!mUserInputWs.empty() && mUserInputWsOnNewThread)
-
1182  {
-
1183  // Thread 0, queues 0 -> 1
-
1184  mThreadManager.add(mThreadId, mUserInputWs, queueIn++, queueOut++);
-
1185  if (spWScaleAndSizeExtractor != nullptr && spWCvMatToOpInput != nullptr)
-
1186  {
-
1187  threadIdPP();
-
1188  // Thread 1, queues 1 -> 2
-
1189  if (spWCvMatToOpOutput == nullptr)
-
1190  mThreadManager.add(mThreadId, {spWIdGenerator, spWScaleAndSizeExtractor, spWCvMatToOpInput},
-
1191  queueIn++, queueOut++);
-
1192  else
-
1193  mThreadManager.add(mThreadId, {spWIdGenerator, spWScaleAndSizeExtractor, spWCvMatToOpInput,
-
1194  spWCvMatToOpOutput}, queueIn++, queueOut++);
-
1195  }
-
1196  else
-
1197  mThreadManager.add(mThreadId, spWIdGenerator, queueIn++, queueOut++);
-
1198  }
-
1199  // If custom user Worker in same thread or producer on same thread
-
1200  else
-
1201  {
-
1202  std::vector<TWorker> workersAux;
-
1203  // Custom user Worker
-
1204  if (!mUserInputWs.empty())
-
1205  workersAux = mergeVectors(workersAux, mUserInputWs);
-
1206  // OpenPose producer
-
1207  else if (wDatumProducer != nullptr)
-
1208  workersAux = mergeVectors(workersAux, {wDatumProducer});
-
1209  // Otherwise
-
1210  else if (mThreadManagerMode != ThreadManagerMode::Asynchronous
-
1211  && mThreadManagerMode != ThreadManagerMode::AsynchronousIn)
-
1212  error("No input selected.", __LINE__, __FUNCTION__, __FILE__);
-
1213  // ID generator
-
1214  workersAux = mergeVectors(workersAux, {spWIdGenerator});
-
1215  // Scale & cv::Mat to OP format
-
1216  if (spWScaleAndSizeExtractor != nullptr && spWCvMatToOpInput != nullptr)
-
1217  workersAux = mergeVectors(workersAux, {spWScaleAndSizeExtractor,
-
1218  spWCvMatToOpInput});
-
1219  // cv::Mat to output format
-
1220  if (spWCvMatToOpOutput != nullptr)
-
1221  workersAux = mergeVectors(workersAux, {spWCvMatToOpOutput});
-
1222  // Thread 0 or 1, queues 0 -> 1
-
1223  mThreadManager.add(mThreadId, workersAux, queueIn++, queueOut++);
-
1224  }
-
1225  threadIdPP();
-
1226  // Pose estimation & rendering
-
1227  // Thread 1 or 2...X, queues 1 -> 2, X = 2 + #GPUs
-
1228  if (!spWPoses.empty())
-
1229  {
-
1230  if (mMultiThreadEnabled)
-
1231  {
-
1232  for (auto& wPose : spWPoses)
-
1233  {
-
1234  mThreadManager.add(mThreadId, wPose, queueIn, queueOut);
-
1235  threadIdPP();
-
1236  }
-
1237  }
-
1238  else
-
1239  {
-
1240  if (spWPoses.size() > 1)
-
1241  log("Multi-threading disabled, only 1 thread running. All GPUs have been disabled but the"
-
1242  " first one, which is defined by gpuNumberStart (e.g. in the OpenPose demo, it is set"
-
1243  " with the `--num_gpu_start` flag).", Priority::High);
-
1244  mThreadManager.add(mThreadId, spWPoses.at(0), queueIn, queueOut);
-
1245  }
-
1246  queueIn++;
-
1247  queueOut++;
-
1248  }
-
1249  // If custom user Worker and uses its own thread
-
1250  if (!mUserPostProcessingWs.empty() && mUserPostProcessingWsOnNewThread)
-
1251  {
-
1252  // Post processing workers
-
1253  if (!mPostProcessingWs.empty())
-
1254  {
-
1255  // Thread 2 or 3, queues 2 -> 3
-
1256  mThreadManager.add(mThreadId, mPostProcessingWs, queueIn++, queueOut++);
-
1257  threadIdPP();
-
1258  }
-
1259  // User processing workers
-
1260  // Thread 3 or 4, queues 3 -> 4
-
1261  mThreadManager.add(mThreadId, mUserPostProcessingWs, queueIn++, queueOut++);
-
1262  threadIdPP();
-
1263  // Output workers
-
1264  if (!mOutputWs.empty())
+
984  }
+
985 
+
986  template<typename TDatums, typename TWorker, typename TQueue>
+
987  void Wrapper<TDatums, TWorker, TQueue>::start()
+
988  {
+
989  try
+
990  {
+
991  configureThreadManager();
+
992  log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
+
993  mThreadManager.start();
+
994  }
+
995  catch (const std::exception& e)
+
996  {
+
997  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
+
998  }
+
999  }
+
1000 
+
1001  template<typename TDatums, typename TWorker, typename TQueue>
+
1002  void Wrapper<TDatums, TWorker, TQueue>::stop()
+
1003  {
+
1004  try
+
1005  {
+
1006  mThreadManager.stop();
+
1007  }
+
1008  catch (const std::exception& e)
+
1009  {
+
1010  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
+
1011  }
+
1012  }
+
1013 
+
1014  template<typename TDatums, typename TWorker, typename TQueue>
+
1015  bool Wrapper<TDatums, TWorker, TQueue>::isRunning() const
+
1016  {
+
1017  try
+
1018  {
+
1019  return mThreadManager.isRunning();
+
1020  }
+
1021  catch (const std::exception& e)
+
1022  {
+
1023  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
+
1024  return false;
+
1025  }
+
1026  }
+
1027 
+
1028  template<typename TDatums, typename TWorker, typename TQueue>
+
1029  bool Wrapper<TDatums, TWorker, TQueue>::tryEmplace(std::shared_ptr<TDatums>& tDatums)
+
1030  {
+
1031  try
+
1032  {
+
1033  if (!mUserInputWs.empty())
+
1034  error("Emplace cannot be called if an input worker was already selected.",
+
1035  __LINE__, __FUNCTION__, __FILE__);
+
1036  return mThreadManager.tryEmplace(tDatums);
+
1037  }
+
1038  catch (const std::exception& e)
+
1039  {
+
1040  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
+
1041  return false;
+
1042  }
+
1043  }
+
1044 
+
1045  template<typename TDatums, typename TWorker, typename TQueue>
+
1046  bool Wrapper<TDatums, TWorker, TQueue>::waitAndEmplace(std::shared_ptr<TDatums>& tDatums)
+
1047  {
+
1048  try
+
1049  {
+
1050  if (!mUserInputWs.empty())
+
1051  error("Emplace cannot be called if an input worker was already selected.",
+
1052  __LINE__, __FUNCTION__, __FILE__);
+
1053  return mThreadManager.waitAndEmplace(tDatums);
+
1054  }
+
1055  catch (const std::exception& e)
+
1056  {
+
1057  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
+
1058  return false;
+
1059  }
+
1060  }
+
1061 
+
1062  template<typename TDatums, typename TWorker, typename TQueue>
+
1063  bool Wrapper<TDatums, TWorker, TQueue>::tryPush(const std::shared_ptr<TDatums>& tDatums)
+
1064  {
+
1065  try
+
1066  {
+
1067  if (!mUserInputWs.empty())
+
1068  error("Push cannot be called if an input worker was already selected.",
+
1069  __LINE__, __FUNCTION__, __FILE__);
+
1070  return mThreadManager.tryPush(tDatums);
+
1071  }
+
1072  catch (const std::exception& e)
+
1073  {
+
1074  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
+
1075  return false;
+
1076  }
+
1077  }
+
1078 
+
1079  template<typename TDatums, typename TWorker, typename TQueue>
+
1080  bool Wrapper<TDatums, TWorker, TQueue>::waitAndPush(const std::shared_ptr<TDatums>& tDatums)
+
1081  {
+
1082  try
+
1083  {
+
1084  if (!mUserInputWs.empty())
+
1085  error("Push cannot be called if an input worker was already selected.",
+
1086  __LINE__, __FUNCTION__, __FILE__);
+
1087  return mThreadManager.waitAndPush(tDatums);
+
1088  }
+
1089  catch (const std::exception& e)
+
1090  {
+
1091  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
+
1092  return false;
+
1093  }
+
1094  }
+
1095 
+
1096  template<typename TDatums, typename TWorker, typename TQueue>
+
1097  bool Wrapper<TDatums, TWorker, TQueue>::tryPop(std::shared_ptr<TDatums>& tDatums)
+
1098  {
+
1099  try
+
1100  {
+
1101  if (!mUserOutputWs.empty())
+
1102  error("Pop cannot be called if an output worker was already selected.",
+
1103  __LINE__, __FUNCTION__, __FILE__);
+
1104  return mThreadManager.tryPop(tDatums);
+
1105  }
+
1106  catch (const std::exception& e)
+
1107  {
+
1108  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
+
1109  return false;
+
1110  }
+
1111  }
+
1112 
+
1113  template<typename TDatums, typename TWorker, typename TQueue>
+
1114  bool Wrapper<TDatums, TWorker, TQueue>::waitAndPop(std::shared_ptr<TDatums>& tDatums)
+
1115  {
+
1116  try
+
1117  {
+
1118  if (!mUserOutputWs.empty())
+
1119  error("Pop cannot be called if an output worker was already selected.",
+
1120  __LINE__, __FUNCTION__, __FILE__);
+
1121  return mThreadManager.waitAndPop(tDatums);
+
1122  }
+
1123  catch (const std::exception& e)
+
1124  {
+
1125  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
+
1126  return false;
+
1127  }
+
1128  }
+
1129 
+
1130  template<typename TDatums, typename TWorker, typename TQueue>
+
1131  void Wrapper<TDatums, TWorker, TQueue>::reset()
+
1132  {
+
1133  try
+
1134  {
+
1135  mConfigured = false;
+
1136  mThreadManager.reset();
+
1137  mThreadId = 0ull;
+
1138  // Reset
+
1139  mUserInputWs.clear();
+
1140  wDatumProducer = nullptr;
+
1141  spWScaleAndSizeExtractor = nullptr;
+
1142  spWCvMatToOpInput = nullptr;
+
1143  spWCvMatToOpOutput = nullptr;
+
1144  spWPoses.clear();
+
1145  mPostProcessingWs.clear();
+
1146  mUserPostProcessingWs.clear();
+
1147  mOutputWs.clear();
+
1148  spWGui = nullptr;
+
1149  mUserOutputWs.clear();
+
1150  }
+
1151  catch (const std::exception& e)
+
1152  {
+
1153  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
+
1154  }
+
1155  }
+
1156 
+
1157  template<typename TDatums, typename TWorker, typename TQueue>
+
1158  void Wrapper<TDatums, TWorker, TQueue>::configureThreadManager()
+
1159  {
+
1160  try
+
1161  {
+
1162  // The less number of queues -> the less lag
+
1163 
+
1164  // Security checks
+
1165  if (!mConfigured)
+
1166  error("Configure the Wrapper class before calling `start()`.", __LINE__, __FUNCTION__, __FILE__);
+
1167  if ((wDatumProducer == nullptr) == (mUserInputWs.empty())
+
1168  && mThreadManagerMode != ThreadManagerMode::Asynchronous
+
1169  && mThreadManagerMode != ThreadManagerMode::AsynchronousIn)
+
1170  {
+
1171  const auto message = "You need to have 1 and only 1 producer selected. You can introduce your own"
+
1172  " producer by using setWorkerInput() or use the OpenPose default producer by"
+
1173  " configuring it in the configure function) or use the"
+
1174  " ThreadManagerMode::Asynchronous(In) mode.";
+
1175  error(message, __LINE__, __FUNCTION__, __FILE__);
+
1176  }
+
1177  if (mOutputWs.empty() && mUserOutputWs.empty() && spWGui == nullptr
+
1178  && mThreadManagerMode != ThreadManagerMode::Asynchronous
+
1179  && mThreadManagerMode != ThreadManagerMode::AsynchronousOut)
+
1180  {
+
1181  error("No output selected.", __LINE__, __FUNCTION__, __FILE__);
+
1182  }
+
1183 
+
1184  // Thread Manager:
+
1185  // Clean previous thread manager (avoid configure to crash the program if used more than once)
+
1186  mThreadManager.reset();
+
1187  mThreadId = 0ull;
+
1188  auto queueIn = 0ull;
+
1189  auto queueOut = 1ull;
+
1190  // If custom user Worker and uses its own thread
+
1191  spWIdGenerator = std::make_shared<WIdGenerator<std::shared_ptr<TDatums>>>();
+
1192  if (!mUserInputWs.empty() && mUserInputWsOnNewThread)
+
1193  {
+
1194  // Thread 0, queues 0 -> 1
+
1195  mThreadManager.add(mThreadId, mUserInputWs, queueIn++, queueOut++);
+
1196  if (spWScaleAndSizeExtractor != nullptr && spWCvMatToOpInput != nullptr)
+
1197  {
+
1198  threadIdPP();
+
1199  // Thread 1, queues 1 -> 2
+
1200  if (spWCvMatToOpOutput == nullptr)
+
1201  mThreadManager.add(mThreadId, {spWIdGenerator, spWScaleAndSizeExtractor, spWCvMatToOpInput},
+
1202  queueIn++, queueOut++);
+
1203  else
+
1204  mThreadManager.add(mThreadId, {spWIdGenerator, spWScaleAndSizeExtractor, spWCvMatToOpInput,
+
1205  spWCvMatToOpOutput}, queueIn++, queueOut++);
+
1206  }
+
1207  else
+
1208  mThreadManager.add(mThreadId, spWIdGenerator, queueIn++, queueOut++);
+
1209  }
+
1210  // If custom user Worker in same thread or producer on same thread
+
1211  else
+
1212  {
+
1213  std::vector<TWorker> workersAux;
+
1214  // Custom user Worker
+
1215  if (!mUserInputWs.empty())
+
1216  workersAux = mergeVectors(workersAux, mUserInputWs);
+
1217  // OpenPose producer
+
1218  else if (wDatumProducer != nullptr)
+
1219  workersAux = mergeVectors(workersAux, {wDatumProducer});
+
1220  // Otherwise
+
1221  else if (mThreadManagerMode != ThreadManagerMode::Asynchronous
+
1222  && mThreadManagerMode != ThreadManagerMode::AsynchronousIn)
+
1223  error("No input selected.", __LINE__, __FUNCTION__, __FILE__);
+
1224  // ID generator
+
1225  workersAux = mergeVectors(workersAux, {spWIdGenerator});
+
1226  // Scale & cv::Mat to OP format
+
1227  if (spWScaleAndSizeExtractor != nullptr && spWCvMatToOpInput != nullptr)
+
1228  workersAux = mergeVectors(workersAux, {spWScaleAndSizeExtractor,
+
1229  spWCvMatToOpInput});
+
1230  // cv::Mat to output format
+
1231  if (spWCvMatToOpOutput != nullptr)
+
1232  workersAux = mergeVectors(workersAux, {spWCvMatToOpOutput});
+
1233  // Thread 0 or 1, queues 0 -> 1
+
1234  mThreadManager.add(mThreadId, workersAux, queueIn++, queueOut++);
+
1235  }
+
1236  threadIdPP();
+
1237  // Pose estimation & rendering
+
1238  // Thread 1 or 2...X, queues 1 -> 2, X = 2 + #GPUs
+
1239  if (!spWPoses.empty())
+
1240  {
+
1241  if (mMultiThreadEnabled)
+
1242  {
+
1243  for (auto& wPose : spWPoses)
+
1244  {
+
1245  mThreadManager.add(mThreadId, wPose, queueIn, queueOut);
+
1246  threadIdPP();
+
1247  }
+
1248  }
+
1249  else
+
1250  {
+
1251  if (spWPoses.size() > 1)
+
1252  log("Multi-threading disabled, only 1 thread running. All GPUs have been disabled but the"
+
1253  " first one, which is defined by gpuNumberStart (e.g. in the OpenPose demo, it is set"
+
1254  " with the `--num_gpu_start` flag).", Priority::High);
+
1255  mThreadManager.add(mThreadId, spWPoses.at(0), queueIn, queueOut);
+
1256  }
+
1257  queueIn++;
+
1258  queueOut++;
+
1259  }
+
1260  // If custom user Worker and uses its own thread
+
1261  if (!mUserPostProcessingWs.empty() && mUserPostProcessingWsOnNewThread)
+
1262  {
+
1263  // Post processing workers
+
1264  if (!mPostProcessingWs.empty())
1265  {
-
1266  // Thread 4 or 5, queues 4 -> 5
-
1267  mThreadManager.add(mThreadId, mOutputWs, queueIn++, queueOut++);
+
1266  // Thread 2 or 3, queues 2 -> 3
+
1267  mThreadManager.add(mThreadId, mPostProcessingWs, queueIn++, queueOut++);
1268  threadIdPP();
1269  }
-
1270  }
-
1271  // If custom user Worker in same thread or producer on same thread
-
1272  else
-
1273  {
-
1274  // Post processing workers + User post processing workers + Output workers
-
1275  auto workersAux = mergeVectors(mPostProcessingWs, mUserPostProcessingWs);
-
1276  workersAux = mergeVectors(workersAux, mOutputWs);
-
1277  if (!workersAux.empty())
-
1278  {
-
1279  // Thread 2 or 3, queues 2 -> 3
-
1280  mThreadManager.add(mThreadId, workersAux, queueIn++, queueOut++);
-
1281  threadIdPP();
-
1282  }
-
1283  }
-
1284  // User output worker
-
1285  // Thread Y, queues Q -> Q+1
-
1286  if (!mUserOutputWs.empty())
-
1287  {
-
1288  if (mUserOutputWsOnNewThread)
+
1270  // User processing workers
+
1271  // Thread 3 or 4, queues 3 -> 4
+
1272  mThreadManager.add(mThreadId, mUserPostProcessingWs, queueIn++, queueOut++);
+
1273  threadIdPP();
+
1274  // Output workers
+
1275  if (!mOutputWs.empty())
+
1276  {
+
1277  // Thread 4 or 5, queues 4 -> 5
+
1278  mThreadManager.add(mThreadId, mOutputWs, queueIn++, queueOut++);
+
1279  threadIdPP();
+
1280  }
+
1281  }
+
1282  // If custom user Worker in same thread or producer on same thread
+
1283  else
+
1284  {
+
1285  // Post processing workers + User post processing workers + Output workers
+
1286  auto workersAux = mergeVectors(mPostProcessingWs, mUserPostProcessingWs);
+
1287  workersAux = mergeVectors(workersAux, mOutputWs);
+
1288  if (!workersAux.empty())
1289  {
-
1290  mThreadManager.add(mThreadId, mUserOutputWs, queueIn++, queueOut++);
-
1291  threadIdPP();
-
1292  }
-
1293  else
-
1294  mThreadManager.add(mThreadId-1, mUserOutputWs, queueIn++, queueOut++);
-
1295  }
-
1296  // OpenPose GUI
-
1297  if (spWGui != nullptr)
+
1290  // Thread 2 or 3, queues 2 -> 3
+
1291  mThreadManager.add(mThreadId, workersAux, queueIn++, queueOut++);
+
1292  threadIdPP();
+
1293  }
+
1294  }
+
1295  // User output worker
+
1296  // Thread Y, queues Q -> Q+1
+
1297  if (!mUserOutputWs.empty())
1298  {
-
1299  // Thread Y+1, queues Q+1 -> Q+2
-
1300  mThreadManager.add(mThreadId, spWGui, queueIn++, queueOut++);
-
1301  threadIdPP();
-
1302  }
-
1303  log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
-
1304  }
-
1305  catch (const std::exception& e)
-
1306  {
-
1307  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
1308  }
-
1309  }
-
1310 
-
1311  template<typename TDatums, typename TWorker, typename TQueue>
-
1312  unsigned long long Wrapper<TDatums, TWorker, TQueue>::threadIdPP()
-
1313  {
-
1314  try
-
1315  {
-
1316  if (mMultiThreadEnabled)
-
1317  mThreadId++;
-
1318  return mThreadId;
+
1299  if (mUserOutputWsOnNewThread)
+
1300  {
+
1301  mThreadManager.add(mThreadId, mUserOutputWs, queueIn++, queueOut++);
+
1302  threadIdPP();
+
1303  }
+
1304  else
+
1305  mThreadManager.add(mThreadId-1, mUserOutputWs, queueIn++, queueOut++);
+
1306  }
+
1307  // OpenPose GUI
+
1308  if (spWGui != nullptr)
+
1309  {
+
1310  // Thread Y+1, queues Q+1 -> Q+2
+
1311  mThreadManager.add(mThreadId, spWGui, queueIn++, queueOut++);
+
1312  threadIdPP();
+
1313  }
+
1314  log("", Priority::Low, __LINE__, __FUNCTION__, __FILE__);
+
1315  }
+
1316  catch (const std::exception& e)
+
1317  {
+
1318  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
1319  }
-
1320  catch (const std::exception& e)
-
1321  {
-
1322  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
-
1323  return 0ull;
-
1324  }
-
1325  }
-
1326 
-
1327  extern template class Wrapper<DATUM_BASE_NO_PTR>;
-
1328 }
-
1329 
-
1330 #endif // OPENPOSE_WRAPPER_WRAPPER_HPP
+
1320  }
+
1321 
+
1322  template<typename TDatums, typename TWorker, typename TQueue>
+
1323  unsigned long long Wrapper<TDatums, TWorker, TQueue>::threadIdPP()
+
1324  {
+
1325  try
+
1326  {
+
1327  if (mMultiThreadEnabled)
+
1328  mThreadId++;
+
1329  return mThreadId;
+
1330  }
+
1331  catch (const std::exception& e)
+
1332  {
+
1333  error(e.what(), __LINE__, __FUNCTION__, __FILE__);
+
1334  return 0ull;
+
1335  }
+
1336  }
+
1337 
+
1338  extern template class Wrapper<DATUM_BASE_NO_PTR>;
+
1339 }
+
1340 
+
1341 #endif // OPENPOSE_WRAPPER_WRAPPER_HPP
PoseModel poseModel
Definition: wrapperStructPose.hpp:87
Point< int > netInputSize
Definition: wrapperStructPose.hpp:30
@@ -1322,17 +1333,17 @@ $(document).ready(function(){initNavTree('wrapper_8hpp_source.html','');});
bool addPartCandidates
Definition: wrapperStructPose.hpp:140
Definition: wPoseSaver.hpp:12
bool identification
Definition: wrapperStructPose.hpp:162
-
bool tryPush(const std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1052
+
bool tryPush(const std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1063
Definition: wrapperStructPose.hpp:16
std::string writeKeypoint
Definition: wrapperStructOutput.hpp:37
float alphaKeypoint
Definition: wrapperStructFace.hpp:39
bool frameFlip
Definition: wrapperStructInput.hpp:41
Definition: wFaceSaver.hpp:12
-
void stop()
Definition: wrapper.hpp:991
+
void stop()
Definition: wrapper.hpp:1002
float alphaKeypoint
Definition: wrapperStructHand.hpp:59
-
bool tryPop(std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1086
-
void exec()
Definition: wrapper.hpp:961
+
bool tryPop(std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1097
+
void exec()
Definition: wrapper.hpp:972
@@ -1365,9 +1376,9 @@ $(document).ready(function(){initNavTree('wrapper_8hpp_source.html','');});
float scaleGap
Definition: wrapperStructPose.hpp:74
RenderMode renderMode
Definition: wrapperStructPose.hpp:80
-
bool waitAndEmplace(std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1035
+
bool waitAndEmplace(std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1046
Definition: wrapper.hpp:32
-
bool tryEmplace(std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1018
+
bool tryEmplace(std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1029
float scaleRange
Definition: wrapperStructHand.hpp:40
int gpuNumberStart
Definition: wrapperStructPose.hpp:59
RenderMode renderMode
Definition: wrapperStructFace.hpp:33
@@ -1378,8 +1389,8 @@ $(document).ready(function(){initNavTree('wrapper_8hpp_source.html','');});
Definition: wVideoSaver.hpp:11
Definition: wOpOutputToCvMat.hpp:11
-
bool waitAndPush(const std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1069
-
void start()
Definition: wrapper.hpp:976
+
bool waitAndPush(const std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1080
+
void start()
Definition: wrapper.hpp:987
bool realTimeProcessing
Definition: wrapperStructInput.hpp:36
OP_API std::string formatAsDirectory(const std::string &directoryPathString)
@@ -1395,7 +1406,7 @@ $(document).ready(function(){initNavTree('wrapper_8hpp_source.html','');});
Definition: wFaceRenderer.hpp:11
-
bool waitAndPop(std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1103
+
bool waitAndPop(std::shared_ptr< TDatums > &tDatums)
Definition: wrapper.hpp:1114
std::shared_ptr< Producer > producerSharedPtr
Definition: wrapperStructInput.hpp:19
Definition: threadManager.hpp:16
Definition: wPoseRenderer.hpp:11
@@ -1431,7 +1442,7 @@ $(document).ready(function(){initNavTree('wrapper_8hpp_source.html','');});
ScaleMode keypointScale
Definition: wrapperStructPose.hpp:46
ThreadManagerMode
Definition: enumClasses.hpp:9
int gpuNumber
Definition: wrapperStructPose.hpp:53
-
bool isRunning() const
Definition: wrapper.hpp:1004
+
bool isRunning() const
Definition: wrapper.hpp:1015
void setWorkerInput(const TWorker &worker, const bool workerOnNewThread=true)
Definition: wrapper.hpp:323
float renderThreshold
Definition: wrapperStructFace.hpp:52
int frameRotate
Definition: wrapperStructInput.hpp:47