线性插值

先讲一下线性插值:已知数据 (x0, y0) 与 (x1, y1),要计算 [x0, x1] 区间内某一位置 x 在直线上的y值(反过来也是一样,略):

y−y0x−x0=y1−y0x1−x0
y=x1−xx1−x0y0+x−x0x1−x0y1

上面比较好理解吧,仔细看就是用x和x0,x1的距离作为一个权重,用于y0和y1的加权。双线性插值本质上就是在两个方向上做线性插值。

双线性插值

在数学上,双线性插值是有两个变量的插值函数的线性插值扩展,其核心思想是在两个方向分别进行一次线性插值[1]。见下图:

假如我们想得到未知函数 f 在点 P = (x, y) 的值,假设我们已知函数 f 在 Q11 = (x1, y1)、Q12 = (x1, y2), Q21 = (x2, y1) 以及 Q22 = (x2, y2) 四个点的值。最常见的情况,f就是一个像素点的像素值。首先在 x 方向进行线性插值,得到



然后在 y 方向进行线性插值,得到

综合起来就是双线性插值最后的结果:



由于图像双线性插值只会用相邻的4个点,因此上述公式的分母都是1。opencv中的源码如下,用了一些优化手段,比如用整数计算代替float(下面代码中的*2048就是变11位小数为整数,最后有两个连乘,因此>>22位),以及源图像和目标图像几何中心的对齐

SrcX=(dstX+0.5)* (srcWidth/dstWidth) -0.5

SrcY=(dstY+0.5) * (srcHeight/dstHeight)-0.5

这个要重点说一下,源图像和目标图像的原点(0,0)均选择左上角,然后根据插值公式计算目标图像每点像素,假设你需要将一幅5x5的图像缩小成3x3,那么源图像和目标图像各个像素之间的对应关系如下。如果没有这个中心对齐,根据基本公式去算,就会得到左边这样的结果;而用了对齐,就会得到右边的结果:

cv::Mat matSrc, matDst1, matDst2;  

matSrc = cv::imread("lena.jpg", 2 | 4);
matDst1 = cv::Mat(cv::Size(800, 1000), matSrc.type(), cv::Scalar::all(0));
matDst2 = cv::Mat(matDst1.size(), matSrc.type(), cv::Scalar::all(0)); double scale_x = (double)matSrc.cols / matDst1.cols;
double scale_y = (double)matSrc.rows / matDst1.rows; uchar* dataDst = matDst1.data;
int stepDst = matDst1.step;
uchar* dataSrc = matSrc.data;
int stepSrc = matSrc.step;
int iWidthSrc = matSrc.cols;
int iHiehgtSrc = matSrc.rows; for (int j = 0; j < matDst1.rows; ++j)
{
float fy = (float)((j + 0.5) * scale_y - 0.5);
int sy = cvFloor(fy);
fy -= sy;
sy = std::min(sy, iHiehgtSrc - 2);
sy = std::max(0, sy); short cbufy[2];
cbufy[0] = cv::saturate_cast<short>((1.f - fy) * 2048);
cbufy[1] = 2048 - cbufy[0]; for (int i = 0; i < matDst1.cols; ++i)
{
float fx = (float)((i + 0.5) * scale_x - 0.5);
int sx = cvFloor(fx);
fx -= sx; if (sx < 0) {
fx = 0, sx = 0;
}
if (sx >= iWidthSrc - 1) {
fx = 0, sx = iWidthSrc - 2;
} short cbufx[2];
cbufx[0] = cv::saturate_cast<short>((1.f - fx) * 2048);
cbufx[1] = 2048 - cbufx[0]; for (int k = 0; k < matSrc.channels(); ++k)
{
*(dataDst+ j*stepDst + 3*i + k) = (*(dataSrc + sy*stepSrc + 3*sx + k) * cbufx[0] * cbufy[0] +
*(dataSrc + (sy+1)*stepSrc + 3*sx + k) * cbufx[0] * cbufy[1] +
*(dataSrc + sy*stepSrc + 3*(sx+1) + k) * cbufx[1] * cbufy[0] +
*(dataSrc + (sy+1)*stepSrc + 3*(sx+1) + k) * cbufx[1] * cbufy[1]) >> 22;
}
}
}
cv::imwrite("linear_1.jpg", matDst1); cv::resize(matSrc, matDst2, matDst1.size(), 0, 0, 1);
cv::imwrite("linear_2.jpg", matDst2);

好了,本篇到这里,欢迎大家分享转载,注明出处即可。

参考资料

[1] 双线性插值(Bilinear Interpolation)

[2] OpenCV ——双线性插值(Bilinear interpolation)

[3] 双线性插值算法及需要注意事项

[4] OpenCV中resize函数五种插值算法的实现过程

三十分钟理解:线性插值,双线性插值Bilinear Interpolation算法的更多相关文章

  1. [转载]三十分钟理解:线性插值,双线性插值Bilinear Interpolation算法

    [转载]三十分钟理解:线性插值,双线性插值Bilinear Interpolation算法 来源:https://blog.csdn.net/xbinworld/article/details/656 ...

  2. 三十分钟理解:双调排序Bitonic Sort,适合并行计算的排序算法

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld 技术交流QQ群:433250724,欢迎对算法.技术.应用感兴趣的同学加入 双调排序是data-indepen ...

  3. [重磅]Deep Forest,非神经网络的深度模型,周志华老师最新之作,三十分钟理解!

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术感兴趣的同学加入. 深度学习最大的贡献,个人认为就是表征 ...

  4. 三十分钟理解计算图上的微积分:Backpropagation,反向微分

    神经网络的训练算法,目前基本上是以Backpropagation (BP) 反向传播为主(加上一些变化),NN的训练是在1986年被提出,但实际上,BP 已经在不同领域中被重复发明了数十次了(参见 G ...

  5. 三十分钟理解博弈论“纳什均衡” -- Nash Equilibrium

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术感兴趣的同学加入. 纳什均衡(或者纳什平衡),Nash ...

  6. 数字图像处理实验(4):PROJECT 02-04 [Multiple Uses],Zooming and Shrinking Images by Bilinear Interpolation 标签: 图像处理MATLAB

    实验要求: Zooming and Shrinking Images by Bilinear Interpolation Objective To manipulate another techniq ...

  7. 【转】三十分钟学会STL算法

    转载自: http://net.pku.edu.cn/~yhf/UsingSTL.htm 这是本小人书.原名是<using stl>,不知道是谁写的.不过我倒觉得很有趣,所以化了两个晚上把 ...

  8. 线性插值&双线性插值&三线性插值

    http://www.cnblogs.com/yingying0907/archive/2012/11/21/2780092.html 內插是数学领域数值分析中的通过已知的离散数据求未知数据的过程或方 ...

  9. 【转】三十分钟掌握STL

    转自http://net.pku.edu.cn/~yhf/UsingSTL.htm 三十分钟掌握STL 这是本小人书.原名是<using stl>,不知道是谁写的.不过我倒觉得很有趣,所以 ...

随机推荐

  1. C++——内存对象 禁止产生堆对象 禁止产生栈对象

    用C或C++写程序,需要更多地关注内存,这不仅仅是因为内存的分配是否合理直接影响着程序的效率和性能,更为主要的是,当我们操作内存的时候一不小心就会出现问题,而且很多时候,这些问题都是不易发觉的,比如内 ...

  2. 【bzoj4898】商旅

    Portal -->bzoj4898 Solution ​ 这题的话..首先答案的形式应该是\(01\)分数规划了 ​ 然后比较关键的一步在于,我们需要简化一下交易的过程 ​ 具体一点就是,我们 ...

  3. ThinkPHP+Memcache的缓存方案总结

    简介: ThinkPHP用S()方法可以缓存数据,这在访问数据库时非常有用,可以在有限时间内当数据库无变化时从缓存取数据,有变化时从数据库取数据. Memcached+Memcache是一个将数据保存 ...

  4. 将new Date() 格式化为 ’2018-10-11‘ 的字符串格式

    function dateToString( date , format ){ if(!date) return ""; if (!Common.type.isDate(date) ...

  5. NOIP模拟3

    期望得分:30+90+100=220 实际得分:30+0+10=40 T1智障错误:n*m是n行m列,硬是做成了m行n列 T2智障错误:读入三个数写了两个%d T3智障错误:数值相同不代表是同一个数 ...

  6. dp ZOJ 3956

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3956 Course Selection System Time Limit ...

  7. 2017 ACM-ICPC 西安网络赛 F.Trig Function Chebyshev多项式

    自己太菜,数学基础太差,这场比赛做的很糟糕.本来想吐槽出题人怎么都出很数学的题,现在回过头来想还是因为自己太垃圾,竞赛就是要多了解点东西. 找$f(cos(x))=cos(nx)$中$x^m$的系数模 ...

  8. A Beginner’s Guide to Eigenvectors, PCA, Covariance and Entropy

    A Beginner’s Guide to Eigenvectors, PCA, Covariance and Entropy Content: Linear Transformations Prin ...

  9. What are the advantages of different classification algorithms?

    What are the advantages of different classification algorithms? For instance, if we have large train ...

  10. Spark RDD中的aggregate函数

    转载自:http://blog.csdn.net/qingyang0320/article/details/51603243 针对Spark的RDD,API中有一个aggregate函数,本人理解起来 ...