2017-01-30 34 views
1

同じ変換行列を使用してitkイメージとvtk polydataを変換する必要がありますが、問題があります。vtkのpolydataとitkの変換方法の一致方法

すべてのコードとテストデータはここにある:ここhttps://github.com/jmerkow/vtk_itk_rotate

でのrelavent部分である:

import SimpleITK as sitk 
import vtk 
import numpy as np 
def rotate_img(img, rotation_center=None, theta_x=0,theta_y=0, theta_z=0, translation=(0,0,0), interp=sitk.sitkLinear, pixel_type=None, default_value=None): 
    if not rotation_center: 
     rotation_center = np.array(img.GetOrigin())+np.array(img.GetSpacing())*np.array(img.GetSize())/2 
    if default_value is None: 
     default_value = img.GetPixel(0,0,0) 
    pixel_type = img.GetPixelIDValue() 

    rigid_euler = sitk.Euler3DTransform(rotation_center, theta_x, theta_y, theta_z, translation) 
    return sitk.Resample(img, img, rigid_euler, interp, default_value, pixel_type) 

def rotate_polydata(pd, rotation_center, theta_x=0,theta_y=0, theta_z=0, translation=(0,0,0)): 
    rigid_euler = sitk.Euler3DTransform(rotation_center, -theta_x, -theta_y, -theta_z, translation) 
    matrix = np.zeros([4,4]) 
    old_matrix=np.array(rigid_euler.GetMatrix()).reshape(3,3) 
    matrix[:3,:3] = old_matrix 
    matrix[-1,-1] = 1 

    # to rotate about a center we first need to translate 
    transform_t = vtk.vtkTransform() 
    transform_t.Translate(-rotation_center) 
    transformer_t = vtk.vtkTransformPolyDataFilter() 
    transformer_t.SetTransform(transform_t) 
    transformer_t.SetInputData(pd) 
    transformer_t.Update() 

    transform = vtk.vtkTransform() 
    transform.SetMatrix(matrix.ravel()) 

    transformer = vtk.vtkTransformPolyDataFilter() 
    transformer.SetTransform(transform) 
    transformer.SetInputConnection(transformer_t.GetOutputPort()) 
    transformer.Update() 

    # translate back 
    transform_t2 = vtk.vtkTransform() 
    transform_t2.Translate(rotation_center) 
    transformer_t2 = vtk.vtkTransformPolyDataFilter() 
    transformer_t2.SetTransform(transform_t2) 
    transformer_t2.SetInputConnection(transformer.GetOutputPort()) 
    transformer_t2.Update() 

    return transformer_t2.GetOutputDataObject(0) 

datafn = 'test.mha' 
polydata_file = 'test.vtp' 
reader = vtk.vtkXMLPolyDataReader() 
reader.SetFileName(polydata_file) 
reader.Update() 
pd = reader.GetOutput() 

img = sitk.ReadImage(datafn) 
seg = pd_to_itk_image(pd, img) 
rotation_center = np.array(img.GetOrigin())+np.array(img.GetSpacing())*np.array(img.GetSize())/2 
thetas = [0, 50] 
thetas = [0, 50] 
for theta_x in thetas: 
    for theta_y in thetas: 
     for theta_z in thetas: 
      theta_xr = theta_x/180.*np.pi 
      theta_yr = theta_y/180.*np.pi 
      theta_zr = theta_z/180.*np.pi 
      img_rot=rotate_img(img, theta_z=theta_zr, theta_y=theta_yr, theta_x=theta_xr) 
      seg_rot=rotate_img(seg, theta_z=theta_zr, theta_y=theta_yr, theta_x=theta_xr, interp=sitk.sitkNearestNeighbor, default_value=0) 
      pd_rot = rotate_polydata(pd, rotation_center, theta_z=theta_zr, theta_y=theta_yr, theta_x=theta_xr) 
      seg_pd_rot = pd_to_itk_image(pd_rot, img_rot) 
      mse = ((sitk.GetArrayFromImage(seg_pd_rot)-sitk.GetArrayFromImage(seg_rot))**2.).mean() 

      print theta_x, theta_y, theta_z, mse 

#this outputs for this particular volume: 
#0 0 0 mse: 0.0 
#0 0 50 mse: 50.133369863 visually about the same 
#0 50 0 mse: 25.2197787166 visually about the same 
#0 50 50 mse: 863.588476181 visually totally different 
#50 0 0 mse: 20.4021692276 visually about the same 
#50 0 50 mse: 546.699844301 visually totally different 
#50 50 0 mse: 662.337975204 visually totally different 
#50 50 50 mse: 339.220945537 visually totally different 

このコードはpolydataから生成されたバイナリボリュームを回転させ、上の同じ回転動作を行いますpolydataはそれからバイナリボリュームを生成します。私はこれらの2つの結果が(ほぼ)同じになると期待しますが、複数の軸を中心に回転させると、全く異なる2つの回転が得られます。 私は変換行列を1つの行列からとり、それを直接他の行列に適用するので、これは困惑しています。

2つの操作で同じ変換が実行されるようにこれらの変換を設定するにはどうすればよいですか?そして、なぜ我々は別の結果に終わるのでしょうか?

+0

この例では役に立つかもしれません:https://itk.org/Wiki/ITK/Examples/WishList/IO/itkVtkImageConvertDICOM –

答えて

0

ありがとうございましたDženan私は正しい方向に向いています。

この場合、答えは簡単でした。 VTKとITKは、行列の乗算に異なる行/列の主要フォーマットを使用します。だから答えは単純に行列をvtkTransformに入れる前に転置することでした。

ここに新しい機能があります。

def rotate_polydata(pd, rotation_center, theta_x=0,theta_y=0, theta_z=0): 
    #I don't want to deal with translation 
    translation=(0,0,0) 
    rigid_euler = sitk.Euler3DTransform(rotation_center, theta_x, theta_y, theta_z, translation) 
    matrix = np.zeros([4,4]) 
    old_matrix=np.array(rigid_euler.GetMatrix()).reshape(3,3) 
    matrix[:3,:3] = old_matrix 
    matrix[-1,-1] = 1 
    #ITK and VTK use different orders. 
    matrix= matrix.T 

    # to rotate about a center we first need to translate 
    transform_t = vtk.vtkTransform() 
    transform_t.Translate(-rotation_center) 
    transformer_t = vtk.vtkTransformPolyDataFilter() 
    transformer_t.SetTransform(transform_t) 
    transformer_t.SetInputData(pd) 
    transformer_t.Update() 

    transform = vtk.vtkTransform() 
    transform.SetMatrix(matrix.ravel()) 
    transform.Translate(translation) 
    transform.PostMultiply() 

    transformer = vtk.vtkTransformPolyDataFilter() 
    transformer.SetTransform(transform) 
    transformer.SetInputConnection(transformer_t.GetOutputPort()) 
    transformer.Update() 

    # translate back 
    transform_t2 = vtk.vtkTransform() 
    transform_t2.Translate(rotation_center) 
    transformer_t2 = vtk.vtkTransformPolyDataFilter() 
    transformer_t2.SetTransform(transform_t2) 
    transformer_t2.SetInputConnection(transformer.GetOutputPort()) 
    transformer_t2.Update() 

    return transformer_t2.GetOutputDataObject(0) 
0

オイラー角の次数は最終結果 [Wikipedia]で重要です。また、行列の事前乗算は、逆乗算 [vtkTransform]の逆順になっています。 vtkTransform::PostMultiply()を呼び出すか、rotate_polydata関数で変換の順序を逆にしてください。これは簡単に試すことができます。それはそれを解決しない場合は

は、ITKはComputeOffsetTransformPointComputeMatrixに変換を適用する方法を検討し、VTKはvtkLinearTransformPointでそれをしませんか。それは行動の違いを説明し、同じ変換を達成する方法の手掛かりを提供するはずです。

+0

べきではないため、私は1から行列を取り、それを入れておりますので問題ありませもう片方に?それは提供されている行列を計算していません。 – jmerkow

+0

これは、1軸回りに回転するだけで、それ以上回転しない場合にはなぜ動作するのか説明していません。 – jmerkow

+0

VTKの場合、sitk.Euler3DTransformに負の角度を指定しているため、全く同じ行列を取得できません。 ITKとVTKの行のメジャーとカラムのメジャーを混在させているかもしれませんが、それはある角度に対しては負の角度で動作するかもしれませんが、それ以上では動作しないかもしれません。 Pythonコードではなく、C++コードをデバッグするための設定があります。 –

関連する問題