5252import net .imagej .axis .CalibratedAxis ;
5353import net .imagej .axis .DefaultLinearAxis ;
5454import net .imagej .space .DefaultCalibratedSpace ;
55+ import net .imglib2 .Cursor ;
5556import net .imglib2 .img .Img ;
5657import net .imglib2 .img .ImgView ;
5758import net .imglib2 .img .array .ArrayImg ;
59+ import net .imglib2 .img .array .ArrayImgFactory ;
5860import net .imglib2 .img .basictypeaccess .array .ArrayDataAccess ;
5961import net .imglib2 .img .basictypeaccess .array .ByteArray ;
6062import net .imglib2 .img .basictypeaccess .array .DoubleArray ;
7476import net .imglib2 .type .numeric .real .DoubleType ;
7577import net .imglib2 .type .numeric .real .FloatType ;
7678import net .imglib2 .util .Fraction ;
79+ import net .imglib2 .view .Views ;
7780
7881/**
7982 * Aggregation operator which merges images.
@@ -467,7 +470,7 @@ private static SettingsModelString createAxisLabelModel() {
467470
468471 private String m_axisLabel ;
469472
470- /* aggregated pixel data */
473+ /* aggregated pixel data (in case of a 2D input) */
471474 private ArrayList <A > m_data = null ;
472475
473476 // dialog components
@@ -484,6 +487,18 @@ private static SettingsModelString createAxisLabelModel() {
484487
485488 private RealTypeHandler <T , A , ADA > m_typeHandler ;
486489
490+ /**
491+ * Required to determine the size of the result image for the nD case (n > 2)
492+ * and keep track of the current position in the result image
493+ */
494+ private long m_rowCount ;
495+ private long m_rowIdx ;
496+
497+ /**
498+ * Result image in case of an input >2D
499+ */
500+ private Img <T > m_resImg ;
501+
487502 public ImgMergeOperator () {
488503 super ("Merge Image" , "Merge Image" , "Merge Image" );
489504 }
@@ -498,7 +513,7 @@ public ImgMergeOperator(final GlobalSettings globalSettings, final String axisLa
498513 m_smAxisLabel .setStringValue (axisLabel );
499514 }
500515 m_axisLabel = m_smAxisLabel .getStringValue ();
501-
516+ m_rowCount = globalSettings . getNoOfRows ();
502517 }
503518
504519 /**
@@ -522,59 +537,70 @@ protected boolean computeInternal(final DataRow row, final DataCell cell) {
522537 }
523538
524539 if (m_dims != null ) {
525- for (int i = 0 ; i < 2 ; i ++) {
540+ for (int i = 0 ; i < m_dims . length - 1 ; i ++) {
526541 if (imgPlus .dimension (i ) != m_dims [i ]) {
527542 throw new IllegalArgumentException (
528543 "Image " + imgPlus .getName () + " not compatible with first-row image. Different dimension!" );
529544 }
530545 }
531-
532546 }
533547
534- if (m_data == null ) {
535- m_type = imgPlus .firstElement ().createVariable ();
536- if (m_type instanceof ByteType ) {
537- m_typeHandler = (RealTypeHandler <T , A , ADA >)new ByteTypeHandler ();
538- } else if (m_type instanceof UnsignedByteType ) {
539- m_typeHandler = (RealTypeHandler <T , A , ADA >)new UnsignedByteTypeHandler ();
540- } else if (m_type instanceof UnsignedShortType ) {
541- m_typeHandler = (RealTypeHandler <T , A , ADA >)new UnsignedShortTypeHandler ();
542- } else if (m_type instanceof ShortType ) {
543- m_typeHandler = (RealTypeHandler <T , A , ADA >)new ShortTypeHandler ();
544- } else if (m_type instanceof IntType ) {
545- m_typeHandler = (RealTypeHandler <T , A , ADA >)new IntTypeHandler ();
546- } else if (m_type instanceof LongType ) {
547- m_typeHandler = (RealTypeHandler <T , A , ADA >)new LongTypeHandler ();
548- } else if (m_type instanceof FloatType ) {
549- m_typeHandler = (RealTypeHandler <T , A , ADA >)new FloatTypeHandler ();
550- } else if (m_type instanceof DoubleType ) {
551- m_typeHandler = (RealTypeHandler <T , A , ADA >)new DoubleTypeHandler ();
552- } else {
553- throw new IllegalArgumentException (
554- "Pixel type " + m_type .getClass ().getSimpleName () + " not supported for merging." );
555- }
556- m_data = new ArrayList <A >();
548+ int numHyperPlanes = -1 ;
549+ int hyperPlaneSize = -1 ;
550+ if (m_data == null && m_resImg == null ) {
551+ //first iteration -> create data structures
557552
558553 final CalibratedAxis [] axes = new CalibratedAxis [imgPlus .numDimensions ()];
559554 imgPlus .axes (axes );
560- final CalibratedAxis [] newAxes = new CalibratedAxis [3 ];
561- for (int i = 0 ; i < 2 ; i ++) {
555+ final CalibratedAxis [] newAxes = new CalibratedAxis [axes . length + 1 ];
556+ for (int i = 0 ; i < axes . length ; i ++) {
562557 newAxes [i ] = axes [i ];
563558 }
564559
565560 //TODO: How to support different types of calibrates spaces/axis.
566- newAxes [2 ] = new DefaultLinearAxis (Axes .get (m_axisLabel ));
561+ newAxes [newAxes . length - 1 ] = new DefaultLinearAxis (Axes .get (m_axisLabel ));
567562 m_metadata = new DefaultImgMetadata (new DefaultCalibratedSpace (newAxes ), imgPlus , imgPlus , imgPlus );
568- m_dims = new long [3 ];
569- m_dims [0 ] = imgPlus .dimension (0 );
570- m_dims [1 ] = imgPlus .dimension (1 );
563+ m_dims = new long [newAxes .length ];
564+ imgPlus .dimensions (m_dims );
571565
566+ m_type = imgPlus .firstElement ().createVariable ();
567+ if (imgPlus .numDimensions () == 2 ) {
568+ hyperPlaneSize = 1 ;
569+ for (int i = 0 ; i < imgPlus .numDimensions (); i ++) {
570+ hyperPlaneSize *=imgPlus .dimension (i );
571+ }
572+ numHyperPlanes = (int )(imgPlus .size () / hyperPlaneSize );
573+ m_dims [m_dims .length - 1 ] += numHyperPlanes ;
574+
575+ if (m_type instanceof ByteType ) {
576+ m_typeHandler = (RealTypeHandler <T , A , ADA >)new ByteTypeHandler ();
577+ } else if (m_type instanceof UnsignedByteType ) {
578+ m_typeHandler = (RealTypeHandler <T , A , ADA >)new UnsignedByteTypeHandler ();
579+ } else if (m_type instanceof UnsignedShortType ) {
580+ m_typeHandler = (RealTypeHandler <T , A , ADA >)new UnsignedShortTypeHandler ();
581+ } else if (m_type instanceof ShortType ) {
582+ m_typeHandler = (RealTypeHandler <T , A , ADA >)new ShortTypeHandler ();
583+ } else if (m_type instanceof IntType ) {
584+ m_typeHandler = (RealTypeHandler <T , A , ADA >)new IntTypeHandler ();
585+ } else if (m_type instanceof LongType ) {
586+ m_typeHandler = (RealTypeHandler <T , A , ADA >)new LongTypeHandler ();
587+ } else if (m_type instanceof FloatType ) {
588+ m_typeHandler = (RealTypeHandler <T , A , ADA >)new FloatTypeHandler ();
589+ } else if (m_type instanceof DoubleType ) {
590+ m_typeHandler = (RealTypeHandler <T , A , ADA >)new DoubleTypeHandler ();
591+ } else {
592+ throw new IllegalArgumentException (
593+ "Pixel type " + m_type .getClass ().getSimpleName () + " not supported for merging." );
594+ }
595+ m_data = new ArrayList <A >();
596+ } else {
597+ //create res img
598+ m_dims [m_dims .length - 1 ] = m_rowCount ;
599+ m_resImg = new ArrayImgFactory ().create (m_dims , m_type );
600+ m_rowIdx = 0 ;
601+ }
572602 }
573603
574- final int planeSize = (int )(imgPlus .dimension (0 ) * imgPlus .dimension (1 ));
575- final int numPlanes = (int )(imgPlus .size () / planeSize );
576- m_dims [2 ] += numPlanes ;
577-
578604 //in case of a previous virtual operation (img is wrapped in a ImgView), first execute the operation in order to get the 'physical' pixel data
579605 Img <T > img ;
580606 if (imgPlus .getImg () instanceof ImgView ) {
@@ -583,27 +609,41 @@ protected boolean computeInternal(final DataRow row, final DataCell cell) {
583609 img = imgPlus .getImg ();
584610 }
585611
586- // copy data
587- if (img instanceof ArrayImg ) {
588- for (int i = 0 ; i < numPlanes ; i ++) {
589- final A plane = m_typeHandler .createArray (planeSize );
590- m_typeHandler .copyData ((A )((ArrayDataAccess <A >)((ArrayImg )img ).update (null ))
591- .getCurrentStorageArray (), plane , 0 );
592- m_data .add (plane );
593- }
612+ if (imgPlus .numDimensions () == 2 ) {
613+ //in case of 2D we can efficiently copy the data arrays
614+ // copy data
615+ if (img instanceof ArrayImg ) {
616+ for (int i = 0 ; i < numHyperPlanes ; i ++) {
617+ final A plane = m_typeHandler .createArray (hyperPlaneSize );
618+ m_typeHandler
619+ .copyData ((A )((ArrayDataAccess <A >)((ArrayImg )img ).update (null )).getCurrentStorageArray (),
620+ plane , 0 );
621+ m_data .add (plane );
622+ }
594623
595- } else if (imgPlus .getImg () instanceof PlanarImg ) {
624+ } else if (imgPlus .getImg () instanceof PlanarImg ) {
596625
597- for (int i = 0 ; i < ((PlanarImg )img ).numSlices (); i ++) {
598- final A plane = m_typeHandler .createArray (planeSize );
599- m_typeHandler .copyData ((A )((ArrayDataAccess <A >)((PlanarImg )img ).getPlane (i ))
600- .getCurrentStorageArray (), plane , 0 );
601- m_data .add (plane );
626+ for (int i = 0 ; i < ((PlanarImg )img ).numSlices (); i ++) {
627+ final A plane = m_typeHandler .createArray (hyperPlaneSize );
628+ m_typeHandler
629+ .copyData ((A )((ArrayDataAccess <A >)((PlanarImg )img ).getPlane (i )).getCurrentStorageArray (),
630+ plane , 0 );
631+ m_data .add (plane );
632+ }
633+ } else {
634+ if (imgPlus .numDimensions () != (m_dims .length - 1 )) {
635+ throw new IllegalArgumentException ("Image type not supported, yet." );
636+ }
602637 }
603638 } else {
604- if (imgPlus .numDimensions () != (m_dims .length - 1 )) {
605- throw new IllegalArgumentException ("Image type not supported, yet." );
639+ //just transfer the pixel values to the already created result image
640+ //TODO guarantee same iteration order
641+ Cursor <T > dest = Views .hyperSlice (m_resImg , m_resImg .numDimensions () - 1 , m_rowIdx ).cursor ();
642+ for (T t : imgPlus ) {
643+ dest .fwd ();
644+ dest .get ().set (t );
606645 }
646+ m_rowIdx ++;
607647 }
608648
609649 return false ;
@@ -637,24 +677,36 @@ protected DataType getDataType(final DataType origType) {
637677 */
638678 @ Override
639679 public String getDescription () {
640- return "Merges the n-dimension to one (n+1) dimensional image object. The images to be merged must have the same X and Y dimensions and same pixel type as the first image in the group. If not, they will be skipped." ;
680+ return "Merges the n-dimension to one (n+1) dimensional image object. The images to be merged must have exactly the same dimensions and same pixel type as the first image in the group. If not, they will be skipped." ;
641681 }
642682
643683 /**
644684 * {@inheritDoc}
645685 */
646686 @ Override
647687 protected DataCell getResultInternal () {
648- final ArrayList <ADA > mirror = new ArrayList <ADA >(m_data .size ());
649- for (int i = 0 ; i < m_data .size (); i ++) {
650- mirror .add (m_typeHandler .wrap (m_data .get (i )));
651- }
652- final CustomPlanarImg img = new CustomPlanarImg (mirror , m_dims , new Fraction (1 , 1 ));
653- img .setLinkedType (m_typeHandler .createLinkedType (img ));
654- try {
655- return getImgPlusCellFactory ().createCell (new ImgPlus (img , m_metadata ));
656- } catch (final IOException e ) {
657- throw new RuntimeException (e );
688+ if (m_data != null ) {
689+ //in case 2D images have been merged
690+ final ArrayList <ADA > mirror = new ArrayList <ADA >(m_data .size ());
691+ for (int i = 0 ; i < m_data .size (); i ++) {
692+ mirror .add (m_typeHandler .wrap (m_data .get (i )));
693+ }
694+ final CustomPlanarImg img = new CustomPlanarImg (mirror , m_dims , new Fraction (1 , 1 ));
695+ img .setLinkedType (m_typeHandler .createLinkedType (img ));
696+ try {
697+ return getImgPlusCellFactory ().createCell (new ImgPlus (img , m_metadata ));
698+ } catch (final IOException e ) {
699+ //TODO better error handling
700+ throw new RuntimeException (e );
701+ }
702+ } else {
703+ assert m_resImg != null ;
704+ try {
705+ return getImgPlusCellFactory ().createCell (new ImgPlus (m_resImg , m_metadata ));
706+ } catch (IOException e ) {
707+ //TODO better error handling
708+ throw new RuntimeException (e );
709+ }
658710 }
659711 }
660712
0 commit comments