antspymm 1.5.1__py3-none-any.whl → 1.5.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
antspymm/mm.py CHANGED
@@ -2198,9 +2198,10 @@ def dti_numpy_to_image( reference_image, tensorarray, upper_triangular=True):
2198
2198
  def transform_and_reorient_dti( fixed, moving_dti, composite_transform, py_based=True, verbose=False, **kwargs):
2199
2199
  """
2200
2200
  apply a transform to DTI in the style of ants.apply_transforms. this function
2201
- expects a pre-computed composite transform which it will use to reorient
2202
- the DTI using preservation of principle directions.
2203
-
2201
+ expects a pre-computed composite transform which it will use to reorient
2202
+ the DTI using preservation of principle directions. BUG fix by cookpa 2025
2203
+ 06 18.
2204
+
2204
2205
  fixed : antsImage reference space
2205
2206
 
2206
2207
  moving_dti : antsImage DTI in upper triangular format
@@ -2224,34 +2225,36 @@ def transform_and_reorient_dti( fixed, moving_dti, composite_transform, py_based
2224
2225
  dtiw = []
2225
2226
  for k in range(len(dtsplit)):
2226
2227
  dtiw.append( ants.apply_transforms( fixed, dtsplit[k], composite_transform ) )
2227
- dtiw=ants.merge_channels(dtiw)
2228
+ dtiw=ants.merge_channels(dtiw) # resampled into fixed space but still based in moving index space
2228
2229
  if verbose:
2229
2230
  print("reorient tensors locally: compose and get reo image")
2230
- locrot = ants.deformation_gradient( ants.image_read(composite_transform),
2231
+ locrot = ants.deformation_gradient( ants.image_read(composite_transform),
2231
2232
  to_rotation = True, py_based=py_based ).numpy()
2232
- rebaser = np.dot( np.transpose( fixed.direction ), moving_dti.direction )
2233
+ # rebases from moving index to fixed index space. Not quite what we need here
2234
+ # rebaser = np.dot( np.transpose( fixed.direction ), moving_dti.direction )
2233
2235
  if verbose:
2234
2236
  print("convert UT to full tensor")
2235
2237
  dtiw2tensor = triangular_to_tensor( dtiw )
2236
2238
  if verbose:
2237
- print("rebase tensors to new space via iterator")
2239
+ print("rebase tensors to new space and apply reorientation via iterator")
2238
2240
  it = np.ndindex( fixed.shape )
2239
2241
  for i in it:
2240
- # direction * dt * direction.transpose();
2241
2242
  mmm = dtiw2tensor[i]
2242
- # transform rebase
2243
+ # Rebase mmm to physical space
2244
+ mmm = np.dot( mmm, np.transpose( moving_dti.direction ) )
2245
+ mmm = np.dot( moving_dti.direction, mmm )
2246
+ # Now apply local rotation
2243
2247
  locrotx = np.reshape( locrot[i], [3,3] )
2244
2248
  mmm = np.dot( mmm, np.transpose( locrotx ) )
2245
2249
  mmm = np.dot( locrotx, mmm )
2246
- # physical space rebase
2247
- mmm = np.dot( mmm, np.transpose( rebaser ) )
2248
- mmm = np.dot( rebaser, mmm )
2250
+ # Now rebase to fixed index space
2251
+ mmm = np.dot( mmm, np.transpose( fixed.direction ) )
2252
+ mmm = np.dot( fixed.direction, mmm )
2249
2253
  dtiw2tensor[i] = mmm
2250
2254
  if verbose:
2251
2255
  print("done with rebasing")
2252
2256
  return dti_numpy_to_image( fixed, dtiw2tensor )
2253
2257
 
2254
-
2255
2258
  def dti_reg(
2256
2259
  image,
2257
2260
  avg_b0,
@@ -3655,8 +3658,8 @@ def efficient_tensor_fit( gtab, fit_method, imagein, maskin, diffusion_model='DT
3655
3658
 
3656
3659
 
3657
3660
  def efficient_dwi_fit(gtab, diffusion_model, imagein, maskin,
3658
- model_params=None, bvals_to_use=None,
3659
- chunk_size=10, num_threads=1, verbose=True):
3661
+ model_params=None, bvals_to_use=None,
3662
+ chunk_size=1024, num_threads=1, verbose=True):
3660
3663
  """
3661
3664
  Efficient and optionally parallelized diffusion model reconstruction using DiPy.
3662
3665
 
@@ -3675,7 +3678,7 @@ def efficient_dwi_fit(gtab, diffusion_model, imagein, maskin,
3675
3678
  bvals_to_use : list of int, optional
3676
3679
  Subset of b-values to use for the fit (e.g., [0, 1000, 2000]).
3677
3680
  chunk_size : int, optional
3678
- Z-axis slice chunk size.
3681
+ Maximum number of voxels per chunk (default 1024).
3679
3682
  num_threads : int, optional
3680
3683
  Number of parallel threads.
3681
3684
  verbose : bool, optional
@@ -3707,23 +3710,25 @@ def efficient_dwi_fit(gtab, diffusion_model, imagein, maskin,
3707
3710
  img_data = imagein.numpy()
3708
3711
  mask = maskin.numpy().astype(bool)
3709
3712
  X, Y, Z, N = img_data.shape
3713
+ inplane_size = X * Y
3714
+
3715
+ # Convert chunk_size from voxel count to number of slices
3716
+ slices_per_chunk = max(1, chunk_size // inplane_size)
3710
3717
 
3711
3718
  if verbose:
3712
3719
  print(f"[INFO] Image shape: {img_data.shape}")
3713
3720
  print(f"[INFO] Using model: {diffusion_model}")
3714
- print(f"[INFO] Chunk size: {chunk_size} | Threads: {num_threads}")
3721
+ print(f"[INFO] Max voxels per chunk: {chunk_size} (→ {slices_per_chunk} slices) | Threads: {num_threads}")
3715
3722
 
3716
- # Filter shells if specified
3717
3723
  if bvals_to_use is not None:
3718
3724
  bvals_to_use = set(bvals_to_use)
3719
3725
  sel = np.isin(gtab.bvals, list(bvals_to_use))
3720
3726
  img_data = img_data[..., sel]
3721
- gtab = gradient_table(gtab.bvals[sel], gtab.bvecs[sel])
3727
+ gtab = gradient_table(gtab.bvals[sel], bvecs=gtab.bvecs[sel])
3722
3728
  if verbose:
3723
3729
  print(f"[INFO] Selected b-values: {sorted(bvals_to_use)}")
3724
3730
  print(f"[INFO] Selected volumes: {sel.sum()} / {N}")
3725
3731
 
3726
- # Choose model
3727
3732
  def get_model(name, gtab, **params):
3728
3733
  if name == 'DTI':
3729
3734
  return dti.TensorModel(gtab, **params)
@@ -3736,14 +3741,13 @@ def efficient_dwi_fit(gtab, diffusion_model, imagein, maskin,
3736
3741
 
3737
3742
  model = get_model(diffusion_model, gtab, **model_params)
3738
3743
 
3739
- # Output volumes initialized to zero
3740
3744
  FA_vol = np.zeros((X, Y, Z), dtype=np.float32)
3741
3745
  MD_vol = np.zeros((X, Y, Z), dtype=np.float32)
3742
3746
  RGB_vol = np.zeros((X, Y, Z, 3), dtype=np.float32)
3743
3747
  has_tensor_metrics = diffusion_model in ['DTI', 'FreeWater']
3744
3748
 
3745
3749
  def process_chunk(z_start):
3746
- z_end = min(Z, z_start + chunk_size)
3750
+ z_end = min(Z, z_start + slices_per_chunk)
3747
3751
  local_data = img_data[:, :, z_start:z_end, :]
3748
3752
  local_mask = mask[:, :, z_start:z_end]
3749
3753
  masked_data = local_data * local_mask[..., None]
@@ -3758,8 +3762,7 @@ def efficient_dwi_fit(gtab, diffusion_model, imagein, maskin,
3758
3762
  return z_start, z_end, FA, MD, RGB
3759
3763
  return z_start, z_end, None, None, None
3760
3764
 
3761
- # Run processing
3762
- chunks = range(0, Z, chunk_size)
3765
+ chunks = range(0, Z, slices_per_chunk)
3763
3766
  if num_threads > 1:
3764
3767
  with ThreadPoolExecutor(max_workers=num_threads) as executor:
3765
3768
  futures = {executor.submit(process_chunk, z): z for z in chunks}
@@ -4455,7 +4458,7 @@ def dwi_deterministic_tracking(
4455
4458
  gtab = gradient_table(bvals, bvecs=bvecs, atol=2.0 )
4456
4459
  if mask is None:
4457
4460
  mask = ants.threshold_image( fa, fa_thresh, 2.0 ).iMath("GetLargestComponent")
4458
- dwi_data = dwi.numpy() # dwi_img.get_fdata()
4461
+ dwi_data = dwi.numpy()
4459
4462
  dwi_mask = mask.numpy() == 1
4460
4463
  dti_model = dti.TensorModel(gtab,fit_method=fit_method)
4461
4464
  if verbose:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: antspymm
3
- Version: 1.5.1
3
+ Version: 1.5.3
4
4
  Summary: multi-channel/time-series medical image processing with antspyx
5
5
  Author-email: "Avants, Gosselin, Tustison, Reardon" <stnava@gmail.com>
6
6
  License: Apache-2.0
@@ -0,0 +1,7 @@
1
+ antspymm/__init__.py,sha256=DnkidUfEu3Dl0tuWNTA-9VOUkBtH_cROKiPGNNXNagU,4637
2
+ antspymm/mm.py,sha256=8iZxrWenPeLhwc1dxDgvAhgNGZHOahTi1LegOhmHkL8,527319
3
+ antspymm-1.5.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
4
+ antspymm-1.5.3.dist-info/METADATA,sha256=pfNoP9vDefzKmOfRYk5z68qAJXXSmY2ELLLaRioiSHs,25939
5
+ antspymm-1.5.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
6
+ antspymm-1.5.3.dist-info/top_level.txt,sha256=iyD1sRhCKzfwKRJLq5ZUeV9xsv1cGQl8Ejp6QwXM1Zg,9
7
+ antspymm-1.5.3.dist-info/RECORD,,
@@ -1,7 +0,0 @@
1
- antspymm/__init__.py,sha256=DnkidUfEu3Dl0tuWNTA-9VOUkBtH_cROKiPGNNXNagU,4637
2
- antspymm/mm.py,sha256=oPHhV70IhFXCKI26rP5HgKpkb2OjqCWkqoy4cSxJXqA,526866
3
- antspymm-1.5.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
4
- antspymm-1.5.1.dist-info/METADATA,sha256=_I4UmZGWLM6KkmTJc21wKW1DrjT2TY723C1jr7LA3Fw,25939
5
- antspymm-1.5.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
6
- antspymm-1.5.1.dist-info/top_level.txt,sha256=iyD1sRhCKzfwKRJLq5ZUeV9xsv1cGQl8Ejp6QwXM1Zg,9
7
- antspymm-1.5.1.dist-info/RECORD,,