dbdicom 0.2.1__py3-none-any.whl → 0.2.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.

Potentially problematic release.


This version of dbdicom might be problematic. Click here for more details.

Files changed (50) hide show
  1. dbdicom/__init__.py +4 -3
  2. dbdicom/create.py +34 -97
  3. dbdicom/dro.py +174 -0
  4. dbdicom/ds/dataset.py +29 -3
  5. dbdicom/ds/types/mr_image.py +18 -7
  6. dbdicom/extensions/__init__.py +10 -0
  7. dbdicom/{wrappers → extensions}/dipy.py +191 -205
  8. dbdicom/extensions/elastix.py +503 -0
  9. dbdicom/extensions/matplotlib.py +107 -0
  10. dbdicom/extensions/numpy.py +271 -0
  11. dbdicom/{wrappers → extensions}/scipy.py +130 -31
  12. dbdicom/{wrappers → extensions}/skimage.py +1 -1
  13. dbdicom/extensions/sklearn.py +243 -0
  14. dbdicom/extensions/vreg.py +1390 -0
  15. dbdicom/external/dcm4che/bin/emf2sf +57 -57
  16. dbdicom/manager.py +70 -36
  17. dbdicom/pipelines.py +66 -0
  18. dbdicom/record.py +266 -43
  19. dbdicom/types/instance.py +17 -3
  20. dbdicom/types/series.py +1900 -404
  21. dbdicom/utils/image.py +152 -21
  22. dbdicom/utils/vreg.py +327 -135
  23. dbdicom-0.2.3.dist-info/METADATA +88 -0
  24. {dbdicom-0.2.1.dist-info → dbdicom-0.2.3.dist-info}/RECORD +27 -41
  25. {dbdicom-0.2.1.dist-info → dbdicom-0.2.3.dist-info}/WHEEL +1 -1
  26. dbdicom/external/__pycache__/__init__.cpython-310.pyc +0 -0
  27. dbdicom/external/__pycache__/__init__.cpython-37.pyc +0 -0
  28. dbdicom/external/dcm4che/__pycache__/__init__.cpython-310.pyc +0 -0
  29. dbdicom/external/dcm4che/__pycache__/__init__.cpython-37.pyc +0 -0
  30. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-310.pyc +0 -0
  31. dbdicom/external/dcm4che/bin/__pycache__/__init__.cpython-37.pyc +0 -0
  32. dbdicom/external/dcm4che/lib/linux-x86/libclib_jiio.so +0 -0
  33. dbdicom/external/dcm4che/lib/linux-x86-64/libclib_jiio.so +0 -0
  34. dbdicom/external/dcm4che/lib/linux-x86-64/libopencv_java.so +0 -0
  35. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio.so +0 -0
  36. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis.so +0 -0
  37. dbdicom/external/dcm4che/lib/solaris-sparc/libclib_jiio_vis2.so +0 -0
  38. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio.so +0 -0
  39. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis.so +0 -0
  40. dbdicom/external/dcm4che/lib/solaris-sparcv9/libclib_jiio_vis2.so +0 -0
  41. dbdicom/external/dcm4che/lib/solaris-x86/libclib_jiio.so +0 -0
  42. dbdicom/external/dcm4che/lib/solaris-x86-64/libclib_jiio.so +0 -0
  43. dbdicom/wrappers/__init__.py +0 -7
  44. dbdicom/wrappers/elastix.py +0 -855
  45. dbdicom/wrappers/numpy.py +0 -119
  46. dbdicom/wrappers/sklearn.py +0 -151
  47. dbdicom/wrappers/vreg.py +0 -273
  48. dbdicom-0.2.1.dist-info/METADATA +0 -276
  49. {dbdicom-0.2.1.dist-info → dbdicom-0.2.3.dist-info}/LICENSE +0 -0
  50. {dbdicom-0.2.1.dist-info → dbdicom-0.2.3.dist-info}/top_level.txt +0 -0
dbdicom/utils/image.py CHANGED
@@ -1,8 +1,94 @@
1
+ import math
1
2
  import numpy as np
2
3
  from scipy.interpolate import interpn
3
4
  from scipy.ndimage import affine_transform
4
5
 
5
6
 
7
+ def as_mosaic(array, rows=None):
8
+ """Reformat a 3D array (x,y,z) into a 2D mosaic"""
9
+
10
+ nz = array.shape[2]
11
+ if rows is None:
12
+ rows = math.ceil(math.sqrt(nz))
13
+ cols = math.ceil(nz/rows)
14
+ mosaic = np.zeros((array.shape[0]*cols, array.shape[1]*rows))
15
+ for k in range(nz):
16
+ j = math.floor(k/cols)
17
+ i = k-j*cols
18
+ mosaic[
19
+ i*array.shape[0]:(i+1)*array.shape[0],
20
+ j*array.shape[1]:(j+1)*array.shape[1],
21
+ ] = array[:,:,k]
22
+ return mosaic
23
+
24
+
25
+
26
+
27
+ def ellipsoid(a, b, c, spacing=(1., 1., 1.), levelset=False):
28
+ """
29
+ Generates ellipsoid with semimajor axes aligned with grid dimensions
30
+ on grid with specified `spacing`.
31
+
32
+ Parameters
33
+ ----------
34
+ a : float
35
+ Length of semimajor axis aligned with x-axis.
36
+ b : float
37
+ Length of semimajor axis aligned with y-axis.
38
+ c : float
39
+ Length of semimajor axis aligned with z-axis.
40
+ spacing : tuple of floats, length 3
41
+ Spacing in (x, y, z) spatial dimensions.
42
+ levelset : bool
43
+ If True, returns the level set for this ellipsoid (signed level
44
+ set about zero, with positive denoting interior) as np.float64.
45
+ False returns a binarized version of said level set.
46
+
47
+ Returns
48
+ -------
49
+ ellip : (N, M, P) array
50
+ Ellipsoid centered in a correctly sized array for given `spacing`.
51
+ Boolean dtype unless `levelset=True`, in which case a float array is
52
+ returned with the level set above 0.0 representing the ellipsoid.
53
+
54
+ Note
55
+ ----
56
+ This function is copy-pasted directly from skimage source code without modification - this to avoid bringing in skimage as an essential dependency.
57
+
58
+ """
59
+ if (a <= 0) or (b <= 0) or (c <= 0):
60
+ raise ValueError('Parameters a, b, and c must all be > 0')
61
+
62
+ offset = np.r_[1, 1, 1] * np.r_[spacing]
63
+
64
+ # Calculate limits, and ensure output volume is odd & symmetric
65
+ low = np.ceil(- np.r_[a, b, c] - offset)
66
+ high = np.floor(np.r_[a, b, c] + offset + 1)
67
+
68
+ for dim in range(3):
69
+ if (high[dim] - low[dim]) % 2 == 0:
70
+ low[dim] -= 1
71
+ num = np.arange(low[dim], high[dim], spacing[dim])
72
+ if 0 not in num:
73
+ low[dim] -= np.max(num[num < 0])
74
+
75
+ # Generate (anisotropic) spatial grid
76
+ x, y, z = np.mgrid[low[0]:high[0]:spacing[0],
77
+ low[1]:high[1]:spacing[1],
78
+ low[2]:high[2]:spacing[2]]
79
+
80
+ if not levelset:
81
+ arr = ((x / float(a)) ** 2 +
82
+ (y / float(b)) ** 2 +
83
+ (z / float(c)) ** 2) <= 1
84
+ else:
85
+ arr = ((x / float(a)) ** 2 +
86
+ (y / float(b)) ** 2 +
87
+ (z / float(c)) ** 2) - 1
88
+
89
+ return arr
90
+
91
+
6
92
  def multislice_affine_transform(array_source, affine_source, output_affine, slice_thickness=None, **kwargs):
7
93
  """Generalization of scipy's affine transform.
8
94
 
@@ -370,10 +456,10 @@ def affine_matrix( # single slice function
370
456
  return affine
371
457
 
372
458
 
373
- def slice_location(
374
- image_orientation, # ImageOrientationPatient
375
- image_position, # ImagePositionPatient
376
- ):
459
+ def slice_location(
460
+ image_orientation:list, # ImageOrientationPatient
461
+ image_position:list, # ImagePositionPatient
462
+ ) -> float:
377
463
  """Calculate Slice Location"""
378
464
 
379
465
  row_cosine = np.array(image_orientation[:3])
@@ -383,6 +469,27 @@ def slice_location(
383
469
  return np.dot(np.array(image_position), slice_cosine)
384
470
 
385
471
 
472
+ def image_position_from_slice_location(slice_location:float, affine=np.eye(4))->list:
473
+ v = dismantle_affine_matrix(affine)
474
+ return list(affine[:3, 3] + slice_location * np.array(v['slice_cosine']))
475
+
476
+
477
+ def image_position_patient(affine, number_of_slices):
478
+ slab = dismantle_affine_matrix(affine)
479
+ image_positions = []
480
+ image_locations = []
481
+ for s in range(number_of_slices):
482
+ pos = [
483
+ slab['ImagePositionPatient'][i]
484
+ + s*slab['SpacingBetweenSlices']*slab['slice_cosine'][i]
485
+ for i in range(3)
486
+ ]
487
+ loc = np.dot(np.array(pos), np.array(slab['slice_cosine']))
488
+ image_positions.append(pos)
489
+ image_locations.append(loc)
490
+ return image_positions, image_locations
491
+
492
+
386
493
  def affine_matrix_multislice(
387
494
  image_orientation, # ImageOrientationPatient (assume same for all slices)
388
495
  image_positions, # ImagePositionPatient for all slices
@@ -442,22 +549,6 @@ def affine_to_RAH(affine):
442
549
  return np.matmul(rot_180, affine)
443
550
 
444
551
 
445
- def image_position_patient(affine, number_of_slices):
446
- slab = dismantle_affine_matrix(affine)
447
- image_positions = []
448
- image_locations = []
449
- for s in range(number_of_slices):
450
- pos = [
451
- slab['ImagePositionPatient'][i]
452
- + s*slab['SpacingBetweenSlices']*slab['slice_cosine'][i]
453
- for i in range(3)
454
- ]
455
- loc = np.dot(np.array(pos), np.array(slab['slice_cosine']))
456
- image_positions.append(pos)
457
- image_locations.append(loc)
458
- return image_positions, image_locations
459
-
460
-
461
552
  def clip(array, value_range = None):
462
553
 
463
554
  array[np.isnan(array)] = 0
@@ -467,7 +558,47 @@ def clip(array, value_range = None):
467
558
  return np.clip(array, value_range[0], value_range[1])
468
559
 
469
560
 
470
- def scale_to_range(array, bits_allocated):
561
+ def scale_to_range(array, bits_allocated, signed=False):
562
+
563
+ range = 2.0**bits_allocated - 1
564
+ if signed:
565
+ minval = -2.0**(bits_allocated-1)
566
+ else:
567
+ minval = 0
568
+ maximum = np.amax(array)
569
+ minimum = np.amin(array)
570
+ if maximum == minimum:
571
+ slope = 1
572
+ else:
573
+ slope = range / (maximum - minimum)
574
+ intercept = -slope * minimum + minval
575
+ array *= slope
576
+ array += intercept
577
+
578
+ if bits_allocated == 8:
579
+ if signed:
580
+ return array.astype(np.int8), slope, intercept
581
+ else:
582
+ return array.astype(np.uint8), slope, intercept
583
+ if bits_allocated == 16:
584
+ if signed:
585
+ return array.astype(np.int16), slope, intercept
586
+ else:
587
+ return array.astype(np.uint16), slope, intercept
588
+ if bits_allocated == 32:
589
+ if signed:
590
+ return array.astype(np.int32), slope, intercept
591
+ else:
592
+ return array.astype(np.uint32), slope, intercept
593
+ if bits_allocated == 64:
594
+ if signed:
595
+ return array.astype(np.int64), slope, intercept
596
+ else:
597
+ return array.astype(np.uint64), slope, intercept
598
+
599
+
600
+ def _scale_to_range(array, bits_allocated):
601
+ # Obsolete - generalized as above
471
602
 
472
603
  range = 2.0**bits_allocated - 1
473
604
  maximum = np.amax(array)