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