opencv中插值算法详解

您所在的位置:网站首页 matlab中的插值函数有哪些 opencv中插值算法详解

opencv中插值算法详解

2023-12-22 06:54| 来源: 网络整理| 查看: 265

导读

做图像处理的同学应该经常都会用到图像的缩放,我们都知道图片存储的时候其实就是一个矩阵,所以在对图像进行缩放操作的时候,也就是在对矩阵进行操作,如果想要将图片放大,这里我们就需要用到过采样算法来扩大矩阵,利用欠采样来缩小图像。 在这里插入图片描述 如上图所示,左图是原图像矩阵,右图是扩大后的图像矩阵,右图中的橙色点表示的是矩阵扩大之后通过插值算法填充的像素值。所以,这篇文章我们主要探讨的就是如何来通过插值算法来填充像素值

相关函数介绍

在opencv中提供了一个resize函数用来调整图像的大小,里面提供了好几种不同的插值算法,如下图所示 在这里插入图片描述 这里我们主要介绍最常用的前5中插值算法,最后两种插值算法主要是应用在仿射变换中,cv.WARP_FILL_OUTLIERS在从src到dst变换的时候可能会出现异常值,通过这个设定可以将异常值的像素置0。而cv.WARP_INVERSE_MAP是应用在仿射变换的逆变换,从dst到src的变换,关于仿射变换的更多资料可以参考我的上篇文章一文搞懂仿射变换

插值算法效果对比

在这里插入图片描述 我们通过随机生成一个5×5的图片,然后通过不同的插值算法将其放大10倍之后,来对比最终图片的效果。

import cv2 import numpy as np from matplotlib import pyplot as plt #随机生成一张图片用于测试插值算法 img = np.uint8(np.random.randint(0,255,size=(5,5))) height,width = img.shape #设定通过插值之后图片的size new_dimension = (50,50) def img_draw_subplot(subplot_position,img,title_name,cmap): plt.subplot(subplot_position) plt.title(title_name) plt.imshow(img,cmap) def image_interpolation(img,new_dimension,inter_method): inter_img = cv2.resize(img,new_dimension,interpolation=inter_method) return inter_img #设置cmap cmap = "gray" #最近邻插值算法 nearest_img = image_interpolation(img,new_dimension,cv2.INTER_NEAREST) #双线性插值算法,resize函数默认的插值算法 linear_img = image_interpolation(img,new_dimension,cv2.INTER_LINEAR) #三次样条插值算法 cubic_img = image_interpolation(img,new_dimension,cv2.INTER_CUBIC) #区域插值 area_img = image_interpolation(img,new_dimension,cv2.INTER_AREA) #Lanczos插值 lanczos_img = image_interpolation(img,new_dimension,cv2.INTER_LANCZOS4) img_draw_subplot(231,img,"src Image",cmap=cmap) img_draw_subplot(232,nearest_img,"Nearest interpolation",cmap=cmap) img_draw_subplot(233,linear_img,"Linear interpolation",cmap=cmap) img_draw_subplot(234,cubic_img,"cubic interpolation",cmap=cmap) img_draw_subplot(235,area_img,"Area interpolation",cmap=cmap) img_draw_subplot(236,lanczos_img,"Lanczos interpolation",cmap=cmap) plt.show()

如果大家觉得灰度图不方便观察,我们可以通过设置plt.imshow的cmap参数来控制颜色,matplotlib提供了几种不同的类别的色彩映射方式

cmap的类别 Sequential 通常使用单一的色调,逐渐增加亮度和颜色,可以用来表示有序的信息 在这里插入图片描述Diverging 通过改变两种不同的颜色的亮度和饱和度,在中间以不饱和的颜色相遇,通常来用绘制具有关键的中间值或者数据偏离零的信息 在这里插入图片描述Cyclic 改变两种不同颜色的亮度,在中间和开始/结束以不饱和的颜色相遇,应用于在端点出环绕的信息。 在这里插入图片描述Qualitative 用于表示没有关系和排序的信息 在这里插入图片描述Miscellaneous 同上 在这里插入图片描述 这里我们为了方便观察不同插值算法之间的区别,我们可以选用杂色来来观察,这里我就随机选用了Set1,只需要将上面代码中的cmap改成了Set1即可 在这里插入图片描述 通过初步观察不同插值算法后的效果图片我们可以发现,最近邻插值和区域插值算法的效果,而线性插值、三次样条插值、Lanczos插值整体效果看起来差不多,不过细节部分还是有所差别,接下来我们就从这几种插值算法来分析一下。 最近邻插值(Nearest Interpolation)

最近邻插值也称近端插值,是一种在一维或多维空间上进行多变元插值的简单方法。插值是一种通过已知的、离散的数据点,在范围内推求新数据点的过程或方法。最近邻插值算法选择距离所求数据点最近点的值,并且根本不考虑其他相邻点的值,从而产生一个分段常数的内插值来作为所求数据点的值。 在这里插入图片描述 如上图所示,黑色的×表示需要插入的值,它会选择距离它最近的 P x + 1 , y P_{x+1,y} Px+1,y​的值来作为它的值。 如果距离四个点的距离都相等,最近邻插值会如何选择? 在这里插入图片描述

通过上图不能发现,当插入的值距离四个点都相等时,会选择距离最近的左上角的值,这是 因为图像坐标系的原点位于左上角。 线性插值(Linear interpolation)

这里的线性插值其实是指双线性插值,这种插值算法也是resize函数中默认使用的插值算法。 双线性插值,也被称为双线性内插。双线插值是对线性插值在二维坐标系上的扩展,用于对双变量函数进行插值,其核心思想是在两个方向上分别进行一次线性插值。 为了帮助大家更好的理解双线性插值算法,我们先来看线性插值 假设我们已知坐标 ( x 0 , y 0 ) (x_0,y_0) (x0​,y0​)与 ( x 1 , y 1 ) (x_1,y_1) (x1​,y1​),我们想要得到在区间 [ x 0 , x 1 ] [x_0,x_1] [x0​,x1​]上任意位置 x x x所对应 y y y的值,如下图所示 在这里插入图片描述 我们可以求出直线的方程,然后将 x x x坐标代入到方程就可以求出对应的 y y y值,通过直线方程的两点式可以得到 y − y 0 x − x 0 = y 1 − y 0 x 1 − x 0 \frac{y-y_0}{x-x_0}=\frac{y_1-y_0}{x_1-x_0}\\ x−x0​y−y0​​=x1​−x0​y1​−y0​​ 然后我们根据已知的 x x x,将其代入上式可得 y = y 0 + ( x − x 0 ) y 1 − y 0 x 1 − x 0 = y 0 + ( x − x 0 ) y 1 − ( x − x 0 ) y 0 x 1 − x 0 y=y_0+(x-x_0)\frac{y_1-y_0}{x_1-x_0}=y_0+\frac{(x-x_0)y_1-(x-x_0)y_0}{x_1-x_0} y=y0​+(x−x0​)x1​−x0​y1​−y0​​=y0​+x1​−x0​(x−x0​)y1​−(x−x0​)y0​​ 再了解线性插值以后,我们再来看看双线性插值 假如我们想得到未知函数 f f f在点 P = ( x , y ) P=(x,y) P=(x,y)的值,假设我们已知函数 f f f在 Q 11 = ( x 1 , y 1 ) Q_{11}=(x_1,y_1) Q11​=(x1​,y1​), Q 12 = ( x 1 , y 2 ) Q_{12}=(x_1,y_2) Q12​=(x1​,y2​), Q 21 = ( x 2 , y 1 ) Q_{21}=(x_2,y_1) Q21​=(x2​,y1​)及 Q 22 = ( x 2 , y 2 ) Q_{22}=(x_2,y_2) Q22​=(x2​,y2​)四个点的值 在这里插入图片描述 首先在 x x x方向进行线性插值,利用 Q 11 Q_{11} Q11​和 Q 21 Q_{21} Q21​可以求得 R 1 R_1 R1​的 y y y值,利用 Q 12 Q_{12} Q12​和 Q 22 Q_{22} Q22​可以求得 R 2 R_2 R2​的 y y y值 f ( R 1 ) ≈ x 2 − x x 2 − x 1 f ( Q 11 ) + x − x 1 x 2 − x 1 f ( Q 21 ) f ( R 2 ) ≈ x 2 − x x 2 − x 1 f ( Q 12 ) + x − x 1 x 2 − x 1 f ( Q 22 ) f(R_1)\approx\frac{x_2-x}{x_2-x_1}f(Q_{11})+\frac{x-x_1}{x_2-x_1}f(Q_{21})\\ f(R_2)\approx\frac{x_2-x}{x_2-x_1}f(Q_{12})+\frac{x-x_1}{x_2-x_1}f(Q_{22}) f(R1​)≈x2​−x1​x2​−x​f(Q11​)+x2​−x1​x−x1​​f(Q21​)f(R2​)≈x2​−x1​x2​−x​f(Q12​)+x2​−x1​x−x1​​f(Q22​) 细心的同学也许发现了,这个插值好像与线性插值并不是一模一样的,所以我们用的是 ≈ \approx ≈而非 = = =,这里其实采用的是一种加权平均算法结合两点来计算其中一点的 y y y值,主要是根据计算点距离两个端点在x方向上的距离来计算计算点y值所占的比例。 接下来,我们再利用已经计算出来的 R 1 R_1 R1​和 R 2 R_2 R2​来 P P P点的插值,可得 f ( P ) ≈ y 2 − y y 2 − y 1 f ( R 1 ) + y − y 1 y 2 − y 1 f ( R 2 ) = y 2 − y y 2 − y 1 ( x 2 − x x 2 − x 1 f ( Q 11 ) + x − x 1 x 2 − x 1 f ( Q 21 ) ) + y − y 1 y 2 − y 1 ( x 2 − x x 2 − x 1 f ( Q 12 ) + x − x 1 x 2 − x 1 f ( Q 22 ) ) = 1 ( x 2 − x 1 ) ( y 2 − y 1 ) ( f ( Q 11 ) ( x 2 − x ) ( y 2 − y ) + f ( Q 21 ) ( x − x 1 ) ( y 2 − y ) + f ( Q 12 ) ( x 2 − x ) ( y − y 1 ) + f ( Q 22 ) ( x − x 1 ) ( y − y 1 ) ) = 1 ( x 2 − x 1 ) ( y 2 − y 1 ) [ x 2 − x x − x 1 ] [ f ( Q 11 ) f ( Q 12 ) f ( Q 21 ) f ( Q 22 ) ] [ y 2 − y y − y 1 ] \begin{aligned} f(P)&\approx\frac{y_2-y}{y_2-y_1}f(R_1)+\frac{y-y_1}{y_2-y_1}f(R_2)\\ &=\frac{y_2-y}{y_2-y_1}(\frac{x_2-x}{x_2-x_1}f(Q_{11})+\frac{x-x_1}{x_2-x_1}f(Q_{21}))\\&\quad+\frac{y-y_1}{y_2-y_1}(\frac{x_2-x}{x_2-x_1}f(Q_{12})+\frac{x-x_1}{x_2-x_1}f(Q_{22}))\\&=\frac{1}{(x_2-x_1)(y_2-y_1)}(f(Q_{11})(x_2-x)(y_2-y)\\&\quad+f(Q_{21})(x-x_1)(y_2-y)+f(Q_{12})(x_2-x)(y-y_1)\\&\quad+f(Q_{22})(x-x_1)(y-y_1))\\&=\frac{1}{(x_2-x_1)(y_2-y_1)}[x_2-x \quad x-x_1] \left[ \begin{matrix} f(Q_{11}) & f(Q_{12})\\ f(Q_{21}) & f(Q_{22})\\ \end{matrix} \right] \left[ \begin{matrix} y_2-y\\ y-y_1\\ \end{matrix} \right] \end{aligned} f(P)​≈y2​−y1​y2​−y​f(R1​)+y2​−y1​y−y1​​f(R2​)=y2​−y1​y2​−y​(x2​−x1​x2​−x​f(Q11​)+x2​−x1​x−x1​​f(Q21​))+y2​−y1​y−y1​​(x2​−x1​x2​−x​f(Q12​)+x2​−x1​x−x1​​f(Q22​))=(x2​−x1​)(y2​−y1​)1​(f(Q11​)(x2​−x)(y2​−y)+f(Q21​)(x−x1​)(y2​−y)+f(Q12​)(x2​−x)(y−y1​)+f(Q22​)(x−x1​)(y−y1​))=(x2​−x1​)(y2​−y1​)1​[x2​−xx−x1​][f(Q11​)f(Q21​)​f(Q12​)f(Q22​)​][y2​−yy−y1​​]​ 仔细观察上面的公式不难发现,其实 P P P点的值等于周围四个点与P点所构成的四个对角矩形面积的加权平均 在这里插入图片描述 在这里插入图片描述

双三次插值(Bicubic interpolation)

双三次插值是一种更加复杂的插值算法,是二维空间中最常用的插值算法,相对双线性插值的图像边缘更加平滑,函数 f f f在点 ( x , y ) (x,y) (x,y)的值可以通过矩形网格中最近的十六个采样点的加权平均得到,这里需要使用两个多项式插值三次函数,每个方向使用一个。 双三次插值通过以下公式进行计算: ∑ i = 0 3 ∑ j = 0 3 a i j x i y j \sum_{i=0}^{3}\sum_{j=0}^{3}a_{ij}x^{i}y^{j} i=0∑3​j=0∑3​aij​xiyj 计算系数 a i j a_{ij} aij​的过程依赖于插值数据的特性。如果已知插值函数的导数,常用的方法就是使用四个顶点的高度以及每个顶点的三个导数。一阶导数 h ′ x h'x h′x与 h ′ y h'y h′y表示 x x x与 y y y方向的表面斜率,二阶相互导数 h ′ ′ x y h''xy h′′xy表示同时在 x x x与 y y y方向的斜率。这些值可以通过分别对 x x x与 y y y向量取微分得到。对于网格单元的每个顶点,将局部坐标 ( 0 , 0 ) 、 ( 1 , 0 ) 、 ( 0 , 1 ) 、 ( 1 , 1 ) (0,0)、(1,0)、(0,1)、(1,1) (0,0)、(1,0)、(0,1)、(1,1)代入这些方程,再解这16个方程。 看了上面这段话之后,貌似还是不太好理解,接下来我们看一个例子,双三次插值常用的BiCubic函数如下图 在这里插入图片描述 上式中的 a a a取-0.5即可,函数图像如下 在这里插入图片描述 对待插值的像素点 ( x , y ) (x,y) (x,y)( x , y x,y x,y可为浮点数),取其附近的4×4领域点 ( x i , y i ) (x_i,y_i) (xi​,yi​)其中 i , j = 0 , 1 , 2 , 3 i,j=0,1,2,3 i,j=0,1,2,3。按下面的公式进行插值计算: 在这里插入图片描述 例如,我们需要求解 P P P点值,在 P P P点周围有16个点 在这里插入图片描述 首先,我们要求出当前像素与 P P P点的距离,比如 a 00 a_{00} a00​距离 P ( x + u , y + v ) P(x+u,y+v) P(x+u,y+v)的距离为 ( 1 + u , 1 + v ) (1+u,1+v) (1+u,1+v),那么我们可以得到 a 00 a_{00} a00​对应的系数为 ( W ( 1 + u ) , W ( 1 + v ) ) (W(1+u),W(1+v)) (W(1+u),W(1+v)),所以 a 11 a_{11} a11​的系数为 ( W ( u ) , W ( v ) ) (W(u),W(v)) (W(u),W(v)), a 22 a_{22} a22​的系数为 ( W ( 1 − u ) , W ( 1 − v ) ) (W(1-u),W(1-v)) (W(1−u),W(1−v)), a 33 a_{33} a33​的系数为 W ( 2 − u ) , W ( 2 − v ) W(2-u),W(2-v) W(2−u),W(2−v),同理可以得到剩下点的系数,再根据上面的函数就可以求出 P P P点的值。 关于双三次插值函数更加详细介绍可以参考: Cubic Convolution Interpolation for Digital Image Processing

区域插值(Area interpolation)

区域插值算法主要分两种情况,缩小图像和放大图像的工作原理并不相同。

缩小图像 如果图像缩小的比例是整数倍,在调用INTER_LINEAR_EXACT插值算法时,如果图像的宽和高的缩小比例都是2,而且图像的通道数不是2,实际上会调用INTER_AREA。在调用INTER_LINEAR时,如果图像的宽和高的缩小比例都是2,实际上是会调用INTER_AREA。 INTER_AREA实际上是个box filter,类似于均值滤波器。放大图像 如果放大图像的比例是整数倍,与最近邻插值相似。如果放大的比例不是整数倍,则会采用线性插值。 Lanczos插值

Lanczos插值属于一种模板算法,需要通过计算模板中的权重信息来计算 x x x对应的值。 对于一维信息,假如我们输入的点集为 X X X,那么,Lanczos对应有个窗口模板Window,窗口中每个位置的权重计算如下: 在这里插入图片描述 在这里插入图片描述 通常a取2或者3,当a=2时,该算法适应于图像缩小的插值。当a=3时,算法适用于图像放大的插值。根据计算出来的权重信息,然后再根据 x x x即可求出对应的加权平均: 在这里插入图片描述

插值算法耗时比较

对于不同的插值算法,在缩放因子不同的时候,耗时会有所区别,具体对照如下表所示 在这里插入图片描述

总结

如果要缩小图像,推荐使用INTER_AREA插值效果最好,如果要放大图像,INTER_CUBIC效果最好,但是速度较慢,可以考虑使用INTER_LINEAR速度较快,效果也还不错。 参考: 1.http://www.1zlab.com/wiki/python-opencv-tutorial/opencv-interpolation-algrithm/ 2.维基百科线性插值 3.维基百科双三次插值 4.https://blog.csdn.net/nandina179/article/details/85330552 5.https://blog.csdn.net/qq_29058565/article/details/52769497 6.https://blog.csdn.net/u010555688/article/details/24352343 7.https://zhuanlan.zhihu.com/p/38493205



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3