55import gzip
66from hashlib import sha1
77from decimal import Decimal
8- from copy import copy
8+ from copy import copy
99
1010import numpy as np
1111
@@ -379,8 +379,54 @@ class Fake(object):
379379 setattr (fake_frame , seq_name , [fake_element ])
380380 frames .append (fake_frame )
381381 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+
384430class TestMultiFrameWrapper (TestCase ):
385431 # Test MultiframeWrapper
386432 MINIMAL_MF = {
@@ -406,47 +452,66 @@ def test_shape(self):
406452 assert_raises (AssertionError , getattr , dw , 'image_shape' )
407453 fake_mf ['NumberOfFrames' ] = 4
408454 # 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 ))
419459 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
421461 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 ))
424463 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
427465 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 ))
431468 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
433470 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 ))
437473 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
439475 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 ))
443477 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
445479 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 ))
449481 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 ))
450515
451516 def test_iop (self ):
452517 # Test Image orient patient for multiframe
@@ -562,12 +627,9 @@ def test_data_fake(self):
562627 assert_raises (didw .WrapperError , dw .get_data )
563628 # Make shape and indices
564629 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 ))
571633 assert_equal (MFW (fake_mf ).image_shape , (2 , 3 , 4 ))
572634 # Still fails - no data
573635 assert_raises (didw .WrapperError , dw .get_data )
@@ -582,11 +644,9 @@ def test_data_fake(self):
582644 fake_mf ['RescaleSlope' ] = 2.0
583645 fake_mf ['RescaleIntercept' ] = - 1
584646 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 ))
590650 sorted_data = data [..., [3 , 1 , 2 , 0 ]]
591651 fake_mf ['pixel_array' ] = np .rollaxis (sorted_data , 2 )
592652 assert_array_equal (MFW (fake_mf ).get_data (), data * 2.0 - 1 )
@@ -608,11 +668,7 @@ def test_data_fake(self):
608668 [1 , 2 , 1 , 2 ],
609669 [1 , 3 , 1 , 2 ],
610670 [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 ))
616672 shape = (2 , 3 , 4 , 2 , 2 )
617673 data = np .arange (np .prod (shape )).reshape (shape )
618674 sorted_data = data .reshape (shape [:2 ] + (- 1 ,), order = 'F' )
0 commit comments