Changeset 7748


Ignore:
Timestamp:
09/13/11 15:33:40 (8 years ago)
Author:
curtis
Message:

Progress on Prairie TIFF stitching. Seems to work.

Single-image TIFFs are compiled into TIFF stacks for compatibility with
"Stitch Collection of Images" plugin. Stage coordinates are also
normalized so that tiles start at (0, 0) so that the stitching plugin
does not allocate needless black space when creating the mosaic.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/projects/misc-plugins/src/main/java/loci/plugins/StitchPrairieTiff.java

    r7747 r7748  
    4646import java.util.ArrayList; 
    4747import java.util.Calendar; 
     48import java.util.Collections; 
    4849import java.util.Date; 
    4950import java.util.List; 
     
    5455import javax.xml.parsers.SAXParser; 
    5556import javax.xml.parsers.SAXParserFactory; 
     57 
     58import loci.formats.CoreMetadata; 
     59import loci.formats.FormatException; 
     60import loci.formats.IFormatReader; 
     61import loci.formats.IFormatWriter; 
     62import loci.formats.MetadataTools; 
     63import loci.formats.in.MinimalTiffReader; 
     64import loci.formats.meta.IMetadata; 
     65import loci.formats.out.TiffWriter; 
     66import ome.xml.model.primitives.PositiveInteger; 
    5667 
    5768import org.xml.sax.Attributes; 
     
    90101                if (!success) return; 
    91102 
    92                 final String tileConfigPath = createTileConfiguration(file); 
     103                final File tileFile = createTileConfiguration(file); 
    93104                IJ.showStatus(""); 
    94                 if (tileConfigPath == null) return; 
     105                if (tileFile == null) return; 
    95106 
    96107                if (stitch) { 
    97108                        IJ.showStatus("Performing stitching..."); 
    98                         executeStitching(tileConfigPath); 
     109                        executeStitching(tileFile.getAbsolutePath()); 
    99110                        IJ.showStatus("Stitching complete."); 
    100111                } 
     
    153164         * plugins. 
    154165         */ 
    155         private String createTileConfiguration(final File dataFile) { 
     166        private File createTileConfiguration(final File dataFile) { 
     167                final File baseDir = dataFile.getParentFile(); 
    156168                try { 
    157169                        IJ.showStatus("Parsing stage positions..."); 
    158170                        final List<Pt> coords = parseCoords(dataFile); 
     171                        Collections.sort(coords); 
     172 
     173                        IJ.showStatus("Normalizing coordinates..."); 
     174                        normalizeCoords(coords); 
     175 
     176                        IJ.showStatus("Converting TIFFs to stacks..."); 
     177                        final List<Pt> newCoords = convertTIFFs(baseDir, coords); 
    159178 
    160179                        IJ.showStatus("Generating tile configuration file..."); 
    161                         final File tileFile = writeTileFile(dataFile.getParentFile(), coords); 
     180                        final File tileFile = writeTileFile(dataFile.getParentFile(), newCoords); 
    162181                        IJ.log("Wrote tile configuration:"); 
    163182                        IJ.log(tileFile.getAbsolutePath()); 
    164183                        IJ.log(""); 
    165184 
    166                         return tileFile.getAbsolutePath(); 
     185                        return tileFile; 
     186                } 
     187                catch (final FormatException e) { 
     188                        IJ.handleException(e); 
    167189                } 
    168190                catch (final IOException e) { 
     
    170192                } 
    171193                return null; 
     194        } 
     195 
     196        /** Ensures coordinates begin at (0, 0). */ 
     197        private void normalizeCoords(List<Pt> coords) { 
     198                // find minimum coordinates 
     199                double minX = Double.POSITIVE_INFINITY, minY = Double.POSITIVE_INFINITY; 
     200                for (Pt pt : coords) { 
     201                        if (pt.x < minX) minX = pt.x; 
     202                        if (pt.y < minY) minY = pt.y; 
     203                } 
     204                // normalize coordinates so minimum is (0, 0) 
     205                for (Pt pt : coords) { 
     206                        pt.x -= minX; 
     207                        pt.y -= minY; 
     208                } 
     209        } 
     210 
     211        /** 
     212         * Compiles the collection of single-plane TIFFs into TIFF stacks along Z, one 
     213         * stack per tile. 
     214         */ 
     215        private List<Pt> convertTIFFs(final File baseDir, final List<Pt> coords) 
     216                throws FormatException, IOException 
     217        { 
     218                if (coords == null || coords.size() == 0) return null; 
     219                final int firstIndex = coords.get(0).gridIndex; 
     220 
     221                final ArrayList<Pt> newCoords = new ArrayList<Pt>(); 
     222 
     223                // compute list of stack sizes 
     224                final ArrayList<Integer> stackSizes = computeStackSizes(coords, firstIndex); 
     225 
     226                // convert individual TIFF files to TIFF stacks 
     227                final IFormatReader reader = new MinimalTiffReader(); 
     228                final IFormatWriter writer = new TiffWriter(); 
     229                int outIndex = 0; 
     230                boolean outValid = false; 
     231                String outName = null; 
     232                byte[] buf = null; 
     233                int lastIndex = 0; 
     234                int p = -1; 
     235                for (final Pt pt : coords) { 
     236                        p++; 
     237                        IJ.showStatus("Processing plane " + p + "/" + coords.size()); 
     238                        IJ.showProgress(p, coords.size()); 
     239 
     240                        if (pt.gridIndex != lastIndex) { 
     241                                // new tile has begun 
     242                                lastIndex = pt.gridIndex; 
     243 
     244                                outName = "ZStack-" + pt.filename.replaceAll("_[0-9]+\\.tif", ".tif"); 
     245                                final File outFile = new File(baseDir, outName); 
     246                                outValid = !outFile.exists(); 
     247 
     248                                final Pt newPt = new Pt(); 
     249                                newCoords.add(newPt); 
     250                                newPt.filename = outName; 
     251                                newPt.x = pt.x; 
     252                                newPt.y = pt.y; 
     253                                newPt.z = pt.z; 
     254 
     255                                writer.close(); 
     256                                outIndex = 0; 
     257                        } 
     258                        if (!outValid) continue; // output stack already written 
     259 
     260                        // read planes from input and write to output 
     261                        final String inId = new File(baseDir, pt.filename).getAbsolutePath(); 
     262                        final IMetadata meta = MetadataTools.createOMEXMLMetadata(); 
     263                        reader.setMetadataStore(meta); 
     264                        reader.setId(inId); 
     265                        final int imageCount = reader.getImageCount(); 
     266                        for (int i = 0; i < imageCount; i++) { 
     267                                if (buf == null) { 
     268                                        // allocate new buffer 
     269                                        buf = reader.openBytes(i); 
     270                                } 
     271                                else { 
     272                                        // reuse allocated buffer 
     273                                        reader.openBytes(i, buf); 
     274                                } 
     275                                if (outIndex == 0) { 
     276                                        // initialize fresh writer's dimensional metadata 
     277                                        final IMetadata outMeta = MetadataTools.createOMEXMLMetadata(); 
     278                                        final CoreMetadata core = reader.getCoreMetadata()[0]; 
     279                                        MetadataTools.populateMetadata(outMeta, 0, null, core); 
     280                                        final int sizeZ = stackSizes.get(0); 
     281                                        stackSizes.remove(0); // lazy 
     282                                        outMeta.setPixelsSizeZ(new PositiveInteger(sizeZ), 0); 
     283                                        writer.setMetadataRetrieve(outMeta); 
     284                                        final String outId = new File(baseDir, outName).getAbsolutePath(); 
     285                                        writer.setId(outId); 
     286                                } 
     287                                writer.saveBytes(outIndex++, buf); 
     288                        } 
     289                        reader.close(); 
     290                } 
     291                writer.close(); 
     292 
     293                return newCoords; 
     294        } 
     295 
     296        private ArrayList<Integer> computeStackSizes(final List<Pt> coords, 
     297                final int firstIndex) 
     298        { 
     299                final ArrayList<Integer> stackSizes = new ArrayList<Integer>(); 
     300                int stackSize = 0; 
     301                int lastIndex = firstIndex; 
     302                for (final Pt pt : coords) { 
     303                        if (pt.gridIndex == lastIndex) { 
     304                                stackSize++; 
     305                        } 
     306                        else { 
     307                                stackSizes.add(stackSize); 
     308                                stackSize = 1; 
     309                                lastIndex = pt.gridIndex; 
     310                        } 
     311                } 
     312                stackSizes.add(stackSize); 
     313                return stackSizes; 
    172314        } 
    173315 
     
    224366         *  
    225367         * @param dir The directory where the data files are. 
    226          * @return The full path to the file where tile configuration was written. 
     368         * @return The full path to the file where tile configurations was written. 
    227369         * @throws IOException If something goes wrong writing the file. 
    228370         */ 
     
    230372                throws IOException 
    231373        { 
    232                 // create tile configuration file 
     374                // get current datestamp 
    233375                final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'-'HHmmss"); 
    234376                final Date now = Calendar.getInstance().getTime(); 
     377                final String datestamp = sdf.format(now); 
     378 
     379                // create tile configuration file 
    235380                final File tileFile = 
    236                         new File(dir, "TileConfiguration-" + sdf.format(now) + ".txt"); 
     381                        new File(dir, "TileConfiguration-" + datestamp + ".txt"); 
    237382                final PrintWriter out = new PrintWriter(tileFile); 
    238383 
    239384                // write data to file 
    240                 writeHeader(out, 3); 
     385                writeHeader(out); 
    241386                for (final Pt pt : coords) { 
    242387                        writeLine(out, dir, pt.filename, 3, pt.x, pt.y, pt.z); 
     
    247392        } 
    248393 
    249         private static void writeHeader(final PrintWriter out, final int dim) { 
     394        private static void writeHeader(final PrintWriter out) { 
    250395                out.println("# Define the number of dimensions we are working on"); 
    251                 out.println("dim = " + dim); 
     396                out.println("dim = 3"); 
    252397                out.println(); 
    253398                out.println("# Define the image coordinates"); 
     
    312457        } 
    313458 
    314         // -- Helper classes -- 
    315  
    316         static class Pt { 
     459        static class Pt implements Comparable<Pt> { 
    317460 
    318461                String filename; 
    319462                double x, y, z; 
     463                int gridIndex; 
     464 
     465                @Override 
     466                public int compareTo(final Pt pt) { 
     467                        if (gridIndex < pt.gridIndex) return gridIndex - pt.gridIndex; 
     468                        if (z != pt.z) return z < pt.z ? -1 : 1; 
     469                        return filename.compareTo(pt.filename); 
     470                } 
     471 
    320472        } 
    321473 
     
    327479                private double x, y, z; 
    328480                private double xMicrons, yMicrons; 
     481                private int gridIndex; 
    329482 
    330483                PrairieHandler(final List<Pt> coords) { 
     
    357510                                else if (key.equals("micronsPerPixel_YAxis")) { 
    358511                                        yMicrons = Double.parseDouble(value); 
     512                                } 
     513                                else if (key.equals("xYStageGridIndex")) { 
     514                                        gridIndex = Integer.parseInt(value); 
    359515                                } 
    360516                        } 
     
    371527                                pt.y = y / yMicrons; 
    372528                                pt.z = z; 
     529                                pt.gridIndex = gridIndex; 
    373530                                coords.add(pt); 
    374531                                clearState(); 
     
    380537                        x = y = z = Double.NaN; 
    381538                        xMicrons = yMicrons = 1; 
     539                        gridIndex = 0; 
    382540                } 
    383541 
Note: See TracChangeset for help on using the changeset viewer.