很长时间不敲代码,感觉一闲下来就忘了很多。想着把一些图像算法自己实现一遍也好,一方面加深算法的学习和理解,另一方面又可以练练编码能力。对于我这个非科班出身的,也挺有好处的。
不管那么多,先把这个坑挖了。闲着想敲代码了就慢慢填。
下面先把图像处理中常见的三种插值算法实现了。先解释一下什么叫插值。老样子先看看维基百科怎么解释。
数学的数值分析领域中,内插或称插值(英语:interpolation)是一种通过已知的、离散的数据点,在范围内推求新数据点的过程或方法。
450px-Splined_epitrochoid.svg.png
一组离散数据点在一个外延的插值。曲线中实际已知数据点是红色的;连接它们的蓝色曲线即为插值。
再举个例子:
x1 = 1, y1 = 3
x2 = 3, y2 = 7
x3 = 5, y3 = 24
求x = 4时, y = ?
所以可以看到,可以这么理解插值,在一个函数里面,自变量是离散有间隔的,插值就是往自变量的间隔之间插入新的自变量,然后求解新的自变量函数值。这有什么作用呢,从上图可以看到,散点图是可以利用插值来拟合曲线的,蓝色的就是插入的密密麻麻的点。
然而在图像处理上的应用可以体现在图像的缩放上面。如放大一张图片,在像素点的层面上其实就是往像素点之间插入新的像素点从而增大图像的分辨率。
插值算法有很多种,具体可以参考维基百科插值
这里就实现图像处理比较常用的三种:最近邻域差值、双线性插值、双三次插值
最近邻域插值
最近邻域内插法(Nearest Neighbor interpolation)
最近邻域是三种插值之中最简单的一种,原理就是选取距离插入的像素点(x+u, y+v)【注:x,y为整数, u,v为小数】最近的一个像素点,用它的像素点的灰度值代替插入的像素点。说到距离,顺便复习一下像素点之间的三种空间距离。
对于像素p、q和z,分别具有坐标(x,y),(s,t)和(u,v),如果
(1) D(p,q) ≥ 0 (当且仅当p=q时,D(p,q)=0)
(2) D(p,q) = D(q,p)
(3) D(p,z) ≤ D(p,q) + D(q,z)
则称D是距离函数或度量
欧氏距离.gif
D4距离(城市距离)
D4距离.gif
D8距离(棋盘距离)
D8距离.gif
这里代码实现采用的是欧式距离
//最近邻域插值
//根据目标图像的像素点(浮点坐标)找到原始图像中的4个像素点,取距离该像素点最近的一个原始像素值作为该点的值。
#include
#include
namespace mycv {
void nearestIntertoplation(cv::Mat& src, cv::Mat& dst, const int rows, const int cols);
}//mycv
double distance(const double x1, const double y1, const double x2, const double y2);//两点之间距离,这里用欧式距离
int main()
{
cv::Mat img = cv::imread("lena.jpg", 0);
if (img.empty()) return -1;
cv::Mat dst;
mycv::nearestIntertoplation(img, dst, 600, 600);
cv::imshow("img", img);
cv::imshow("dst", dst);
cv::waitKey(0);
return 0;
return 0;
}//main
void mycv::nearestIntertoplation(cv::Mat& src, cv::Mat& dst, const int rows, const int cols)
{
//比例尺
const double scale_row = static_cast(src.rows) / rows;
const double scale_col = static_cast(src.rows) / cols;
//扩展src到dst
dst = cv::Mat(rows, cols, src.type());
assert(src.channels() == 1 && dst.channels() == 1);</