Odom: support features-only frames (#1767)

* Odom: support features-only frames

* odom: fixed input keypoint scaling when Odom/Decimation is used

* fixing octave scaling when decimating image in Memory

* Gating negative octave scaling on decimation

* backward compatibility with octave issue

* narrowing the change, cleanup comments

* fixing corrupted file copy on windows
This commit is contained in:
matlabbe
2026-09-19 23:48:45 -07:00
committed by GitHub
parent 1fe713cc1f
commit 9ed83a71db
9 changed files with 234 additions and 10 deletions
+28 -1
View File
@@ -779,6 +779,26 @@ Transform Odometry::process(SensorData & data, const Transform & guessIn, Odomet
}
// Features that came with the frame are placed in the full size image, while what
// is about to be registered is the decimated one and the calibration that goes
// with it, so bring them along. They are scaled back below with whatever the
// registration returns, leaving the caller its own frame of reference.
if(!decimatedData.keypoints().empty())
{
std::vector<cv::KeyPoint> decimatedKpts = decimatedData.keypoints();
double log2value = log(double(_imageDecimation))/log(2.0);
for(unsigned int i=0; i<decimatedKpts.size(); ++i)
{
decimatedKpts[i].pt.x /= _imageDecimation;
decimatedKpts[i].pt.y /= _imageDecimation;
decimatedKpts[i].size /= _imageDecimation;
// Never below the finest level of the decimated image, which is as fine
// as its detail goes; ORB refuses a negative octave outright.
decimatedKpts[i].octave = std::max(0, int(decimatedKpts[i].octave - log2value));
}
decimatedData.setFeatures(decimatedKpts, decimatedData.keypoints3D(), decimatedData.descriptors());
}
// compute transform
t = this->computeTransform(decimatedData, guess, info);
@@ -817,7 +837,14 @@ Transform Odometry::process(SensorData & data, const Transform & guessIn, Odomet
}
}
}
else if(!data.imageRaw().empty() || !data.laserScanRaw().isEmpty() || (this->canProcessAsyncIMU() && !data.imu().empty()))
// A frame that brings its own features carries no image, and a frame whose scene was
// empty carries no feature either, so neither says whether there is a frame at all.
// The calibration does: it is there when a camera produced this data.
else if(!data.imageRaw().empty() ||
!data.cameraModels().empty() ||
!data.stereoCameraModels().empty() ||
!data.laserScanRaw().isEmpty() ||
(this->canProcessAsyncIMU() && !data.imu().empty()))
{
t = this->computeTransform(data, guess, info);
}