图像缩放是将图像按照一定比例放大或者缩小,对于数字图像而言,像素的坐标是离散型非负整数,但是在进行缩放的过程中有可能产生浮点坐标值。例如,原图像坐标(9,9)在缩小一倍时会变成(4.5,4.5),这显然是一个无效的坐标。因此需要用到图像插值方法。常见的插值算法有最邻近插值法、双线性插值法,二次立方插值法,三次立方插值法等。本文主要介绍最邻近插值、双线性插值和三次立方插值,其他一些高阶的插值算法,以后再做研究。
1.最近邻插值
最近邻插值是最简单的图像缩放处理方法,其原理是提取原图像中与其邻域最近像素值来作为目标图像相对应的像素值。简单来说就是四舍五入,浮点坐标的像素值等于距离该点最近的输入图像的像素值。最邻近插值几乎没有多余的运算,速度相当快。但是这种邻近取值的方法是很粗糙的,会造成图像的马赛克、锯齿等现象。
假设原图像中的点A0(x0,y0)经过缩放后目标图像中的坐标为A1(x1,y1),x方向和y方向的缩放比例为kx与ky,则变换矩阵为:
在opencv中提供了3个浮点数转换成整数的函数,分别是cvRound、cvFloor和cvCeil。cvRound函数返回和参数最接近的整数值,四舍五入。CvFloot函数返回不大于参数的最大整数值,向下取整。cvCeil返回不小于参数的最下整数值,向上取整。
最近邻插值的实现代码如下:
void NearstInterpolation(const Mat& srcImage, Mat &dstImage, double kx, double ky)
{
CV_Assert(srcImage.data != NULL);
double inv_kx = 1.0 / kx;
double inv_ky = 1.0 / ky;
int srcRowNum = srcImage.rows;
int srcColNum = srcImage.cols;
int dstRowNum = cvRound(srcImage.rows * ky);
int dstColNum = cvRound(srcImage.cols * kx);
dstImage.create(dstRowNum, dstColNum, srcImage.type());
for(int i = 0; i < dstRowNum; i++)
{
int y = cvRound(i * inv_ky);
if(y > srcRowNum - 1)
{
y = srcRowNum - 1;
}
for(int j = 0; j < dstColNum; j++)
{
int x = cvRound(j * inv_kx);
if(x > srcColNum - 1)
{
x = srcColNum - 1;
}
dstImage.at<Vec3b>(i, j) = srcImage.at<Vec3b>(y, x);
}
}
}
2.双线性