When you zoom into an image or change your window’s resolution, you are trying to redraw whatever images were in the window without knowing all of the pixel information. In order to accurately render the scaled images, you must use information that you do know, and predict the information you do not. Two techniques commonly used for this are Bilinear Interpolation and Nearest Neighbor.

When faced with implementing these techniques, I decided to approach the task in a way that was easy to visualize and debug. I started by making a simple Pixel class, that would hold my color information and make image operations simple. It looks something like this:

class Pixel { public: Pixel() : r(0), g(0), b(0), a(255) {} void operator=(const Pixel& rhs) { r = rhs.r; g = rhs.g; b = rhs.b; a = rhs.a; } unsigned char r; unsigned char g; unsigned char b; unsigned char a; }

You can add more functionality of course, but for the sake of this tutorial let’s keep it nice and simple.

Now that we have our Pixel class setup, store your loaded image into a 2D vector of Pixels. This will allow for easy visualization of the algorithms I am covering today as well as future image processing algorithms. And now, without further ado lets get into the two resizing algorithms.

**Nearest Neighbor:**

Nearest Neighbor is a very simple algorithm. In order to get the missing pixel information, we simply round to get the closest corresponding pixel in the original image. Here are the variables we will need:

**imageIn**: the 2D vector of Pixels representing the original image

**imageOut**: the 2D vector of Pixels that will represent the resized image

**width**: will be the width of the resized image

**height**: will be the height of the resized image

**xRatio**: the ratio of the amount that the window has resized in the X direction

**yRatio**: the ratio of the amount that the window has resized in the Y direction

void NearestNeighbor(const std::vector& imageIn, std::vector& imageOut, int& width, int& height, double xRatio, double yRatio) { //calculate the new image size based on how the screen was resized width = (int)(originalWidth / xRatio); height = (int)(originalHeight / yRatio); imageOut.resize(height); for(int y = 0; y = imageIn.size()) yIndex = imageIn.size() - 1; imageOut[y].resize(width); for (int x = 0; x = imageIn[0].size()) xIndex = imageIn[0].size() - 1; imageOut[y][x] = (imageIn[yIndex][xIndex]); } } }

**Bilinear Interpolation:**

Bilinear Interpolation, although more complicated, will often generate a more accurate result than Nearest Neighbor. It takes the information of pixels near the pixel we are looking at then interpolates between them, giving us a great guess of what information that pixel should have. We will use the same inputs as we did for Nearest Neighbor:

**imageIn**: the 2D vector of Pixels representing the original image

**imageOut**: the 2D vector of Pixels that will represent the resized image

**width**: will be the width of the resized image

**height**: will be the height of the resized image

**xRatio**: the ratio of the amount that the window has resized in the X direction

**yRatio**: the ratio of the amount that the window has resized in the Y direction

void BilinearInterpolation(const std::vector& imageIn, std::vector& imageOut, int& width, int& height, double xRatio, double yRatio) { //calculate new image size based on how the screen was resized width= (int)(originalWidth / xRatio); height= (int)(originalHeight / yRatio); imageOut.resize(height); for (int y = 0; y = imageIn.size()) y1 = imageIn.size() - 2; if (y2 >= imageIn.size()) y2 = imageIn.size() - 1; //the interpolation value for the y direction float beta = (float)(y2 - y1) / (float)(y - y1); imageOut[y].resize(width); for (int x = 0; x = imageIn[0].size()) x1 = imageIn[0].size() - 2; if (x2 >= imageIn[0].size()) x2 = imageIn[0].size() - 1; Pixel pixel; //the interpolation value for the x direction float alpha = (float)(x2 - x1) / (float)(x - x1); Pixel fxy1, fxy2; for (int i = 0; i < 3; ++i) { fxy1[i] = (unsigned char)((1.0f - alpha) * (imageIn[y1][x1])[i] + alpha * (imageIn[y1][x2])[i]); fxy2[i] = (unsigned char)((1.0f - alpha) * (imageIn[y2][x1])[i] + alpha * (imageIn[y2][x2])[i]); } for (int i = 0; i < 3; ++i) { pixel[i] = (unsigned char)((1.0f - beta) * fxy1[i] + beta * fxy2[i]); } imageOut[y][x] = pixel; } } }

And that's that! Now all you have to do is convert the 2D vector of Pixels to whatever you will be passing in to your graphics pipeline. Have fun!