Ask Your Question

Revision history [back]

click to hide/show revision 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

  • remap support three data formats for its coordinate maps:
    • tuple of 16SC2 and 16UC1,
    • pair of two 32FC1, for X and Y respectively,
    • A single 32FC2 which contains pair of (X, Y)

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.

click to hide/show revision 2
added explanation to resize as well as remap

Situation

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.


The output of 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.


The output of 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

  • remap support three data formats for its coordinate maps:
    • tuple of 16SC2 and 16UC1,
    • pair of two 32FC1, for X and Y respectively,
    • A single 32FC2 which contains pair of (X, Y)

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.