Python 如何将这个numpy旋转代码矢量化? 目标是:
我想矢量化(或加速)这段代码。它围绕其中心点旋转3dPython 如何将这个numpy旋转代码矢量化? 目标是:,python,numpy,Python,Numpy,我想矢量化(或加速)这段代码。它围绕其中心点旋转3dnumpy模型(让x、y、z表示尺寸;然后我们要围绕z轴旋转)。np模型是“开”或“关”的二元体素 我打赌一些基本的矩阵运算可以做到这一点,比如取一层并将旋转矩阵应用于每个元素。唯一的问题是小数;既然cos(pi/6)==sqrt(3)/2,我应该在哪里拥有新的价值地 守则: 其中rotate()是: def rotate(arr, theta): ''' Rotates theta clockwise
numpy
模型(让x、y、z表示尺寸;然后我们要围绕z轴旋转)。np模型是“开”或“关”的二元体素
我打赌一些基本的矩阵运算可以做到这一点,比如取一层并将旋转矩阵应用于每个元素。唯一的问题是小数;既然cos(pi/6)==sqrt(3)/2
,我应该在哪里拥有新的价值地
守则:
其中rotate()
是:
def rotate(arr, theta):
'''
Rotates theta clockwise
rotated.shape == arr.shape, unlike scipy.ndimage.rotate(), which inflates size and also does some strange mixing
'''
if theta == int(theta):
theta *= pi / 180
theta = -theta
# theta=-theta b/c clockwise. Otherwise would default to counterclockwise
rotated =np.zeros(arr.shape)
#print rotated.shape[0], rotated.shape[1]
y_mid = arr.shape[0]//2
x_mid = arr.shape[1]//2
val = 0
for x_new in range(rotated.shape[1]):
for y_new in range(rotated.shape[0]):
x_centered = x_new - x_mid
y_centered = y_new - y_mid
x = x_centered*cos(theta) - y_centered*sin(theta)
y = x_centered*sin(theta) + y_centered*cos(theta)
x += x_mid
y += y_mid
x = int(round(x)); y = int(round(y)) # cast so range() picks it up
# lossy rotation
if x in range(arr.shape[1]) and y in range(arr.shape[0]):
val = arr[y,x]
rotated[y_new,x_new] = val
#print val
#print x,y
return rotated
下面是一些代码,供同样做3d建模的人使用。它很好地解决了我的特定用例。还在琢磨如何在合适的平面上旋转。希望对您也有帮助:
def rotate_model(m, theta):
'''
Redefines the prev 'rotate_model()' method
theta has to be in degrees
'''
rotated = scipy.ndimage.rotate(m, theta, axes=(1,2))
# have tried (1,0), (2,0), and now (1,2)
# ^ z is "up" and "2"
# scipy.ndimage.rotate() shrinks the model
# TODO: regrow it back
x_r = rotated.shape[1]
y_r = rotated.shape[0]
x_m = m.shape[1]
y_m = m.shape[0]
x_diff = abs(x_r - x_m)
y_diff = abs(y_r - y_m)
if x_diff%2==0 and y_diff%2==0:
return rotated[
x_diff//2 : x_r-x_diff//2,
y_diff//2 : y_r-y_diff//2,
:
]
elif x_diff%2==0 and y_diff%2==1:
# if this shift ends up turning the model to shit in a few iterations,
# change the following lines to include a flag that alternates cutting off the top and bottom bits of the array
return rotated[
x_diff//2 : x_r-x_diff//2,
y_diff//2+1 : y_r-y_diff//2,
:
]
elif x_diff%2==1 and y_diff%2==0:
return rotated[
x_diff//2+1 : x_r-x_diff//2,
y_diff//2 : y_r-y_diff//2,
:
]
else:
# x_diff%2==1 and y_diff%2==1:
return rotated[
x_diff//2+1 : x_r-x_diff//2,
y_diff//2+1 : y_r-y_diff//2,
:
]
您的代码中有几个问题。首先,如果要将原始图像拟合到旋转的网格上,则需要更大的网格(通常)。或者,想象一个规则的网格,但对象的形状(矩形)被旋转,从而成为“菱形”。很明显,如果你想适应整个菱形,你需要一个更大的输出网格(数组)。另一方面,您在代码中说“
rotated.shape==arr.shape
,而不像scipy.ndimage.rotate()
,它使大小膨胀”。如果是这样的话,也许您不想拟合整个对象?所以,也许可以这样做:rotated=np.zeros(arr.shape)
。但一般来说,是的,一个必须有一个更大的网格,以适应整个输入图像旋转后
另一个问题是正在进行的角度转换:
if theta == int(theta):
theta *= pi / 180
theta = -theta
为什么???当我想将图像旋转1弧度时会发生什么?还是2弧度?我被禁止使用整数弧度吗?我认为您试图在这个函数中做的太多了,因此使用它会非常混乱。只需要调用方将角度转换为弧度。或者,如果输入theta
始终以度为单位,则可以在该函数中执行此操作。或者,您可以添加另一个名为的参数,例如,单位
,调用者可以将其设置为弧度
或度
。不要试图根据输入的“整数度”来猜测它
现在,让我们稍微重写一下您的代码:
rotated = np.zeros_like(arr) # instead of np.zero(arr.shape)
y_mid = arr.shape[0] // 2
x_mid = arr.shape[1] // 2
# val = 0 <- this is unnecessary
# pre-compute cos(theta) and sin(theta):
cs = cos(theta)
sn = sin(theta)
for x_new in range(rotated.shape[1]):
for y_new in range(rotated.shape[0]):
x = int(round((x_new - x_mid) * cs - (y_new - y_mid) * sn + x_mid)
y = int(round((x_new - x_mid) * sn - (y_new - y_mid) * cs + y_mid)
# just use comparisons, don't search through many values!
if 0 <= x < arr.shape[1] and 0 <= y < arr.shape[0]:
rotated[y_new, x_new] = arr[y, x]
rotated=np.zero_like(arr)#而不是np.zero(arr.shape)
y_mid=arr.shape[0]//2
x_mid=arr.shape[1]//2
#val=0我只是想到了一些东西;如果我在布尔型上尝试scipy.ndimage.rotate()
,可能它们不会像在数字上那样添加。确认…@AGNGazer我不是100%确定结束一个问题的标准,但我要的是代码。我不是问“如何在极坐标和笛卡尔坐标之间转换?”这是一个数学问题。我的问题在本质上是非常计算性和实用性的,你必须理解(在一般情况下)没有办法旋转一堆像素,旋转的坐标是整数。因此,您需要将原始图像I(I,j)
重新采样到新的网格I(I',j')
。所以,是的,如果你的问题没有问题-你可以四舍五入到最近的网格节点。如果你需要做得更好-使用插值。我误解了你的问题。
rotated = np.zeros_like(arr) # instead of np.zero(arr.shape)
y_mid = arr.shape[0] // 2
x_mid = arr.shape[1] // 2
# val = 0 <- this is unnecessary
# pre-compute cos(theta) and sin(theta):
cs = cos(theta)
sn = sin(theta)
for x_new in range(rotated.shape[1]):
for y_new in range(rotated.shape[0]):
x = int(round((x_new - x_mid) * cs - (y_new - y_mid) * sn + x_mid)
y = int(round((x_new - x_mid) * sn - (y_new - y_mid) * cs + y_mid)
# just use comparisons, don't search through many values!
if 0 <= x < arr.shape[1] and 0 <= y < arr.shape[0]:
rotated[y_new, x_new] = arr[y, x]
import numpy as np
def rotate(arr, theta, unit='rad'):
# deal with theta units:
if unit.startswith('deg'):
theta = np.deg2rad(theta)
# for convenience, store array size:
ny, nx = arr.shape
# generate arrays of indices and flatten them:
y_new, x_new = np.indices(arr.shape)
x_new = x_new.ravel()
y_new = y_new.ravel()
# compute center of the array:
x0 = nx // 2
y0 = ny // 2
# compute old coordinates
xc = x_new - x0
yc = y_new - y0
x = np.round(np.cos(theta) * xc - np.sin(theta) * yc + x0).astype(np.int)
y = np.round(np.sin(theta) * xc - np.cos(theta) * yc + y0).astype(np.int)
# main idea to deal with indices is to create a mask:
mask = (x >= 0) & (x < nx) & (y >= 0) & (y < ny)
# ... and then select only those coordinates (both in
# input and "new" coordinates) that satisfy the above condition:
x = x[mask]
y = y[mask]
x_new = x_new[mask]
y_new = y_new[mask]
# map input values to output pixels *only* for selected "good" pixels:
rotated = np.zeros_like(arr)
rotated[y_new, x_new] = arr[y, x]
return rotated