本文来自我的个人博客 https://www.zhangshenghai.com/posts/48467/
有时,在进行图像处理时,将源图像的一个像素对应到目标图像上时,对应目标图像上的像素坐标是小数,那么这个时候就需要进行插值了,本文给出了两种图像旋转时常用的插值算法的实现。
灰度最近邻插值
首先来看看最近邻插值,这最简单的插值算法,不需要计算,只需把与待求坐标的相邻四个像素中最近的坐标的像素值赋值给待求像素。
双线性插值
双线性内插法是利用待求象素四个邻象素的灰度在两个方向上作线性内插。
实现代码
下面贴出我基于OpenCV的一个简单代码实现。
class Interpolation{
public:
Mat nearest(cv::Mat img, float angle)
{
int len = (int)(sqrtf(pow(img.rows, 2) + pow(img.cols, 2)) + 0.5);
Mat retMat = Mat::zeros(len, len, CV_8UC1);
float anglePI = angle * CV_PI / 180;
int xSm, ySm;
for(int i = 0; i < retMat.rows; i++)
for(int j = 0; j < retMat.cols; j++)
{
xSm = (int)((i-retMat.rows/2)*cos(anglePI) - (j-retMat.cols/2)*sin(anglePI) + 0.5);
ySm = (int)((i-retMat.rows/2)*sin(anglePI) + (j-retMat.cols/2)*cos(anglePI) + 0.5);
xSm += img.rows / 2;
ySm += img.cols / 2;
if(xSm >= img.rows || ySm >= img.cols || xSm <= 0 || ySm <= 0){
retMat.at<uchar >(i, j) = 0;
}
else{
retMat.at<uchar >(i, j) = img.at<uchar >(xSm, ySm);
}
}
return retMat;
}
Mat bilinear(cv::Mat img, float angle)
{
int len = (int)(sqrtf(pow(img.rows, 2) + pow(img.cols, 2)) + 0.5);
Mat retMat = Mat::zeros(len, len, CV_8UC1);
float anglePI = angle * CV_PI / 180;
float alpha, beta;
for(int i = 0; i < retMat.rows; i++)
for(int j = 0; j < retMat.cols; j++)
{
float resu = (i-retMat.rows/2)*cos(anglePI) - (j-retMat.cols/2)*sin(anglePI) + img.rows / 2;
float resv = (i-retMat.rows/2)*sin(anglePI) + (j-retMat.cols/2)*cos(anglePI) + img.cols / 2;
int u = (int) resu;
int v = (int) resv;
if (resu >= u) alpha = resu - u;
else alpha = u - resu;
if (resv >= v) beta = resv - v;
else beta = v - resv;
// cout << alpha << ' ' << beta << endl;
if(u >= img.rows || v >= img.cols || u <= 0 || v <= 0){
retMat.at<uchar >(i, j) = 0;
}
else{
int res = (1 - alpha) * (1 - beta) * img.at<uchar >(u, v) +
alpha * (1-beta) * img.at<uchar >(u+1, v) +
(1 - alpha) * beta * img.at<uchar >(u, v+1) +
alpha * beta * img.at<uchar >(u+1, v+1);
retMat.at<uchar >(i, j) = res;
}
}
return retMat;
}
};