tim*_*day 16 python numpy matplotlib rotation scipy
我对API感到困惑scipy.ndimage.interpolation.affine_transform.从这个问题来看,我不是唯一一个.我实际上想要做更多有趣的事情,affine_transform而不仅仅是旋转图像,但旋转会为初学者做.(是的,我很清楚scipy.ndimage.interpolation.rotate,但弄清楚如何驾驶affine_transform是我感兴趣的).
当我想在像OpenGL这样的系统中做这种事情的时候,我想在计算变换时会考虑一个2x2旋转矩阵R围绕一个中心c,因此想到p要被转换的点(p-c)R+c= pR+c-cR,这给出了一个c-cR术语来使用作为转换的翻译组件. 然而,根据上面的问题,scipy's affine_transform确实" 先偏移 ",所以我们实际上需要计算一个偏移量s,(p-c)R+c=(p+s)R以便通过一些重新排列给出s=(c-cR)R'其中R'的倒数R.
如果我把它插入ipython笔记本(pylab模式;下面的代码可能需要一些额外的导入):
img=scipy.misc.lena()
#imshow(img,cmap=cm.gray);show()
centre=0.5*array(img.shape)
a=15.0*pi/180.0
rot=array([[cos(a),sin(a)],[-sin(a),cos(a)]])
offset=(centre-centre.dot(rot)).dot(linalg.inv(rot))
rotimg=scipy.ndimage.interpolation.affine_transform(
img,rot,order=2,offset=offset,cval=0.0,output=float32
)
imshow(rotimg,cmap=cm.gray);show()
Run Code Online (Sandbox Code Playgroud)
我明白了

不幸的是,它没有围绕中心旋转.
那么我在这里缺少什么诀窍?
tim*_*day 17
一旦treddy的答案给我一个工作基线,我设法得到了一个更好的工作模型affine_transform.它实际上并不像原始问题提示中链接的问题那么奇怪.
基本上,每个点(坐标)p在输出图像中被变换到pT+s其中T和s是传递给函数的矩阵和偏移量.因此,如果我们希望c_out输出中的点映射到c_in输入图像并从输入图像中采样,通过旋转R和(可能是各向异性)缩放,S我们需要pT+s = (p-c_out)RS+c_in重新排列以产生s = (c_int-c_out)T(带T=RS).
出于某种原因,我需要通过transform.T,affine_transform但我不会太担心; 可能与右边的变换(上面假设)与左边的变换的列坐标的行坐标有关.
所以这是一个旋转居中图像的简单测试:
src=scipy.misc.lena()
c_in=0.5*array(src.shape)
c_out=array((256.0,256.0))
for i in xrange(0,7):
a=i*15.0*pi/180.0
transform=array([[cos(a),-sin(a)],[sin(a),cos(a)]])
offset=c_in-c_out.dot(transform)
dst=scipy.ndimage.interpolation.affine_transform(
src,transform.T,order=2,offset=offset,output_shape=(512,512),cval=0.0,output=float32
)
subplot(1,7,i+1);axis('off');imshow(dst,cmap=cm.gray)
show()
Run Code Online (Sandbox Code Playgroud)

这是针对不同图像尺寸进行修改的
src=scipy.misc.lena()[::2,::2]
c_in=0.5*array(src.shape)
c_out=array((256.0,256.0))
for i in xrange(0,7):
a=i*15.0*pi/180.0
transform=array([[cos(a),-sin(a)],[sin(a),cos(a)]])
offset=c_in-c_out.dot(transform)
dst=scipy.ndimage.interpolation.affine_transform(
src,transform.T,order=2,offset=offset,output_shape=(512,512),cval=0.0,output=float32
)
subplot(1,7,i+1);axis('off');imshow(dst,cmap=cm.gray)
show()
Run Code Online (Sandbox Code Playgroud)

这是一个具有各向异性缩放的版本,以补偿源图像的各向异性分辨率.
src=scipy.misc.lena()[::2,::4]
c_in=0.5*array(src.shape)
c_out=array((256.0,256.0))
for i in xrange(0,7):
a=i*15.0*pi/180.0
transform=array([[cos(a),-sin(a)],[sin(a),cos(a)]]).dot(diag(([0.5,0.25])))
offset=c_in-c_out.dot(transform)
dst=scipy.ndimage.interpolation.affine_transform(
src,transform.T,order=2,offset=offset,output_shape=(512,512),cval=0.0,output=float32
)
subplot(1,7,i+1);axis('off');imshow(dst,cmap=cm.gray)
show()
Run Code Online (Sandbox Code Playgroud)

小智 10
根据@timday的见解,matrix并offset在输出坐标系中定义,我将提供以下问题的读数,它符合线性代数中的标准符号,并允许理解图像的缩放.我在这里使用T.inv=T^-1伪python表示法来表示矩阵的逆矩阵并*表示点积.
对于o输出图像中的每个点,affine_transform找到i输入图像中的对应点i=T.inv*o+s,其中,2x2变换矩阵matrix=T.inv的倒数用于定义前向仿射变换,并且offset=s是输出坐标中定义的平移.对于纯粹的旋转T=R=[[cos,-sin],[sin,cos]],在这种特殊情况下matrix=T.inv=T.T,这就是@timday必须仍然应用转置的原因(或者可以只使用负角度).
偏移的值s完全按照@timday描述的方式找到:如果c_in应该在仿射变换后定位c_out(例如输入中心应放置在输出中心),c_in=T.inv*c_out+s或者s=c_in-T.inv*c_out(注意传统的数学顺序)这里使用的矩阵乘积,矩阵*向量,这就是使用逆序的@timday,在他的代码中此时不需要转置).
如果一个人想要S先缩放然后再进行一次旋转R它会保持这一点T=R*S,因此T.inv=S.inv*R.inv(注意相反的顺序).例如,如果想要使图像在列方向('x')上加倍宽,那么S=diag((1, 2)),因此S.inv=diag((1, 0.5)).
src = scipy.misc.lena()
c_in = 0.5 * array(src.shape)
dest_shape = (512, 1028)
c_out = 0.5 * array(dest_shape)
for i in xrange(0, 7):
a = i * 15.0 * pi / 180.0
rot = array([[cos(a), -sin(a)], [sin(a), cos(a)]])
invRot = rot.T
invScale = diag((1.0, 0.5))
invTransform = dot(invScale, invRot)
offset = c_in - dot(invTransform, c_out)
dest = scipy.ndimage.interpolation.affine_transform(
src, invTransform, order=2, offset=offset, output_shape=dest_shape, cval=0.0, output=float32
)
subplot(1, 7, i + 1);axis('off');imshow(dest, cmap=cm.gray)
show()
Run Code Online (Sandbox Code Playgroud)
如果要首先旋转图像,然后拉伸图像,则需要反转点积的顺序:
invTransform = dot(invRot, invScale)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11091 次 |
| 最近记录: |