Changeset 6668


Ignore:
Timestamp:
07/08/10 14:35:59 (9 years ago)
Author:
curtis
Message:

Fix autoscaling bugs, and rework autoscaling tests.

Location:
trunk/components/loci-plugins
Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/components/loci-plugins/src/loci/plugins/in/Colorizer.java

    r6659 r6668  
    215215    } 
    216216 
     217    // for calibrated data, the offset from zero 
     218    final double zeroOffset = getZeroOffset(imp); 
     219 
    217220    // fill in default display ranges as appropriate 
    218     final int bitDepth = reader.getBitsPerPixel(); 
    219     // NB: ImageJ does not directly support signed data (it is merely 
    220     // unsigned data shifted downward by half via a "calibration"), 
    221     // so the following min and max values also work for signed. 
    222     final double min = 0; 
    223     final double max = Math.pow(2, bitDepth) - 1; 
    224     for (int c=0; c<cSize; c++) { 
    225       if (Double.isNaN(cMin[c])) cMin[c] = min; 
    226       if (Double.isNaN(cMax[c])) cMax[c] = max; 
     221    final double min, max; 
     222    if (FormatTools.isFloatingPoint(pixelType)) { 
     223      // no defined min and max values for floating point data 
     224      min = max = Double.NaN; 
     225    } 
     226    else { 
     227      final int bitDepth = reader.getBitsPerPixel(); 
     228      final double halfPow = Math.pow(2, bitDepth - 1); 
     229      final double fullPow = 2 * halfPow; 
     230      final boolean signed = FormatTools.isSigned(pixelType); 
     231      if (signed) { 
     232        // signed data is centered at 0 
     233        min = -halfPow; 
     234        max = halfPow - 1; 
     235      } 
     236      else { 
     237        // unsigned data begins at 0 
     238        min = 0; 
     239        max = fullPow - 1; 
     240      } 
     241      for (int c=0; c<cSize; c++) { 
     242        if (Double.isNaN(cMin[c])) cMin[c] = min; 
     243        if (Double.isNaN(cMax[c])) cMax[c] = max; 
     244      } 
    227245    } 
    228246 
     
    233251      for (int c=0; c<cSize; c++) { 
    234252        LUT lut = compImage.getChannelLut(c + 1); 
    235         // NB: Uncalibrate min/max values before assigning to LUT min/max. 
    236         double minOffset = 0; 
    237         final Calibration cal = imp.getCalibration(); 
    238         if (cal.getFunction() == Calibration.STRAIGHT_LINE) { 
    239           // adjust minimum offset for signed data 
    240           double[] coeffs = cal.getCoefficients(); 
    241           if (coeffs.length > 0) minOffset = coeffs[0]; 
    242         } 
    243         lut.min = cMin[c] - minOffset; 
    244         lut.max = cMax[c] - minOffset; 
     253        // NB: Uncalibrate values before assigning to LUT min/max. 
     254        lut.min = cMin[c] - zeroOffset; 
     255        lut.max = cMax[c] - zeroOffset; 
    245256      } 
    246257    } 
     
    253264        if (cMax[c] > globalMax) globalMax = cMax[c]; 
    254265      } 
     266      // NB: Uncalibrate values before assigning to display range min/max. 
     267      globalMin -= zeroOffset; 
     268      globalMax -= zeroOffset; 
    255269 
    256270      // apply global display range 
     
    259273        // NB: Should never occur. ;-) 
    260274        final ColorProcessor colorProc = (ColorProcessor) proc; 
    261         colorProc.setMinAndMax(min, max, 3); 
    262       } 
    263       else proc.setMinAndMax(min, max); 
     275        colorProc.setMinAndMax(globalMin, globalMax, 3); 
     276      } 
     277      else proc.setMinAndMax(globalMin, globalMax); 
    264278    } 
    265279  } 
     
    314328  } 
    315329 
     330  private static double getZeroOffset(ImagePlus imp) { 
     331    final Calibration cal = imp.getCalibration(); 
     332    if (cal.getFunction() != Calibration.STRAIGHT_LINE) return 0; 
     333    final double[] coeffs = cal.getCoefficients(); 
     334    if (coeffs == null || coeffs.length == 0) return 0; 
     335    return coeffs[0]; 
     336  } 
     337 
    316338} 
  • trunk/components/loci-plugins/test/loci/plugins/in/ImporterTest.java

    r6654 r6668  
    1010import static org.junit.Assert.assertTrue; 
    1111import static org.junit.Assert.fail; 
    12  
    1312import ij.CompositeImage; 
    1413import ij.ImagePlus; 
    1514import ij.ImageStack; 
    16 import ij.measure.Calibration; 
    1715import ij.process.ImageProcessor; 
    1816import ij.process.LUT; 
     
    9088//    - improve, comment, and generalize code for increased coverage 
    9189 
     90/** 
     91 * A class for testing the Bio-Formats Importer behavior. 
     92 * 
     93 * @author Barry DeZonia bdezonia at wisc.edu 
     94 */ 
    9295public class ImporterTest { 
    9396 
     97  /** Whether to log debugging messages to stdout. */ 
     98  static final boolean DEBUG = false; 
     99 
    94100  private enum Axis {Z,C,T}; 
    95101 
    96102  private enum ChannelOrder {ZCT, ZTC, CZT, CTZ, TZC, TCZ}; 
    97103 
    98   /** Whether to log debugging messages to stdout. */ 
    99   private static final boolean DEBUG = false; 
    100  
    101104  private static final boolean[] BOOLEAN_STATES = new boolean[] {false, true}; 
    102  
    103   private static final int[] PIXEL_TYPES = new int[] { 
    104       FormatTools.FLOAT, FormatTools.DOUBLE, 
    105       FormatTools.UINT8, FormatTools.UINT16, FormatTools.UINT32, 
    106       FormatTools.INT8,  FormatTools.INT16,  FormatTools.INT32 
    107       }; 
    108105 
    109106  private static Color[] DEFAULT_COLOR_ORDER = 
     
    339336  private int getEffectiveSizeC(ImagePlus imp) { return getField(imp, "nChannels"); } 
    340337 
    341   // TODO : this code written to pass tests - looks wrong on a number of pixel types 
    342   /** returns the maximum pixel value for a given pixel type */ 
    343   private long maxPixelValue(int pixType) 
    344   { 
    345     if (FormatTools.isFloatingPoint(pixType)) 
    346       return 4294967296L; // expected Float.MAX_VALUE or maybe Double.MAX_VALUE 
    347  
    348     switch (pixType) 
    349     { 
    350       case FormatTools.INT8:    return 255; // expected: Byte.MAX_VALUE 
    351       case FormatTools.INT16:   return 65535;  // expected: Short.MAX_VALUE 
    352       case FormatTools.INT32:   return 4294967296L; // expected INTEGER.MAX_VALUE and also off by 1 from unsigned max 
    353       case FormatTools.UINT8:   return 255; 
    354       case FormatTools.UINT16:  return 65535; 
    355       case FormatTools.UINT32:  return 4294967295L; // off by 1 from unsigned max 
    356                                             // TODO : prev line modified to get autoscale working better. Off by 1 not true. 
    357  
    358       default: 
    359         throw new IllegalArgumentException("maxPixelValue() - unknown pixel type passed in: " + pixType); 
    360     } 
    361   } 
    362  
    363338  /** returns the minimum pixel value for a given pixel type */ 
    364339  private long minPixelValue(int pixType) 
     
    382357  } 
    383358 
    384   /** returns the expected min value within a FakeFile plane based on pixel type and if autoscale desired */ 
    385   private long expectedMin(int pixType, boolean wantAutoscale) 
    386   { 
    387     long min; 
    388  
    389     if (wantAutoscale || (FormatTools.isFloatingPoint(pixType))) 
    390       min = minPixelValue(pixType); 
    391     else // not autoscaling - get min/max of pixel type 
    392       min = 0; 
    393  
    394     if (pixType == FormatTools.INT16)  // hack : clamp like IJ does 
    395       if (min < 0) 
    396         min = 0; 
    397  
    398     return min; 
    399   } 
    400  
    401   /** returns the expected max value within a FakeFile plane based on pixel type and if autoscale desired */ 
    402   private long expectedMax(int pixType, boolean wantAutoscale, long maxPixVal, long maxIndex) 
    403   {                     // TODO - call Math.max() at point of call. Simplify this method to take a maxVal. 
    404     long max; 
    405  
    406     if (wantAutoscale || (FormatTools.isFloatingPoint(pixType))) 
    407       max = Math.max( maxPixVal, maxIndex); 
    408     else // not autoscaling - get min/max of pixel type 
    409       max = maxPixelValue(pixType); 
    410  
    411     if (pixType == FormatTools.INT16)  // hack : clamp like IJ does 
    412       if (max > 65535) 
    413         max = 65535; 
    414  
    415     return max; 
    416   } 
    417359 
    418360  /** set an ImagePlus' position relative to CZT ordering (matches imp.setPosition()) */ 
     
    873815 
    874816  /** tests that the Calibration of an ImagePlus of signed integer data is correct */ 
    875   private void calibrationTest(ImagePlus imp, int pixType) 
    876   { 
    877     // IJ handles BF INT32 as float. So the test is invalid in that case 
    878     if (pixType == FormatTools.INT32) 
    879       return; 
    880  
    881     if (FormatTools.isSigned(pixType) && !FormatTools.isFloatingPoint(pixType)) 
    882     { 
    883       Calibration cal = imp.getCalibration(); 
    884       assertEquals(Calibration.STRAIGHT_LINE,cal.getFunction()); 
    885       double[] coeffs = cal.getCoefficients(); 
    886       int bitsPerPix = FormatTools.getBytesPerPixel(pixType) * 8; 
    887       assertEquals(-(Math.pow(2, (bitsPerPix-1))),coeffs[0],0); 
    888       assertEquals(1,coeffs[1],0); 
    889     } 
    890   } 
    891  
    892   /** tests that an ImagePlus' set of ImageProcessors have their mins and maxes set appropriately */ 
    893   private void minMaxTest(ImagePlus imp, long expectedMin, long expectedMax) 
    894   { 
    895     if (imp instanceof CompositeImage) { 
    896       CompositeImage ci = (CompositeImage) imp; 
    897       for (int c = 0; c < ci.getNChannels(); c++) { 
    898         LUT lut = ci.getChannelLut(c + 1); 
    899 if (expectedMax != lut.max) {//TEMP 
    900   log("expected=" + expectedMax +", actual=" + lut.max);//TEMP 
    901   log("imp=" + imp + ", sizeC=" + imp.getNChannels());//TEMP 
    902 }//TEMP 
    903         assertEquals(expectedMax,lut.max,0.1); 
    904         assertEquals(expectedMin,lut.min,0.1); 
    905       } 
    906     } 
    907     else { 
    908       ImageStack st = imp.getStack(); 
    909       int numSlices = st.getSize(); 
    910       for (int i = 0; i < numSlices; i++) 
    911       { 
    912         ImageProcessor proc = st.getProcessor(i+1); 
    913         assertEquals(expectedMax,proc.getMax(),0.1); 
    914         assertEquals(expectedMin,proc.getMin(),0.1); 
    915       } 
    916     } 
    917   } 
     817 
    918818 
    919819  /** tests if images split on Z are ordered correctly */ 
     
    13741274  } 
    13751275 
    1376   /** tests BF's options.setAutoscale() */ 
    1377   private void autoscaleTester(int pixType, boolean wantAutoscale) 
    1378   { 
    1379     if (DEBUG) log("autoscaleTester() : pix "+FormatTools.getPixelTypeString(pixType)+" scale "+wantAutoscale); 
    1380  
    1381     if ((pixType == FormatTools.UINT8) && (wantAutoscale)) 
    1382       if (DEBUG) log("  broken case"); 
    1383  
    1384     final int sizeZ = 2, sizeC = 3, sizeT = 4, sizeX = 51, sizeY = 16; 
    1385     final String path = constructFakeFilename("autoscale",pixType, sizeX, sizeY, sizeZ, sizeC, sizeT, -1, false, -1, false, -1); 
    1386  
    1387     ImagePlus[] imps = null; 
    1388  
    1389     try { 
    1390       ImporterOptions options = new ImporterOptions(); 
    1391       options.setAutoscale(wantAutoscale); 
    1392       options.setId(path); 
    1393       imps = BF.openImagePlus(options); 
    1394     } 
    1395     catch (IOException e) { 
    1396       fail(e.getMessage()); 
    1397     } 
    1398     catch (FormatException e) { 
    1399       fail(e.getMessage()); 
    1400     } 
    1401  
    1402     impsCountTest(imps,1); 
    1403  
    1404     ImagePlus imp = imps[0]; 
    1405  
    1406     xyzctTest(imp,sizeX,sizeY,sizeZ,sizeC,sizeT); 
    1407  
    1408     stackTest(imp,sizeZ*sizeC*sizeT); 
    1409  
    1410     calibrationTest(imp,pixType); 
    1411  
    1412     long maxPixVal = minPixelValue(pixType)+sizeX-1; 
    1413     long maxIndex = sizeZ*sizeC*sizeT - 1; 
    1414  
    1415     long expectedMax = expectedMax(pixType,wantAutoscale,maxPixVal,maxIndex); 
    1416     long expectedMin = expectedMin(pixType,wantAutoscale); 
    1417  
    1418     minMaxTest(imp,expectedMin,expectedMax); 
    1419   } 
    14201276 
    14211277  private void ascendingValuesTest(byte[] data, int expectedLength) 
     
    20801936  // note - this test needs to rely on crop() to get predictable nonzero minimums 
    20811937 
    2082   /** tests BF's options.setCrop() and options.setCropRegion() with options.setAutoscale() */ 
    2083   private void comboCropAndAutoscaleTester(int pixType, int sizeX, int sizeY, int sizeZ, int sizeC, int sizeT, 
    2084       int originCropX, int originCropY, int sizeCrop) 
    2085   { 
    2086     final String path = constructFakeFilename("cropAutoscale",pixType, sizeX, sizeY, sizeZ, sizeC, sizeT, -1, false, -1, false, -1); 
    2087  
    2088     // needed for this test 
    2089     verifyCropInput(sizeX,sizeY,originCropX,originCropY,sizeCrop); 
    2090  
    2091     ImagePlus[] imps = null; 
    2092  
    2093     try { 
    2094       ImporterOptions options = new ImporterOptions(); 
    2095       options.setAutoscale(true); 
    2096       options.setCrop(true); 
    2097       options.setCropRegion(0,new Region(originCropX,originCropY,sizeCrop,sizeCrop)); 
    2098       options.setId(path); 
    2099       imps = BF.openImagePlus(options); 
    2100     } 
    2101     catch (IOException e) { 
    2102       fail(e.getMessage()); 
    2103     } 
    2104     catch (FormatException e) { 
    2105       fail(e.getMessage()); 
    2106     } 
    2107  
    2108     impsCountTest(imps,1); 
    2109  
    2110     ImagePlus imp = imps[0]; 
    2111  
    2112     xyzctTest(imps[0],sizeCrop,sizeCrop,sizeZ,sizeC,sizeT); 
    2113  
    2114     stackTest(imp,(sizeZ*sizeC*sizeT)); 
    2115  
    2116     calibrationTest(imp,pixType); 
    2117  
    2118     long expectedMax = minPixelValue(pixType) + originCropX + sizeCrop - 1; 
    2119     long expectedMin = minPixelValue(pixType) + originCropX; 
    2120  
    2121     if (pixType == FormatTools.INT16)  // hack : clamp like IJ does 
    2122     { 
    2123       if (expectedMin < 0) 
    2124         expectedMin = 0; 
    2125       if (expectedMax > 65535) 
    2126         expectedMax = 65535; 
    2127     } 
    2128  
    2129     // NOTE - the minMaxTest can't work for INT32 as it has more precision than can be represented by IJ's GRAY32 float 
    2130     if (pixType != FormatTools.INT32) 
    2131       minMaxTest(imp,expectedMin,expectedMax); 
    2132   } 
    2133  
    21341938  /** tests BF's options.setConcatenate() with options.setSplitFocalPlanes() */ 
    21351939  private void comboConcatSplitFocalPlanesTester() 
     
    25672371  public void testColorAutoscale() 
    25682372  { 
    2569     // note - can't autoscale a virtualStack. No need to test it. 
    2570  
    2571     for (int pixType : PIXEL_TYPES) { 
    2572       for (boolean autoscale : BOOLEAN_STATES) { 
    2573         if (DEBUG) log("testColorAutoscale(): pixType = "+FormatTools.getPixelTypeString(pixType)+" autoscale = "+autoscale); 
    2574         autoscaleTester(pixType,autoscale); 
    2575       } 
    2576     } 
    2577   } 
     2373    new AutoscaleTest().testAutoscale(); 
     2374  } 
     2375 
    25782376 
    25792377  @Test 
     
    25852383 
    25862384/* TODO - underlying BF code is not working. Comment out for now 
    2587  
    25882385  @Test 
    25892386  public void testMemoryRecordModifications() 
     
    28172614  } 
    28182615 
    2819   @Test 
    2820   public void testComboCropAutoscale() 
    2821   { 
    2822     // note - crop and autoscale both don't work with virtualStacks. No need to test virtual here. 
    2823  
    2824     // try a simple test: single small byte type image 
    2825     comboCropAndAutoscaleTester(FormatTools.UINT8,240,240,1,1,1,70,40,25); 
    2826  
    2827     // try multiple dimensions 
    2828     comboCropAndAutoscaleTester(FormatTools.UINT8,240,240,4,3,2,51,15,13); 
    2829  
    2830     // try various pixTypes 
    2831     for (int pixType : PIXEL_TYPES) 
    2832       comboCropAndAutoscaleTester(pixType,240,240,2,2,2,225,225,10); 
    2833   } 
    28342616 
    28352617  /* 
Note: See TracChangeset for help on using the changeset viewer.