nppiResizeSqrPixel_8u_C1R() produces low quality images


when the function is used to scale an image down to 1/3 and with a 0.0/0.0 pixel shift does it produce indistinguishable images regardless of most of the interpolation algorithms.

This affects the interpolations “nearest neighbor”, “linear”, “cubic”, “catmulrom” and “lanczos”. The interpolations “bspline”, “c05b03” and “super sampling” however do produce distinguishable images.

A pixel shift of 0.5/0.5 fixes this and the interpolations can again be distinguished, but the image itself will show the pixel shift, too, making this not an acceptable fix.

This occurs with CUDA 7.5 and 8.0rc1.

If this had been only between “catmulrom” and “lanczos” would it have been acceptable as a limitation, but it affects the “linear” and “cubic” interpolations and effectively turns these into “nearest neighbor”.

An example:
The first three columns show images produced with nppiResizeSqrPixel_8u_C1R().

Is this a bug, an inaccuracy or a limitation of some kind?

To add to this, there seems to be a discrepancy regarding the shift calculation for the “super sampling” interpolation when compared to the others.

The documentation describes the shift values as follows:

ResizeSqrPixel attempts to choose source pixels that would approximately represent the center of the des-
tination pixels. It does so by using the following scaling formula to select source pixels for interpolation:

nAdjustedXFactor = 1.0 / nXFactor;
nAdjustedYFactor = 1.0 / nYFactor;
nAdjustedXShift = nXShift * nAdjustedXFactor + ((1.0 - nAdjustedXFactor) * 0.5);
nAdjustedYShift = nYShift * nAdjustedYFactor + ((1.0 - nAdjustedYFactor) * 0.5);
nSrcX = nAdjustedXFactor * nDstX - nAdjustedXShift;
nSrcY = nAdjustedYFactor * nDstY - nAdjustedYShift;

I could find one example code (see $SAMPLESDIR/7_CUDALibraries/jpegNPP/jpegNPP.cpp) where this function is being used. There the pixel shift is set to 0.5/0.5. FFmpeg uses 0.0/0.0 for it.

According to the above formula should the ideal shift be calculated as:

IdealXShift = 0.5-0.5XFactor
IdealYShift = 0.5-0.5

This however causes the “super sampling” algorithm not to write into the upper and left border of the destination even when according to the calculation the centres of the pixels now make perfect sense (i.e. with a resize down to 33.333% or 1/3rd will the centre of the destination pixel at 10/10 fall precisely onto 30/30 of the source).
The other algorithms do write fully into the destination region though (but still produce indistinguishable and low quality images).

Question: Which is the best pixel shift one should use?

It is my opinion that the ideal shift value should be 0.0/0.0 as this is the least misleading. Having to calculate a precise shift value to “hit” the exact centres of the pixels should be part of the NPPI function.

This is outside my area of expertise, but you may want to consult the documentation for Intel’s IPP (the function ippiResizeSqrPixel_8u_C1R in particular) as a secondary resource, since many NPP functions are designed to be drop-in replacements for the IPP function with the equivalent name.

Thanks for the hint. It did not make things easier … The function has been deprecated with Intel IPP 9 and the only other documentation still available is for IPP v8. v8 then states the function has been marked as deprecated as of v7 and alternatives should be used instead. The alternative functions are however not present in either CUDA 7.5 or 8.0rc1.

When comparing both functions can one find several differences. Both, Nvidia and Intel, give a formula for the shift value and they are different from one another.

Not sure what to make of this. It isn’t helping and it doesn’t seem that the function is here to stay either…

Consider filing a bug with NVIDIA, it seems something is amiss with the NPP implementation. The bug reporting form is linked directly from the CUDA registered developer website. You may want to check whether the function has been deprecated or removed in CUDA 8.0 RC. You could also file an enhancement request (same form as for bugs, just prefix the synopsis with “RFE:”) for NPP to add the functionality IPP now uses to replace ippiResizeSqrPixel_8u_C1R().

Thank you for your advise. It’s what I’ve done.