2013-11-23 90 views
12

我很困惑的API到scipy.ndimage.interpolation.affine_transform。並且由this issue來判斷,我不是唯一的一個。我實際上想要用affine_transform來做更有趣的事情,而不僅僅是旋轉一張圖片,但是一個輪換對於初學者來說可以做。 (是的,我很清楚scipy.ndimage.interpolation.rotate,但搞清楚如何駕駛affine_transform是我感興趣的地方)。如何使用scipy.ndimage.interpolation.affine_transform旋轉關於其中心的圖像?

當我想要做這樣的事情,比如OpenGL系統,我覺得在被改造(p-c)R+c計算變換施加一個2x2的旋轉矩陣R圍繞中心c,因此想點p的方面= pR+c-cR,它給出了c-cR術語用作變換的轉換組件。 然而,根據上述問題,SciPy的的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() 

我得到

rotated but not about centre lena image

不幸的是不旋轉約中心。

那麼我在這裏失蹤的訣竅是什麼?

+1

只是做一些簡單的&骯髒的測試我注意到,採取消極的抵消價值似乎圍繞中心旋轉。 – treddy

+0

啊哈!是的,很好,在這裏證實。看來我的scipy系統模型應該是'(p-s)R'。把這作爲答案,我會接受它。 – timday

回答

4

只是做一些快速&骯髒的測試我注意到,你的偏移量的負值似乎圍繞中心旋轉。

13

一旦treddy的回答讓我工作的基線,我設法得到affine_transform更好的工作模式。它並不像原始問題提示中鏈接的問題那麼古怪。

基本上,在輸出圖像中的每個點(座標)p變換爲pT+s其中Ts是傳遞給函數的矩陣和偏移量。 因此,如果我們想點c_out在輸出將被映射到和從c_in從輸入圖像取樣,用旋轉R和(可能的各向異性的)縮放S我們需要pT+s = (p-c_out)RS+c_in,其可被重新安排,得到s = (c_int-c_out)T(與T=RS)。

出於某種原因,我需要通過transform.Taffine_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() 

Spinning Lena

這裏是它的修改不同的圖像大小

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() 

Spinning small Lena

而這裏的一個版本各向異性縮放比例nsate用於源圖像的各向異性分辨率。

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() 

Spinning anisotropic Lena

+0

真棒,我怎麼能讓它旋轉並填充屏幕? (在角落處不會留下任何黑色/透明空間? –

+0

)您必須將足夠高的關於圖像中心的縮放因子合併到變換中;對於方形窗口中的方形圖像,需要sqrt(2) – timday

+1

任何人都在2016年來到這裏注意到,似乎有一個最近的scipy bugfix可能會或可能不會改變上面的一些細節;請參閱https://github.com/scipy/scipy/issues/ 2255和https://github.com/scipy/scipy/pull/5794 – timday

9

基於從@timday是matrixoffset有識之士在輸出定義座標系,我要提出的問題如下閱讀,這與線性代數的標準符號和配合也允許理解圖像的縮放比例。我在這裏使用T.inv=T^-1作爲僞python符號來表示矩陣的逆,而*表示點積。

對於輸出圖像中的每個點oaffine_transform找到對應的點i輸入圖像中的作爲i=T.inv*o+s,其中matrix=T.inv是2×2的變換矩陣的一個將用來定義向前仿射變換和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() 

Lena: first stretched, then rotated

如果圖像將被首先旋轉,然後拉伸,需要扭轉的點積的順序:

invTransform = dot(invRot, invScale) 

Lena: first rotated, then stretched

相關問題