Autonomy Software C++ 24.5.1
Welcome to the Autonomy Software repository of the Mars Rover Design Team (MRDT) at Missouri University of Science and Technology (Missouri S&T)! API reference contains the source code and other resources for the development of the autonomy software for our Mars rover. The Autonomy Software project aims to compete in the University Rover Challenge (URC) by demonstrating advanced autonomous capabilities and robust navigation algorithms.
Loading...
Searching...
No Matches
ObjectDetector Class Reference

This class implements a modular and easy to use object detector for a single camera. Given a camera name, this class will detect objects using the depth measure from a ZED camera and/or inferenced objects from a custom trained model. This class and it's detections are ran in a different thread. More...

#include <ObjectDetector.h>

Inheritance diagram for ObjectDetector:
Collaboration diagram for ObjectDetector:

Public Member Functions

 ObjectDetector (std::shared_ptr< BasicCamera > pBasicCam, const bool bEnableTracking=false, const int nDetectorMaxFPS=30, const bool bEnableRecordingFlag=false, const int nNumDetectedObjectsRetrievalThreads=5, const bool bUsingGpuMats=false)
 Construct a new Object Detector:: Object Detector object.
 
 ObjectDetector (std::shared_ptr< ZEDCamera > pZEDCam, const bool bEnableTracking=false, const int nDetectorMaxFPS=30, const bool bEnableRecordingFlag=false, const int nNumDetectedObjectsRetrievalThreads=5, const bool bUsingGpuMats=false)
 Construct a new Object Detector:: Object Detector object.
 
 ~ObjectDetector ()
 Destroy the Object Detector:: Object Detector object.
 
std::future< bool > RequestDetectionOverlayFrame (cv::Mat &cvFrame)
 Request a copy of the frame containing the detected objects from all detection methods drawn onto the frame.
 
std::future< bool > RequestLastGoodDetectionOverlayFrame (cv::Mat &cvFrame)
 Request a copy of the frame containing the last known good detected objects from all detection methods drawn onto the frame.
 
std::future< bool > RequestDetectedObjects (std::vector< objectdetectutils::Object > &vObjects)
 Request a copy of the most update to date vector of the detected objects from all detection methods.
 
bool InitTorchDetection (const std::string &szModelPath, yolomodel::pytorch::PyTorchInterpreter::HardwareDevices eDevice=yolomodel::pytorch::PyTorchInterpreter::HardwareDevices::eCUDA)
 Initialize the PyTorch interpreter for object detection.
 
void EnableTorchDetection (const float fMinObjectConfidence=0.4f, const float fNMSThreshold=0.6f)
 Enable the PyTorch detection method for this ObjectDetector.
 
void DisableTorchDetection ()
 Set the flag to enable or disable object detection with the torch model.
 
void SetDetectorMaxFPS (const int nRecordingFPS)
 Set the max FPS of the detector.
 
void SetEnableRecordingFlag (const bool bEnableRecordingFlag)
 Set the flag to enable or disable recording of the overlay output.
 
bool GetIsReady ()
 Check if the ObjectDetector is ready to be used.
 
int GetDetectorMaxFPS () const
 Get the max FPS of the detector.
 
bool GetEnableRecordingFlag () const
 Get the flag to enable or disable recording of the overlay output.
 
std::string GetCameraName ()
 Get the camera name.
 
cv::Size GetProcessFrameResolution () const
 Get the process frame resolution.
 
- Public Member Functions inherited from AutonomyThread< void >
 AutonomyThread ()
 Construct a new Autonomy Thread object.
 
virtual ~AutonomyThread ()
 Destroy the Autonomy Thread object. If the parent object or main thread is destroyed or exited while this thread is still running, a race condition will occur. Stopping and joining the thread here insures that the main program can't exit if the user forgot to stop and join the thread.
 
void Start ()
 When this method is called, it starts a new thread that runs the code within the ThreadedContinuousCode method. This is the users main code that will run the important and continuous code for the class.
 
void RequestStop ()
 Signals threads to stop executing user code, terminate. DOES NOT JOIN. This method will not force the thread to exit, if the user code is not written properly and contains WHILE statement or any other long-executing or blocking code, then the thread will not exit until the next iteration.
 
void Join ()
 Waits for thread to finish executing and then closes thread. This method will block the calling code until thread is finished.
 
bool Joinable () const
 Check if the code within the thread and all pools created by it are finished executing and the thread is ready to be closed.
 
AutonomyThreadState GetThreadState () const
 Accessor for the Threads State private member.
 
std::string GetThreadUUID () const
 Accessor for the Thread U U I D private member.
 
IPSGetIPS ()
 Accessor for the Frame I P S private member.
 
void SetMainThreadPriority (AutonomyThreadPriority ePriority)
 Set the OS priority for the main continuous thread.
 
void SetPoolThreadPriority (AutonomyThreadPriority ePriority)
 Set the OS priority for the highly parallelized pool threads.
 

Private Member Functions

void ThreadedContinuousCode () override
 This method will run continuously in a separate thread. New frames from the given camera are grabbed and the objects for the camera image are detected using the PyTorch interpreter. The detected objects are then filtered and stored. Then any requests for the current objects are fulfilled via a call and join of the thread pooled code.
 
void PooledLinearCode () override
 This method will run in a thread pool. It will be called by the main thread and will run the code within the PooledLinearCode() method. This is meant to be used as an internal utility of the child class to further improve parallelization.
 
void UpdateDetectedObjects (std::vector< objectdetectutils::Object > &vNewlyDetectedObjects)
 Update the detected objects with the newly detected objects.
 

Private Attributes

std::shared_ptr< Camera< cv::Mat > > m_pCamera
 
std::shared_ptr< yolomodel::pytorch::PyTorchInterpreterm_pTorchDetector
 
std::atomic< float > m_fTorchMinObjectConfidence
 
std::atomic< float > m_fTorchNMSThreshold
 
std::atomic_bool m_bTorchInitialized
 
std::atomic_bool m_bTorchEnabled
 
std::shared_ptr< tracking::MultiTrackerm_pMultiTracker
 
bool m_bUsingZedCamera
 
bool m_bUsingGpuMats
 
bool m_bCameraIsOpened
 
bool m_bEnableTracking
 
int m_nNumDetectedObjectsRetrievalThreads
 
std::string m_szCameraName
 
std::atomic_bool m_bEnableRecordingFlag
 
std::vector< objectdetectutils::Objectm_vNewlyDetectedObjects
 
std::vector< objectdetectutils::Objectm_vDetectedObjects
 
geoops::RoverPose m_stRoverPose
 
cv::Mat m_cvFrame
 
cv::cuda::GpuMat m_cvGPUFrame
 
cv::Mat m_cvLastGoodOverlayFrame
 
cv::Mat m_cvDetectionOverlayFrame
 
cv::Mat m_cvTorchProcFrame
 
cv::Mat m_cvPointCloud
 
cv::cuda::GpuMat m_cvGPUPointCloud
 
std::queue< containers::FrameFetchContainer< cv::Mat > > m_qDetectionOverlayFramesCopySchedule
 
std::queue< containers::FrameFetchContainer< cv::Mat > > m_qLastGoodDetectionOverlayFramesCopySchedule
 
std::queue< containers::DataFetchContainer< std::vector< objectdetectutils::Object > > > m_qDetectedObjectCopySchedule
 
std::shared_mutex m_muPoolScheduleMutex
 
std::shared_mutex m_muDetectionOverlayCopyMutex
 
std::shared_mutex m_muLastGoodDetectionOverlayCopyMutex
 
std::shared_mutex m_muArucoDataCopyMutex
 

Additional Inherited Members

- Public Types inherited from AutonomyThread< void >
enum  AutonomyThreadState
 
enum  AutonomyThreadPriority
 
- Protected Member Functions inherited from AutonomyThread< void >
void RunPool (const unsigned int nNumTasksToQueue, const unsigned int nNumThreads=2, const bool bForceStopCurrentThreads=false)
 When this method is called, it starts/adds tasks to a thread pool that runs nNumTasksToQueue copies of the code within the PooledLinearCode() method using nNumThreads number of threads. This is meant to be used as an internal utility of the child class to further improve parallelization. Default value for nNumThreads is 2.
 
void RunDetachedPool (const unsigned int nNumTasksToQueue, const unsigned int nNumThreads=2, const bool bForceStopCurrentThreads=false)
 When this method is called, it starts a thread pool full of threads that don't return std::futures (like a placeholder for the thread return type). This means the thread will not have a return type and there is no way to determine if the thread has finished other than calling the Join() method. Only use this if you want to 'set and forget'. It will be faster as it doesn't return futures. Runs PooledLinearCode() method code. This is meant to be used as an internal utility of the child class to further improve parallelization.
 
void ParallelizeLoop (const int nNumThreads, const N tTotalIterations, F &&tLoopFunction)
 Given a ref-qualified looping function and an arbitrary number of iterations, this method will divide up the loop and run each section in a thread pool. This function must not return anything. This method will block until the loop has completed.
 
void ClearPoolQueue ()
 Clears any tasks waiting to be ran in the queue, tasks currently running will remain running.
 
void JoinPool ()
 Waits for pool to finish executing tasks. This method will block the calling code until thread is finished.
 
bool PoolJoinable () const
 Check if the internal pool threads are done executing code and the queue is empty.
 
void SetMainThreadIPSLimit (int nMaxIterationsPerSecond=0)
 Mutator for the Main Thread Max I P S private member.
 
int GetPoolNumOfThreads ()
 Accessor for the Pool Num Of Threads private member.
 
int GetPoolQueueLength ()
 Accessor for the Pool Queue Size private member.
 
std::vector< void > GetPoolResults ()
 Accessor for the Pool Results private member. The action of getting results will destroy and remove them from this object. This method blocks if the thread is not finished, so no need to call JoinPool() before getting results.
 
int GetMainThreadMaxIPS () const
 Accessor for the Main Thread Max I P S private member.
 
- Protected Attributes inherited from AutonomyThread< void >
IPS m_IPS
 

Detailed Description

This class implements a modular and easy to use object detector for a single camera. Given a camera name, this class will detect objects using the depth measure from a ZED camera and/or inferenced objects from a custom trained model. This class and it's detections are ran in a different thread.

Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2023-10-24

Constructor & Destructor Documentation

◆ ObjectDetector() [1/2]

ObjectDetector::ObjectDetector ( std::shared_ptr< BasicCamera pBasicCam,
const bool  bEnableTracking = false,
const int  nDetectorMaxFPS = 30,
const bool  bEnableRecordingFlag = false,
const int  nNumDetectedObjectsRetrievalThreads = 5,
const bool  bUsingGpuMats = false 
)

Construct a new Object Detector:: Object Detector object.

Parameters
pBasicCam- A pointer to the BasicCam to use for detection.
bEnableTracking- Whether or not to enable tracking of detected objects.
nDetectorMaxFPS- The max FPS limit the detector can run at.
bEnableRecordingFlag- Whether or not this ObjectDetector's overlay output should be recorded.
nNumDetectedObjectsRetrievalThreads- The number of threads to use when fulfilling requests for the detected objects. Default is 5.
bUsingGpuMats- Whether or not the given camera name will be using GpuMats.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
42{
43 // Initialize member variables.
44 m_pCamera = pBasicCam;
45 m_bEnableTracking = bEnableTracking;
46 m_bUsingZedCamera = false; // Toggle ZED functions off.
47 m_bEnableRecordingFlag = bEnableRecordingFlag;
48 m_nNumDetectedObjectsRetrievalThreads = nNumDetectedObjectsRetrievalThreads;
49 m_bUsingGpuMats = bUsingGpuMats;
50 m_bTorchInitialized = false;
51 m_bTorchEnabled = false;
52 m_bCameraIsOpened = false;
53 m_szCameraName = pBasicCam->GetCameraLocation();
54 m_stRoverPose = geoops::RoverPose();
55
56 // Create a multi-tracker for tracking multiple objects from the torch detectors.
57 m_pMultiTracker = std::make_shared<tracking::MultiTracker>(constants::BBOX_TRACKER_LOST_TIMEOUT,
58 constants::BBOX_TRACKER_MAX_TRACK_TIME,
59 constants::BBOX_TRACKER_IOU_MATCH_THRESHOLD);
60
61 // Set max IPS of main thread.
62 this->SetMainThreadIPSLimit(nDetectorMaxFPS);
63
64 // Submit logger message.
65 LOG_INFO(logging::g_qSharedLogger, "ObjectDetector created for camera at path/index: {}", m_szCameraName);
66}
void SetMainThreadIPSLimit(int nMaxIterationsPerSecond=0)
Mutator for the Main Thread Max I P S private member.
Definition AutonomyThread.hpp:530
This struct is used by the WaypointHandler to provide an easy way to store all pose data about the ro...
Definition GeospatialOperations.hpp:708
Here is the call graph for this function:

◆ ObjectDetector() [2/2]

ObjectDetector::ObjectDetector ( std::shared_ptr< ZEDCamera pZEDCam,
const bool  bEnableTracking = false,
const int  nDetectorMaxFPS = 30,
const bool  bEnableRecordingFlag = false,
const int  nNumDetectedObjectsRetrievalThreads = 5,
const bool  bUsingGpuMats = false 
)

Construct a new Object Detector:: Object Detector object.

Parameters
pZEDCam- A pointer to the ZEDCamera to use for detection.
bEnableTracking- Whether or not to enable tracking of detected objects.
nDetectorMaxFPS- The max FPS limit the detector can run at.
bEnableRecordingFlag- Whether or not this ObjectDetector's overlay output should be recorded.
nNumDetectedObjectsRetrievalThreads- The number of threads to use when fulfilling requests for the detected objects. Default is 5.
bUsingGpuMats- Whether or not the given camera name will be using GpuMats.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
88{
89 // Initialize member variables.
90 m_pCamera = pZEDCam;
91 m_bEnableTracking = bEnableTracking;
92 m_bUsingZedCamera = true; // Toggle ZED functions on.
93 m_bEnableRecordingFlag = bEnableRecordingFlag;
94 m_nNumDetectedObjectsRetrievalThreads = nNumDetectedObjectsRetrievalThreads;
95 m_bUsingGpuMats = bUsingGpuMats;
96 m_bTorchInitialized = false;
97 m_bTorchEnabled = false;
98 m_bCameraIsOpened = false;
99 m_szCameraName = pZEDCam->GetCameraModel() + "_" + std::to_string(pZEDCam->GetCameraSerial());
100 m_stRoverPose = geoops::RoverPose();
101
102 // Create a multi-tracker for tracking multiple objects from the torch detectors.
103 m_pMultiTracker = std::make_shared<tracking::MultiTracker>(constants::BBOX_TRACKER_LOST_TIMEOUT,
104 constants::BBOX_TRACKER_IOU_MATCH_THRESHOLD,
105 constants::BBOX_TRACKER_IOU_MATCH_THRESHOLD);
106
107 // Set max IPS of main thread.
108 this->SetMainThreadIPSLimit(nDetectorMaxFPS);
109
110 // Submit logger message.
111 LOG_INFO(logging::g_qSharedLogger, "ObjectDetector created for camera: {}", m_szCameraName);
112}
Here is the call graph for this function:

◆ ~ObjectDetector()

ObjectDetector::~ObjectDetector ( )

Destroy the Object Detector:: Object Detector object.

Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
122{
123 // Stop threaded code.
124 this->RequestStop();
125 this->Join();
126
127 // Submit logger message.
128 LOG_INFO(logging::g_qSharedLogger, "ObjectDetector for camera {} has been destroyed.", this->GetCameraName());
129}
void Join()
Waits for thread to finish executing and then closes thread. This method will block the calling code ...
Definition AutonomyThread.hpp:203
void RequestStop()
Signals threads to stop executing user code, terminate. DOES NOT JOIN. This method will not force the...
Definition AutonomyThread.hpp:187
std::string GetCameraName()
Get the camera name.
Definition ObjectDetector.cpp:707
Here is the call graph for this function:

Member Function Documentation

◆ RequestDetectionOverlayFrame()

std::future< bool > ObjectDetector::RequestDetectionOverlayFrame ( cv::Mat cvFrame)

Request a copy of the frame containing the detected objects from all detection methods drawn onto the frame.

Parameters
cvFrame- The cv::Mat frame to copy the detection overlay image to.
Returns
std::future<bool> - The future that will be set to true when the frame is copied.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
455{
456 // Assemble the DataFetchContainer.
457 containers::FrameFetchContainer<cv::Mat> stContainer(cvFrame, PIXEL_FORMATS::eObjectDetection);
458
459 // Acquire lock on pool copy queue.
460 std::unique_lock<std::shared_mutex> lkScheduler(m_muPoolScheduleMutex);
461 // Append frame fetch container to the schedule queue.
462 m_qDetectionOverlayFramesCopySchedule.push(stContainer);
463 // Release lock on the frame schedule queue.
464 lkScheduler.unlock();
465
466 // Return the future from the promise stored in the container.
467 return stContainer.pCopiedFrameStatus->get_future();
468}
This struct is used to carry references to camera frames for scheduling and copying....
Definition FetchContainers.hpp:88

◆ RequestLastGoodDetectionOverlayFrame()

std::future< bool > ObjectDetector::RequestLastGoodDetectionOverlayFrame ( cv::Mat cvFrame)

Request a copy of the frame containing the last known good detected objects from all detection methods drawn onto the frame.

Parameters
cvFrame- The cv::Mat frame to copy the detection overlay image to.
Returns
std::future<bool> - The future that will be set to true when the frame is copied.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
481{
482 // Assemble the DataFetchContainer.
483 containers::FrameFetchContainer<cv::Mat> stContainer(cvFrame, PIXEL_FORMATS::eObjectDetection);
484
485 // Acquire lock on pool copy queue.
486 std::unique_lock<std::shared_mutex> lkScheduler(m_muPoolScheduleMutex);
487 // Append frame fetch container to the schedule queue.
488 m_qLastGoodDetectionOverlayFramesCopySchedule.push(stContainer);
489 // Release lock on the frame schedule queue.
490 lkScheduler.unlock();
491
492 // Return the future from the promise stored in the container.
493 return stContainer.pCopiedFrameStatus->get_future();
494}

◆ RequestDetectedObjects()

std::future< bool > ObjectDetector::RequestDetectedObjects ( std::vector< objectdetectutils::Object > &  vObjects)

Request a copy of the most update to date vector of the detected objects from all detection methods.

Parameters
vObjects- The vector of detected objects to copy the detected objects to.
Returns
std::future<bool> - The future that will be set to true when the objects are copied.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
507{
508 // Assemble the DataFetchContainer.
510
511 // Acquire lock on pool copy queue.
512 std::unique_lock<std::shared_mutex> lkScheduler(m_muPoolScheduleMutex);
513 // Append frame fetch container to the schedule queue.
514 m_qDetectedObjectCopySchedule.push(stContainer);
515 // Release lock on the frame schedule queue.
516 lkScheduler.unlock();
517
518 // Return the future from the promise stored in the container.
519 return stContainer.pCopiedDataStatus->get_future();
520}
This struct is used to carry references to any datatype for scheduling and copying....
Definition FetchContainers.hpp:164

◆ InitTorchDetection()

bool ObjectDetector::InitTorchDetection ( const std::string &  szModelPath,
yolomodel::pytorch::PyTorchInterpreter::HardwareDevices  eDevice = yolomodel::pytorch::PyTorchInterpreter::HardwareDevices::eCUDA 
)

Initialize the PyTorch interpreter for object detection.

Parameters
szModelPath- The path to the PyTorch model file.
eDevice- The hardware device to use for inference (e.g., CPU or GPU).
Returns
true - Model was opened and loaded successfully onto the torch device.
false - Model was not opened and loaded successfully onto the torch device.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
534{
535 // Initialize a new YOLOModel object.
536 m_pTorchDetector = std::make_shared<yolomodel::pytorch::PyTorchInterpreter>(szModelPath, eDevice);
537
538 // Check if device/model was opened without issue.
539 if (m_pTorchDetector->IsReadyForInference())
540 {
541 // Update member variable.
542 m_bTorchInitialized = true;
543 // Return status.
544 return true;
545 }
546 else
547 {
548 // Submit logger message.
549 LOG_ERROR(logging::g_qSharedLogger, "Unable to initialize Torch detection for ObjectDetector.");
550 // Update member variable.
551 m_bTorchInitialized = false;
552 // Return status.
553 return false;
554 }
555}

◆ EnableTorchDetection()

void ObjectDetector::EnableTorchDetection ( const float  fMinObjectConfidence = 0.4f,
const float  fNMSThreshold = 0.6f 
)

Enable the PyTorch detection method for this ObjectDetector.

Parameters
fMinObjectConfidence- The minimum confidence threshold for detected objects.
fNMSThreshold- The non-maximum suppression threshold for filtering overlapping detections.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
567{
568 // Update member variables.
569 m_fTorchMinObjectConfidence = fMinObjectConfidence;
570 m_fTorchNMSThreshold = fNMSThreshold;
571
572 // Check if torch model has been initialized.
573 if (m_bTorchInitialized)
574 {
575 // Update member variable.
576 m_bTorchEnabled = true;
577 }
578 else
579 {
580 // Submit logger message.
581 LOG_WARNING(logging::g_qSharedLogger, "Tried to enable torch detection for ObjectDetector but it has not been initialized yet!");
582 // Update member variable.
583 m_bTorchEnabled = false;
584 }
585}

◆ DisableTorchDetection()

void ObjectDetector::DisableTorchDetection ( )

Set the flag to enable or disable object detection with the torch model.

Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
595{
596 // Update member variable.
597 m_bTorchEnabled = false;
598}

◆ SetDetectorMaxFPS()

void ObjectDetector::SetDetectorMaxFPS ( const int  nRecordingFPS)

Set the max FPS of the detector.

Parameters
nRecordingFPS- The max FPS of the detector.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
609{
610 // Set the max iterations per second of the main thread.
611 this->SetMainThreadIPSLimit(nRecordingFPS);
612}
Here is the call graph for this function:

◆ SetEnableRecordingFlag()

void ObjectDetector::SetEnableRecordingFlag ( const bool  bEnableRecordingFlag)

Set the flag to enable or disable recording of the overlay output.

Parameters
bEnableRecordingFlag- The flag to enable or disable recording of the overlay output.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
623{
624 // Update member variable.
625 m_bEnableRecordingFlag = bEnableRecordingFlag;
626}

◆ GetIsReady()

bool ObjectDetector::GetIsReady ( )

Check if the ObjectDetector is ready to be used.

Returns
true - The ObjectDetector is ready to be used.
false - The ObjectDetector is not ready to be used.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
638{
639 // Create instance variables.
640 bool bDetectorIsReady = false;
641
642 // Check if this detectors thread is currently running.
643 if (this->GetThreadState() == AutonomyThreadState::eRunning)
644 {
645 // Check if using ZEDCam or BasicCam.
646 if (m_bUsingZedCamera)
647 {
648 // Check if camera is NOT open.
649 if (std::dynamic_pointer_cast<ZEDCamera>(m_pCamera)->GetCameraIsOpen())
650 {
651 // Set camera opened toggle.
652 bDetectorIsReady = true;
653 }
654 }
655 else
656 {
657 // Check if camera is NOT open.
658 if (std::dynamic_pointer_cast<BasicCamera>(m_pCamera)->GetCameraIsOpen())
659 {
660 // Set camera opened toggle.
661 bDetectorIsReady = true;
662 }
663 }
664 }
665
666 // Return if this detector is ready or not.
667 return bDetectorIsReady;
668}
AutonomyThreadState GetThreadState() const
Accessor for the Threads State private member.
Definition AutonomyThread.hpp:237
Here is the call graph for this function:

◆ GetDetectorMaxFPS()

int ObjectDetector::GetDetectorMaxFPS ( ) const

Get the max FPS of the detector.

Returns
int - The max FPS of the detector.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
679{
680 // Return the max FPS of the detector.
681 return this->GetMainThreadMaxIPS();
682}
int GetMainThreadMaxIPS() const
Accessor for the Main Thread Max I P S private member.
Definition AutonomyThread.hpp:594
Here is the call graph for this function:

◆ GetEnableRecordingFlag()

bool ObjectDetector::GetEnableRecordingFlag ( ) const

Get the flag to enable or disable recording of the overlay output.

Returns
true - The flag to enable or disable recording of the overlay output.
false - The flag to enable or disable recording of the overlay output.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
694{
695 // Return the enable recording flag.
696 return m_bEnableRecordingFlag;
697}

◆ GetCameraName()

std::string ObjectDetector::GetCameraName ( )

Get the camera name.

Returns
std::string - The camera name.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
708{
709 // Return the camera name.
710 return m_szCameraName;
711}
Here is the caller graph for this function:

◆ GetProcessFrameResolution()

cv::Size ObjectDetector::GetProcessFrameResolution ( ) const

Get the process frame resolution.

Returns
cv::Size - The process frame resolution.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
722{
723 // Check if using a ZED camera.
724 if (m_bUsingZedCamera)
725 {
726 // Concatenate camera model name and serial number.
727 return std::dynamic_pointer_cast<ZEDCamera>(m_pCamera)->GetPropResolution();
728 }
729 else
730 {
731 // Concatenate camera path or index.
732 return std::dynamic_pointer_cast<BasicCamera>(m_pCamera)->GetPropResolution();
733 }
734}

◆ ThreadedContinuousCode()

void ObjectDetector::ThreadedContinuousCode ( )
overrideprivatevirtual

This method will run continuously in a separate thread. New frames from the given camera are grabbed and the objects for the camera image are detected using the PyTorch interpreter. The detected objects are then filtered and stored. Then any requests for the current objects are fulfilled via a call and join of the thread pooled code.

Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05

Implements AutonomyThread< void >.

143{
144 // Check if using ZEDCam or BasicCam.
145 if (m_bUsingZedCamera)
146 {
147 // Check if camera is NOT open.
148 if (!std::dynamic_pointer_cast<ZEDCamera>(m_pCamera)->GetCameraIsOpen())
149 {
150 // Set camera opened toggle.
151 m_bCameraIsOpened = false;
152
153 // If camera's not open on first iteration of thread, it's probably not present, so stop.
154 if (this->GetThreadState() == AutonomyThreadState::eStarting)
155 {
156 // Shutdown threads for this ZEDCam.
157 this->RequestStop();
158
159 // Submit logger message.
160 LOG_CRITICAL(logging::g_qSharedLogger,
161 "ObjectDetector start was attempted for ZED camera with serial number {}, but camera never properly opened or it has been closed/rebooted! "
162 "This object detector will now stop.",
163 std::dynamic_pointer_cast<ZEDCamera>(m_pCamera)->GetCameraSerial());
164 }
165 }
166 else
167 {
168 // Set camera opened toggle.
169 m_bCameraIsOpened = true;
170 }
171 }
172 else
173 {
174 // Check if camera is NOT open.
175 if (!std::dynamic_pointer_cast<BasicCamera>(m_pCamera)->GetCameraIsOpen())
176 {
177 // Set camera opened toggle.
178 m_bCameraIsOpened = false;
179
180 // If camera's not open on first iteration of thread, it's probably not present, so stop.
181 if (this->GetThreadState() == AutonomyThreadState::eStarting)
182 {
183 // Shutdown threads for this BasicCam.
184 this->RequestStop();
185
186 // Submit logger message.
187 LOG_CRITICAL(logging::g_qSharedLogger,
188 "ObjectDetector start was attempted for BasicCam at {}, but camera never properly opened or it has become disconnected!",
189 std::dynamic_pointer_cast<BasicCamera>(m_pCamera)->GetCameraLocation());
190 }
191 }
192 else
193 {
194 // Set camera opened toggle.
195 m_bCameraIsOpened = true;
196 }
197 }
198
199 // Check if camera is opened.
200 if (m_bCameraIsOpened)
201 {
202 // Create future for indicating when the frame has been copied.
203 std::future<bool> fuPointCloudCopyStatus;
204 std::future<bool> fuRegularFrameCopyStatus;
205 bool bRequestingPointCloud = false;
206
207 // Check if the camera is setup to use CPU or GPU mats.
208 if (m_bUsingZedCamera)
209 {
210 bRequestingPointCloud = true;
211 // Check if the ZED camera is returning cv::cuda::GpuMat or cv:Mat.
212 if (m_bUsingGpuMats)
213 {
214 // Grabs point cloud from ZEDCam. Dynamic casts Camera to ZEDCamera* so we can use ZEDCam methods.
215 fuPointCloudCopyStatus = std::dynamic_pointer_cast<ZEDCamera>(m_pCamera)->RequestPointCloudCopy(m_cvGPUPointCloud);
216 // Get the regular RGB image from the camera.
217 fuRegularFrameCopyStatus = std::dynamic_pointer_cast<ZEDCamera>(m_pCamera)->RequestFrameCopy(m_cvGPUFrame);
218 }
219 else
220 {
221 // Grabs point cloud from ZEDCam.
222 fuPointCloudCopyStatus = std::dynamic_pointer_cast<ZEDCamera>(m_pCamera)->RequestPointCloudCopy(m_cvPointCloud);
223 fuRegularFrameCopyStatus = std::dynamic_pointer_cast<ZEDCamera>(m_pCamera)->RequestFrameCopy(m_cvFrame);
224 }
225 }
226 else
227 {
228 // Grab frames from camera.
229 fuRegularFrameCopyStatus = std::dynamic_pointer_cast<BasicCamera>(m_pCamera)->RequestFrameCopy(m_cvFrame);
230 }
231
232 // Safe polling wrapper to prevent deadlocks.
233 bool bCloudReady = !bRequestingPointCloud; // True by default if we don't need a point cloud
234 bool bFrameReady = false;
235
236 // Keep polling as long as the thread hasn't been asked to stop.
237 while (this->GetThreadState() == AutonomyThreadState::eRunning)
238 {
239 if (!bCloudReady && fuPointCloudCopyStatus.wait_for(std::chrono::milliseconds(10)) == std::future_status::ready)
240 bCloudReady = true;
241
242 if (!bFrameReady && fuRegularFrameCopyStatus.wait_for(std::chrono::milliseconds(10)) == std::future_status::ready)
243 bFrameReady = true;
244
245 if (bCloudReady && bFrameReady)
246 break;
247 }
248
249 // If the thread is shutting down, break out of the loop gracefully
250 if (this->GetThreadState() != AutonomyThreadState::eRunning)
251 {
252 return;
253 }
254
255 // Process the retrieved frames
256 if (m_bUsingZedCamera)
257 {
258 if (m_bUsingGpuMats)
259 {
260 if (fuPointCloudCopyStatus.get() && fuRegularFrameCopyStatus.get())
261 {
262 // Download mat from GPU memory.
263 m_cvGPUPointCloud.download(m_cvPointCloud);
264 m_cvGPUFrame.download(m_cvFrame);
265 // Drop alpha channel.
266 cv::cvtColor(m_cvFrame, m_cvFrame, cv::COLOR_BGRA2BGR);
267 }
268 else
269 {
270 LOG_WARNING(logging::g_qSharedLogger, "ObjectDetector unable to get point cloud or frame from ZEDCam!");
271 }
272 }
273 else
274 {
275 if (!fuPointCloudCopyStatus.get())
276 LOG_WARNING(logging::g_qSharedLogger, "ObjectDetector unable to get point cloud from ZEDCam!");
277 if (!fuRegularFrameCopyStatus.get())
278 LOG_WARNING(logging::g_qSharedLogger, "ObjectDetector unable to get regular frame from ZEDCam!");
279 }
280 }
281 else
282 {
283 if (!fuRegularFrameCopyStatus.get())
284 {
285 LOG_WARNING(logging::g_qSharedLogger, "ObjectDetector unable to get RGB image from BasicCam!");
286 }
287 }
288
290 // Actual detection logic goes here.
292 // Check if the frame is empty.
293 if (m_cvFrame.empty())
294 {
295 // Submit logger message.
296 LOG_WARNING(logging::g_qSharedLogger, "Frame from camera is empty!");
297 return;
298 }
299
300 // Clear the list of newly detected objects.
301 m_vNewlyDetectedObjects.clear();
302 // Clone frames.
303 m_cvDetectionOverlayFrame = m_cvFrame.clone();
304 m_cvTorchProcFrame = m_cvFrame.clone();
305 // Copy the camera frame to the pre-processing frame and overlay frame.
306 cv::cvtColor(m_cvTorchProcFrame, m_cvTorchProcFrame, cv::COLOR_BGR2RGB);
307
308 // Check if torch detection if turned on.
309 if (m_bTorchEnabled)
310 {
311 // Detect objects in the image.
312 std::vector<objectdetectutils::Object> vNewTorchObjects =
313 torchobject::Detect(m_cvTorchProcFrame, *m_pTorchDetector, m_fTorchMinObjectConfidence, m_fTorchNMSThreshold);
314
315 // Add Torch objects to the list of newly detected objects.
316 m_vNewlyDetectedObjects.insert(m_vNewlyDetectedObjects.end(), vNewTorchObjects.begin(), vNewTorchObjects.end());
317 }
318
319 // Set the FOV of the camera in the object structs for this detector's camera.
320 for (objectdetectutils::Object& stObject : m_vNewlyDetectedObjects)
321 {
322 // Set the UUID of the detector that detected this object to this ObjectDetector's camera name so we can associate it with this detector.
323 stObject.szDetectorUUID = this->GetThreadUUID();
324 // Set object FOV parameter to this object detectors camera's FOV.
325 stObject.dHorizontalFOV = m_pCamera->GetPropHorizontalFOV();
326 }
327
328 // Merge the newly detected objects with the pre-existing detected objects.
329 this->UpdateDetectedObjects(m_vNewlyDetectedObjects);
330
331 // Draw object overlays onto normal image.
332 torchobject::DrawDetections(m_cvDetectionOverlayFrame, m_vDetectedObjects);
333
334 // Check if the detected objects vector is not empty.
335 if (!m_vDetectedObjects.empty())
336 {
337 // It's not empty so we should have a valid overlay frame with detections drawn on it.
338 m_cvLastGoodOverlayFrame = m_cvDetectionOverlayFrame.clone();
339 }
341 }
342
343 // Acquire a shared_lock on the detected objects copy queue.
344 std::shared_lock<std::shared_mutex> lkSchedulers(m_muPoolScheduleMutex);
345 // Check if the detected object copy queue is empty.
346 if (!m_qDetectionOverlayFramesCopySchedule.empty() || !m_qLastGoodDetectionOverlayFramesCopySchedule.empty() || !m_qDetectedObjectCopySchedule.empty())
347 {
348 size_t siQueueLength = m_qDetectionOverlayFramesCopySchedule.size() + m_qLastGoodDetectionOverlayFramesCopySchedule.size() + m_qDetectedObjectCopySchedule.size();
349 // Start the thread pool to store multiple copies of the detected objects to the requesting threads
350 this->RunDetachedPool(siQueueLength, m_nNumDetectedObjectsRetrievalThreads);
351 // Wait for thread pool to finish.
352 this->JoinPool();
353 // Release lock on frame copy queue.
354 lkSchedulers.unlock();
355 }
356}
std::string GetThreadUUID() const
Accessor for the Thread U U I D private member.
Definition AutonomyThread.hpp:247
void RunDetachedPool(const unsigned int nNumTasksToQueue, const unsigned int nNumThreads=2, const bool bForceStopCurrentThreads=false)
When this method is called, it starts a thread pool full of threads that don't return std::futures (l...
Definition AutonomyThread.hpp:399
void JoinPool()
Waits for pool to finish executing tasks. This method will block the calling code until thread is fin...
Definition AutonomyThread.hpp:502
void UpdateDetectedObjects(std::vector< objectdetectutils::Object > &vNewlyDetectedObjects)
Update the detected objects with the newly detected objects.
Definition ObjectDetector.cpp:744
CV_NODISCARD_STD Mat clone() const
bool empty() const
void download(OutputArray dst) const
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0)
COLOR_BGRA2BGR
COLOR_BGR2RGB
void DrawDetections(cv::Mat &cvDetectionsFrame, const std::vector< objectdetectutils::Object > &vDetectedTags)
Given a vector of objectdetectutils::Object structs draw each tag corner and confidence onto the give...
Definition TorchObjectDetection.hpp:102
std::vector< objectdetectutils::Object > Detect(const cv::Mat &cvFrame, yolomodel::pytorch::PyTorchInterpreter &trPyTorchDetector, const float fMinObjectConfidence=0.40f, const float fNMSThreshold=0.60f)
Detects objects in the given image using a PyTorch model.
Definition TorchObjectDetection.hpp:45
Represents a single detected object.
Definition ObjectDetectionUtility.hpp:73
Here is the call graph for this function:

◆ PooledLinearCode()

void ObjectDetector::PooledLinearCode ( )
overrideprivatevirtual

This method will run in a thread pool. It will be called by the main thread and will run the code within the PooledLinearCode() method. This is meant to be used as an internal utility of the child class to further improve parallelization.

Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05

Implements AutonomyThread< void >.

368{
370 // Detection Overlay Frame queue.
372 // Acquire sole writing access to the detectedObjectCopySchedule.
373 std::unique_lock<std::shared_mutex> lkObjectOverlayFrameQueue(m_muDetectionOverlayCopyMutex);
374 // Check if there are unfulfilled requests.
375 if (!m_qDetectionOverlayFramesCopySchedule.empty())
376 {
377 // Get frame container out of queue.
378 containers::FrameFetchContainer<cv::Mat> stContainer = m_qDetectionOverlayFramesCopySchedule.front();
379 // Pop out of queue.
380 m_qDetectionOverlayFramesCopySchedule.pop();
381 // Release lock.
382 lkObjectOverlayFrameQueue.unlock();
383
384 // Check which frame we should copy.
385 switch (stContainer.eFrameType)
386 {
387 case PIXEL_FORMATS::eObjectDetection: *stContainer.pFrame = m_cvDetectionOverlayFrame.clone(); break;
388 default: *stContainer.pFrame = m_cvDetectionOverlayFrame.clone(); break;
389 }
390
391 // Signal future that the frame has been successfully retrieved.
392 stContainer.pCopiedFrameStatus->set_value(true);
393 }
394
396 // Last GoodDetection Overlay Frame queue.
398 // Acquire sole writing access to the detectedObjectCopySchedule.
399 std::unique_lock<std::shared_mutex> lkLastGoodObjectOverlayFrameQueue(m_muLastGoodDetectionOverlayCopyMutex);
400 // Check if there are unfulfilled requests.
401 if (!m_qLastGoodDetectionOverlayFramesCopySchedule.empty())
402 {
403 // Get frame container out of queue.
404 containers::FrameFetchContainer<cv::Mat> stContainer = m_qLastGoodDetectionOverlayFramesCopySchedule.front();
405 // Pop out of queue.
406 m_qLastGoodDetectionOverlayFramesCopySchedule.pop();
407 // Release lock.
408 lkLastGoodObjectOverlayFrameQueue.unlock();
409
410 // Check which frame we should copy.
411 switch (stContainer.eFrameType)
412 {
413 case PIXEL_FORMATS::eObjectDetection: *stContainer.pFrame = m_cvLastGoodOverlayFrame.clone(); break;
414 default: *stContainer.pFrame = m_cvLastGoodOverlayFrame.clone(); break;
415 }
416
417 // Signal future that the frame has been successfully retrieved.
418 stContainer.pCopiedFrameStatus->set_value(true);
419 }
420
422 // Object queue.
424 // Acquire sole writing access to the detectedObjectCopySchedule.
425 std::unique_lock<std::shared_mutex> lkObjectQueue(m_muArucoDataCopyMutex);
426 // Check if there are unfulfilled requests.
427 if (!m_qDetectedObjectCopySchedule.empty())
428 {
429 // Get frame container out of queue.
430 containers::DataFetchContainer<std::vector<objectdetectutils::Object>> stContainer = m_qDetectedObjectCopySchedule.front();
431 // Pop out of queue.
432 m_qDetectedObjectCopySchedule.pop();
433 // Release lock.
434 lkObjectQueue.unlock();
435
436 // Copy the detected objects to the target location
437 *stContainer.pData = m_vDetectedObjects;
438
439 // Signal future that the frame has been successfully retrieved.
440 stContainer.pCopiedDataStatus->set_value(true);
441 }
442}
Here is the call graph for this function:

◆ UpdateDetectedObjects()

void ObjectDetector::UpdateDetectedObjects ( std::vector< objectdetectutils::Object > &  vNewlyDetectedObjects)
private

Update the detected objects with the newly detected objects.

Parameters
vNewlyDetectedObjects- The vector of newly detected objects to update the detected objects with.
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-05-05
745{
746 // Check if tracking is enabled.
747 if (m_bEnableTracking)
748 {
749 // Check if the given object vector is empty
750 if (vNewlyDetectedObjects.empty())
751 {
752 // Since the objects are empty that means the detector has not detected any new ground truth objects.
753 // In this case we will fallback to relying on the multi-tracker to track the objects and just update the objects
754 // stored in the m_vDetectedObjects vector.
755 // This is necessary because the torch detector is not perfect and may not detect all objects in the frame
756 // and it doesn't have the ability to track objects over time.
757 // We will use the multi-tracker to track the objects over time and update the bounding box data for the objects.
758
759 // Update the multi-tracker with the current frame.
760 m_pMultiTracker->Update(m_cvFrame);
761 }
762 else
763 {
764 // Loop through the newly detected objects.
765 for (objectdetectutils::Object& stObject : vNewlyDetectedObjects)
766 {
767 // Add the newly detected objects to the multi-tracker.
768 bool bMatchedObjectToExistingTracker = m_pMultiTracker->InitTracker(m_cvFrame, stObject.pBoundingBox, constants::BBOX_TRACKER_TYPE);
769 // Check if the object was matched to an existing tracker.
770 if (!bMatchedObjectToExistingTracker)
771 {
772 // Add the new object to the member variable list.
773 m_vDetectedObjects.emplace_back(stObject);
774 }
775 else
776 {
777 // Find the object with the same bounding box pointer and update the ID and confidence.
778 for (objectdetectutils::Object& stExistingObject : m_vDetectedObjects)
779 {
780 // Check if the bounding box pointers are the same.
781 if (stObject.pBoundingBox == stExistingObject.pBoundingBox)
782 {
783 // Update the ID and confidence of the existing object.
784 stExistingObject.dConfidence = stObject.dConfidence;
785 }
786 }
787 }
788 }
789
790 // Update the multi-tracker with the current frame.
791 m_pMultiTracker->Update(m_cvFrame);
792 }
793
794 // Loop through the detected objects and check if there are any we need to remove, and also update the time last seen.
795 for (std::vector<objectdetectutils::Object>::iterator itObject = m_vDetectedObjects.begin(); itObject != m_vDetectedObjects.end();)
796 {
797 // Check if the bounding box is 0,0,0,0.
798 if (itObject->pBoundingBox->x == 0 && itObject->pBoundingBox->y == 0 && itObject->pBoundingBox->width == 0 && itObject->pBoundingBox->height == 0)
799 {
800 // Remove the object from the vector.
801 itObject = m_vDetectedObjects.erase(itObject);
802 }
803 else
804 {
805 ++itObject;
806 }
807 }
808 }
809 else
810 {
811 // If tracking is not enabled, we will just clear the detected objects and add the new ones.
812 m_vDetectedObjects.clear();
813 // Loop through the newly detected objects and add them to the detected objects vector.
814 for (objectdetectutils::Object& stObject : vNewlyDetectedObjects)
815 {
816 // Set the object creation time to 0. The objects aren't being tracked, so we can't really tell their age.
817 stObject.tmCreation = std::chrono::system_clock::time_point::min();
818
819 // Add the new object to the member variable list.
820 m_vDetectedObjects.emplace_back(stObject);
821 }
822 }
823
824 // Check if we are using a ZED camera.
825 if (m_bUsingZedCamera)
826 {
827 // Check if the point cloud is empty.
828 if (!m_cvPointCloud.empty())
829 {
830 // Get the rover pose from the waypoint handler.
831 m_stRoverPose = globals::g_pStateMachineHandler->SmartRetrieveRoverPose();
832
833 // Find the camera's position in UTM coordinates by applying the camera offset to the rover pose.
834 geoops::UTMCoordinate stCamera = m_stRoverPose.GetUTMCoordinate();
835
836 // Translate the camera's local offsets into global Easting/Northing.
837 double dRoverHeadingRad = m_stRoverPose.GetCompassHeading() * (CV_PI / 180.0);
838 double dRotatedX = (m_pCamera->GetCameraPoseOffset().dPosY * sin(dRoverHeadingRad)) + (m_pCamera->GetCameraPoseOffset().dPosX * cos(dRoverHeadingRad));
839 double dRotatedY = (m_pCamera->GetCameraPoseOffset().dPosY * cos(dRoverHeadingRad)) - (m_pCamera->GetCameraPoseOffset().dPosX * sin(dRoverHeadingRad));
840
841 // Apply the rotated offsets to the global coordinates.
842 stCamera.dEasting += dRotatedX;
843 stCamera.dNorthing += dRotatedY;
844 stCamera.dAltitude += m_pCamera->GetCameraPoseOffset().dPosZ;
845
846 // Creating variables for the camera pose offset values.
847 double dQW = m_pCamera->GetCameraPoseOffset().dQW;
848 double dQX = m_pCamera->GetCameraPoseOffset().dQX;
849 double dQY = m_pCamera->GetCameraPoseOffset().dQY;
850 double dQZ = m_pCamera->GetCameraPoseOffset().dQZ;
851
852 // Update the rover pose's heading to match the camera's heading. We will need to calculate the camera's heading using the quaternion.
853 double dSinYCosP = 2.0 * (dQW * dQZ + dQX * dQY);
854 double dCosYCosP = 1.0 - 2.0 * (dQY * dQY + dQZ * dQZ);
855 double dCameraHeading = std::atan2(dSinYCosP, dCosYCosP) * (180.0 / CV_PI);
856
857 // Add the relative camera heading to the absolute rover heading
858 double dAbsoluteCameraHeading = m_stRoverPose.GetCompassHeading() + dCameraHeading;
859
860 // Recreate the rover pose with the camera's adjusted position and heading.
861 geoops::RoverPose stCameraPose = geoops::RoverPose(stCamera, dAbsoluteCameraHeading);
862
863 // Loop through the objects and use their center point to lookup their distance in the point cloud.
864 for (objectdetectutils::Object& stObject : m_vDetectedObjects)
865 {
866 // Use either width of height for the neighborhood size.
867 int nNeighborhoodSize = std::min(stObject.pBoundingBox->width, stObject.pBoundingBox->height);
868 // Geolocate the object in the point cloud.
870 m_cvPointCloud,
871 stCameraPose,
872 cv::Point(stObject.pBoundingBox->x + stObject.pBoundingBox->width / 2, stObject.pBoundingBox->y + stObject.pBoundingBox->height / 2),
873 nNeighborhoodSize);
874
875 // Depending on the class name of the model, set the object type.
876 if (stObject.szClassName == "mallet")
877 {
878 stObject.eDetectionType = objectdetectutils::ObjectDetectionType::eMallet;
879 }
880 else if (stObject.szClassName == "bottle")
881 {
882 stObject.eDetectionType = objectdetectutils::ObjectDetectionType::eWaterBottle;
883 }
884 else if (stObject.szClassName == "pick")
885 {
886 stObject.eDetectionType = objectdetectutils::ObjectDetectionType::eRockPick;
887 }
888
889 // Calculate the yaw angle to the tag using the center point of the tag and the camera's field of view.
890 // This is a fallback in case the geolocation fails for some reason, we can still provide a relative angle to the tag.
891 // Get the center X pixel coordinate of the object's bounding box.
892 double dObjectCenterX = stObject.pBoundingBox->x + (stObject.pBoundingBox->width / 2.0);
893 // Get the center X pixel coordinate of the camera frame.
894 double dFrameCenterX = m_cvFrame.cols / 2.0;
895 // Calculate the offset in pixels from the center of the camera frame.
896 // (Positive offset = target is to the right, Negative = target is to the left)
897 double dPixelOffsetX = dObjectCenterX - dFrameCenterX;
898 // Calculate how many real-world degrees each pixel represents.
899 double dDegreesPerPixel = stObject.dHorizontalFOV / static_cast<double>(m_cvFrame.cols);
900 // Multiply the pixel offset by the degrees per pixel to get the relative yaw angle.
901 stObject.dYawAngle = dPixelOffsetX * dDegreesPerPixel;
902 // Explicitly set distance to 0.0 so the autonomy state machines know the depth map failed
903 // and will properly fall back to using this calculated dYawAngle.
904 stObject.dStraightLineDistance = 0.0;
905
906 // Check if the geolocation is valid. If it is overwrite the yaw angle and distance with the geolocation data.
907 if (stGeolocation != geoops::Waypoint())
908 {
909 // Since this is a object detection, set the object's waypoint type appropriately.
910 stGeolocation.eType = geoops::WaypointType::eObjectWaypoint;
911 // Calculate the geo measurement and print the distance to the object.
912 geoops::GeoMeasurement stMeasurement =
913 geoops::CalculateGeoMeasurement(m_stRoverPose.GetUTMCoordinate(), stObject.stGeolocatedPosition.GetUTMCoordinate());
914
915 // Check that the distance is in a reasonable range.
916 if (stMeasurement.dDistanceMeters > 0.0 && stMeasurement.dDistanceMeters < 25.0)
917 {
918 // Set the object's geolocation.
919 stObject.stGeolocatedPosition = stGeolocation;
920 // Use the rover heading and the azimuth angle to calculate the relative heading to the object.
921 stObject.dYawAngle = numops::AngularDifference(m_stRoverPose.GetCompassHeading(), stMeasurement.dStartRelativeBearing);
922 // Set the straight line distance to the object.
923 stObject.dStraightLineDistance = stMeasurement.dDistanceMeters;
924 }
925 }
926 }
927 }
928 }
929 else
930 {
931 // Estimate the positions of the objects using some basic trig.
932 for (objectdetectutils::Object& stObject : m_vDetectedObjects)
933 {
934 // Use some trig to get the location of the object.
936 }
937 }
938}
geoops::RoverPose SmartRetrieveRoverPose(bool bIMUHeading=true)
This method is used to retrieve the rover's current position and heading. It uses the GPS data from t...
Definition StateMachineHandler.cpp:375
#define CV_PI
__device__ __forceinline__ float1 cos(const uchar1 &a)
__device__ __forceinline__ float4 sin(const uchar4 &a)
geoops::Waypoint GeolocateBox(const cv::Mat &cvPointcloud, const geoops::RoverPose &stCameraPose, const cv::Point &cvPixel, int nNeighborhoodSize=5, float fDepthPercentileTarget=0.20f, float fDepthToleranceMeters=0.5f)
Converts pixel coordinates in a ZED2i pointcloud into global UTM coordinates, given the camera's curr...
Definition Geolocate.hpp:57
GeoMeasurement CalculateGeoMeasurement(const GPSCoordinate &stCoord1, const GPSCoordinate &stCoord2)
The shortest path between two points on an ellipsoid at (lat1, lon1) and (lat2, lon2) is called the g...
Definition GeospatialOperations.hpp:553
constexpr T AngularDifference(T tFirstValue, T tSecondValue)
Calculates the distance in degrees between two angles. This function accounts for wrap around so that...
Definition NumberOperations.hpp:201
void EstimatePoseFromCameraFrame(Object &stTag)
Estimate the pose of a tag from a camera frame.
Definition ObjectDetectionUtility.hpp:178
This struct is used to store the distance, arc length, and relative bearing for a calculated geodesic...
Definition GeospatialOperations.hpp:83
double GetCompassHeading() const
Accessor for the Compass Heading private member.
Definition GeospatialOperations.hpp:787
const geoops::UTMCoordinate & GetUTMCoordinate() const
Accessor for the geoops::UTMCoordinate member variable.
Definition GeospatialOperations.hpp:767
This struct stores/contains information about a UTM coordinate.
Definition GeospatialOperations.hpp:211
This struct is used by the WaypointHandler class to store location, size, and type information about ...
Definition GeospatialOperations.hpp:423
Here is the call graph for this function:
Here is the caller graph for this function:

The documentation for this class was generated from the following files: