neuroreg 0.2.0.dev0__tar.gz → 0.4.0.dev0__tar.gz

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.
Files changed (75) hide show
  1. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/PKG-INFO +162 -13
  2. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/README.md +161 -12
  3. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/__init__.py +2 -0
  4. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/cli/coreg.py +1 -1
  5. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/cli/lta.py +194 -6
  6. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/cli/robreg.py +12 -21
  7. neuroreg-0.4.0.dev0/neuroreg/cli/segreg.py +264 -0
  8. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/image/__init__.py +4 -1
  9. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/image/map.py +136 -17
  10. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/gd.py +11 -18
  11. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/irls.py +3 -3
  12. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/powell.py +7 -12
  13. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/robreg.py +2 -2
  14. neuroreg-0.4.0.dev0/neuroreg/segreg/__init__.py +10 -0
  15. neuroreg-0.4.0.dev0/neuroreg/segreg/atlas.py +164 -0
  16. neuroreg-0.4.0.dev0/neuroreg/segreg/centroids.py +237 -0
  17. neuroreg-0.4.0.dev0/neuroreg/segreg/data/fsaverage_centroids.json +217 -0
  18. neuroreg-0.4.0.dev0/neuroreg/segreg/data/fsaverage_data.json +62 -0
  19. neuroreg-0.4.0.dev0/neuroreg/segreg/io.py +89 -0
  20. neuroreg-0.4.0.dev0/neuroreg/segreg/labels.py +105 -0
  21. neuroreg-0.4.0.dev0/neuroreg/segreg/points.py +368 -0
  22. neuroreg-0.4.0.dev0/neuroreg/segreg/register.py +442 -0
  23. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/transforms/__init__.py +14 -0
  24. neuroreg-0.4.0.dev0/neuroreg/transforms/afni.py +150 -0
  25. neuroreg-0.4.0.dev0/neuroreg/transforms/antsmat.py +146 -0
  26. neuroreg-0.4.0.dev0/neuroreg/transforms/fsl.py +252 -0
  27. neuroreg-0.4.0.dev0/neuroreg/transforms/itk.py +203 -0
  28. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/transforms/lta.py +98 -36
  29. neuroreg-0.4.0.dev0/neuroreg/transforms/niftyreg.py +118 -0
  30. neuroreg-0.4.0.dev0/neuroreg/transforms/regdat.py +206 -0
  31. neuroreg-0.4.0.dev0/neuroreg/transforms/xfm.py +226 -0
  32. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg.egg-info/PKG-INFO +162 -13
  33. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg.egg-info/SOURCES.txt +20 -2
  34. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg.egg-info/entry_points.txt +1 -0
  35. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/pyproject.toml +5 -1
  36. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/tests/test_coreg.py +2 -2
  37. neuroreg-0.4.0.dev0/tests/test_lta.py +861 -0
  38. neuroreg-0.4.0.dev0/tests/test_segreg.py +559 -0
  39. neuroreg-0.2.0.dev0/tests/test_lta_diff.py +0 -397
  40. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/LICENSE +0 -0
  41. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/_sys_info.py +0 -0
  42. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/_version.py +0 -0
  43. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/bbreg/__init__.py +0 -0
  44. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/bbreg/cost.py +0 -0
  45. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/bbreg/io.py +0 -0
  46. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/bbreg/optimize.py +0 -0
  47. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/bbreg/projection.py +0 -0
  48. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/bbreg/register.py +0 -0
  49. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/bbreg/sampling.py +0 -0
  50. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/cli/__init__.py +0 -0
  51. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/cli/bbreg.py +0 -0
  52. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/cli/sys_info.py +0 -0
  53. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/image/centroid.py +0 -0
  54. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/image/pyramid.py +0 -0
  55. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/image/segmentation.py +0 -0
  56. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/image/smooth.py +0 -0
  57. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/__init__.py +0 -0
  58. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/coreg.py +0 -0
  59. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/device.py +0 -0
  60. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/init.py +0 -0
  61. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/losses.py +0 -0
  62. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/optimize.py +0 -0
  63. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/reg_model.py +0 -0
  64. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/imreg/robust.py +0 -0
  65. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/transforms/matrices.py +0 -0
  66. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg/transforms/metrics.py +0 -0
  67. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg.egg-info/dependency_links.txt +0 -0
  68. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg.egg-info/requires.txt +0 -0
  69. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/neuroreg.egg-info/top_level.txt +0 -0
  70. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/setup.cfg +0 -0
  71. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/tests/test_bbreg.py +0 -0
  72. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/tests/test_cli.py +0 -0
  73. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/tests/test_irls.py +0 -0
  74. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/tests/test_robreg.py +0 -0
  75. {neuroreg-0.2.0.dev0 → neuroreg-0.4.0.dev0}/tests/test_robust_weights.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: neuroreg
3
- Version: 0.2.0.dev0
3
+ Version: 0.4.0.dev0
4
4
  Summary: A package for 3D neuroimaging registration with PyTorch.
5
5
  Author: Martin Reuter
6
6
  Maintainer: Martin Reuter
@@ -105,7 +105,9 @@ The main user-facing tools are:
105
105
  (Powell-based by default, analogous to FreeSurfer/SPM `mri_coreg`)
106
106
  - **`bbreg`** – boundary-based registration using cortical WM surfaces or segmentations
107
107
  (extending FreeSurfer's `bbregister`)
108
- - **`lta`** – transform comparison / inversion / concatenation utilities
108
+ - **`segreg`** – segmentation-based registration via label centroids
109
+ (rigid/affine, including atlas-centroid and upright/self-flip modes)
110
+ - **`lta`** – transform comparison, inversion, concatenation, and conversion utilities
109
111
 
110
112
  This project is a work-in-progress in an early development stage. It is developed by
111
113
  the creator of FreeSurfer's `mri_robust_register` as an efficient pure Python
@@ -312,15 +314,65 @@ Run `bbreg -h` for a full argument summary with defaults.
312
314
 
313
315
  ---
314
316
 
315
- ### `lta` — LTA transform utilities
317
+ ### `segreg` — segmentation-based registration
316
318
 
317
- Unified command for manipulating FreeSurfer LTA transform files with three
318
- subcommands: `diff`, `invert`, and `concat`.
319
+ Registers a moving segmentation by aligning label centroids to another
320
+ segmentation, to bundled atlas centroids such as `fsaverage`, or to a
321
+ left-right flipped self target for upright/midspace workflows. The centroid
322
+ fit now supports translation-only (`3`), rigid (`6`), similarity /
323
+ global-scale (`7`), anisotropic no-shear scaling (`9`), or full affine
324
+ (`12`) transforms.
325
+
326
+ `segreg` can also write mapped outputs while the package does not yet have a
327
+ separate transform-application CLI. If `--movimg` is provided, `--mapmov` and
328
+ `--mapmovhdr` map that intensity image with the recovered transform; otherwise
329
+ those outputs map the moving segmentation itself.
319
330
 
320
331
  ```
321
- lta diff LTA1 [LTA2] [options] # Compare transforms
322
- lta invert INPUT OUTPUT # Invert a transform
323
- lta concat LTA1 LTA2 OUTPUT # Concatenate two transforms
332
+ segreg --mov <moving_seg.mgz> (--ref <ref_seg.mgz> | --ref-centroids <centroids.json> | --atlas fsaverage | --flipped) [options]
333
+ ```
334
+
335
+ **Common outputs**
336
+
337
+ - `--lta FILE` writes the recovered transform as an LTA.
338
+ - `--movimg FILE` provides a separate intensity image for `--mapmov` or `--mapmovhdr`.
339
+ - `--mapmov FILE` writes a resliced mapped output. It maps `--movimg` when provided; otherwise it reslices the moving segmentation itself.
340
+ - `--mapmovhdr FILE` writes a header-only mapped output. It maps `--movimg` when provided; otherwise it remaps the moving segmentation itself.
341
+
342
+ **Examples**
343
+
344
+ ```bash
345
+ # Register a subject segmentation to another segmentation
346
+ segreg --mov sub-01/aparc+aseg.mgz --ref sub-02/aparc+aseg.mgz \
347
+ --lta sub01_to_sub02.lta
348
+
349
+ # Register a segmentation, then map a separate intensity image with the same transform
350
+ segreg --mov subj/mri/aparc+aseg.mgz --movimg subj/mri/orig.mgz --atlas fsaverage \
351
+ --lta subj_to_fsaverage.lta --mapmov orig_in_fsaverage_space.mgz
352
+
353
+ # If --movimg is omitted, --mapmov maps the segmentation itself
354
+ segreg --mov subj/mri/aparc+aseg.mgz --atlas fsaverage \
355
+ --mapmov aparc_aseg_in_fsaverage_space.mgz
356
+
357
+ # Export centroid JSON only
358
+ segreg --mov subj/mri/aparc+aseg.mgz --atlas fsaverage \
359
+ --write-mov-centroids subj_centroids.json --write-ref-centroids fsaverage_centroids.json
360
+ ```
361
+
362
+ Run `segreg -h` for a full argument summary with defaults.
363
+
364
+ ---
365
+
366
+ ### `lta` — LTA and linear-transform utilities
367
+
368
+ Unified command for manipulating FreeSurfer-adjacent linear transforms with four
369
+ subcommands: `diff`, `invert`, `concat`, and `convert`.
370
+
371
+ ```
372
+ lta diff LTA1 [LTA2] [options] # Compare transforms
373
+ lta invert INPUT OUTPUT # Invert a transform
374
+ lta concat LTA1 LTA2 OUTPUT # Concatenate two transforms
375
+ lta convert INPUT OUTPUT [--src-img SRC --dst-img DST] # Convert formats
324
376
  ```
325
377
 
326
378
  ---
@@ -418,8 +470,104 @@ lta concat fMRI_to_T1.lta T1_to_MNI.lta fMRI_to_MNI.lta
418
470
  lta concat moving_to_intermediate.lta intermediate_to_fixed.lta moving_to_fixed.lta
419
471
  ```
420
472
 
473
+ ---
474
+
475
+ #### `lta convert` — Convert between transform formats
476
+
477
+ Converts between `.lta`, `.xfm`, volumetric tkregister `.dat`/`.reg`, FSL `.mat`/`.fslmat`, ITK/ANTs 3D affine text transforms, experimental ANTs Matlab-format affine transforms, experimental AFNI affine text transforms, and NiftyReg affine text matrices by normalizing through an internal RAS-to-RAS `LTA`.
478
+
479
+ **Usage**
480
+
481
+ ```
482
+ lta convert INPUT OUTPUT [--in-format {lta,xfm,fsl,regdat,itk,antsmat,afni,niftyreg}]
483
+ [--out-format {lta,xfm,fsl,regdat,itk,antsmat,afni,niftyreg}]
484
+ [--src-img SRC] [--dst-img DST]
485
+ [--out-type {ras2ras,vox2vox}]
486
+ [--subject SUBJECT] [--fscale FSCALE]
487
+ [--float2int {tkregister,round,floor}]
488
+ ```
489
+
490
+ **Supported formats**
491
+
492
+ - `.lta` — FreeSurfer Linear Transform Array
493
+ - `.xfm` — MNI/MINC linear transform
494
+ - `.dat` — old tkregister volumetric `register.dat` format
495
+ - `.mat` / `.fslmat` — FSL FLIRT affine matrix
496
+ - `.tfm` — ITK/ANTs 3D affine text transform
497
+ - `*GenericAffine.mat` — experimental ANTs / ITK Matlab-format affine transform
498
+ - `.aff12.1D` — experimental AFNI affine text matrix
499
+ - `.niftyreg.txt` — NiftyReg 3D affine text matrix
500
+
421
501
  **Notes**
422
502
 
503
+ - Reading `register.dat` requires both `--src-img` and `--dst-img`, because the
504
+ stored matrix is defined in tkregister coordinates rather than scanner RAS.
505
+ - Reading FSL `.mat` / `.fslmat` also requires both `--src-img` and `--dst-img`,
506
+ because the stored matrix is defined in FSL voxel conventions rather than
507
+ scanner RAS.
508
+ - Reading `.xfm`, ITK/ANTs text affines, experimental ANTs `.mat`, experimental
509
+ AFNI affine text, or NiftyReg text matrices without images still preserves the
510
+ transform matrix, but the resulting LTA geometry blocks stay marked as `valid=0`
511
+ unless you provide `--src-img` and `--dst-img`.
512
+ - Use `--in-format` / `--out-format` for ambiguous filenames such as `.txt`, `.1D`, or `.mat`.
513
+ - ITK/ANTs text support currently targets 3D affine transforms only, not binary or
514
+ composite transform files.
515
+ - Experimental ANTs `.mat` support is implemented via SciPy using ITK Matlab IO semantics.
516
+ - Experimental AFNI support targets affine text matrices in AFNI's DICOM/LPS convention.
517
+ - NiftyReg stores the inverse target-to-source RAS matrix in the file, matching
518
+ FreeSurfer's `lta_convert` handling.
519
+ - `--subject`, `--fscale`, and `--float2int` apply when writing `register.dat`.
520
+ - `--out-type` applies when writing `.lta` output.
521
+
522
+ **Examples**
523
+
524
+ ```bash
525
+ # XFM -> LTA with explicit image geometry
526
+ lta convert talairach.xfm talairach.lta --src-img mov.mgz --dst-img ref.mgz
527
+
528
+ # LTA -> XFM
529
+ lta convert sub01_to_mni.lta sub01_to_mni.xfm
530
+
531
+ # LTA -> tkregister register.dat
532
+ lta convert bold_to_orig.lta bold_to_orig.dat --subject sub-01 --fscale 0.1
533
+
534
+ # tkregister register.dat -> LTA
535
+ lta convert bold_to_orig.dat bold_to_orig.lta --src-img bold.nii.gz --dst-img orig.mgz
536
+
537
+ # LTA -> FSL FLIRT matrix
538
+ lta convert bold_to_orig.lta bold_to_orig.mat
539
+
540
+ # FSL FLIRT matrix -> LTA
541
+ lta convert bold_to_orig.mat bold_to_orig_from_fsl.lta --src-img bold.nii.gz --dst-img orig.mgz
542
+
543
+ # LTA -> ITK/ANTs text affine
544
+ lta convert bold_to_orig.lta bold_to_orig.tfm
545
+
546
+ # ITK/ANTs text affine (.txt requires explicit format override)
547
+ lta convert bold_to_orig.txt bold_to_orig_from_itk.lta --in-format itk --src-img bold.nii.gz --dst-img orig.mgz
548
+
549
+ # LTA -> experimental ANTs GenericAffine .mat
550
+ lta convert bold_to_orig.lta bold_to_orig0GenericAffine.mat
551
+
552
+ # Experimental ANTs GenericAffine .mat -> LTA (.mat is otherwise assumed FSL)
553
+ lta convert bold_to_orig0GenericAffine.mat bold_to_orig_from_antsmat.lta
554
+ lta convert some_affine.mat bold_to_orig_from_antsmat.lta --in-format antsmat
555
+
556
+ # LTA -> experimental AFNI affine text
557
+ lta convert bold_to_orig.lta bold_to_orig.aff12.1D
558
+
559
+ # Experimental AFNI affine text -> LTA (.1D may need explicit format override)
560
+ lta convert bold_to_orig.aff12.1D bold_to_orig_from_afni.lta
561
+
562
+ # LTA -> NiftyReg affine text matrix (.txt requires explicit format override)
563
+ lta convert bold_to_orig.lta bold_to_orig.txt --out-format niftyreg
564
+
565
+ # NiftyReg affine text matrix -> LTA
566
+ lta convert bold_to_orig.txt bold_to_orig_from_niftyreg.lta --in-format niftyreg
567
+ ```
568
+
569
+ **General notes**
570
+
423
571
  - All metrics are numerically matched to FreeSurfer's `lta_diff` (except for a
424
572
  known bug in the C++ single-transform corner metric, which is fixed here).
425
573
  - When only one LTA is supplied to `diff`, the transform is compared against identity.
@@ -486,11 +634,12 @@ transform_bbreg, model_bbreg = bbreg(
486
634
 
487
635
  Current DOF support is:
488
636
 
489
- | Command / API path | Supported DOF |
490
- |------------------------------|---------------------|
491
- | `robreg` / public `robreg()` | `6` only |
492
- | `coreg` / public `coreg()` | `3`, `6`, `9`, `12` |
493
- | `bbreg` / public `bbreg()` | `6`, `9`, `12` |
637
+ | Command / API path | Supported DOF |
638
+ |------------------------------|--------------------------|
639
+ | `robreg` / public `robreg()` | `6` only |
640
+ | `coreg` / public `coreg()` | `3`, `6`, `9`, `12` |
641
+ | `bbreg` / public `bbreg()` | `6`, `9`, `12` |
642
+ | `segreg` / public `segreg()` | `3`, `6`, `7`, `9`, `12` |
494
643
 
495
644
  The public `robreg` path is intentionally rigid-only for now because it tracks
496
645
  the current IRLS implementation.
@@ -15,7 +15,9 @@ The main user-facing tools are:
15
15
  (Powell-based by default, analogous to FreeSurfer/SPM `mri_coreg`)
16
16
  - **`bbreg`** – boundary-based registration using cortical WM surfaces or segmentations
17
17
  (extending FreeSurfer's `bbregister`)
18
- - **`lta`** – transform comparison / inversion / concatenation utilities
18
+ - **`segreg`** – segmentation-based registration via label centroids
19
+ (rigid/affine, including atlas-centroid and upright/self-flip modes)
20
+ - **`lta`** – transform comparison, inversion, concatenation, and conversion utilities
19
21
 
20
22
  This project is a work-in-progress in an early development stage. It is developed by
21
23
  the creator of FreeSurfer's `mri_robust_register` as an efficient pure Python
@@ -222,15 +224,65 @@ Run `bbreg -h` for a full argument summary with defaults.
222
224
 
223
225
  ---
224
226
 
225
- ### `lta` — LTA transform utilities
227
+ ### `segreg` — segmentation-based registration
226
228
 
227
- Unified command for manipulating FreeSurfer LTA transform files with three
228
- subcommands: `diff`, `invert`, and `concat`.
229
+ Registers a moving segmentation by aligning label centroids to another
230
+ segmentation, to bundled atlas centroids such as `fsaverage`, or to a
231
+ left-right flipped self target for upright/midspace workflows. The centroid
232
+ fit now supports translation-only (`3`), rigid (`6`), similarity /
233
+ global-scale (`7`), anisotropic no-shear scaling (`9`), or full affine
234
+ (`12`) transforms.
235
+
236
+ `segreg` can also write mapped outputs while the package does not yet have a
237
+ separate transform-application CLI. If `--movimg` is provided, `--mapmov` and
238
+ `--mapmovhdr` map that intensity image with the recovered transform; otherwise
239
+ those outputs map the moving segmentation itself.
229
240
 
230
241
  ```
231
- lta diff LTA1 [LTA2] [options] # Compare transforms
232
- lta invert INPUT OUTPUT # Invert a transform
233
- lta concat LTA1 LTA2 OUTPUT # Concatenate two transforms
242
+ segreg --mov <moving_seg.mgz> (--ref <ref_seg.mgz> | --ref-centroids <centroids.json> | --atlas fsaverage | --flipped) [options]
243
+ ```
244
+
245
+ **Common outputs**
246
+
247
+ - `--lta FILE` writes the recovered transform as an LTA.
248
+ - `--movimg FILE` provides a separate intensity image for `--mapmov` or `--mapmovhdr`.
249
+ - `--mapmov FILE` writes a resliced mapped output. It maps `--movimg` when provided; otherwise it reslices the moving segmentation itself.
250
+ - `--mapmovhdr FILE` writes a header-only mapped output. It maps `--movimg` when provided; otherwise it remaps the moving segmentation itself.
251
+
252
+ **Examples**
253
+
254
+ ```bash
255
+ # Register a subject segmentation to another segmentation
256
+ segreg --mov sub-01/aparc+aseg.mgz --ref sub-02/aparc+aseg.mgz \
257
+ --lta sub01_to_sub02.lta
258
+
259
+ # Register a segmentation, then map a separate intensity image with the same transform
260
+ segreg --mov subj/mri/aparc+aseg.mgz --movimg subj/mri/orig.mgz --atlas fsaverage \
261
+ --lta subj_to_fsaverage.lta --mapmov orig_in_fsaverage_space.mgz
262
+
263
+ # If --movimg is omitted, --mapmov maps the segmentation itself
264
+ segreg --mov subj/mri/aparc+aseg.mgz --atlas fsaverage \
265
+ --mapmov aparc_aseg_in_fsaverage_space.mgz
266
+
267
+ # Export centroid JSON only
268
+ segreg --mov subj/mri/aparc+aseg.mgz --atlas fsaverage \
269
+ --write-mov-centroids subj_centroids.json --write-ref-centroids fsaverage_centroids.json
270
+ ```
271
+
272
+ Run `segreg -h` for a full argument summary with defaults.
273
+
274
+ ---
275
+
276
+ ### `lta` — LTA and linear-transform utilities
277
+
278
+ Unified command for manipulating FreeSurfer-adjacent linear transforms with four
279
+ subcommands: `diff`, `invert`, `concat`, and `convert`.
280
+
281
+ ```
282
+ lta diff LTA1 [LTA2] [options] # Compare transforms
283
+ lta invert INPUT OUTPUT # Invert a transform
284
+ lta concat LTA1 LTA2 OUTPUT # Concatenate two transforms
285
+ lta convert INPUT OUTPUT [--src-img SRC --dst-img DST] # Convert formats
234
286
  ```
235
287
 
236
288
  ---
@@ -328,8 +380,104 @@ lta concat fMRI_to_T1.lta T1_to_MNI.lta fMRI_to_MNI.lta
328
380
  lta concat moving_to_intermediate.lta intermediate_to_fixed.lta moving_to_fixed.lta
329
381
  ```
330
382
 
383
+ ---
384
+
385
+ #### `lta convert` — Convert between transform formats
386
+
387
+ Converts between `.lta`, `.xfm`, volumetric tkregister `.dat`/`.reg`, FSL `.mat`/`.fslmat`, ITK/ANTs 3D affine text transforms, experimental ANTs Matlab-format affine transforms, experimental AFNI affine text transforms, and NiftyReg affine text matrices by normalizing through an internal RAS-to-RAS `LTA`.
388
+
389
+ **Usage**
390
+
391
+ ```
392
+ lta convert INPUT OUTPUT [--in-format {lta,xfm,fsl,regdat,itk,antsmat,afni,niftyreg}]
393
+ [--out-format {lta,xfm,fsl,regdat,itk,antsmat,afni,niftyreg}]
394
+ [--src-img SRC] [--dst-img DST]
395
+ [--out-type {ras2ras,vox2vox}]
396
+ [--subject SUBJECT] [--fscale FSCALE]
397
+ [--float2int {tkregister,round,floor}]
398
+ ```
399
+
400
+ **Supported formats**
401
+
402
+ - `.lta` — FreeSurfer Linear Transform Array
403
+ - `.xfm` — MNI/MINC linear transform
404
+ - `.dat` — old tkregister volumetric `register.dat` format
405
+ - `.mat` / `.fslmat` — FSL FLIRT affine matrix
406
+ - `.tfm` — ITK/ANTs 3D affine text transform
407
+ - `*GenericAffine.mat` — experimental ANTs / ITK Matlab-format affine transform
408
+ - `.aff12.1D` — experimental AFNI affine text matrix
409
+ - `.niftyreg.txt` — NiftyReg 3D affine text matrix
410
+
331
411
  **Notes**
332
412
 
413
+ - Reading `register.dat` requires both `--src-img` and `--dst-img`, because the
414
+ stored matrix is defined in tkregister coordinates rather than scanner RAS.
415
+ - Reading FSL `.mat` / `.fslmat` also requires both `--src-img` and `--dst-img`,
416
+ because the stored matrix is defined in FSL voxel conventions rather than
417
+ scanner RAS.
418
+ - Reading `.xfm`, ITK/ANTs text affines, experimental ANTs `.mat`, experimental
419
+ AFNI affine text, or NiftyReg text matrices without images still preserves the
420
+ transform matrix, but the resulting LTA geometry blocks stay marked as `valid=0`
421
+ unless you provide `--src-img` and `--dst-img`.
422
+ - Use `--in-format` / `--out-format` for ambiguous filenames such as `.txt`, `.1D`, or `.mat`.
423
+ - ITK/ANTs text support currently targets 3D affine transforms only, not binary or
424
+ composite transform files.
425
+ - Experimental ANTs `.mat` support is implemented via SciPy using ITK Matlab IO semantics.
426
+ - Experimental AFNI support targets affine text matrices in AFNI's DICOM/LPS convention.
427
+ - NiftyReg stores the inverse target-to-source RAS matrix in the file, matching
428
+ FreeSurfer's `lta_convert` handling.
429
+ - `--subject`, `--fscale`, and `--float2int` apply when writing `register.dat`.
430
+ - `--out-type` applies when writing `.lta` output.
431
+
432
+ **Examples**
433
+
434
+ ```bash
435
+ # XFM -> LTA with explicit image geometry
436
+ lta convert talairach.xfm talairach.lta --src-img mov.mgz --dst-img ref.mgz
437
+
438
+ # LTA -> XFM
439
+ lta convert sub01_to_mni.lta sub01_to_mni.xfm
440
+
441
+ # LTA -> tkregister register.dat
442
+ lta convert bold_to_orig.lta bold_to_orig.dat --subject sub-01 --fscale 0.1
443
+
444
+ # tkregister register.dat -> LTA
445
+ lta convert bold_to_orig.dat bold_to_orig.lta --src-img bold.nii.gz --dst-img orig.mgz
446
+
447
+ # LTA -> FSL FLIRT matrix
448
+ lta convert bold_to_orig.lta bold_to_orig.mat
449
+
450
+ # FSL FLIRT matrix -> LTA
451
+ lta convert bold_to_orig.mat bold_to_orig_from_fsl.lta --src-img bold.nii.gz --dst-img orig.mgz
452
+
453
+ # LTA -> ITK/ANTs text affine
454
+ lta convert bold_to_orig.lta bold_to_orig.tfm
455
+
456
+ # ITK/ANTs text affine (.txt requires explicit format override)
457
+ lta convert bold_to_orig.txt bold_to_orig_from_itk.lta --in-format itk --src-img bold.nii.gz --dst-img orig.mgz
458
+
459
+ # LTA -> experimental ANTs GenericAffine .mat
460
+ lta convert bold_to_orig.lta bold_to_orig0GenericAffine.mat
461
+
462
+ # Experimental ANTs GenericAffine .mat -> LTA (.mat is otherwise assumed FSL)
463
+ lta convert bold_to_orig0GenericAffine.mat bold_to_orig_from_antsmat.lta
464
+ lta convert some_affine.mat bold_to_orig_from_antsmat.lta --in-format antsmat
465
+
466
+ # LTA -> experimental AFNI affine text
467
+ lta convert bold_to_orig.lta bold_to_orig.aff12.1D
468
+
469
+ # Experimental AFNI affine text -> LTA (.1D may need explicit format override)
470
+ lta convert bold_to_orig.aff12.1D bold_to_orig_from_afni.lta
471
+
472
+ # LTA -> NiftyReg affine text matrix (.txt requires explicit format override)
473
+ lta convert bold_to_orig.lta bold_to_orig.txt --out-format niftyreg
474
+
475
+ # NiftyReg affine text matrix -> LTA
476
+ lta convert bold_to_orig.txt bold_to_orig_from_niftyreg.lta --in-format niftyreg
477
+ ```
478
+
479
+ **General notes**
480
+
333
481
  - All metrics are numerically matched to FreeSurfer's `lta_diff` (except for a
334
482
  known bug in the C++ single-transform corner metric, which is fixed here).
335
483
  - When only one LTA is supplied to `diff`, the transform is compared against identity.
@@ -396,11 +544,12 @@ transform_bbreg, model_bbreg = bbreg(
396
544
 
397
545
  Current DOF support is:
398
546
 
399
- | Command / API path | Supported DOF |
400
- |------------------------------|---------------------|
401
- | `robreg` / public `robreg()` | `6` only |
402
- | `coreg` / public `coreg()` | `3`, `6`, `9`, `12` |
403
- | `bbreg` / public `bbreg()` | `6`, `9`, `12` |
547
+ | Command / API path | Supported DOF |
548
+ |------------------------------|--------------------------|
549
+ | `robreg` / public `robreg()` | `6` only |
550
+ | `coreg` / public `coreg()` | `3`, `6`, `9`, `12` |
551
+ | `bbreg` / public `bbreg()` | `6`, `9`, `12` |
552
+ | `segreg` / public `segreg()` | `3`, `6`, `7`, `9`, `12` |
404
553
 
405
554
  The public `robreg` path is intentionally rigid-only for now because it tracks
406
555
  the current IRLS implementation.
@@ -3,6 +3,7 @@ from neuroreg._sys_info import sys_info # noqa: F401
3
3
  from neuroreg.bbreg.register import register_surface as bbreg # noqa: F401
4
4
  from neuroreg.imreg.coreg import coreg # noqa: F401
5
5
  from neuroreg.imreg.robreg import robreg # noqa: F401
6
+ from neuroreg.segreg import segreg # noqa: F401
6
7
  from neuroreg.transforms import ( # noqa: F401
7
8
  LINEAR_RAS_TO_RAS,
8
9
  LINEAR_VOX_TO_VOX,
@@ -14,6 +15,7 @@ __all__ = [
14
15
  "bbreg",
15
16
  "coreg",
16
17
  "robreg",
18
+ "segreg",
17
19
  "sys_info",
18
20
  "LINEAR_RAS_TO_RAS",
19
21
  "LINEAR_VOX_TO_VOX",
@@ -229,7 +229,7 @@ def main(args=None) -> None:
229
229
  v2v = coreg(mov_img, ref_img, **kwargs)
230
230
  v2v_cpu = v2v.detach().cpu()
231
231
 
232
- LTA.from_matrix(v2v_cpu.numpy(), ns.mov, cast(Any, mov_img), ns.ref, cast(Any, ref_img), lta_type=0).write(ns.out)
232
+ LTA.from_matrix(v2v_cpu.numpy(), ns.mov, mov_img, ns.ref, ref_img, lta_type=0).write(ns.out)
233
233
  logger.info("Wrote LTA: %s", ns.out)
234
234
  print(f"Output: {ns.out}")
235
235