瀏覽代碼

Smol fix for bigger patients

Luka 6 天之前
父節點
當前提交
69036d3c40
共有 2 個文件被更改,包括 901 次插入145 次删除
  1. 258 21
      FirstTryLinear.txt
  2. 643 124
      SeekTransformModule/SeekTransformModule.py

+ 258 - 21
FirstTryLinear.txt

@@ -6,6 +6,10 @@ from scipy.spatial.transform import Rotation as R
 import slicer
 from DICOMLib import DICOMUtils
 from collections import deque
+import SimpleITK as sitk
+import sitkUtils
+
+#exec(open("C:/Users/lkomar/Documents/Prostata/FirstTryRegister.py").read())
 
 # Define a threshold for grouping nearby points (in voxel space)
 #distance_threshold = 4  # This can be adjusted based on your dataset
@@ -131,7 +135,19 @@ def detect_points_region_growing(volume_name, intensity_threshold=3000, x_min=90
 
     return unique_centroids
 
-def compute_rigid_transform(moving_points, fixed_points):
+
+
+def compute_Kabsch_rotation(moving_points, fixed_points):
+    """
+    Computes the optimal rotation matrix to align moving_points to fixed_points.
+    
+    Parameters:
+    moving_points (list or ndarray): List of points to be rotated CBCT
+    fixed_points (list or ndarray): List of reference points CT
+
+    Returns:
+    ndarray: Optimal rotation matrix.
+    """
     assert len(moving_points) == len(fixed_points), "Point lists must be the same length."
 
     # Convert to numpy arrays
@@ -151,23 +167,164 @@ def compute_rigid_transform(moving_points, fixed_points):
 
     # SVD decomposition
     U, _, Vt = np.linalg.svd(H)
-    R_optimal = np.dot(Vt.T, U.T)
+    Rotate_optimal = np.dot(Vt.T, U.T)
 
     # Correct improper rotation (reflection)
-    if np.linalg.det(R_optimal) < 0:
+    if np.linalg.det(Rotate_optimal) < 0:
+        Vt[-1, :] *= -1
+        Rotate_optimal = np.dot(Vt.T, U.T)
+
+    return Rotate_optimal
+
+def compute_Horn_rotation(moving_points, fixed_points):
+    """
+    Computes the optimal rotation matrix using Horn's method.
+
+    Parameters:
+    moving_points (list or ndarray): List of points to be rotated, CBCT
+    fixed_points (list or ndarray): List of reference points, CT
+
+    Returns:
+    ndarray: Optimal rotation matrix.
+    """
+    assert len(moving_points) == len(fixed_points), "Point lists must be the same length."
+    
+    moving = np.array(moving_points)
+    fixed = np.array(fixed_points)
+    
+    # Compute centroids
+    centroid_moving = np.mean(moving, axis=0)
+    centroid_fixed = np.mean(fixed, axis=0)
+    
+    # Center the points
+    moving_centered = moving - centroid_moving
+    fixed_centered = fixed - centroid_fixed
+    
+    # Compute cross-dispersion matrix
+    H = np.dot(moving_centered.T, fixed_centered)
+    
+    # Compute SVD of H
+    U, _, Vt = np.linalg.svd(H)
+    
+    # Compute rotation matrix
+    R = np.dot(Vt.T, U.T)
+    
+    # Ensure a proper rotation (avoid reflection)
+    if np.linalg.det(R) < 0:
         Vt[-1, :] *= -1
-        R_optimal = np.dot(Vt.T, U.T)
+        R = np.dot(Vt.T, U.T)
+    
+    return R
+
+def compute_quaternion_rotation(moving_points, fixed_points):
+    """
+    Computes the optimal rotation matrix using quaternions.
+
+    Parameters:
+    moving_points (list or ndarray): List of points to be rotated.
+    fixed_points (list or ndarray): List of reference points.
+
+    Returns:
+    ndarray: Optimal rotation matrix.
+    """
+    assert len(moving_points) == len(fixed_points), "Point lists must be the same length."
+    
+    moving = np.array(moving_points)
+    fixed = np.array(fixed_points)
+    
+    # Compute centroids
+    centroid_moving = np.mean(moving, axis=0)
+    centroid_fixed = np.mean(fixed, axis=0)
+    
+    # Center the points
+    moving_centered = moving - centroid_moving
+    fixed_centered = fixed - centroid_fixed
+    
+    # Construct the cross-dispersion matrix
+    M = np.dot(moving_centered.T, fixed_centered)
+    
+    # Construct the N matrix for quaternion solution
+    A = M - M.T
+    delta = np.array([A[1, 2], A[2, 0], A[0, 1]])
+    trace = np.trace(M)
+    
+    N = np.zeros((4, 4))
+    N[0, 0] = trace
+    N[1:, 0] = delta
+    N[0, 1:] = delta
+    N[1:, 1:] = M + M.T - np.eye(3) * trace
+    
+    # Compute the eigenvector corresponding to the maximum eigenvalue
+    eigvals, eigvecs = np.linalg.eigh(N)
+    q_optimal = eigvecs[:, np.argmax(eigvals)]  # Optimal quaternion
+    
+    # Convert quaternion to rotation matrix
+    w, x, y, z = q_optimal
+    R = np.array([
+        [1 - 2*(y**2 + z**2), 2*(x*y - z*w), 2*(x*z + y*w)],
+        [2*(x*y + z*w), 1 - 2*(x**2 + z**2), 2*(y*z - x*w)],
+        [2*(x*z - y*w), 2*(y*z + x*w), 1 - 2*(x**2 + y**2)]
+    ])
+    
+    return R
+
+def compute_translation(moving_points, fixed_points, rotation_matrix):
+    """
+    Computes the translation vector to align moving_points to fixed_points given a rotation matrix.
+    
+    Parameters:
+    moving_points (list or ndarray): List of points to be translated.
+    fixed_points (list or ndarray): List of reference points.
+    rotation_matrix (ndarray): Rotation matrix.
+
+    Returns:
+    ndarray: Translation vector.
+    """
+    # Convert to numpy arrays
+    moving = np.array(moving_points)
+    fixed = np.array(fixed_points)
+
+    # Compute centroids
+    centroid_moving = np.mean(moving, axis=0)
+    centroid_fixed = np.mean(fixed, axis=0)
 
     # Compute translation
-    translation = centroid_fixed - np.dot(centroid_moving, R_optimal)
+    translation = centroid_fixed - np.dot(centroid_moving, rotation_matrix)
+
+    return translation
+
+# def apply_transform(points, rotation_matrix, translation_vector):
+#     points = np.array(points)
+#     transformed_points = np.dot(points, rotation_matrix.T) + translation_vector
+#     return transformed_points
 
-    return R_optimal, translation
+def apply_transform(volume, rotation_matrix, translation_vector):
+    """
+    Transforms a 3D volume using a given rotation matrix and translation vector.
 
-def apply_transform(points, rotation_matrix, translation_vector):
-    points = np.array(points)
-    transformed_points = np.dot(points, rotation_matrix.T) + translation_vector
-    return transformed_points
+    Parameters:
+    volume (sitk.Image): Input 3D volume to be transformed.
+    rotation_matrix (ndarray): 3x3 rotation matrix.
+    translation_vector (ndarray): 1x3 translation vector.
 
+    Returns:
+    sitk.Image: Transformed 3D volume.
+    """
+    # Create an affine transform
+    transform = sitk.AffineTransform(3)
+    transform.SetMatrix(rotation_matrix.flatten())
+    translation_vector = translation_vector.tolist()
+    transform.SetTranslation(translation_vector)
+
+    # Resample the volume
+    resampler = sitk.ResampleImageFilter()
+    resampler.SetReferenceImage(volume)
+    resampler.SetInterpolator(sitk.sitkLinear)  # Linear interpolation
+    resampler.SetTransform(transform)
+    resampler.SetDefaultPixelValue(0)  # Background value for areas outside the original volume
+
+    transformed_volume = resampler.Execute(volume)
+    return transformed_volume
 
 
 
@@ -210,16 +367,96 @@ for volumeNode in slicer.util.getNodesByClass("vtkMRMLScalarVolumeNode"):
 #     print(f"{scan_type} Volume '{vol_name}': {len(points)} points detected.")
 
 
-cbct_points = [centroid for centroid, _ in volume_points_dict[("CBCT", "CBCT1")]]  # Extract only centroids (coordinates)
-ct_points = [centroid for centroid, _ in volume_points_dict[("CT", "CT")]]  # Extract only centroids (coordinates)
-print("CBCT points: ", np.array(cbct_points))
-# Ensure we have enough points for registration
-if len(cbct_points) >= 3 and len(ct_points) >= 3:
-    rotation_matrix, translation_vector = compute_rigid_transform(cbct_points, ct_points)
-    transformed_cbct_points = apply_transform(cbct_points, rotation_matrix, translation_vector)
+if cbct_list and ct_list:
+    # Izberi prvi CT volumen kot referenco
+    ct_volume_name = ct_list[0]
+    ct_points = [centroid for centroid, _ in volume_points_dict[("CT", ct_volume_name)]]
+
+    if len(ct_points) < 3:
+        print("CT volumen nima dovolj točk za registracijo.")
+    else:
+        print("CT points: ", np.array(ct_points))
+        
+        for cbct_volume_name in cbct_list:
+            # Izvleci točke za trenutni CBCT volumen
+            cbct_points = [centroid for centroid, _ in volume_points_dict[("CBCT", cbct_volume_name)]]
 
-    print("Optimal Rotation Matrix:\n", rotation_matrix)
-    print("Translation Vector:\n", translation_vector)
-    print("Transformed CBCT Points:\n", transformed_cbct_points)
+            print(f"\nProcessing CBCT Volume: {cbct_volume_name}")
+            if len(cbct_points) < 3:
+                print(f"CBCT Volume '{cbct_volume_name}' nima dovolj točk za registracijo.")
+                continue
+
+            #print("CBCT points: ", np.array(cbct_points))
+
+            # Compute rotation matrices using different methods
+            svd_rotation_matrix = compute_Kabsch_rotation(cbct_points, ct_points)
+            horn_rotation_matrix = compute_Horn_rotation(cbct_points, ct_points)
+            quaternion_rotation_matrix = compute_quaternion_rotation(cbct_points, ct_points)
+
+            # Compute translations for each method
+            svd_translation_vector = compute_translation(cbct_points, ct_points, svd_rotation_matrix)
+            horn_translation_vector = compute_translation(cbct_points, ct_points, horn_rotation_matrix)
+            quaternion_translation_vector = compute_translation(cbct_points, ct_points, quaternion_rotation_matrix)
+
+            # Display the results for the current CBCT volume
+            print("\nSVD Method:")
+            print("Rotation Matrix:\n", svd_rotation_matrix)
+            print("Translation Vector:\n", svd_translation_vector)
+
+            print("\nHorn Method:")
+            print("Rotation Matrix:\n", horn_rotation_matrix)
+            print("Translation Vector:\n", horn_translation_vector)
+
+            print("\nQuaternion Method:")
+            print("Rotation Matrix:\n", quaternion_rotation_matrix)
+            print("Translation Vector:\n", quaternion_translation_vector)
+
+            # Apply chosen transformation (select one method manually)
+            chosen_rotation_matrix = svd_rotation_matrix  # Change to horn_rotation_matrix or quaternion_rotation_matrix if needed
+            chosen_translation_vector = svd_translation_vector #also change here
+
+            # Pridobitev CBCT slike kot SimpleITK
+            cbct_volume_node = slicer.util.getNode(cbct_volume_name)
+            cbct_image_sitk = sitkUtils.PullVolumeFromSlicer(cbct_volume_node)
+
+            transformed_cbct_image = apply_transform(cbct_image_sitk, chosen_rotation_matrix, chosen_translation_vector)
+
+            print(f"\nTransformed Volume '{cbct_volume_name}' using SVD Method")
+
+            # Shranimo nazaj v Slicer
+            sitkUtils.PushVolumeToSlicer(transformed_cbct_image, name=f"Transformed_{cbct_volume_name}")
 else:
-    print("Not enough points for registration.")
+    print("CBCT ali CT volumen ni bil najden.")
+
+
+# def compute_rigid_transform(moving_points, fixed_points):
+#     assert len(moving_points) == len(fixed_points), "Point lists must be the same length."
+
+#     # Convert to numpy arrays
+#     moving = np.array(moving_points)
+#     fixed = np.array(fixed_points)
+
+#     # Compute centroids
+#     centroid_moving = np.mean(moving, axis=0)
+#     centroid_fixed = np.mean(fixed, axis=0)
+
+#     # Center the points
+#     moving_centered = moving - centroid_moving
+#     fixed_centered = fixed - centroid_fixed
+
+#     # Compute covariance matrix
+#     H = np.dot(moving_centered.T, fixed_centered)
+
+#     # SVD decomposition
+#     U, _, Vt = np.linalg.svd(H)
+#     Rotate_optimal = np.dot(Vt.T, U.T)
+
+#     # Correct improper rotation (reflection)
+#     if np.linalg.det(Rotate_optimal) < 0:
+#         Vt[-1, :] *= -1
+#         Rotate_optimal = np.dot(Vt.T, U.T)
+
+#     # Compute translation
+#     translation = centroid_fixed - np.dot(centroid_moving, Rotate_optimal)
+
+#     return Rotate_optimal, translation

文件差異過大導致無法顯示
+ 643 - 124
SeekTransformModule/SeekTransformModule.py


部分文件因文件數量過多而無法顯示