不知道双线性插值应用在三维图像上还叫不叫双线性插值。
进入正题,三维图像是用numpy数组存储的三维矩阵。
这个T就是变换矩阵,当其分别绕X、Y、Z轴旋转的时候,T分别为:
但是呢,这里有一个问题,一般来说我们会想把我们的图像绕着图像的中心旋转,但是如果你直接套用上面的公式的话会发现图像时绕着x轴,y轴和z轴旋转的,所以我们先得转换一下坐标,将旋转中心由原点变成图像的中点。
这里的处理其实很简单,只需要做一下简单的平移,平移矩阵如下:
N、M、O分别对应图像的长、宽、高的一半
进行完上面的变换之后就可以进行旋转变换了
变换完之后,再通过下面的平移矩阵将坐标变换回去就好了,平移矩阵如下:
所以,最后面旋转的公式为:
更多三维图像的变换可以参看以下博客:
https://blog.csdn.net/zl908760230/article/details/53965395
但是,仅仅只是通过上面的坐标变换后得到的图像一定会由问题,因为旋转之后有的地方根本就没有对应的值。所以这时候就要对这些空位进行插值了。
这里仅介绍双线性插值,插值的过程可以概括如下:
先构造旋转后的图,然后通过将该图反向旋转回去找对应的值进行填空。这样子就能够将旋转后图像的所有值都补上。
三维图像的双线性插值可以根据二维图像来推,一篇介绍二维图像的双线性插值:
https://www.cnblogs.com/sdxk/p/4056223.html
看看图片就能理解了,然后画个三维图像慢慢推三维的,我这里仅仅是单独绕着X、Y、Z一个轴旋转,所以和双线性插值也没什么区别了。当然写完代码之后还是要好好测试一下的,你会发现很多意想不到的错误。
python代码如下:
import numpy as np
# 旋转,axis为旋转轴,0,1,2分别代表x,y,z轴
# theta为旋转角度,单位已改为度,非弧度
# center为旋转中心,其为一维np数组[x,y,z],默认值为图像中心点
def rotation(data, axis, theta, c = np.array([])):# c代表旋转点
theta = -np.pi * theta / 180
if c.size == 0:
c = np.array([np.floor((data.shape[0]-1)/2), np.floor((data.shape[1]-1)/2), np.floor((data.shape[1]-1)/2)])
s = data.shape
mean = np.mean(data)
# new_data = np.ones(s) * mean # 补均值
new_data = np.zeros(s) # 补零
# 绕x轴旋转
if axis == 0:
for i in range(0, s[0]):
for j in range(0, s[1]):
for k in range(0, s[2]):
x = i
y = (j-c[1])*np.cos(theta)-(k-c[2])*np.sin(theta)+c[1]
if(y < 0 or y > s[1]-1):
continue
z = (j-c[1])*np.sin(theta)+(k-c[2])*np.cos(theta)+c[2]
if(z < 0 or z > s[2]-1):
continue
y1 = np.floor(y).astype(int)
y2 = np.ceil(y).astype(int)
z1 = np.floor(z).astype(int)
z2 = np.ceil(z).astype(int)
dy = y - y1
dz = z - z1
new_data[i,j,k] = (data[x,y1,z1]*(1-dy)+data[x,y2,z1]*dy)*(1-dz) + (data[x,y1,z2]*(1-dy)+data[x,y2,z2]*dy)*dz
# 绕y轴旋转
elif axis == 1:
for i in range(0, s[0]):
for j in range(0, s[1]):
for k in range(0, s[2]):
y = j
x = (i-c[0])*np.cos(theta)-(k-c[2])*np.sin(theta)+c[0]
if(x < 0 or x > s[0]-1):
continue
z = (i-c[0])*np.sin(theta)+(k-c[2])*np.cos(theta)+c[2]
if(z < 0 or z > s[2]-1):
continue
x1 = np.floor(x).astype(int)
x2 = np.ceil(x).astype(int)
z1 = np.floor(z).astype(int)
z2 = np.ceil(z).astype(int)
dx = x - x1
dz = z - z1
new_data[i,j,k] = (data[x1,y,z1]*(1-dx)+data[x2,y,z1]*dx)*(1-dz) + (data[x1,y,z2]*(1-dx)+data[x2,y,z2]*dx)*dz
# 绕z轴旋转
else:
for i in range(0, s[0]):
for j in range(0, s[1]):
for k in range(0, s[2]):
z = k
x = (i-c[0])*np.cos(theta)-(j-c[1])*np.sin(theta)+c[0]
if(x < 0 or x > s[0]-1):
continue
y = (i-c[0])*np.sin(theta)+(j-c[1])*np.cos(theta)+c[1]
if(y < 0 or y > s[1]-1):
continue
x1 = np.floor(x).astype(int)
x2 = np.ceil(x).astype(int)
y1 = np.floor(y).astype(int)
y2 = np.ceil(y).astype(int)
dx = x - x1
dy = y - y1
new_data[i,j,k] = (data[x1,y1,z]*(1-dx)+data[x2,y1,z]*dx)*(1-dy) + (data[x1,y2,z]*(1-dx)+data[x2,y2,z]*dx)*dy
return new_data