简介

在图像处理中,平移变换、旋转变换以及放缩变换是一些基础且常用的操作。这些几何变换并不改变图象的象素值,只是在图象平面上进行象素的重新排列。在一幅输入图象opencv的插值函数 opencv插值方法_插值中,灰度值仅在整数位置上有定义。然而,输出图象[x,y]的灰度值一般由处在非整数坐标上的opencv的插值函数 opencv插值方法_算法原理_02值来决定。这就需要插值算法来进行处理,常见的插值算法有最近邻插值、双线性插值和三次样条插值。

学习目标

  • 了解插值算法与常见几何变换之间的关系
  • 理解插值算法的原理
  • 掌握OpenCV框架下插值算法API的使用

内容介绍

  • 插值算法原理介绍
  • 最近邻插值算法
  • 双线性插值算法
  • OpenCV代码实践
  • cv.resize()各项参数及含义
  • 动手实现(由读者自己完成)

算法理论介绍与推荐

最近邻插值算法原理

最近邻插值,是指将目标图像中的点,对应到源图像中后,找到最相邻的整数点,作为插值后的输出。

opencv的插值函数 opencv插值方法_双线性插值_03

如上图所示,目标图像中的某点投影到原图像中的位置为点P,此时易知,opencv的插值函数 opencv插值方法_算法原理_04.
一个例子:

如下图所示,将一幅3X3的图像放大到4X4,用opencv的插值函数 opencv插值方法_双线性插值_05表示目标图像,opencv的插值函数 opencv插值方法_插值_06表示原图像,我们有如下公式:

opencv的插值函数 opencv插值方法_插值_07

opencv的插值函数 opencv插值方法_opencv的插值函数_08

opencv的插值函数 opencv插值方法_插值_09

opencv的插值函数 opencv插值方法_插值_10


缺点: 用该方法作放大处理时,在图象中可能出现明显的块状效应

双线性插值

在讲双线性插值之前先看以一下线性插值,线性插值多项式为:

opencv的插值函数 opencv插值方法_opencv的插值函数_11

opencv的插值函数 opencv插值方法_算法原理_12

opencv的插值函数 opencv插值方法_插值_13

双线性插值就是线性插值在二维时的推广,在两个方向上做三次线性插值,具体操作如下图所示:

opencv的插值函数 opencv插值方法_opencv的插值函数_14

opencv的插值函数 opencv插值方法_opencv的插值函数_15为两个变量的函数,其在单位正方形顶点的值已知。假设我们希望通过插值得到正方形内任意点的函数值。则可由双线性方程: opencv的插值函数 opencv插值方法_算法原理_16

来定义的一个双曲抛物面与四个已知点拟合。

首先对上端的两个顶点进行线性插值得:

opencv的插值函数 opencv插值方法_算法原理_17

类似地,再对底端的两个顶点进行线性插值有: opencv的插值函数 opencv插值方法_插值_18

最后,做垂直方向的线性插值,以确定:

opencv的插值函数 opencv插值方法_算法原理_19

整理得:

opencv的插值函数 opencv插值方法_插值_20

映射方法

向前映射法

可以将几何运算想象成一次一个象素地转移到输出图象中。如果一个输入象素被映射到四个输出象素之间的位置,则其灰度值就按插值算法在4个输出象素之间进行分配。称为向前映射法,或象素移交影射。

注:从原图象坐标计算出目标图象坐标镜像、平移变换使用这种计算方法

向后映射法

向后映射法(或象素填充算法)是输出象素一次一个地映射回到输入象素中,以便确定其灰度级。如果一个输出象素被映射到4个输入象素之间,则其灰度值插值决定,向后空间变换是向前变换的逆。

注:从结果图象的坐标计算原图象的坐标

  • 旋转、拉伸、放缩可以使用
  • 解决了漏点的问题,出现了马赛克

基于OpenCV的实现(Python)

函数原型:

cv2.resize(src, dsize[, dst[, fx[, fy[, interpolation]]]])

参数:

参数

描述

src

【必需】原图像

dsize

【必需】输出图像所需大小

fx

【可选】沿水平轴的比例因子

fy

【可选】沿垂直轴的比例因子

interpolation

【可选】插值方式

src

【必需】原图像

插值方式:

cv.INTER_NEAREST

最近邻插值

cv.INTER_LINEAR

双线性插值

cv.INTER_CUBIC

基于4x4像素邻域的3次插值法

cv.INTER_AREA

基于局部像素的重采样

通常,缩小使用cv.INTER_AREA,放缩使用cv.INTER_CUBIC(较慢)和cv.INTER_LINEAR(较快效果也不错)。默认情况下,所有的放缩都使用cv.INTER_LINEAR。
代码实践:

import cv2
img = cv2.imread('./erkang.jpg', cv2.IMREAD_UNCHANGED)

print('Original Dimensions : ',img.shape)

scale_percent = 30       # percent of original size
width = int(img.shape[1] * scale_percent / 100)
height = int(img.shape[0] * scale_percent / 100)
dim = (width, height)
# resize image
resized = cv2.resize(img, dim, interpolation = cv2.INTER_LINEAR)

fx = 1.5
fy = 1.5
resized1 = cv2.resize(resized, dsize=None, fx=fx, fy=fy, interpolation = cv2.INTER_NEAREST)

resized2 = cv2.resize(resized, dsize=None, fx=fx, fy=fy, interpolation = cv2.INTER_LINEAR)
print('Resized Dimensions : ',resized.shape)

cv2.imshow("Resized image", resized)
cv2.imshow("INTER_NEAREST image", resized1)
cv2.imshow("INTER_LINEAR image", resized2)
cv2.waitKey(0)
cv2.destroyAllWindows()
Original Dimensions :  (360, 640, 3)
Resized Dimensions :  (108, 192, 3)

0.3倍缩小,双线性插值

opencv的插值函数 opencv插值方法_插值_21


1.5倍放大,最近邻插值

opencv的插值函数 opencv插值方法_双线性插值_22

1.5倍放大,双线性插值

opencv的插值函数 opencv插值方法_双线性插值_23



总结

插值算法是很多几何变换的基础和前置条件,对插值算法细节的掌握有助于对其他算法的理解,为自己的学习打下坚实的基础。