What does nppiResize_8u_C1R do when shrinking ?

Dear Nvidia Forum,
I have a question relating to the documentation of NVIDIA Performance Primitives.
The documentation covers all methods and provides a very brief description for each of them, but some technical details are left over.

I have a speed critical section of my code related to image shrinking.
nppiResize_8u_C1R seems to be a good candidate, however it is unspecified what this method does when shrinking an image.
Will it subsample the input image ? Will it average neighbor pixels ? Will it apply a Gaussian filter and then subsample ?

My code does signal processing, not computer graphics, so I need to know exactly what happens to each bit during processing.
Some clarification on this point (and future improvements on the documentation), are most welcome.

Your answer will avoid me the pain of reverse engineering this function (i.e. do some tests to guess what the methods do).

Thanks you very much for your support.
Regards,
rodrigob.

Hi Rodrigo,

and thanks for using NPP. As you have already suspected, the Resize function does not apply any filtering for image minification. It simply samples the image according the the filtering modes mentioned in the documentation (point, linear, cubic).

–Frank

The documentation does not explain what happens when you shrink the data. The interpolation mode (point, linear, cubic) only make sense when make the image bigger.

What does “linear interpolation” do when you shrink the image by one half ?

This is what I would like to know. My guess is that all modes do “nearest point” when shrinking, but I cannot tell just from the documentation.

Interpolation applies to shrinking too. It will determine whether your output results from a single pixel in the source image or whether it’s an average of 4 (linear) or even 16 (cubic) pixels from the original image.

Well… actually it does not.

I just wrote a small test program that reads an image, makes two copies and calls nppiResize_8u_C1R using NPPI_INTER_NN in one case and NPPI_INTER_LINEAR in the other.

When shrinking down, both calls results in exactly the same image (sum of absolute difference between them is zero).

The interpolation logic does not apply to the shrinking case. This is a documentation bug, I hope Nvidia will fix it in the next release (and provide an accelerated procedure to do shrinking).

Regards,

rodrigob.

Do you notice interpolation if you shrink by a non-integer ratio, such as 2.5x? If you shrink by 2x the bilinear texture sampling might just align perfectly with source pixels and not perform any averaging. How about NPPI_INTER_CUBIC?

Yes, I see your point.

Still, I am looking for a shrinking function that will average the pixels, when shrinking by 2, I would like each resulting pixel to be the average of the corresponding 4 input pixels.

nppiResize (or any nppi function I know of) seem not to offer this feature.

I have implemented it by myself (quite a simple cuda kernel).

Thanks for the comments.

Regards,

rodrigob.

Hello rodrigob

I’ve the same problem. I have to shrink images using the average. Maybe you like to share your experience with me.

thank you,

jjm

As mentioned I ended up implementing my own kernel. The code is quite straight forward.

The only tip I can give is that reading the input image from texture seems 10~20% faster than just using global memory.

Also, I use cudatemplates extensively to make my life writing CUDA kernels easier (for the allocation and handling of data).

https://github.com/rodrigob/cudatemplates

Regards,

rodrigob.

Can anyone tell me how to use the Resize function in cuda NPP ? I have a source image, I converted it to Y Cb Cr colour space by using the nppiRGBToYCbCr_8u_C3R NPP function which works, then I wrote a kernel to extract the three components and stored them as separate images. Till this everything works correctly. Now I want to resize the 3 channels. But the resize NPP function does not work correctly. Is this the right way to use it ?

double ratio_aim = 25;
NppiSize srcSize = {srcWidth, srcHeight};
int srcLineStep = srcWidth;
NppiRect srcROI = {srcWidth, srcHeight};
NppiSize resdstROI = {(int)srcWidthratio_aim, (int)srcHeightratio_aim};
int yLine,cbLine, crLine;

Npp8u *y_img = nppiMalloc_8u_C1(resdstROI.width, resdstROI.height, &yLine);
Npp8u *cb_img = nppiMalloc_8u_C1(resdstROI.width, resdstROI.height, &cbLine);
Npp8u *cr_img = nppiMalloc_8u_C1(resdstROI.width, resdstROI.height, &crLine);

nppiResize_8u_C1R(y_channel, srcSize, srcLineStep, srcROI, y_img, yLine, resdstROI, 0.25, 0.25, 4);
nppiResize_8u_C1R(cb_channel, srcSize, srcLineStep, srcROI, cb_img, cbLine, resdstROI, ratio_aim, ratio_aim, 4);
nppiResize_8u_C1R(cr_channel, srcSize, srcLineStep, srcROI, cr_img, crLine, resdstROI, ratio_aim, ratio_aim, 4);

Thanks,