OpenCV 学习笔记

OpenCV 笔记(23):图像的缩放——图像的缩放——立方插值

2024-02-22  本文已影响0人  fengzhizi715

1. 立方插值

立方插值算法也被称为双三次、双立方插值算法。

1.1 三次插值 (Cubic Interpolation)

先介绍一下三次插值算法,它是一种使用三次多项式拟合一组数据的插值方法。三次插值通常用于图像缩放和重采样。

三次插值的实现方式有很多种,例如牛顿多项式插值、拉格朗日多项式插值、Hermite 三次多项式插值、三次样条插值,每种方式都有其自身的优点和复杂性。

插值多项式的形式

适用范围

1.2 三次样条插值 (Cubic Spline Interpolation)

我们以三次样条插值为例进行详细说明。

在数值分析这个数学分支中,样条插值是使用一种名为样条的特殊分段多项式进行插值的形式。由于样条插值可以使用低阶多项式样条实现较小的插值误差,这样就避免了使用高阶多项式所出现的龙格现象,所以样条插值得到了流行。

三次样条函数的定义:

函数 S(x)\in C^2[a, b],且在每个小区间 [x_ix_{i+1}] 上是三次多项式,其中 a= x_0 < x_1 < . . . < x_n= b是给定节点,则称 S(x) 是节点 x_0, x_1, . . . , x_n上的三次样条函数。

三次样条函数满足:

三次样条函数.png

要求出 S(x),在每个小区间 [x_i, x_{i+1}] 上要确定 4 个待定系数,共有 n 个区间,共 4n 个参数要构建 4n 个方程。

S_i(x_{i+1}) = y_{i+1}

S_{i+1}(x_{i+1}) = y_{i+1}

以及第一个和最后一个端点分别满足三次方程,总共 2n 个方程

n-1 个内部点的一阶导数应该是连续的,即在第 i 区间的末点和第 i+1 区间的起点是同一个点,它们的一阶导数也相等,即:S'_i(x_{i+1}) = S'_{i+1}(x_{i+1})

同理:S_i''(x_{i+1}) = S_{i+1}''(x_{i+1})

总共 2n-2 个方程。

加起来一共 4n-2 个方程,还需再加上 2 个方程就可以确定 S(x)。通常可在区间 [a,b] 端点 a = x_0, b = x_n 处各加一个条件(称为边界条件),可根据实际问题的要求给定。常见有以下三种:

S_0'(x_0)=A

S_{n-1}'(x_n)=B

S''(x_0)=S''(x_n)=0

S_0'''(x_0)=S_1'''(x_1)

S_{n-2}'''(x_{n-1})=S_{n-1}'''(x_n)

1.3 双三次样条插值 (Bicubic Spline Interpolation)

双三次样条插值是在二维空间中使用三次样条函数对图像进行插值。它将图像划分为一个网格,并在每个网格点处使用一个三次样条函数来拟合图像数据。在未知点处,通过对相邻网格点的三次样条函数进行插值来获得插值值。

各种插值函数的对比.png

构造 Bicubic 函数:

W(x) = \begin{cases} (a+2)|x|^3-(a+3)|x|^2+1 & \text{for |x|} \le 1\\ a|x|^3-5a|x|^2+8a|x|-4a & \text{for 1 <|x|<2}\\ 0 & \text{otherwise} \end{cases}

对待插值的像素点(x,y),取其附近的 4*4 邻域点(x_i,y_i) (i,j=0,1,2,3)。其插值公式如下:

f(x,y)=\sum_{i=0}^{3}\sum_{j=0}^{3}f(x_i,y_j)W(x-x_i)W(y-y_j)

2. Lanczos 插值 (Lanczos Interpolation)

Lanczos 插值使用 Lanczos 核函数来计算插值后的像素值。Lanczos 核函数是一种低通滤波器,可以消除缩放过程中产生的混叠现象。

Lanczos 核函数定义如下:

L(x) = \begin{cases} sinc(x)sinc(x/a), & \text{if } -a < x < a, \\ 0, & otherwise. \end{cases}

其中,sinc(x) = sin(πx) / (πx),a 是核函数的宽度。

Lanczos 插值的过程如下:

  1. 确定插值点的位置。
  2. 以插值点为中心,在原图像中取一个窗口。
  3. 对窗口中的每个像素,使用 Lanczos 核函数计算其权重。
  4. 将窗口中所有像素的权重和插值值相乘,得到插值点的最终值。

Lanczos 插值公式:

S(x) = \sum_{i=\lfloor x \rfloor-a+1}^{\lfloor x \rfloor+a} s_iL(x-i)

Lanczos 插值的优点

Lanczos 插值的缺点

3. OpenCV 中的 resize() 函数使用示例

OpenCV 封装好了很多图像缩放方法的算法。在 OpenCV C++ 中的 resize() 函数用于调整图像大小,它可以根据指定的尺寸和插值方法对图像进行缩放。

void resize( InputArray src, OutputArray dst,
                          Size dsize, double fx = 0, double fy = 0,
                          int interpolation = INTER_LINEAR );

第四个参数 fx: 缩放比例,沿 x 轴的缩放因子。
第五个参数 fx: 缩放比例,沿 y 轴的缩放因子。
第六个参数 interpolation: 插值方法,常用的插值方法包括:

下面的例子使用四种插值方法分别对图像进行缩放:

#include <chrono>
#include <opencv2/opencv.hpp>
#define  millisecond 1000000
#define DEBUG_PRINT(...)  printf( __VA_ARGS__); printf("\n")
#define DEBUG_TIME(time_) auto time_ =std::chrono::high_resolution_clock::now()
#define RUN_TIME(time_)  (double)(time_).count()/millisecond

using namespace std;
using namespace cv;

int main() {
    Mat src = imread(".../grass.jpg");
    imshow("src", src);

    Mat nearest,linear,cubic,lanczos;
    double scale = 1.5;
    DEBUG_PRINT("image size[%d,%d],scale=%3.1f", src.rows,src.cols, scale);

    DEBUG_TIME(T0);
    cv::resize(src, nearest, Size(), scale, scale, cv::INTER_NEAREST);//最近邻插值
    DEBUG_TIME(T1);

    cv::resize(src, linear, Size(), scale, scale, cv::INTER_LINEAR); //双线性插值(默认)
    DEBUG_TIME(T2);

    cv::resize(src, cubic, cv::Size(), scale, scale, cv::INTER_CUBIC); //双三次样条插值
    DEBUG_TIME(T3);

    cv::resize(src, lanczos, cv::Size(), scale, scale, cv::INTER_LANCZOS4); //Lanczos 插值
    DEBUG_TIME(T4);

    DEBUG_PRINT("INTER_NEAREST :%3.3fms", RUN_TIME(T1 - T0));
    DEBUG_PRINT("INTER_LINEAR  :%3.3fms", RUN_TIME(T2 - T1));
    DEBUG_PRINT("INTER_CUBIC   :%3.3fms", RUN_TIME(T3 - T2));
    DEBUG_PRINT("INTER_LANCZOS4:%3.3fms", RUN_TIME(T4 - T3));

    imshow("nearest",nearest);
    imshow("linear",linear);
    imshow("cubic",cubic);
    imshow("lanczos",lanczos);

    waitKey(0);
    return 0;
}

执行结果:

image size[427,640],scale=1.5
INTER_NEAREST :0.567ms
INTER_LINEAR  :0.582ms
INTER_CUBIC   :1.433ms
INTER_LANCZOS4:2.002ms
原图和最近邻插值.png 原图和双线性插值.png 原图和双三次样条插值.png 原图和Lanczos插值.png

4. 总结

三次样条插值、双三次样条插值和 Lanczos 插值都是常用的图像缩放插值方法。

三次样条插值是一种分段插值方法,在每个分段内使用三次多项式进行插值。它具有较高的插值精度,但计算量较大。双三次样条插值是三次样条插值的二维扩展,在两个方向上都使用三次样条进行插值,它具有更高的插值精度和计算量。Lanczos 插值是一种基于 Lanczos 滤波器的插值方法,它使用 Lanczos 滤波器对图像进行卷积,从而获得更平滑、更清晰的插值结果。

三种方法各有优缺点,选择哪种方法取决于实际应用场景和需求。

上一篇 下一篇

猜你喜欢

热点阅读