/* * #%L * Bio-Formats Plugins for ImageJ: a collection of ImageJ plugins including the * Bio-Formats Importer, Bio-Formats Exporter, Bio-Formats Macro Extensions, * Data Browser and Stack Slicer. * %% * Copyright (C) 2006 - 2015 Open Microscopy Environment: * - Board of Regents of the University of Wisconsin-Madison * - Glencoe Software, Inc. * - University of Dundee * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-2.0.html>. * #L% */ package loci.plugins.in; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import ij.CompositeImage; import ij.ImagePlus; import ij.measure.Calibration; import ij.process.LUT; import java.io.IOException; import loci.common.Region; import loci.formats.FormatException; import loci.formats.FormatTools; import loci.plugins.BF; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A class for testing the Bio-Formats Importer's * autoscaling behavior in various cases. * * @author Curtis Rueden ctrueden at wisc.edu */ public class AutoscaleTest { // -- Constants -- protected static final Logger LOGGER = LoggerFactory.getLogger(AutoscaleTest.class); private static final int WIDTH = 51, HEIGHT = 16; private static final int CROP_X = 5, CROP_Y = 10; private static final Region CROP_REGION = new Region(CROP_X, CROP_Y, WIDTH - 2 * CROP_X, HEIGHT - CROP_Y); // -- AutoscaleTest methods -- @Test public void testAutoscale() { // pixel type shorthands final int ui08 = FormatTools.UINT8; final int ui16 = FormatTools.UINT16; final int ui32 = FormatTools.UINT32; final int si08 = FormatTools.INT8; final int si16 = FormatTools.INT16; final int si32 = FormatTools.INT32; final int f32 = FormatTools.FLOAT; final int f64 = FormatTools.DOUBLE; // min and max values for various pixel types final double sMin08 = -128.0, sMax08 = 127.0; final double sMin16 = -32768.0, sMax16 = 32767.0; final double sMin32 = -2147483648.0, sMax32 = 2147483647.0; final double uMin08 = 0.0, uMax08 = 255.0; final double uMin16 = 0.0, uMax16 = 65535.0; final double uMin32 = 0.0, uMax32 = 4294967295.0; // expected values final double noCal = 0.0; final double eMin = 0.0, eMax = WIDTH - 1; final double esMax08 = sMin08 + eMax; final double esMax16 = sMin16 + eMax; final double esMax32 = sMin32 + eMax; // -- vanilla images -- // unsigned integer types, no autoscaling test (ui08, noCal, uMin08, uMax08); test (ui16, noCal, uMin16, uMax16); test (ui32, noCal, uMin32, uMax32 + 1); // !! // signed integer types, no autoscaling test (si08, sMin08, sMin08, sMax08); test (si16, sMin16, sMin16, sMax16); test (si32, noCal, sMin32, sMax32 + 1); // !! // floating point types, no autoscaling (though autoscaling is forced) test ( f32, noCal, eMin, eMax); test ( f64, noCal, eMin, eMax); // unsigned integer types, with autoscaling testA(ui08, noCal, eMin, eMax); testA(ui16, noCal, eMin, eMax); testA(ui32, noCal, eMin, eMax); // signed integer types, with autoscaling testA(si08, sMin08, sMin08, 0.0); testA(si16, sMin16, sMin16, 0.0); testA(si32, noCal, sMin32, 0.0); // floating point types, with autoscaling testA( f32, noCal, eMin, eMax); testA( f64, noCal, eMin, eMax); // unsigned integer types, with autoscaling and crop testC(ui08, noCal, eMin, eMax); testC(ui16, noCal, eMin, eMax); testC(ui32, noCal, eMin, eMax); // signed integer types, with autoscaling and crop testC(si08, sMin08, sMin08, esMax08); testC(si16, sMin16, sMin16, esMax16); //testC(si32, noCal, sMin32, esMax32); // floating point types, with autoscaling and crop testC( f32, noCal, eMin, eMax); testC( f64, noCal, eMin, eMax); // -- composite images -- // unsigned integer types, no autoscaling test (ui08, noCal, uMin08, uMax08, uMin08, uMax08, uMin08, uMax08); test (ui16, noCal, uMin16, uMax16, uMin16, uMax16, uMin16, uMax16); test (ui32, noCal, uMin32, uMax32, uMin32, uMax32, uMin32, uMax32); // signed integer types, no autoscaling test (si08, sMin08, sMin08, sMax08, sMin08, sMax08, sMin08, sMax08); test (si16, sMin16, sMin16, sMax16, sMin16, sMax16, sMin16, sMax16); test (si32, noCal, sMin32, sMax32, sMin32, sMax32, sMin32, sMax32); // floating point types, no autoscaling (though autoscaling is forced) test ( f32, noCal, eMin, eMax, eMin, eMax, eMin, eMax); test ( f64, noCal, eMin, eMax, eMin, eMax, eMin, eMax); // unsigned integer types, with autoscaling testA(ui08, noCal, eMin, eMax, eMin, eMax, eMin, eMax); testA(ui16, noCal, eMin, eMax, eMin, eMax, eMin, eMax); testA(ui32, noCal, eMin, eMax, eMin, eMax, eMin, eMax); // signed integer types, with autoscaling testA(si08, sMin08, sMin08, 0.0, sMin08, 1.0, sMin08, 2.0); testA(si16, sMin16, sMin16, 0.0, sMin16, 1.0, sMin16, 2.0); testA(si32, noCal, sMin32, 0.0, sMin32, 1.0, sMin32, 2.0); // floating point types, with autoscaling testA( f32, noCal, eMin, eMax, eMin, eMax, eMin, eMax); testA( f64, noCal, eMin, eMax, eMin, eMax, eMin, eMax); // unsigned integer types, with autoscaling and crop testC(ui08, noCal, eMin, eMax, eMin, eMax, eMin, eMax); testC(ui16, noCal, eMin, eMax, eMin, eMax, eMin, eMax); testC(ui32, noCal, eMin, eMax, eMin, eMax, eMin, eMax); // signed integer types, with autoscaling and crop testC(si08, sMin08, sMin08, esMax08, sMin08, esMax08, sMin08, esMax08); testC(si16, sMin16, sMin16, esMax16, sMin16, esMax16, sMin16, esMax16); testC(si32, noCal, sMin32, esMax32, sMin32, esMax32, sMin32, esMax32); // floating point types, with autoscaling and crop testC( f32, noCal, eMin, eMax, eMin, eMax, eMin, eMax); testC( f64, noCal, eMin, eMax, eMin, eMax, eMin, eMax); } /** Tester for vanilla (single-channel) images, no autoscale, no crop. */ private void test(int pixelType, double calib, double min, double max) { test(pixelType, false, false, calib, min, max); } /** Tester for vanilla (single-channel) images, with autoscale, no crop. */ private void testA(int pixelType, double calib, double min, double max) { test(pixelType, true, false, calib, min, max); } /** Tester for vanilla (single-channel) images, with autoscale and crop. */ private void testC(int pixelType, double calib, double min, double max) { test(pixelType, true, true, calib, min + CROP_X, max - CROP_X); } /** Tester for composite (multi-channel) images, no autoscale, no crop. */ private void test(int pixelType, double calib, double min1, double max1, double min2, double max2, double min3, double max3) { test(pixelType, false, false, calib, min1, max1, min2, max2, min3, max3); } /** Tester for composite (multi-channel) images, with autoscale, no crop. */ private void testA(int pixelType, double calib, double min1, double max1, double min2, double max2, double min3, double max3) { test(pixelType, true, false, calib, min1, max1, min2, max2, min3, max3); } /** Tester for composite (multi-channel) images, with autoscale and crop. */ private void testC(int pixelType, double calib, double min1, double max1, double min2, double max2, double min3, double max3) { test(pixelType, true, true, calib, min1 + CROP_X, max1 - CROP_X, min2 + CROP_X, max2 - CROP_X, min3 + CROP_X, max3 - CROP_X); } /** Tester for vanilla (single-channel) images. */ private void test(int pixelType, boolean autoscale, boolean crop, double calib, double min, double max) { final ImagePlus imp = setup(pixelType, autoscale, crop, calib, 1); final double actualMin = imp.getDisplayRangeMin(); final double actualMax = imp.getDisplayRangeMax(); assertEquals(min - calib, actualMin, 0.0); assertEquals(max - calib, actualMax, 0.0); } /** Tester for composite (multi-channel) images. */ private void test(int pixelType, boolean autoscale, boolean crop, double calib, double min1, double max1, double min2, double max2, double min3, double max3) { final ImagePlus imp = setup(pixelType, autoscale, crop, calib, 3); final CompositeImage ci = (CompositeImage) imp; final LUT lut1 = ci.getChannelLut(1); final LUT lut2 = ci.getChannelLut(2); final LUT lut3 = ci.getChannelLut(3); assertEquals(min1 - calib, lut1.min, 0.0); assertEquals(max1 - calib, lut1.max, 0.0); assertEquals(min2 - calib, lut2.min, 0.0); assertEquals(max2 - calib, lut2.max, 0.0); assertEquals(min3 - calib, lut3.min, 0.0); assertEquals(max3 - calib, lut3.max, 0.0); } /** Reads the image and performs some initial tests. */ private ImagePlus setup(int pixelType, boolean autoscale, boolean crop, double calib, int sizeC) { final String pix = FormatTools.getPixelTypeString(pixelType); final String id = "autoscale&pixelType=" + pix + "&sizeX=" + WIDTH + "&sizeY=" + HEIGHT + "&sizeC=" + sizeC + ".fake"; ImagePlus[] imps = null; try { final ImporterOptions options = new ImporterOptions(); options.setId(id); options.setAutoscale(autoscale); options.setCrop(crop); if (crop) options.setCropRegion(0, CROP_REGION); imps = BF.openImagePlus(options); } catch (FormatException exc) { fail(exc.getMessage()); LOGGER.debug("", exc); } catch (IOException exc) { fail(exc.getMessage()); LOGGER.debug("", exc); } assertTrue(imps != null && imps.length == 1); final ImagePlus imp = imps[0]; assertEquals(sizeC > 1, imp instanceof CompositeImage); // check calibration function final Calibration cal = imp.getCalibration(); final int calFunction = cal.getFunction(); if (calib == 0) { assertFalse(calFunction == Calibration.STRAIGHT_LINE); } else { assertTrue(calFunction == Calibration.STRAIGHT_LINE); double[] coeffs = cal.getCoefficients(); assertTrue(coeffs.length >= 1); assertEquals(calib, coeffs[0], 0.0); } dump(pix, sizeC, autoscale, crop, imp); return imp; } private void dump(String pix, int sizeC, boolean autoscale, boolean crop, ImagePlus imp) { if (!LOGGER.isDebugEnabled()) { return; } StringBuilder sb = new StringBuilder(); sb.append("pixelType="); for (int s=pix.length(); s<6; s++) sb.append(" "); // fixed width sb.append(pix); sb.append(", sizeC="); sb.append(sizeC); sb.append(", autoscale="); sb.append(autoscale ? " true" : "false"); sb.append(", crop="); sb.append(crop ? " true" : "false"); sb.append(": image="); if (imp instanceof CompositeImage) { final CompositeImage ci = (CompositeImage) imp; sb.append("composite"); for (int c=0; c<sizeC; c++) { final LUT lut = ci.getChannelLut(c + 1); sb.append("; min"); sb.append(c); sb.append("="); sb.append(lut.min); sb.append("; max"); sb.append(c); sb.append("="); sb.append(lut.max); } } else { sb.append(" vanilla"); final double min = imp.getDisplayRangeMin(); final double max = imp.getDisplayRangeMax(); sb.append("; min="); sb.append(min); sb.append("; max="); sb.append(max); } final Calibration cal = imp.getCalibration(); if (cal.getFunction() == Calibration.STRAIGHT_LINE) { sb.append("; calibration="); double[] coeffs = cal.getCoefficients(); sb.append(coeffs[0]); } LOGGER.debug(sb.toString()); } }