摘要
动手实现图像双线性插值——实现图像resize
双线性插值算法原理概括为一句话就是:
输出图上一个像素投影到原图得到的坐标为浮点型,其对应的像素值由相邻的四个点进行双线性插值得到,如果选择一个合适的坐标系,使得这四个点的uv坐标分别为(0, 0)、(0, 1)、(1, 0) 和 (1, 1),那么双线性插值的公式就简化为:
f
(
x
,
y
)
=
f
(
0
,
0
)
(
1
−
x
)
(
1
−
y
)
+
f
(
1
,
0
)
x
(
1
−
y
)
+
f
(
0
,
1
)
(
1
−
x
)
y
+
f
(
1
,
1
)
x
y
f(x, y) = f(0, 0)(1-x)(1-y) + f(1, 0)x(1-y) + f(0, 1)(1-x)y + f(1, 1)xy
f(x,y)=f(0,0)(1−x)(1−y)+f(1,0)x(1−y)+f(0,1)(1−x)y+f(1,1)xy
其中,f(x, y) 表示坐标 (x, y) 处 的像素值。
更详细的算法原理网上都有,这里不多说,文末参考资料里给出了一些个人觉得比较好的参考资料。
下面给出完整的插值代码。
完整代码
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main()
{
// read and show original image
Mat img_raw = imread("original.jpg");
cv::imshow("original", img_raw);
waitKey(0);
// bilinear interpolation
double scale = 2.0;
int32_t out_rows = img_raw.rows * scale + 0.5;
int32_t out_cols = img_raw.cols * scale + 0.5;
Mat img_out(out_rows, out_cols, img_raw.type(), Scalar::all(0));
for (int32_t i = 0; i < img_out.rows; ++i)
{
Vec3b *p_out_row = img_out.ptr<Vec3b>(i);
for (int32_t j = 0; j < img_out.cols; ++j)
{
double raw_v = i * (1.0 / scale);
double raw_u = j * (1.0 / scale);
// do not deal with the border situation
if (0 <= raw_u && raw_u + 1 < img_raw.cols && 0 <= raw_v && raw_v + 1 < img_raw.rows)
{
Vec3b f00 = img_raw.ptr<Vec3b>((int32_t)raw_v)[(int32_t)raw_u];
Vec3b f01 = img_raw.ptr<Vec3b>((int32_t)(raw_v + 1))[(int32_t)raw_u];
Vec3b f10 = img_raw.ptr<Vec3b>((int32_t)raw_v)[(int32_t)(raw_u + 1)];
Vec3b f11 = img_raw.ptr<Vec3b>((int32_t)(raw_v + 1))[(int32_t)(raw_u + 1)];
// if you choose a coordinate system that makes the four known point coordinates become
// (0, 0), (0, 1), (1, 0), and (1, 1), then the bilinear interpolation formula can reduced to
// f(x, y) = f(0, 0)(1-x)(1-y) + f(1, 0)x(1-y) + f(0, 1)(1-x)y + f(1, 1)xy
double x = (raw_u - (int32_t)raw_u);
double y = (raw_v - (int32_t)raw_v);
// 3 color channel
p_out_row[j][0] = f00[0] * (1 - x) * (1 - y) +
f10[0] * x * (1 - y) +
f01[0] * (1 - x) * y +
f11[0] * x * y;
p_out_row[j][1] = f00[1] * (1 - x) * (1 - y) +
f10[1] * x * (1 - y) +
f01[1] * (1 - x) * y +
f11[1] * x * y;
p_out_row[j][2] = f00[2] * (1 - x) * (1 - y) +
f10[2] * x * (1 - y) +
f01[2] * (1 - x) * y +
f11[2] * x * y;
}
}
}
// show result
cv::imshow("img_out", img_out);
waitKey(0);
return 0;
}
相关/参考链接
OpenCV ——双线性插值(Bilinear interpolation)(给的代码是利用整形替换浮点型的加速版本)
双线性插值算法以及python实现