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
Geolocate.hpp
Go to the documentation of this file.
1
12#ifndef GEOLOCATE_HPP
13#define GEOLOCATE_HPP
14
15#include "../../AutonomyLogging.h"
16#include "../GeospatialOperations.hpp"
17#include "../NumberOperations.hpp"
18
20#include <algorithm>
21#include <cmath>
22#include <numeric>
23#include <opencv2/opencv.hpp>
24#include <vector>
25
27
28
35namespace geoloc
36{
37
55 inline geoops::Waypoint GeolocateBox(const cv::Mat& cvPointcloud, const geoops::RoverPose& stRoverPose, const cv::Point& cvPixel, int nNeighborhoodSize = 5)
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 }
167} // namespace geoloc
168
169#endif // GEOLOCATE_HPP
_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)
Namespace containing functions related to geolocation of objects within camera frames and conversion ...
Definition Geolocate.hpp:36
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 curre...
Definition Geolocate.hpp:55
constexpr T InputAngleModulus(T tValue, T tMinValue, T tMaxValue)
Calculates the modulus of an input angle.
Definition NumberOperations.hpp:165
This struct is used by the WaypointHandler to provide an easy way to store all pose data about the ro...
Definition GeospatialOperations.hpp:677
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