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
geoloc Namespace Reference

Namespace containing functions related to geolocation of objects within camera frames and conversion to global coordinate systems. More...

Functions

geoops::Waypoint GeolocateBox (const cv::Mat &cvPointcloud, const geoops::RoverPose &stRoverPose, const cv::Point &cvPixel, int nNeighborhoodSize=5)
 Converts pixel coordinates in a ZED2i pointcloud into global UTM coordinates, given the rover's current pose and a point cloud from the camera.
 

Detailed Description

Namespace containing functions related to geolocation of objects within camera frames and conversion to global coordinate systems.

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

Function Documentation

◆ GeolocateBox()

geoops::Waypoint geoloc::GeolocateBox ( const cv::Mat cvPointcloud,
const geoops::RoverPose stRoverPose,
const cv::Point cvPixel,
int  nNeighborhoodSize = 5 
)
inline

Converts pixel coordinates in a ZED2i pointcloud into global UTM coordinates, given the rover's current pose and a point cloud from the camera.

Parameters
cvPointcloud- The CV_32FC4 pointcloud from the ZED2i camera.
stRoverPose- The current rover pose containing UTM position and heading.
cvPixel- The pixel coordinates (x, y) of the object of interest.
nNeighborhoodSize- Optional, the size of the neighborhood to sample (must be odd and >= 1, defaults to 5).
Returns
geoops::Waypoint - A waypoint containing the object's UTM coordinates and estimated radius.
Note
This function assumes the ZED SDK coordinate system is LEFT_HANDED_Y_UP. Heading is measured clockwise from north (0 degrees).
Author
clayjay3 (clayt.nosp@m.onra.nosp@m.ycowe.nosp@m.n@gm.nosp@m.ail.c.nosp@m.om)
Date
2025-04-27
56 {
57 // Ensure neighborhood size is at least 1.
58 if (nNeighborhoodSize < 1)
59 {
60 LOG_WARNING(logging::g_qSharedLogger, "GeolocateBox: Invalid neighborhood size {}, defaulting to 5x5", nNeighborhoodSize);
61 nNeighborhoodSize = 5; // Default to 5x5 neighborhood if invalid.
62 }
63
64 // Get the half-width of neighborhood for window calculations.
65 int nHalfSize = nNeighborhoodSize / 2;
66
67 // Create containers for valid points in the neighborhood.
68 std::vector<float> vX, vY, vZ, vDistances;
69
70 // Loop through the neighborhood window.
71 for (int nOffsetY = -nHalfSize; nOffsetY <= nHalfSize; ++nOffsetY)
72 {
73 for (int nOffsetX = -nHalfSize; nOffsetX <= nHalfSize; ++nOffsetX)
74 {
75 // Calculate the current pixel coordinates in the neighborhood.
76 int nCurrY = cvPixel.y + nOffsetY;
77 int nCurrX = cvPixel.x + nOffsetX;
78
79 // Skip out-of-bounds pixels.
80 if (nCurrY < 0 || nCurrY >= cvPointcloud.rows || nCurrX < 0 || nCurrX >= cvPointcloud.cols)
81 {
82 continue;
83 }
84
85 // Access the 3D point at this pixel.
86 cv::Vec4f cvPoint = cvPointcloud.at<cv::Vec4f>(nCurrY, nCurrX);
87
88 // Check if the point is valid. (not zero or NaN)
89 if (cvPoint[2] > 0 && std::isfinite(cvPoint[0]) && std::isfinite(cvPoint[1]) && std::isfinite(cvPoint[2]))
90 {
91 // Add point coordinates to our vectors
92 vX.push_back(cvPoint[0]); // X coordinate in camera frame.
93 vY.push_back(cvPoint[1]); // Y coordinate in camera frame.
94 vZ.push_back(cvPoint[2]); // Z coordinate in camera frame.
95 }
96 }
97 }
98
99 // If no valid points found in the neighborhood.
100 if (vX.empty())
101 {
102 LOG_DEBUG(logging::g_qSharedLogger, "GeolocateBox: No valid points found in neighborhood around pixel ({}, {})", cvPixel.x, cvPixel.y);
103 // Return a waypoint with default values.
104 return geoops::Waypoint();
105 }
106
107 // Calculate the centroid of the valid points in camera coordinates.
108 float fAvgX = std::accumulate(vX.begin(), vX.end(), 0.0f) / vX.size();
109 float fAvgY = std::accumulate(vY.begin(), vY.end(), 0.0f) / vY.size();
110 float fAvgZ = std::accumulate(vZ.begin(), vZ.end(), 0.0f) / vZ.size();
111
112 // Adjust rover degree heading to match unit circle 0 position.
113 double dAdjustedHeading = numops::InputAngleModulus((stRoverPose.GetCompassHeading() * -1.0) + 90.0, 0.0, 360.0);
114 // Convert camera heading to radians. (0 = North, CW positive)
115 double dHeadingRad = dAdjustedHeading * M_PI / 180.0;
116
117 // Get the rover's current UTM position.
118 const geoops::UTMCoordinate& stRoverUTM = stRoverPose.GetUTMCoordinate();
119
120 // Transform camera coordinates to global UTM coordinates.
121 // NOTE: ZED uses left-handed Y-up coordinate system, so:
122 // Camera +X = Right = East when rover faces North
123 // Camera +Y = Up = not used for horizontal positioning
124 // Camera +Z = Forward = North when rover faces North
125
126 // Rotate by rover's heading and translate by rover's position.
127 double dEasting = stRoverUTM.dEasting + (fAvgZ * cos(dHeadingRad) + fAvgX * sin(dHeadingRad));
128 double dNorthing = stRoverUTM.dNorthing + (fAvgZ * sin(dHeadingRad) - fAvgX * cos(dHeadingRad));
129
130 // Calculate altitude by adding camera height to rover's altitude.
131 double dAltitude = stRoverUTM.dAltitude + fAvgY; // Y is up in camera frame.
132
133 // Create a UTM coordinate for the object.
134 geoops::UTMCoordinate stObjectUTM(dEasting, dNorthing, stRoverUTM.nZone, stRoverUTM.bWithinNorthernHemisphere, dAltitude);
135
136 // Estimate the object's radius from the spread of points.
137 double dRadius = 0.0;
138 if (vX.size() > 1)
139 {
140 // Calculate Euclidean distance from each point to the centroid.
141 for (size_t siI = 0; siI < vX.size(); ++siI)
142 {
143 double dX = vX[siI] - fAvgX;
144 double dY = vY[siI] - fAvgY;
145 double dZ = vZ[siI] - fAvgZ;
146 vDistances.push_back(sqrt(dX * dX + dY * dY + dZ * dZ));
147 }
148
149 // Use median distance as radius estimate to be robust against outliers.
150 std::sort(vDistances.begin(), vDistances.end());
151 if (vDistances.size() % 2 == 0)
152 {
153 dRadius = (vDistances[vDistances.size() / 2 - 1] + vDistances[vDistances.size() / 2]) / 2.0;
154 }
155 else
156 {
157 dRadius = vDistances[vDistances.size() / 2];
158 }
159
160 // Apply a scaling factor to better approximate the object's boundary.
161 dRadius *= 1.5; // Empirical scale factor.
162 }
163
164 // Create and return the waypoint with the object's UTM coordinates and radius.
165 return geoops::Waypoint(stObjectUTM, geoops::WaypointType::eUNKNOWN, dRadius);
166 }
_Tp & at(int i0=0)
void sqrt(InputArray src, OutputArray dst)
__device__ __forceinline__ float1 cos(const uchar1 &a)
__device__ __forceinline__ float4 sin(const uchar4 &a)
constexpr T InputAngleModulus(T tValue, T tMinValue, T tMaxValue)
Calculates the modulus of an input angle.
Definition NumberOperations.hpp:165
double GetCompassHeading() const
Accessor for the Compass Heading private member.
Definition GeospatialOperations.hpp:756
const geoops::UTMCoordinate & GetUTMCoordinate() const
Accessor for the geoops::UTMCoordinate member variable.
Definition GeospatialOperations.hpp:736
This struct stores/contains information about a UTM coordinate.
Definition GeospatialOperations.hpp:195
This struct is used by the WaypointHandler class to store location, size, and type information about ...
Definition GeospatialOperations.hpp:392
Here is the call graph for this function:
Here is the caller graph for this function: