一、数学原理
当一幅二维数字图像从源图像N*M被放为(j*N) * (k*M)目标图像是,参照数学斜率计算公式
必然有: (X1 – Xmin)/(Xmax - Xmin) = (Y1 - Ymin)/(Ymax-Ymin)
当Xmin 和 Ymin均为从零开始的像素点时,公式可以简化为:X=Y1 (Xmax/Ymax)
对于任意一幅源图像来说,假设放大后目标图像的宽为Dw高为Dh,任意目标像素点(Dx, Dy)
在源图像上的位置为:
Sx= Dx * (Sh/Dh) // row
Sy= Dy * (Sw/Dw) // column
最简单的图像缩放算法就是最近邻插值。顾名思义,就是将目标图像各点的像素值设为源图像中与其最近的点。假设源图像的宽度和高度分别为w0和h0, 缩放后的目标图像的宽度和高度分别为w1和h1, 那么比例就是float fw = float(w0)/w1; float fh = float(h0)/h1; 对于目标图像中的(x,y)点坐标对应着源图像中的(x0, y0)点。其中:x0 = int(x*fw), y0 = int(y*fh)。
二、代码实现
int _tmain(int argc, _TCHAR* argv[])
{
//导入图像
Mat src = imread("1.jpg");
//显示
imshow("src",src);
//创建矩阵
Mat dst = Mat::zeros(Size(800,1000),CV_8UC3);
//放大的比例
double fRows = 1000 / (float)src.rows;
double fCols = 800 / (float)src.cols;
int primaryX = 0;
int primaryY = 0;
//近邻内插法
for (int i =0; i != dst.rows; ++ i)
{
for (int j = 0; j != dst.cols; ++ j)
{
primaryX = cvRound(i / (double)fRows);
primaryY = cvRound(j / (double)fCols);
if(primaryX<src.rows&&primaryX>= 0&&primaryY>= 0&& primaryY<src.cols)
{
dst.at<cv::Vec3b>(i,j)[0] = src.at<cv::Vec3b>(primaryX,primaryY)[0];
dst.at<cv::Vec3b>(i,j)[1] = src.at<cv::Vec3b>(primaryX,primaryY)[1];
dst.at<cv::Vec3b>(i,j)[2] = src.at<cv::Vec3b>(primaryX,primaryY)[2];
}
}
}
imshow("dst",dst);
waitKey(0);
return 0;
}
三、结果显示与分析
得到的结果如下图所示:
临近点插值算法会产生锯齿效果, 不是一个很好的图像放缩算法,临近点插值算法不改变源像素点到目标像素点的值,只是最简单的位置匹配而已,相比之下,双线性内插值算法和双立方插值算法效果更好,但是计算量更大,临近点插值是计算量最小的防缩算法。