|
RoiDecoder |
|
package ij.io; import ij.gui.*; import java.io.*; import java.util.*; import java.net.*; /* ImageJ/NIH Image 64 byte ROI outline header 2 byte numbers are big-endian signed shorts 0-3 "Iout" 4-5 version (>=217) 6-7 roi type 8-9 top 10-11 left 12-13 bottom 14-15 right 16-17 NCoordinates 18-33 x1,y1,x2,y2 (straight line) 34-35 line width (unused) 36-39 ShapeRoi size (type must be 1 if this value>0) 40-63 reserved (zero) 64-67 x0, y0 (polygon) 68-71 x1, y1 etc. */ /** Decodes an ImageJ, NIH Image or Scion Image ROI. */ public class RoiDecoder { private final int polygon=0, rect=1, oval=2, line=3, freeline=4, polyline=5, noRoi=6, freehand=7, traced=8, angle=9, point=10; private byte[] data; private String path; private InputStream is; private String name; private int size; /** Constructs an RoiDecoder using a file path. */ public RoiDecoder(String path) { this.path = path; } /** Constructs an RoiDecoder using a byte array. */ public RoiDecoder(byte[] bytes, String name) { is = new ByteArrayInputStream(bytes); this.name = name; this.size = bytes.length; } /** Returns the ROI. */ public Roi getRoi() throws IOException { if (path!=null) { File f = new File(path); size = (int)f.length(); if (size>500000) throw new IOException("This is not an ImageJ ROI"); name = f.getName(); is = new FileInputStream(path); } data = new byte[size]; int total = 0; while (total<size) total += is.read(data, total, size-total); is.close(); if (getByte(0)!=73 || getByte(1)!=111) //"Iout" throw new IOException("This is not an ImageJ ROI"); int type = getByte(6); int top= getShort(8); int left = getShort(10); int bottom = getShort(12); int right = getShort(14); int width = right-left; int height = bottom-top; int n = getShort(16); if (name.endsWith(".roi")) name = name.substring(0, name.length()-4); boolean isComposite = getInt(36)>0; if (isComposite) return getShapeRoi(); Roi roi = null; switch (type) { case rect: roi = new Roi(left, top, width, height); break; case oval: roi = new OvalRoi(left, top, width, height); break; case line: int x1 = (int)getFloat(18); int y1 = (int)getFloat(22); int x2 = (int)getFloat(26); int y2 = (int)getFloat(30); roi = new Line(x1, y1, x2, y2); //IJ.write("line roi: "+x1+" "+y1+" "+x2+" "+y2); break; case polygon: case freehand: case traced: case polyline: case freeline: case angle: case point: //IJ.write("type: "+type); //IJ.write("n: "+n); //IJ.write("rect: "+left+","+top+" "+width+" "+height); if (n==0) break; int[] x = new int[n]; int[] y = new int[n]; int base1 = 64; int base2 = base1+2*n; int xtmp, ytmp; for (int i=0; i<n; i++) { xtmp = getShort(base1+i*2); if (xtmp<0) xtmp = 0; ytmp = getShort(base2+i*2); if (ytmp<0) ytmp = 0; x[i] = left+xtmp; y[i] = top+ytmp; //IJ.write(i+" "+getShort(base1+i*2)+" "+getShort(base2+i*2)); } if (type==point) { roi = new PointRoi(x, y, n); break; } int roiType; if (type==polygon) roiType = Roi.POLYGON; else if (type==freehand) roiType = Roi.FREEROI; else if (type==traced) roiType = Roi.TRACED_ROI; else if (type==polyline) roiType = Roi.POLYLINE; else if (type==freeline) roiType = Roi.FREELINE; else if (type==angle) roiType = Roi.ANGLE; else roiType = Roi.FREEROI; roi = new PolygonRoi(x, y, n, roiType); break; default: throw new IOException("Unrecognized ROI type: "+type); } roi.setName(name); return roi; } public Roi getShapeRoi() throws IOException { int type = getByte(6); if (type!=rect) throw new IllegalArgumentException("Invalid composite ROI type"); int top= getShort(8); int left = getShort(10); int bottom = getShort(12); int right = getShort(14); int width = right-left; int height = bottom-top; int n = getInt(36); ShapeRoi roi = null; float[] shapeArray = new float[n]; int base = 64; for(int i=0; i<n; i++) { shapeArray[i] = getFloat(base); base += 4; } roi = new ShapeRoi(shapeArray); roi.setName(name); return roi; } int getByte(int base) { return data[base]&255; } int getShort(int base) { int b0 = data[base]&255; int b1 = data[base+1]&255; int n = (short)((b0<<8) + b1); if (n<-5000) n = (b0<<8) + b1; // assume n>32767 and unsigned return n; } int getInt(int base) { int b0 = data[base]&255; int b1 = data[base+1]&255; int b2 = data[base+2]&255; int b3 = data[base+3]&255; return ((b0<<24) + (b1<<16) + (b2<<8) + b3); } float getFloat(int base) { return Float.intBitsToFloat(getInt(base)); } }
|
RoiDecoder |
|