Converts pixel coordinates in a ZED2i pointcloud into global UTM coordinates, given the camera's current pose and a point cloud from the camera.
63 {
64
65 if (nNeighborhoodSize < 1)
66 {
67 LOG_WARNING(logging::g_qSharedLogger, "GeolocateBox: Invalid neighborhood size {}, defaulting to 5x5", nNeighborhoodSize);
68 nNeighborhoodSize = 5;
69 }
70
71
73
74
75 int nHalfSize = nNeighborhoodSize / 2;
76
77
78 std::vector<cv::Vec4f> vRawPoints;
79 std::vector<float> vRawZ;
80
81
82 for (int nOffsetY = -nHalfSize; nOffsetY <= nHalfSize; ++nOffsetY)
83 {
84 for (int nOffsetX = -nHalfSize; nOffsetX <= nHalfSize; ++nOffsetX)
85 {
86
87 int nCurrY = cvPixel.
y + nOffsetY;
88 int nCurrX = cvPixel.
x + nOffsetX;
89
90
91 if (nCurrY < 0 || nCurrY >= cvPointcloud.
rows || nCurrX < 0 || nCurrX >= cvPointcloud.
cols)
92 {
93 continue;
94 }
95
96
98
99
100 if (cvPoint[2] > 0 && std::isfinite(cvPoint[0]) && std::isfinite(cvPoint[1]) && std::isfinite(cvPoint[2]))
101 {
102 vRawPoints.push_back(cvPoint);
103 vRawZ.push_back(cvPoint[2]);
104 }
105 }
106 }
107
108
109 float fAvgX = 0.0f;
110 float fAvgY = 0.0f;
111 float fAvgZ = 0.0f;
112
113
114 std::vector<float> vX, vY, vZ, vDistances;
115
116
117 if (vRawZ.empty())
118 {
119 LOG_DEBUG(logging::g_qSharedLogger,
"GeolocateBox: Stereovision failed for pixel ({}, {}). Attempting Monocular Fallback.", cvPixel.
x, cvPixel.
y);
120
121
122
123 int nBottomY = std::min(cvPointcloud.
rows - 1, cvPixel.
y + nHalfSize);
124
125
126 float fFy = cvPointcloud.
rows / 2.0f;
127 float fCy = cvPointcloud.
rows / 2.0f;
128
129
130 float fCameraHeight = static_cast<float>(stCameraUTM.dAltitude);
131
132 float fRayAngleY =
atan2(nBottomY - fCy, fFy);
133 float fTotalAngle = fRayAngleY;
134
135
136 if (fTotalAngle <= 0.01f)
137 {
138 LOG_DEBUG(logging::g_qSharedLogger, "GeolocateBox: Fallback failed. Object is on or above the horizon line.");
140 }
141
142 fAvgZ = fCameraHeight /
tan(fTotalAngle);
143 fAvgX = ((cvPixel.
x - (cvPointcloud.
cols / 2.0f)) / fFy) * fAvgZ;
144 fAvgY = -fCameraHeight;
145 }
146 else
147 {
148
149
150 std::sort(vRawZ.begin(), vRawZ.end());
151 size_t unPercentileIndex = static_cast<size_t>(vRawZ.size() * fDepthPercentileTarget);
152 float fTargetZ = vRawZ[unPercentileIndex];
153
154
155 for (const auto& cvPoint : vRawPoints)
156 {
157 if (std::abs(cvPoint[2] - fTargetZ) <= fDepthToleranceMeters)
158 {
159 vX.push_back(cvPoint[0]);
160 vY.push_back(cvPoint[1]);
161 vZ.push_back(cvPoint[2]);
162 }
163 }
164
165 if (!vX.empty())
166 {
167 fAvgX = std::accumulate(vX.begin(), vX.end(), 0.0f) / vX.size();
168 fAvgY = std::accumulate(vY.begin(), vY.end(), 0.0f) / vY.size();
169 fAvgZ = std::accumulate(vZ.begin(), vZ.end(), 0.0f) / vZ.size();
170 }
171 else
172 {
173
174 fAvgX = vRawPoints[unPercentileIndex][0];
175 fAvgY = vRawPoints[unPercentileIndex][1];
176 fAvgZ = vRawPoints[unPercentileIndex][2];
177 }
178 }
179
180
182
183 double dHeadingRad = dAdjustedHeading * M_PI / 180.0;
184
185
186
187
188
189
190
191
192 double dEasting = stCameraUTM.dEasting + (fAvgZ *
cos(dHeadingRad) + fAvgX *
sin(dHeadingRad));
193 double dNorthing = stCameraUTM.dNorthing + (fAvgZ *
sin(dHeadingRad) - fAvgX *
cos(dHeadingRad));
194
195
196 double dAltitude = stCameraUTM.dAltitude + fAvgY;
197
198
199 geoops::UTMCoordinate stObjectUTM(dEasting, dNorthing, stCameraUTM.nZone, stCameraUTM.bWithinNorthernHemisphere, dAltitude);
200
201
202 double dRadius = 0.0;
203 if (vX.size() > 1)
204 {
205
206 for (size_t siI = 0; siI < vX.size(); ++siI)
207 {
208 double dX = vX[siI] - fAvgX;
209 double dY = vY[siI] - fAvgY;
210 double dZ = vZ[siI] - fAvgZ;
211 vDistances.push_back(
sqrt(dX * dX + dY * dY + dZ * dZ));
212 }
213
214
215 std::sort(vDistances.begin(), vDistances.end());
216 if (vDistances.size() % 2 == 0)
217 {
218 dRadius = (vDistances[vDistances.size() / 2 - 1] + vDistances[vDistances.size() / 2]) / 2.0;
219 }
220 else
221 {
222 dRadius = vDistances[vDistances.size() / 2];
223 }
224
225
226 dRadius *= 1.5;
227 }
228
229
230 return geoops::Waypoint(stObjectUTM, geoops::WaypointType::eUNKNOWN, dRadius);
231 }
void sqrt(InputArray src, OutputArray dst)
__device__ __forceinline__ float1 atan2(const uchar1 &a, const uchar1 &b)
__device__ __forceinline__ float1 cos(const uchar1 &a)
__device__ __forceinline__ float4 sin(const uchar4 &a)
__device__ __forceinline__ float3 tan(const uchar3 &a)
constexpr T InputAngleModulus(T tValue, T tMinValue, T tMaxValue)
Calculates the modulus of an input angle.
Definition NumberOperations.hpp:162
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