# How to correctly resize image with a different linear interpolation scheme

I want to double image with an linear interpolation scheme so that even indices of the new image is copied from indices/2 of the original and odd indices would linearly interpolate from the even indices. Example:

``````static Mat prepare_img(bool rows_indexed) {
int rows = 5;
int columns = 5;
Mat img(rows, columns, CV_32F);

for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
if (rows_indexed) {
img.at<float>(i, j) = (float)i;
} else {
img.at<float>(i, j) = (float)j;
}
}
}
return img;
}

static void double_linear(Mat& src, Mat& dst) {
dst.create(Size(src.cols*2, src.rows*2), src.type());

for (int i = 0; i < dst.rows; i = i + 2) {
for (int j = 0; j < dst.cols; j = j + 2) {
dst.at<float>(i, j) = src.at<float>(i/2, j/2);
}
}
for (int i = 0; i < dst.rows; i = i + 2) {
for (int j = 0; j < dst.cols; j = j + 2) {
if (i < dst.cols - 2) {
dst.at<float>(i + 1, j) = (dst.at<float>(i, j) + dst.at<float>(i + 2, j)) / 2;
if (j < dst.cols - 2) {
float a = dst.at<float>(i, j);
float b = dst.at<float>(i + 2, j);
float c = dst.at<float>(i, j + 2);
float d = dst.at<float>(i + 2, j + 2);
dst.at<float>(i + 1, j + 1) = (a + b + c + d) / 4;
}
}
if (j < dst.cols - 2) {
dst.at<float>(i, j + 1) = (dst.at<float>(i, j) + dst.at<float>(i, j + 2)) / 2;
}

if (i >= dst.cols - 2) {
dst.at<float>(i + 1, j) = dst.at<float>(i, j);
dst.at<float>(i + 1, j + 1) = dst.at<float>(i, j + 1);
}

if (j >= dst.cols - 2) {
dst.at<float>(i, j + 1) = dst.at<float>(i, j);
dst.at<float>(i + 1, j + 1) = dst.at<float>(i + 1, j);
}
}
}
}

Mat img1 = prepare_img(true);
std::cout << "image = " << std::endl << format(img1, Formatter::FMT_PYTHON) << std::endl << std::endl;

Mat dbl1;
double_linear(img1, dbl1);
std::cout << "double image = " << std::endl << format(dbl1, Formatter::FMT_PYTHON) << std::endl << std::endl;

Mat img2 = prepare_img(false);
std::cout << "image = " << std::endl << format(img2, Formatter::FMT_PYTHON) << std::endl << std::endl;

Mat dbl2;
double_linear(img2, dbl2);
std::cout << "double image = " << std::endl << format(dbl2, Formatter::FMT_PYTHON) << std::endl << std::endl;
``````

Output:

``````image =
[[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1],
[2, 2, 2, 2, 2],
[3, 3, 3, 3, 3],
[4, 4, 4, 4, 4]]

double image =
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5],
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3],
[3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5],
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
[4, 4, 4, 4, 4, 4, 4, 4, 4, 4]]

image =
[[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]]

double image =
[[0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4],
[0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4],
[0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4],
[0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4],
[0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4],
[0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4],
[0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4],
[0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4],
[0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4],
[0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4]]
``````

Let’s put aside that `double_linear` is not a template function and it works only for 1 channel - ideally I want to do this as fast as possible using OpenCV infrastructure (e.g. even using private API from within my OpenCV clone. I was looking at and trying resize function (opencv/resize.cpp at 4.x · opencv/opencv · GitHub). It seemed to me that if I used INTER_AREA and changed the coefficients to something like [0.5, 0.5] here:
opencv/resize.cpp at 4.x · opencv/opencv · GitHub
and on line 4030

Is that the way to go? Can you give me advice on how to achieve that as generically and as fast as possible?

I will just ignore all that code you posted and recommend that you use `warpAffine()` with a suitable transformation matrix, and the `WARP_INVERSE_MAP` flag, so the matrix directly describes the calculation from destination coordinate to source coordinate.

afaik, INTER_AREA only works for `resize()`, not for any of the warps

if you need a lowpass, do the lowpass explicitly.

or use `pyrDown()`