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