插值算法在图像处理中有很多应用。其中比较常见的操作包括图像缩放、旋转、仿射变换等。下面分别介绍一下这些操作中用到的插值算法。
- 图像缩放:在对图像进行缩放操作时,为了使缩小后的图像不失真,需要进行插值处理来填补空缺的像素。通常使用最近邻插值、双线性插值、三次样条插值等方法。其中最近邻插值简单,但容易出现锯齿状的效果;双线性插值能够得到较为平滑的结果,但在图像中出现高频纹理时会失效;而三次样条插值能够得到更平滑的结果,但计算量比较大。
示例代码:
import cv2
# 最近邻插值
def nearest_interpolation(img, scale):
height, width = img.shape[:2]
new_height, new_width = int(height * scale), int(width * scale)
emptyImage = np.zeros((new_height, new_width, 3), np.uint8)
for i in range(new_height):
for j in range(new_width):
x, y = int(i / scale), int(j / scale)
emptyImage[i, j] = img[x, y]
return emptyImage
# 双线性插值
def linear_interpolation(img, scale):
height, width = img.shape[:2]
new_height, new_width = int(height * scale), int(width * scale)
emptyImage = np.zeros((new_height, new_width, 3), np.uint8)
for i in range(new_height):
for j in range(new_width):
x, y = i / scale, j / scale
x1, y1 = int(x), int(y)
x2, y2 = x1 + 1, y1 + 1
if x2 >= height:
x2 = height - 1
if y2 >= width:
y2 = width - 1
a = (x2 - x) * img[x1, y1] + (x - x1) * img[x2, y1]
b = (x2 - x) * img[x1, y2] + (x - x1) * img[x2, y2]
emptyImage[i, j] = (y2 - y) * a + (y - y1) * b
return emptyImage
# 三次样条插值
def cubic_interpolation(img, scale):
height, width = img.shape[:2]
new_height, new_width = int(height * scale), int(width * scale)
emptyImage = np.zeros((new_height, new_width, 3), np.uint8)
for i in range(new_height):
for j in range(new_width):
x, y = i / scale, j / scale
x1, y1 = int(x), int(y)
u = x - x1
v = y - y1
if x1 >= height-2 or y1 >= width-2 or x1 < 1 or y1 < 1:
continue
a0 = img[x1 - 1, y1 - 1]
a1 = img[x1 - 1, y1]
a2 = img[x1 - 1, y1 + 1]
a3 = img[x1 - 1, y1 + 2]
b0 = img[x1, y1 - 1]
b1 = img[x1, y1]
b2 = img[x1, y1 + 1]
b3 = img[x1, y1 + 2]
c0 = img[x1 + 1, y1 - 1]
c1 = img[x1 + 1, y1]
c2 = img[x1 + 1, y1 + 1]
c3 = img[x1 + 1, y1 + 2]
d0 = img[x1 + 2, y1 - 1]
d1 = img[x1 + 2, y1]
d2 = img[x1 + 2, y1 + 1]
d3 = img[x1 + 2, y1 + 2]
value = a3*u*v + b3*v*(1-u) + c3*(1-v)*u + d3*(1-u)*(1-v)
value += ((a2 - a3)*u + (b2 - b3))*(v**2)*u
value += ((c2 - c3)*v + (d2 - d3))*(u**2)*v
value += ((a0 - a2)*u + (b0 - b2))*(v**2)*(1-u)
value += ((c0 - c2)*v + (d0 - d2))*(u**2)*(1-v)
value += ((a1 - a0)*u + (b1 - b0))*v*(1-u)*(1-v)
value += ((c1 - c0)*v + (d1 - d0))*(1-u)*u*(1-v)
emptyImage[i, j] = np.clip(value, 0, 255)
return emptyImage
- 图像旋转:在对图像进行旋转操作时,为保证图像的平滑性,需要进行插值处理。通常采用最近邻插值、双线性插值等方法。
示例代码:
import cv2
import math
# 最近邻插值
def nearest_interpolation(img, angle):
height, width = img.shape[:2]
emptyImage = np.zeros((height, width, 3), np.uint8)
center_x, center_y = int(height / 2), int(width / 2)
cos = math.cos(math.radians(angle))
sin = math.sin(math.radians(angle))
for i in range(height):
for j in range(width):
new_x = int((i - center_x) * cos + (j - center_y) * sin + center_x)
new_y = int(-(i - center_x) * sin + (j - center_y) * cos + center_y)
if new_x >= height or new_y >= width or new_x < 0 or new_y < 0:
continue
emptyImage[i, j] = img[new_x, new_y]
return emptyImage
# 双线性插值
def linear_interpolation(img, angle):
height, width = img.shape[:2]
emptyImage = np.zeros((height, width, 3), np.uint8)
center_x, center_y = int(height / 2), int(width / 2)
cos = math.cos(math.radians(angle))
sin = math.sin(math.radians(angle))
for i in range(height):
for j in range(width):
new_x = (i - center_x) * cos + (j - center_y) * sin + center_x
new_y = -(i - center_x) * sin + (j - center_y) * cos + center_y
x1, y1 = int(new_x), int(new_y)
x2, y2 = x1 + 1, y1 + 1
if x2 >= height:
x2 = height - 1
if y2 >= width:
y2 = width - 1
a = (x2 - new_x) * img[x1, y1] + (new_x - x1) * img[x2, y1]
b = (x2 - new_x) * img[x1, y2] + (new_x - x1) * img[x2, y2]
emptyImage[i, j] = (y2 - new_y) * a + (new_y - y1) * b
return emptyImage
- 仿射变换:在对图像进行仿射变换时,为了保证变换后的图像能够充分利用原始图像的信息,一般采用双线性插值、三次样条插值等方法进行插值计算。
示例代码:
import cv2
import numpy as np
# 仿射变换
def AffineTransform(src, degree, offset):
height, width, channels = src.shape
emptyImage = np.zeros((height, width, channels), np.uint8)
# affine matrix
theta = degree * np.pi / 180
M = np.array([[np.cos(theta), -np.sin(theta), offset[0]], [np.sin(theta), np.cos(theta), offset[1]], [0, 0, 1]])
# inverse affine matrix
invM = np.linalg.inv(M)
for i in range(height):
for j in range(width):
x, y = np.array([i, j, 1]).dot(invM)[:2]
if x >= height or y >= width or x < 0 or y < 0:
continue
x1, y1 = int(x), int(y)
x2, y2 = x1 + 1, y1 + 1
if x2 >= height:
x2 = height - 1
if y2 >= width:
y2 = width - 1
a = (x2 - x) * src[x1, y1] + (x - x1) * src[x2, y1]
b = (x2 - x) * src[x1, y2] + (x - x1) * src[x2, y2]
emptyImage[i, j] = (y2 - y) * a + (y - y1) * b
return emptyImage