Python三维图像旋转-基于双线性插值的旋转代码

基于双线性插值的三维图像旋转

不知道双线性插值应用在三维图像上还叫不叫双线性插值。

进入正题,三维图像是用numpy数组存储的三维矩阵。

三维图像旋转的基础:

[x', y', z', 1] = [x, y, z, 1]\times T

这个T就是变换矩阵,当其分别绕X、Y、Z轴旋转的时候,T分别为:

T = \begin{bmatrix} 1&0 &0 &0 \\ 0& \cos (\theta ) & \sin (\theta) &0 \\ 0& -\sin (\theta)& \cos (\theta ) &0\\ 0& 0& 0& 1 \end{bmatrix}

T = \begin{bmatrix} \cos (\theta )&0 & -\sin (\theta) &0 \\ 0& 1 & 0 &0 \\ \sin (\theta)& 0& \cos (\theta ) &0\\ 0& 0& 0& 1 \end{bmatrix}

T = \begin{bmatrix} \cos (\theta )& \sin (\theta) &0&0 \\ -\sin (\theta)& \cos (\theta ) & 0 &0 \\ 0& 0& 1 &0\\ 0& 0& 0& 1 \end{bmatrix}

但是呢,这里有一个问题,一般来说我们会想把我们的图像绕着图像的中心旋转,但是如果你直接套用上面的公式的话会发现图像时绕着x轴,y轴和z轴旋转的,所以我们先得转换一下坐标,将旋转中心由原点变成图像的中点。

旋转中心坐标变换:

这里的处理其实很简单,只需要做一下简单的平移,平移矩阵如下:

T_{1} = \begin{bmatrix} \1& 0 &0&0 \\ 0 & 1 & 0 &0 \\ 0& 0& 1 &0\\ -N& -M& -O& 1 \end{bmatrix}

N、M、O分别对应图像的长、宽、高的一半

进行完上面的变换之后就可以进行旋转变换了

变换完之后,再通过下面的平移矩阵将坐标变换回去就好了,平移矩阵如下:

T_{2} = \begin{bmatrix} \1& 0 &0&0 \\ 0 & 1 & 0 &0 \\ 0& 0& 1 &0\\ N& M& O& 1 \end{bmatrix}

所以,最后面旋转的公式为:

[x', y', z', 1] = [x, y, z, 1]\times T_{1}\times T\times T_{2}

更多三维图像的变换可以参看以下博客:

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

 

 

 

你可能感兴趣的:(CV)