图像插值方法比较
本文介绍几种经典插值的原理,代码过程以及对性能作出比较。
简单说来,在对原始图像进行缩放、旋转变换的时候,因为在目标图像中像素分布发生了变换,所以需根据一定的映射规则建立从原始图像到目标图像的转换。
Nearest 差值
顾名思义,最近邻插值就是从原始目标中找到最匹配的位置。不多说,直接上代码。
static int nearestArea(Mat &src, float scale_x, float scale_y, char *argc)
{
Mat dstMat1 = Mat(src.rows * scale_y, src.cols * scale_x, src.type());
typedef BOOST_TYPEOF(*src.data) ElementType;
int WidthSrc = src.cols;
int HeightSrc = src.rows;
int WidthDst = dstMat1.cols;
int HeightDst = dstMat1.rows;
int chal_num = src.channels();
char name[128];
char **ful_name = &argc;
char *prefix = nullptr;
char *subfix = nullptr;
prefix = strsep(ful_name, ".");
subfix = strsep(ful_name, ".");
if (!prefix || !subfix) {
printf("Get subfix from file name failed\n");
return -1;
}
snprintf(name, sizeof(name), "%s_%.2f_%.2f_Nearest.%s", prefix, scale_x, scale_y, subfix);
clock_t start = clock();
for (int w = 0; w < WidthDst; w++) {
float rx = ((float)w + 0.5) / scale_x - 0.5;
int sx = cvFloor(rx);
sx = MIN(sx, WidthSrc - 2);
sx = MAX(0, sx);
short rx_sh_buf[2];
rx_sh_buf[0] = (short)((1.f - rx) * 2048);
rx_sh_buf[1] = 2048 - rx_sh_buf[0];
for (int h = 0; h < HeightDst; h++) {
float ry = ((float)h + 0.5) / scale_y - 0.5;
int sy = cvFloor(ry);
sy = MIN(sy, HeightSrc - 2);
sy = MAX(0, sy);
switch (chal_num) {
case 1:
dstMat1.at<ElementType>(h, w) =
src.at<ElementType>(sy, sx);
break;
case 2:
for (int m = 0; m < 2; m++) {
dstMat1.at<Vec<ElementType, 2>>(h, w)[m] =
src.at<Vec<ElementType, 2>>(sy, sx)[m];
}
break;
case 3:
for (int m = 0; m < 3; m++) {
dstMat1.at<Vec<ElementType, 3>>(h, w)[m] =
src.at<Vec<ElementType, 3>>(sy, sx)[m];
}
break;
default:
break;
}
}
}
clock_t end = clock();
printf("Interpolation time: %f\n", (float)(end - start) / CLOCKS_PER_SEC * 1000);
if (dstMat1.data) {
imwrite(name, dstMat1);
}
return 1;
}
Bi-linear 双线性插值
双线性插值的思路就是利用映射到原始图像匹配点像素临近四个点对目标图像的像素点进行求解。原因在于反向求解匹配像素点的时候,会产生小数,舍入之后会产生较大误差。计算思路可以用下图表示:
X方向
f(R1)≈x−x1x2−x⋅f(Q21