1 | initial version |
What you are seeing is an artifact of the cv::remap
internally using an interpolation weighting table that has limited arithmetic precision.
In your particular example, the multiplication table itself is encoded in 5 bits of precision.
That means every output value is generated by
(TopLeft * weight00 + TopRight * weight01 + BottomLeft * weight10 + BottomRight * weight11)
in which the four weights can take on values in (0, 1/32, 2/32, ... , 31/32, 1).
1.343750 = 1 * (21 / 32) + 2 * (11 / 32)
1.656250 = 1 * (11 / 32) + 2 * (21 / 32)
1.687500 = 1 * (21 / 32) + 3 * (11 / 32)
2.031250 = 1 * (14 / 32) + 2 * (7 / 32) + 3 * (7 / 32) + 4 * (4 / 32)
The clue to this artifact is mentioned in the OpenCV documentation for remap and convertMaps
tuple of 16SC2 and 16UC1
,The first data format is not even explained in the documentation for remap
. If one passes in (x,y)
coordinate values for the first option, it will either fail an assertion or generate a corrupted output.
The answer is hidden in the documentation for the convertMaps
function.
Quoted:
... are converted to a more compact and much faster fixed-point representation. The first output array contains the rounded coordinates and the second array (created only when nninterpolation=false ) contains indices in the interpolation tables.
It is obvious that the documentation can be improved, and that the behavior could have been deprecated or separated into a differently-named function. However, because this behavior has been made available to users for more than a whole decade, it cannot be simply taken off-line as that will break a lot of applications that depend on it.
2 | added explanation to resize as well as remap |
OpenCV is aware of this issue. It is actually on the top of their Volunteer tasks list and on the bug list as issue 3212.
cv::resize
.Firstly, when scaling an image, there is the issue of the choice of physical meaning between the coordinate mapping scheme.
A similar issue occurs in the context of the chroma subsampling process inside JPEG compression. One would think that a constant integer scaling factor would have removed all ambiguity, but that is not true. The issue of "centered" vs "co-sited" mapping is applicable to all discrete image scaling processes, regardless of scaling factors and algorithms. To have a thoughtful discussion, one is advised to study similar cases that had already been well analyzed.
I personally used INTER_AREA
when scaling images, because it is one of the scaling definitions that had the least ambiguity.
cv::remap
.What you are seeing is an artifact of the cv::remap
internally using an interpolation weighting table that has limited arithmetic precision.
In your particular example, the multiplication table itself is encoded in 5 bits of precision.
That means every output value is generated by
(TopLeft * weight00 + TopRight * weight01 + BottomLeft * weight10 + BottomRight * weight11)
in which the four weights can take on values in (0, 1/32, 2/32, ... , 31/32, 1).
1.343750 = 1 * (21 / 32) + 2 * (11 / 32)
1.656250 = 1 * (11 / 32) + 2 * (21 / 32)
1.687500 = 1 * (21 / 32) + 3 * (11 / 32)
2.031250 = 1 * (14 / 32) + 2 * (7 / 32) + 3 * (7 / 32) + 4 * (4 / 32)
The clue to this artifact is mentioned in the OpenCV documentation for remap and convertMaps
tuple of 16SC2 and 16UC1
,The first data format is not even explained in the documentation for remap
. If one passes in (x,y)
coordinate values for the first option, it will either fail an assertion or generate a corrupted output.
The answer is hidden in the documentation for the convertMaps
function.
Quoted:
... are converted to a more compact and much faster fixed-point representation. The first output array contains the rounded coordinates and the second array (created only when nninterpolation=false ) contains indices in the interpolation tables.
It is obvious that the documentation can be improved, and that the behavior could have been deprecated or separated into a differently-named function. However, because this behavior has been made available to users for more than a whole decade, it cannot be simply taken off-line as that will break a lot of applications that depend on it.