Changeset 4848


Ignore:
Timestamp:
02/25/09 19:00:27 (11 years ago)
Author:
curtis
Message:

Fix up MIPAV Bio-Formats plugin:

  • call calcMinMax() to correctly scale LUTs;
  • read in image data in a separate thread;
  • report progress in MIPAV's message text area.
Location:
trunk/utils/mipav
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/utils/mipav/PlugInBioFormatsImporter.java

    r4828 r4848  
    3333import javax.swing.JFileChooser; 
    3434import javax.swing.JFrame; 
     35import javax.swing.SwingUtilities; 
    3536import loci.common.DataTools; 
    3637import loci.formats.*; 
     
    4950public class PlugInBioFormatsImporter implements PlugInFile { 
    5051 
     52  // -- Constants -- 
     53 
     54  /** Update progress bar no more often than this many milliseconds. */ 
     55  protected static final int PROGRESS_THRESHOLD = 100; 
     56 
    5157  // -- Fields -- 
    5258 
     
    8793 
    8894  public void readImage() { 
     95    final ViewUserInterface mipav = ViewUserInterface.getReference(); 
     96 
    8997    // prompt user to choose a file 
    9098    if (chooser == null) { 
     
    92100      chooser.setCurrentDirectory(new File(Preferences.getImageDirectory())); 
    93101    } 
    94     JFrame parent = ViewUserInterface.getReference().getMainFrame(); 
     102    JFrame parent = mipav.getMainFrame(); 
    95103    int rval = chooser.showOpenDialog(parent); 
    96104    if (rval != JFileChooser.APPROVE_OPTION) return; // user canceled 
    97     File file = chooser.getSelectedFile(); 
    98     String name = file.getName(); 
    99     String dir = file.getParent(); 
    100  
    101     // open file using Bio-Formats 
    102     String id = file.getPath(); 
    103     try { 
    104       IMetadata store = MetadataTools.createOMEXMLMetadata(); 
    105       reader.setMetadataStore(store); 
    106       reader.setId(id); 
    107       reader.setOutputOrder("XYZTC"); // MIPAV assumes 4-D data in XYZT order 
    108  
    109       // harvest some core metadata 
    110       int imageCount = reader.getImageCount(); 
    111       boolean little = reader.isLittleEndian(); 
    112       int pixelType = reader.getPixelType(); 
    113       int bpp = FormatTools.getBytesPerPixel(pixelType); 
    114       boolean floating = FormatTools.isFloatingPoint(pixelType); 
    115       int sizeX = reader.getSizeX(); 
    116       int sizeY = reader.getSizeY(); 
    117       int sizeZ = reader.getSizeZ(); 
    118       int sizeT = reader.getSizeT(); 
    119       int sizeC = reader.getSizeC(); 
    120       String imageName = store.getImageName(0); 
    121  
    122       if (sizeC > 1) { 
    123         throw new FormatException( 
    124           "Multichannel data is unsupported at the moment"); 
     105    final File file = chooser.getSelectedFile(); 
     106 
     107    // load the image in a separate thread 
     108    Thread importerThread = new Thread("BioFormats-Importer") { 
     109      public void run() { 
     110        String name = file.getName(); 
     111        String dir = file.getParent(); 
     112 
     113        // open file using Bio-Formats 
     114        setMessage(mipav, "Importing " + name + "...", true); 
     115        String id = file.getPath(); 
     116        try { 
     117          long tic = System.currentTimeMillis(); 
     118 
     119          IMetadata store = MetadataTools.createOMEXMLMetadata(); 
     120          reader.setMetadataStore(store); 
     121          reader.setId(id); 
     122          reader.setOutputOrder("XYZTC"); // MIPAV assumes 4-D data in XYZT order 
     123 
     124          // harvest some core metadata 
     125          int imageCount = reader.getImageCount(); 
     126          boolean little = reader.isLittleEndian(); 
     127          int pixelType = reader.getPixelType(); 
     128          int bpp = FormatTools.getBytesPerPixel(pixelType); 
     129          boolean floating = FormatTools.isFloatingPoint(pixelType); 
     130          int sizeX = reader.getSizeX(); 
     131          int sizeY = reader.getSizeY(); 
     132          int sizeZ = reader.getSizeZ(); 
     133          int sizeT = reader.getSizeT(); 
     134          int sizeC = reader.getSizeC(); 
     135          String imageName = store.getImageName(0); 
     136 
     137          if (sizeC > 1) { 
     138            throw new FormatException( 
     139              "Multichannel data is unsupported at the moment"); 
     140          } 
     141 
     142          // compute MIPAV buffer type 
     143          int mipavType; 
     144          switch (pixelType) { 
     145            case FormatTools.INT8: 
     146              mipavType = ModelStorageBase.BYTE; 
     147              break; 
     148            case FormatTools.UINT8: 
     149              mipavType = ModelStorageBase.UBYTE; 
     150              break; 
     151            case FormatTools.INT16: 
     152              mipavType = ModelStorageBase.SHORT; 
     153              break; 
     154            case FormatTools.UINT16: 
     155              mipavType = ModelStorageBase.USHORT; 
     156              break; 
     157            case FormatTools.INT32: 
     158              mipavType = ModelStorageBase.INTEGER; 
     159              break; 
     160            case FormatTools.UINT32: 
     161              mipavType = ModelStorageBase.UINTEGER; 
     162              break; 
     163            case FormatTools.FLOAT: 
     164              mipavType = ModelStorageBase.FLOAT; 
     165              break; 
     166            case FormatTools.DOUBLE: 
     167              mipavType = ModelStorageBase.DOUBLE; 
     168              break; 
     169            default: 
     170              throw new FormatException("Unsupported pixel type: " + pixelType); 
     171          } 
     172 
     173          // harvest physical resolution 
     174          Float dimPhysSizeX = store.getDimensionsPhysicalSizeX(0, 0); 
     175          Float dimPhysSizeY = store.getDimensionsPhysicalSizeY(0, 0); 
     176          Float dimPhysSizeZ = store.getDimensionsPhysicalSizeZ(0, 0); 
     177          Float dimTimeInc = store.getDimensionsTimeIncrement(0, 0); 
     178          float physSizeX = dimPhysSizeX == null ? 1.0f : dimPhysSizeX.floatValue(); 
     179          float physSizeY = dimPhysSizeY == null ? 1.0f : dimPhysSizeY.floatValue(); 
     180          float physSizeZ = dimPhysSizeZ == null ? 1.0f : dimPhysSizeZ.floatValue(); 
     181          float timeInc = dimTimeInc == null ? 1.0f : dimTimeInc.floatValue(); 
     182 
     183          // compute dimensional extents 
     184          int[] dimExtents = {sizeX, sizeY, sizeZ, sizeT}; 
     185          float[] res = {physSizeX, physSizeY, physSizeZ, timeInc}; 
     186          int[] units = { 
     187            FileInfoBase.MICROMETERS, FileInfoBase.MICROMETERS, 
     188            FileInfoBase.MICROMETERS, FileInfoBase.SECONDS 
     189          }; 
     190 
     191          // create MIPAV image object 
     192          ModelImage modelImage = new ModelImage(mipavType, dimExtents, imageName); 
     193 
     194          // import planes into MIPAV image 
     195          byte[] buf = new byte[bpp * sizeX * sizeY]; 
     196          for (int i=0; i<imageCount; i++) { 
     197            setMessage(mipav, 
     198              "Reading plane #" + (i + 1) + "/" + imageCount, false); 
     199            reader.openBytes(i, buf); 
     200 
     201            // convert byte array to appropriate primitive type 
     202            int offset = i * buf.length; 
     203            Object array = DataTools.makeDataArray(buf, bpp, floating, little); 
     204 
     205            // assign data to MIPAV image object 
     206            switch (mipavType) { 
     207              case ModelStorageBase.BYTE: 
     208              case ModelStorageBase.UBYTE: 
     209                modelImage.importData(offset, (byte[]) array, false); 
     210                break; 
     211              case ModelStorageBase.SHORT: 
     212              case ModelStorageBase.USHORT: 
     213                modelImage.importData(offset, (short[]) array, false); 
     214                break; 
     215              case ModelStorageBase.INTEGER: 
     216              case ModelStorageBase.UINTEGER: 
     217                modelImage.importData(offset, (int[]) array, false); 
     218                break; 
     219              case ModelStorageBase.FLOAT: 
     220                modelImage.importData(offset, (float[]) array, false); 
     221                break; 
     222              case ModelStorageBase.DOUBLE: 
     223                modelImage.importData(offset, (double[]) array, false); 
     224                break; 
     225              default: 
     226                throw new FormatException("Unknown buffer type: " + mipavType); 
     227            } 
     228          } 
     229          setMessage(mipav, "Finishing import...", true); 
     230 
     231          // create a FileInfo object for each image plane 
     232          FileInfoBase[] fileInfo = new FileInfoBase[imageCount]; 
     233          for (int i=0; i<imageCount; i++) { 
     234            // HACK: Use FileInfoImageXML subclass since FileInfoBase is abstract. 
     235            fileInfo[i] = new FileInfoImageXML(name, dir, FileUtility.XML); 
     236            fileInfo[i].setExtents(dimExtents); 
     237            fileInfo[i].setResolutions(res); 
     238            fileInfo[i].setUnitsOfMeasure(units); 
     239            fileInfo[i].setDataType(mipavType); 
     240          } 
     241          modelImage.setFileInfo(fileInfo); 
     242 
     243          // scale color range and display MIPAV image 
     244          modelImage.calcMinMax(); 
     245          new ViewJFrameImage(modelImage); 
     246 
     247          long toc = System.currentTimeMillis(); 
     248          long time = toc - tic; 
     249          long avg = time / imageCount; 
     250          setMessage(mipav, name + ": Read " + imageCount + " planes in " + 
     251            (time / 1000f) + " seconds (" + avg + " ms/plane)", true); 
     252        } 
     253        catch (FormatException exc) { 
     254          exc.printStackTrace(); 
     255          MipavUtil.displayError( 
     256            "An error occurred parsing the file: " + exc.getMessage()); 
     257        } 
     258        catch (IOException exc) { 
     259          exc.printStackTrace(); 
     260          MipavUtil.displayError( 
     261            "An I/O error occurred reading the file: " + exc.getMessage()); 
     262        } 
    125263      } 
    126  
    127       // compute MIPAV buffer type 
    128       int mipavType; 
    129       switch (pixelType) { 
    130         case FormatTools.INT8: 
    131           mipavType = ModelStorageBase.BYTE; 
    132           break; 
    133         case FormatTools.UINT8: 
    134           mipavType = ModelStorageBase.UBYTE; 
    135           break; 
    136         case FormatTools.INT16: 
    137           mipavType = ModelStorageBase.SHORT; 
    138           break; 
    139         case FormatTools.UINT16: 
    140           mipavType = ModelStorageBase.USHORT; 
    141           break; 
    142         case FormatTools.INT32: 
    143           mipavType = ModelStorageBase.INTEGER; 
    144           break; 
    145         case FormatTools.UINT32: 
    146           mipavType = ModelStorageBase.UINTEGER; 
    147           break; 
    148         case FormatTools.FLOAT: 
    149           mipavType = ModelStorageBase.FLOAT; 
    150           break; 
    151         case FormatTools.DOUBLE: 
    152           mipavType = ModelStorageBase.DOUBLE; 
    153           break; 
    154         default: 
    155           throw new FormatException("Unsupported pixel type: " + pixelType); 
    156       } 
    157  
    158       // harvest physical resolution 
    159       Float dimPhysSizeX = store.getDimensionsPhysicalSizeX(0, 0); 
    160       Float dimPhysSizeY = store.getDimensionsPhysicalSizeY(0, 0); 
    161       Float dimPhysSizeZ = store.getDimensionsPhysicalSizeZ(0, 0); 
    162       Float dimTimeInc = store.getDimensionsTimeIncrement(0, 0); 
    163       float physSizeX = dimPhysSizeX == null ? 1.0f : dimPhysSizeX.floatValue(); 
    164       float physSizeY = dimPhysSizeY == null ? 1.0f : dimPhysSizeY.floatValue(); 
    165       float physSizeZ = dimPhysSizeZ == null ? 1.0f : dimPhysSizeZ.floatValue(); 
    166       float timeInc = dimTimeInc == null ? 1.0f : dimTimeInc.floatValue(); 
    167  
    168       // compute dimensional extents 
    169       int[] dimExtents = {sizeX, sizeY, sizeZ, sizeT}; 
    170       float[] res = {physSizeX, physSizeY, physSizeZ, timeInc}; 
    171       int[] units = { 
    172         FileInfoBase.MICROMETERS, FileInfoBase.MICROMETERS, 
    173         FileInfoBase.MICROMETERS, FileInfoBase.SECONDS 
    174       }; 
    175  
    176       // create MIPAV image object 
    177       ModelImage modelImage = new ModelImage(mipavType, dimExtents, imageName); 
    178  
    179       // import planes into MIPAV image 
    180       byte[] buf = new byte[bpp * sizeX * sizeY]; 
    181       for (int i=0; i<imageCount; i++) { 
    182         reader.openBytes(i, buf); 
    183  
    184         // convert byte array to appropriate primitive type 
    185         int offset = i * buf.length; 
    186         Object array = DataTools.makeDataArray(buf, bpp, floating, little); 
    187  
    188         // assign data to MIPAV image object 
    189         switch (mipavType) { 
    190           case ModelStorageBase.BYTE: 
    191           case ModelStorageBase.UBYTE: 
    192             modelImage.importData(offset, (byte[]) array, false); 
    193             break; 
    194           case ModelStorageBase.SHORT: 
    195           case ModelStorageBase.USHORT: 
    196             modelImage.importData(offset, (short[]) array, false); 
    197             break; 
    198           case ModelStorageBase.INTEGER: 
    199           case ModelStorageBase.UINTEGER: 
    200             modelImage.importData(offset, (int[]) array, false); 
    201             break; 
    202           case ModelStorageBase.FLOAT: 
    203             modelImage.importData(offset, (float[]) array, false); 
    204             break; 
    205           case ModelStorageBase.DOUBLE: 
    206             modelImage.importData(offset, (double[]) array, false); 
    207             break; 
    208           default: 
    209             throw new FormatException("Unknown buffer type: " + mipavType); 
    210         } 
    211       } 
    212  
    213       // create a FileInfo object for each image plane 
    214       FileInfoBase[] fileInfo = new FileInfoBase[imageCount]; 
    215       for (int i=0; i<imageCount; i++) { 
    216         // HACK: Use FileInfoImageXML subclass since FileInfoBase is abstract. 
    217         fileInfo[i] = new FileInfoImageXML(name, dir, FileUtility.XML); 
    218         fileInfo[i].setExtents(dimExtents); 
    219         fileInfo[i].setResolutions(res); 
    220         fileInfo[i].setUnitsOfMeasure(units); 
    221         fileInfo[i].setDataType(mipavType); 
    222       } 
    223       modelImage.setFileInfo(fileInfo); 
    224  
    225       // display MIPAV image 
    226       new ViewJFrameImage(modelImage); 
    227     } 
    228     catch (FormatException exc) { 
    229       exc.printStackTrace(); 
    230       MipavUtil.displayError( 
    231         "An error occurred parsing the file: " + exc.getMessage()); 
    232     } 
    233     catch (IOException exc) { 
    234       exc.printStackTrace(); 
    235       MipavUtil.displayError( 
    236         "An I/O error occurred reading the file: " + exc.getMessage()); 
    237     } 
     264    }; 
     265    importerThread.start(); 
    238266  } 
    239267 
     
    242270  } 
    243271 
     272  // -- Helper methods -- 
     273 
     274  private long lastTime = 0; 
     275 
     276  private synchronized void setMessage(final ViewUserInterface mipav, 
     277    final String message, final boolean force) 
     278  { 
     279    long time = System.currentTimeMillis(); 
     280    long elapsed = time - lastTime; 
     281    if (elapsed >= PROGRESS_THRESHOLD || force) { 
     282      lastTime = time; 
     283      SwingUtilities.invokeLater(new Runnable() { 
     284        public void run() { 
     285          mipav.setMessageText(message); 
     286        } 
     287      }); 
     288    } 
     289  } 
     290 
    244291} 
  • trunk/utils/mipav/readme.txt

    r4828 r4848  
    1313   where "/path/to/mipav" is the location of your MIPAV installation. 
    1414 
    15 3) Put the PlugInBioFormatsImporter.class into your user mipav/plugins folder. 
     153) Copy the resultant PlugInBioFormatsImporter*.class files into your user 
     16   mipav/plugins folder. 
    1617 
    17184) Add loci_tools.jar to MIPAV's class path: 
    18      * How to do so is depends on your platform. 
     19     * How to do so depends on your platform. 
    1920     * E.g., in Mac OS X, edit the mipav.app/Contents/Info.plist file. 
    2021 
     
    2324 
    2425------------------------------------------------------------------------------- 
    25 The plugin mostly works, but there are a few problems and open questions: 
     26The plugin works, but there are a couple of problems and open questions: 
    2627 
    27 1) When the image appears onscreen, it looks very washed out, mostly white, 
    28    regardless of the input data. Probing the data yields the correct numerical 
    29    values. Does the LUT need to be configured somehow? 
    30  
    31 2) For the dimensional extents, it seems like MIPAV specifically wants an int 
     281) For the dimensional extents, it seems like MIPAV specifically wants an int 
    3229   array of <= size 4, arranged {width, height, numZSlices, numTimePoints}. Is 
    3330   this correct? The MIPAV API appears to support multidimensional data in 
     
    3633   What are MIPAV's assumptions? 
    3734 
    38 3) Does MIPAV support multichannel data for weird numbers of channels? For 
     352) Does MIPAV support multichannel data for weird numbers of channels? For 
    3936   example, if I have 12-channel data, how do I represent that using the 
    4037   ModelImage API? Due to this uncertainty, the Bio-Formats plugin supports 
Note: See TracChangeset for help on using the changeset viewer.