5
5
import gzip
6
6
from hashlib import sha1
7
7
from decimal import Decimal
8
- from copy import copy
8
+ from copy import copy
9
9
10
10
import numpy as np
11
11
@@ -379,8 +379,54 @@ class Fake(object):
379
379
setattr (fake_frame , seq_name , [fake_element ])
380
380
frames .append (fake_frame )
381
381
return frames
382
-
383
-
382
+
383
+
384
+ def fake_shape_dependents (div_seq , sid_seq = None , sid_dim = None ):
385
+ """ Make a fake dictionary of data that ``image_shape`` is dependent on.
386
+
387
+ Parameters
388
+ ----------
389
+ div_seq : list of tuples
390
+ list of values to use for the `DimensionIndexValues` of each frame.
391
+ sid_seq : list of int
392
+ list of values to use for the `StackID` of each frame.
393
+ sid_dim : int
394
+ the index of the column in 'div_seq' to use as 'sid_seq'
395
+ """
396
+ class DimIdxSeqElem (object ):
397
+ def __init__ (self , dip = (0 , 0 ), fgp = None ):
398
+ self .DimensionIndexPointer = dip
399
+ if fgp is not None :
400
+ self .FunctionalGroupPointer = fgp
401
+ class FrmContSeqElem (object ):
402
+ def __init__ (self , div , sid ):
403
+ self .DimensionIndexValues = div
404
+ self .StackID = sid
405
+ class PerFrmFuncGrpSeqElem (object ):
406
+ def __init__ (self , div , sid ):
407
+ self .FrameContentSequence = [FrmContSeqElem (div , sid )]
408
+ # if no StackID values passed in then use the values at index 'sid_dim' in
409
+ # the value for DimensionIndexValues for it
410
+ if sid_seq is None :
411
+ if sid_dim is None :
412
+ sid_dim = 0
413
+ sid_seq = [div [sid_dim ] for div in div_seq ]
414
+ # create the DimensionIndexSequence
415
+ num_of_frames = len (div_seq )
416
+ dim_idx_seq = [DimIdxSeqElem ()] * num_of_frames
417
+ # add an entry for StackID into the DimensionIndexSequence
418
+ if sid_dim is not None :
419
+ sid_tag = pydicom .datadict .tag_for_name ('StackID' )
420
+ fcs_tag = pydicom .datadict .tag_for_name ('FrameContentSequence' )
421
+ dim_idx_seq [sid_dim ] = DimIdxSeqElem (sid_tag , fcs_tag )
422
+ # create the PerFrameFunctionalGroupsSequence
423
+ frames = [PerFrmFuncGrpSeqElem (div , sid )
424
+ for div , sid in zip (div_seq , sid_seq )]
425
+ return {'NumberOfFrames' : num_of_frames ,
426
+ 'DimensionIndexSequence' : dim_idx_seq ,
427
+ 'PerFrameFunctionalGroupsSequence' : frames }
428
+
429
+
384
430
class TestMultiFrameWrapper (TestCase ):
385
431
# Test MultiframeWrapper
386
432
MINIMAL_MF = {
@@ -406,47 +452,66 @@ def test_shape(self):
406
452
assert_raises (AssertionError , getattr , dw , 'image_shape' )
407
453
fake_mf ['NumberOfFrames' ] = 4
408
454
# PerFrameFunctionalGroupsSequence does not match NumberOfFrames
409
- assert_raises (AssertionError , getattr , dw , 'image_shape' )
410
- # Make some fake frame data for 3D
411
-
412
- def my_fake_frames (div_seq ):
413
- return fake_frames ('FrameContentSequence' ,
414
- 'DimensionIndexValues' ,
415
- div_seq )
416
- div_seq = ((1 , 1 ), (1 , 2 ), (1 , 3 ), (1 , 4 ))
417
- frames = my_fake_frames (div_seq )
418
- fake_mf ['PerFrameFunctionalGroupsSequence' ] = frames
455
+ assert_raises (AssertionError , getattr , dw , 'image_shape' )
456
+ # check 3D shape when StackID index is 0
457
+ div_seq = ((1 , 1 ), (1 , 2 ), (1 , 3 ), (1 , 4 ))
458
+ fake_mf .update (fake_shape_dependents (div_seq , sid_dim = 0 ))
419
459
assert_equal (MFW (fake_mf ).image_shape , (32 , 64 , 4 ))
420
- # Check stack number matching
460
+ # Check stack number matching when StackID index is 0
421
461
div_seq = ((1 , 1 ), (1 , 2 ), (1 , 3 ), (2 , 4 ))
422
- frames = my_fake_frames (div_seq )
423
- fake_mf ['PerFrameFunctionalGroupsSequence' ] = frames
462
+ fake_mf .update (fake_shape_dependents (div_seq , sid_dim = 0 ))
424
463
assert_raises (didw .WrapperError , getattr , MFW (fake_mf ), 'image_shape' )
425
- # Make some fake frame data for 4D
426
- fake_mf ['NumberOfFrames' ] = 6
464
+ # Make some fake frame data for 4D when StackID index is 0
427
465
div_seq = ((1 , 1 , 1 ), (1 , 2 , 1 ), (1 , 1 , 2 ), (1 , 2 , 2 ),
428
- (1 , 1 , 3 ), (1 , 2 , 3 ))
429
- frames = my_fake_frames (div_seq )
430
- fake_mf ['PerFrameFunctionalGroupsSequence' ] = frames
466
+ (1 , 1 , 3 ), (1 , 2 , 3 ))
467
+ fake_mf .update (fake_shape_dependents (div_seq , sid_dim = 0 ))
431
468
assert_equal (MFW (fake_mf ).image_shape , (32 , 64 , 2 , 3 ))
432
- # Check stack number matching for 4D
469
+ # Check stack number matching for 4D when StackID index is 0
433
470
div_seq = ((1 , 1 , 1 ), (1 , 2 , 1 ), (1 , 1 , 2 ), (1 , 2 , 2 ),
434
- (1 , 1 , 3 ), (2 , 2 , 3 ))
435
- frames = my_fake_frames (div_seq )
436
- fake_mf ['PerFrameFunctionalGroupsSequence' ] = frames
471
+ (1 , 1 , 3 ), (2 , 2 , 3 ))
472
+ fake_mf .update (fake_shape_dependents (div_seq , sid_dim = 0 ))
437
473
assert_raises (didw .WrapperError , getattr , MFW (fake_mf ), 'image_shape' )
438
- # Check indices can be non-contiguous
474
+ # Check indices can be non-contiguous when StackID index is 0
439
475
div_seq = ((1 , 1 , 1 ), (1 , 2 , 1 ), (1 , 1 , 3 ), (1 , 2 , 3 ))
440
- frames = my_fake_frames (div_seq )
441
- fake_mf ['NumberOfFrames' ] = 4
442
- fake_mf ['PerFrameFunctionalGroupsSequence' ] = frames
476
+ fake_mf .update (fake_shape_dependents (div_seq , sid_dim = 0 ))
443
477
assert_equal (MFW (fake_mf ).image_shape , (32 , 64 , 2 , 2 ))
444
- # Check indices can include zero
478
+ # Check indices can include zero when StackID index is 0
445
479
div_seq = ((1 , 1 , 0 ), (1 , 2 , 0 ), (1 , 1 , 3 ), (1 , 2 , 3 ))
446
- frames = my_fake_frames (div_seq )
447
- fake_mf ['NumberOfFrames' ] = 4
448
- fake_mf ['PerFrameFunctionalGroupsSequence' ] = frames
480
+ fake_mf .update (fake_shape_dependents (div_seq , sid_dim = 0 ))
449
481
assert_equal (MFW (fake_mf ).image_shape , (32 , 64 , 2 , 2 ))
482
+ # check 3D shape when there is no StackID index
483
+ div_seq = ((1 ,), (2 ,), (3 ,), (4 ,))
484
+ sid_seq = (1 , 1 , 1 , 1 )
485
+ fake_mf .update (fake_shape_dependents (div_seq , sid_seq = sid_seq ))
486
+ assert_equal (MFW (fake_mf ).image_shape , (32 , 64 , 4 ))
487
+ # check 3D stack number matching when there is no StackID index
488
+ div_seq = ((1 ,), (2 ,), (3 ,), (4 ,))
489
+ sid_seq = (1 , 1 , 1 , 2 )
490
+ fake_mf .update (fake_shape_dependents (div_seq , sid_seq = sid_seq ))
491
+ assert_raises (didw .WrapperError , getattr , MFW (fake_mf ), 'image_shape' )
492
+ # check 4D shape when there is no StackID index
493
+ div_seq = ((1 , 1 ), (2 , 1 ), (1 , 2 ), (2 , 2 ), (1 , 3 ), (2 , 3 ))
494
+ sid_seq = (1 , 1 , 1 , 1 , 1 , 1 )
495
+ fake_mf .update (fake_shape_dependents (div_seq , sid_seq = sid_seq ))
496
+ assert_equal (MFW (fake_mf ).image_shape , (32 , 64 , 2 , 3 ))
497
+ # check 4D stack number matching when there is no StackID index
498
+ div_seq = ((1 , 1 ), (2 , 1 ), (1 , 2 ), (2 , 2 ), (1 , 3 ), (2 , 3 ))
499
+ sid_seq = (1 , 1 , 1 , 1 , 1 , 2 )
500
+ fake_mf .update (fake_shape_dependents (div_seq , sid_seq = sid_seq ))
501
+ assert_raises (didw .WrapperError , getattr , MFW (fake_mf ), 'image_shape' )
502
+ # check 3D shape when StackID index is 1
503
+ div_seq = ((1 , 1 ), (2 , 1 ), (3 , 1 ), (4 , 1 ))
504
+ fake_mf .update (fake_shape_dependents (div_seq , sid_dim = 1 ))
505
+ assert_equal (MFW (fake_mf ).image_shape , (32 , 64 , 4 ))
506
+ # Check stack number matching when StackID index is 1
507
+ div_seq = ((1 , 1 ), (2 , 1 ), (3 , 2 ), (4 , 1 ))
508
+ fake_mf .update (fake_shape_dependents (div_seq , sid_dim = 1 ))
509
+ assert_raises (didw .WrapperError , getattr , MFW (fake_mf ), 'image_shape' )
510
+ # Make some fake frame data for 4D when StackID index is 1
511
+ div_seq = ((1 , 1 , 1 ), (2 , 1 , 1 ), (1 , 1 , 2 ), (2 , 1 , 2 ),
512
+ (1 , 1 , 3 ), (2 , 1 , 3 ))
513
+ fake_mf .update (fake_shape_dependents (div_seq , sid_dim = 1 ))
514
+ assert_equal (MFW (fake_mf ).image_shape , (32 , 64 , 2 , 3 ))
450
515
451
516
def test_iop (self ):
452
517
# Test Image orient patient for multiframe
@@ -562,12 +627,9 @@ def test_data_fake(self):
562
627
assert_raises (didw .WrapperError , dw .get_data )
563
628
# Make shape and indices
564
629
fake_mf ['Rows' ] = 2
565
- fake_mf ['Columns' ] = 3
566
- fake_mf ['NumberOfFrames' ] = 4
567
- frames = fake_frames ('FrameContentSequence' ,
568
- 'DimensionIndexValues' ,
569
- ((1 , 1 ), (1 , 2 ), (1 , 3 ), (1 , 4 )))
570
- fake_mf ['PerFrameFunctionalGroupsSequence' ] = frames
630
+ fake_mf ['Columns' ] = 3
631
+ dim_idxs = ((1 , 1 ), (1 , 2 ), (1 , 3 ), (1 , 4 ))
632
+ fake_mf .update (fake_shape_dependents (dim_idxs , sid_dim = 0 ))
571
633
assert_equal (MFW (fake_mf ).image_shape , (2 , 3 , 4 ))
572
634
# Still fails - no data
573
635
assert_raises (didw .WrapperError , dw .get_data )
@@ -582,11 +644,9 @@ def test_data_fake(self):
582
644
fake_mf ['RescaleSlope' ] = 2.0
583
645
fake_mf ['RescaleIntercept' ] = - 1
584
646
assert_array_equal (MFW (fake_mf ).get_data (), data * 2.0 - 1 )
585
- # Check slice sorting
586
- frames = fake_frames ('FrameContentSequence' ,
587
- 'DimensionIndexValues' ,
588
- ((1 , 4 ), (1 , 2 ), (1 , 3 ), (1 , 1 )))
589
- fake_mf ['PerFrameFunctionalGroupsSequence' ] = frames
647
+ # Check slice sorting
648
+ dim_idxs = ((1 , 4 ), (1 , 2 ), (1 , 3 ), (1 , 1 ))
649
+ fake_mf .update (fake_shape_dependents (dim_idxs , sid_dim = 0 ))
590
650
sorted_data = data [..., [3 , 1 , 2 , 0 ]]
591
651
fake_mf ['pixel_array' ] = np .rollaxis (sorted_data , 2 )
592
652
assert_array_equal (MFW (fake_mf ).get_data (), data * 2.0 - 1 )
@@ -608,11 +668,7 @@ def test_data_fake(self):
608
668
[1 , 2 , 1 , 2 ],
609
669
[1 , 3 , 1 , 2 ],
610
670
[1 , 1 , 1 , 2 ]]
611
- frames = fake_frames ('FrameContentSequence' ,
612
- 'DimensionIndexValues' ,
613
- dim_idxs )
614
- fake_mf ['PerFrameFunctionalGroupsSequence' ] = frames
615
- fake_mf ['NumberOfFrames' ] = len (frames )
671
+ fake_mf .update (fake_shape_dependents (dim_idxs , sid_dim = 0 ))
616
672
shape = (2 , 3 , 4 , 2 , 2 )
617
673
data = np .arange (np .prod (shape )).reshape (shape )
618
674
sorted_data = data .reshape (shape [:2 ] + (- 1 ,), order = 'F' )
0 commit comments