4747import net .imglib2 .loops .LoopBuilder ;
4848import net .imglib2 .type .NativeType ;
4949import net .imglib2 .type .numeric .RealType ;
50- import net .imglib2 .util .Intervals ;
5150import org .scijava .convert .ConvertService ;
5251import sc .fiji .snt .Path ;
5352import sc .fiji .snt .SNTUtils ;
@@ -105,8 +104,8 @@ public static ImagePlus getMIP(final ImagePlus imp) {
105104
106105 public static ImagePlus getMIP (final ImagePlus imp , final int startSlice , final int stopSlice ) {
107106 final ImagePlus mip = ZProjector .run (imp , "max" , startSlice , stopSlice );
108- if (mip .getNChannels () == 1 )
109- mip .setLut (imp .getLuts ()[0 ]); // assume single-channel image
107+ if (mip .getNChannels () == 1 && imp . getLuts (). length > 0 )
108+ mip .setLut (imp .getLuts ()[0 ]);
110109 mip .copyScale (imp );
111110 new ContrastEnhancer ().stretchHistogram (mip , 0.35 );
112111 return mip ;
@@ -139,7 +138,7 @@ public static void convertTo8bit(final ImagePlus imp) {
139138 }
140139
141140 public static void convertTo16bit (final ImagePlus imp ) {
142- if (imp .getType () != ImagePlus .GRAY8 ) {
141+ if (imp .getType () != ImagePlus .GRAY16 ) {
143142 final boolean doScaling = ImageConverter .getDoScaling ();
144143 ImageConverter .setDoScaling (true );
145144 new ImageConverter (imp ).convertToGray16 ();
@@ -149,8 +148,8 @@ public static void convertTo16bit(final ImagePlus imp) {
149148
150149 public static ImagePlus convertRGBtoComposite (final ImagePlus imp ) {
151150 if (imp .getType () == ImagePlus .COLOR_RGB ) {
152- imp .hide ();
153151 final boolean isShowing = imp .isVisible ();
152+ imp .hide ();
154153 final ImagePlus res = CompositeConverter .makeComposite (imp );
155154 imp .flush ();
156155 if (isShowing ) res .show ();
@@ -175,7 +174,7 @@ public static ImagePlus open(final String filePathOrUrl, final String title) {
175174 final boolean redirecting = IJ .redirectingErrorMessages ();
176175 IJ .redirectErrorMessages (true );
177176 final ImagePlus imp = IJ .openImage (filePathOrUrl );
178- if (title != null )
177+ if (imp != null && title != null )
179178 imp .setTitle (title );
180179 IJ .redirectErrorMessages (redirecting );
181180 return imp ;
@@ -249,13 +248,9 @@ public static ImagePlus getCT(final ImagePlus imp, final int channel, final int
249248 }
250249
251250 public static void removeSlices (final ImageStack stack , Collection <String > labels ) {
252- int count = 0 ;
253- for (int i = 1 ; i <= stack .size (); i ++) {
254- if ((i - count ) > stack .getSize ())
255- break ;
251+ for (int i = stack .size (); i >= 1 ; i --) {
256252 if (labels .contains (stack .getSliceLabel (i ))) {
257- stack .deleteSlice (i - count );
258- count ++;
253+ stack .deleteSlice (i );
259254 }
260255 }
261256 }
@@ -463,7 +458,7 @@ private static boolean isGrayscale(final BufferedImage image, final int width, f
463458 * plugin); 'OP1'/'OP_1' for the DIADEM OP_1 dataset; 'cil701' and
464459 * 'cil810' for the respective Cell Image Library entries, and
465460 * 'binary timelapse' for a small 4-frame sequence of neurite growth
466- * @return the demo image, or null if data could no be retrieved
461+ * @return the demo image, or null if data could not be retrieved
467462 */
468463 public static ImagePlus demo (final String img ) {
469464 if (img == null )
@@ -774,7 +769,7 @@ public static String ascii(final ImagePlus imp, final boolean dilate, final int
774769 /**
775770 * Converts the specified image into an easy displayable form, i.e., a non-composite 2D image
776771 * If the image is a timelapse, only the first frame is considered; if 3D, a MIP is retrieved;
777- * if multichannel a RGB version is obtained. The image is flattened if its Overlay has ROIs.
772+ * if multichannel, an RGB version is obtained. The image is flattened if its Overlay has ROIs.
778773 *
779774 * @param imp The image to be converted
780775 * @param frame The frame to be considered (ignored if image is not a timelapse)
@@ -814,7 +809,7 @@ else if (imp.getNSlices() > 1) {
814809 * non-background values.
815810 *
816811 * @param imp The image to be cropped
817- * @param backgroundValue the background value typically 'black': 0 for 8-/16bit, 0x000000 for RGB) ,
812+ * @param backgroundValue the background value typically 'black': 0 for 8-/16bit, 0x000000 for RGB,
818813 * or white (255 for 8-bit, 65535 for 16-bir, 0xFFFFFF for RGB)
819814 */
820815 public static void crop (final ImagePlus imp , final Number backgroundValue ) {
@@ -840,34 +835,29 @@ public static void rotate90(final ImagePlus imp, final String direction) {
840835 }
841836
842837 /**
843- * Returns the cropping rectangle around non-background values.
838+ * Returns the cropping rectangle around non-background values, considering
839+ * all slices of the stack.
844840 *
845841 * @param imp The image to be parsed
846842 * @param backgroundValue the background value typically 'black': 0, or white (255 for 8-bit/RGB,
847843 * or 65535 for 16-bit)
848- * @return the rectangular ROI defining non-background bounds
844+ * @return the rectangular ROI defining non-background bounds, or null if all pixels are background
849845 */
850846 public static Roi getForegroundRect (final ImagePlus imp , final Number backgroundValue ) {
851- final ImageProcessor ip = imp .getProcessor ();
852- int w = ip .getWidth (), h = ip .getHeight ();
847+ final ImageStack stack = imp .getStack ();
848+ final int w = imp .getWidth (), h = imp .getHeight ();
853849 int minX = w , maxX = 0 , minY = h , maxY = 0 ;
854- if (imp .getType () == ImagePlus .GRAY32 ) {
855- float bgVal = backgroundValue .floatValue ();
856- for (int y = 0 ; y < h ; y ++) {
857- for (int x = 0 ; x < w ; x ++) {
858- if (Math .abs (ip .getPixelValue (x , y ) - bgVal ) > 0.0001f ) {
859- if (x < minX ) minX = x ;
860- if (x > maxX ) maxX = x ;
861- if (y < minY ) minY = y ;
862- if (y > maxY ) maxY = y ;
863- }
864- }
865- }
866- } else {
867- int bgVal = backgroundValue .intValue ();
850+ final boolean isFloat = imp .getType () == ImagePlus .GRAY32 ;
851+ final float bgFloat = backgroundValue .floatValue ();
852+ final int bgInt = backgroundValue .intValue ();
853+ for (int z = 1 ; z <= stack .size (); z ++) {
854+ final ImageProcessor ip = stack .getProcessor (z );
868855 for (int y = 0 ; y < h ; y ++) {
869856 for (int x = 0 ; x < w ; x ++) {
870- if (ip .getPixelValue (x , y ) != bgVal ) {
857+ final boolean fg = isFloat
858+ ? Math .abs (ip .getPixelValue (x , y ) - bgFloat ) > 0.0001f
859+ : ip .getPixelValue (x , y ) != bgInt ;
860+ if (fg ) {
871861 if (x < minX ) minX = x ;
872862 if (x > maxX ) maxX = x ;
873863 if (y < minY ) minY = y ;
@@ -952,7 +942,6 @@ public static <T extends RealType<T> & NativeType<T>> ImgPlus<T> toImgPlus(final
952942 final RandomAccessibleInterval <T > rai = ImageJFunctions .wrapReal (imp );
953943
954944 // Create contiguous copy to avoid virtual stack issues
955- final long [] dims = Intervals .dimensionsAsLongArray (rai );
956945 final Img <T > img = copyToArrayImg (rai );
957946
958947 // Build axes from calibration
0 commit comments