We are working with 8 Bit masks and some feature points with subpixel precision, so our input coordinates are of type cv::Point2f and we want to access pixel positions.
Since from processing we can’t guarantee that we are inside of the image bounds we typically use something like this:
cv::Point2f pixelPos = {our x, and y subpixel coordinates};
if(pixelPos.x >= 0 && pixelPos.x < mask.cols
&& pixelPos.y >= 0 && pixelPos.y < mask.rows)
{
const uchar maskVal = mask.at<uchar>(pixelPos);
// do whatever to do
}
It looks like cv::Point2f subpixels are truncated (not to-nearest rounded) in the .at matrix method.
However we’ve observed that cv::Point2f to cv::Point conversion uses to-nearest rounding instead of truncation.
Is that correct in general, or depending on some compiler flags?
I’m asking because we’ve also seen that assigning to cv::Point seems to round-to-nearest instead of truncating:
cv::Point2f pixelPos = {our x, and y subpixel coordinates};
cv::Point pixelPos_int = pixelPos; // here pixelPos_int isn't truncated but rounded to nearest.
Is this also correct in general?
We found this behaviour when trying to access the matrix element with the converted (integer) pixel coordinates while checking against the floating point pixel coordinates and seeing some failed assertions in the .at method.
you’re expecting the Mat::at(Point2f) to go through some defined conversion that coerces it to Point first, yes?
the Point constructors will contain explicit rounding. There might be a case of Mat::at() that special-cases on Point2f, or else some path that destructures a Point2f into an at(i0, i1) that truncates due to casting.
I’m not a C++ language lawyer nor do I have much practice or inclination to know the intricacies of the language. There are probably ways to investigate what the C++ type system did here. I wouldn’t know how to get at that. maybe step into the expression with a debugger, while the program is built with a debug version of OpenCV. that should allow the debugger to step into the library and show you meaningful references to source code.
After looking into mat.inl.hpp it looks like there are only overloaded function of ::at for integer values and cv::Point, so no specialized ::at directly visible for cv::Point2f or the template Point type.
I think my question is mostly about whether it is lowly efficient to assign a cv::Point2f to a cv::Point because of extra operations like rounding.
I will try to investigate and add my findings here.
I believe this is it. they’re defining a cast operator.
the saturate_castmight (!) perform the rounding. I’m not sure. regular “float to int” conversions don’t round and I haven’t actually seen any rounding calls or 0.5 constants.
They must have defined their own saturate_cast because C++ only has that from 2026 onwards.
see all the overloads of saturate_cast, specifically those with a specific type? lrintf/lrint seem to be part of C++ 11 and C 99