/* * Copyright (C) 2010-2014 Andreas Maier * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */ package edu.stanford.rsl.conrad.io; import java.io.BufferedOutputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import edu.stanford.rsl.conrad.data.numeric.Grid2D; import edu.stanford.rsl.conrad.utils.CONRAD; import ij.IJ; import ij.ImagePlus; import ij.io.FileInfo; import ij.process.ImageProcessor; /** * Class to stream SEQ Format. Created with a lot of help from Jared Starman. * * @author akmaier * */ public class SEQProjectionSource extends FileProjectionSource { protected boolean debug = true; protected float [] lut; protected int [] Inlut; private boolean directoryMode; private ArrayList<File> fileList; private void initLUT() { lut = new float[65537]; for (int i=0;i<= 16383;i++){ lut[i+1] = ((float)i); } for (int i=0;i<= 16383;i++){ lut[i+1+16384] = ((float)i)*2; } for (int i=0;i<= 16383;i++){ lut[i+1+32768] = ((float)i)*4; } for (int i=0;i<= 16383;i++){ lut[i+1+49152] = ((float)i)*8; } if (fi!=null && fi.width>0 && fi.height>0) { init(); } else { throw new RuntimeException("Format does not match: width = " + fi.width + " height = " + fi.height + " offset = " + fi.offset); } } @Override public void initStream (String filename) throws IOException { File file = new File(filename); if (file.isDirectory()){ // multi file format fileList = new ArrayList<File>(); String [] files = file.list(); Arrays.sort(files); for (String f: files){ if (f.substring(f.length()-4).compareToIgnoreCase(".viv")==0){ fileList.add(new File(file.getAbsolutePath() + "/" +f)); } } if (fileList.size() == 0) throw new IOException("Directory does not contain .viv files"); fi = getHeaderInfo(fileList.get(0).getAbsolutePath()); initLUT(); directoryMode = true; } else { // Code for single file fi = getHeaderInfo(filename); initLUT(); } } /** * Reads the header information from the file into a fileinfo object * @param filename the filename * @return the FileInfo * @throws IOException */ public FileInfo getHeaderInfo( String filename ) throws IOException { if (IJ.debugMode) CONRAD.log("Entering Nrrd_Reader.readHeader():"); FileInfo fi = new FileInfo(); File file = new File(filename); fi.fileName=file.getName(); fi.directory = file.getParent() + "/"; // NB Need RAF in order to ensure that we know file offset RandomAccessFile input = new RandomAccessFile(fi.directory+fi.fileName,"r"); fi.fileType = FileInfo.GRAY8; // just assume this for the mo fi.fileFormat = FileInfo.RAW; fi.nImages = 1; // parse the header file, until reach an empty line// boolean keepReading=true; byte [] values = new byte[4]; input.read(values); fi.offset = (int) convertToUnsignedInt(values,0); //System.out.println("Read " + fi.offset); if (fi.offset != 2048){ throw new IOException("Wrong Header Size; Not an SEQ File."); } byte [] header = new byte [(fi.offset) -4]; input.read(header); fi.width = (int) convertToUnsignedInt(header, 3); fi.height = (int) convertToUnsignedInt(header, 4); fi.nImages = (int) convertToUnsignedInt(header, 6); if (true) { System.out.println("SEQ Reading image with " + fi.nImages + " frames with " + fi.width + "x" + fi.height + " resolution"); } int dataType = (int) convertToUnsignedInt(header, 458); if((dataType & 512)>0){ fi.compression = FileInfo.COMPRESSION_UNKNOWN; } else { fi.compression = FileInfo.COMPRESSION_NONE; } fi.fileType=FileInfo.GRAY16_UNSIGNED; fi.intelByteOrder = true; input.close(); return (fi); } private Grid2D readSingleImage(){ Grid2D revan = super.getNextProjection(); if (revan != null) { try { Thread.sleep(CONRAD.INPUT_QUEUE_DELAY); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } Grid2D uncompressed = new Grid2D(revan.getWidth(), revan.getHeight()); // uncompression int min = Integer.MAX_VALUE; int max = Integer.MIN_VALUE; for (int i = 0; i< revan.getWidth(); i++){ for (int j = 0; j< revan.getHeight(); j++){ int val = (int) (revan.getPixelValue(i, j)); if (val > max) max = val; if (val < min) min = val; if (fi.compression == FileInfo.COMPRESSION_UNKNOWN){ uncompressed.putPixelValue(i,j,lut[val+1]); } else { uncompressed.putPixelValue(i,j,val); } } } //System.out.println("Range: " + min + " " + max); return uncompressed; } else { return null; } } @Override public Grid2D getNextProjection(){ if (!directoryMode) { return readSingleImage(); } else { try{ fi = getHeaderInfo(fileList.get(currentIndex+1).getPath()); initStack(); return readSingleImage(); } catch (IOException e) { e.printStackTrace(); return null; } catch (IndexOutOfBoundsException e){ return null; } } } public void saveViva(ImagePlus imp, String path) { if (imp.getNSlices()<1) return; ImageProcessor improc = imp.getProcessor(); File file = new File(path); DataOutputStream dos = null; initInLUT(); try { dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); FileInfo fi = imp.getFileInfo(); dos.write(convertInt2Bytes(2048)); dos.writeChars("RevK04"); dos.write(convertInt2Bytes(fi.width)); dos.write(convertInt2Bytes(fi.height)); dos.write(convertInt2Bytes(2)); dos.write(convertInt2Bytes(fi.nImages)); byte [] a = {-93,46,90,-36,-50,-73,17,-45,-94,-24,1,16,75,-58,-41,-51,0,0,0,0}; dos.write(a); dos.write(ByteBuffer.allocate(1784).array()); int dataType = 0; if (improc.getMax()>65535) dataType = 514; dos.write(convertInt2Bytes(dataType)); dos.write(ByteBuffer.allocate(208).array()); byte[] bBuff = new byte [imp.getWidth()*imp.getHeight()*2]; for (int j=0;j<imp.getHeight();j++){ for (int k=0;k<imp.getWidth();k++){ float val = (float) (improc.getPixelValue(k, j)); if (dataType == 514){ bBuff[j*imp.getWidth()*2+k*2] = convertInt2UnShort(Inlut[(int)val+1])[0]; bBuff[j*imp.getWidth()*2+k*2+1] = convertInt2UnShort(Inlut[(int)val+1])[1]; } else { bBuff[j*imp.getWidth()*2+k*2] = convertInt2UnShort((int)val)[0]; bBuff[j*imp.getWidth()*2+k*2+1] = convertInt2UnShort((int)val)[1]; } } } dos.write(bBuff); dos.flush(); dos.close(); } catch (Exception e) { e.printStackTrace(); } } private void initInLUT() { Inlut = new int [131073]; for (int i=0;i<= 16383;i++){ Inlut[i+1] = (int)i; } for (int i=16384;i<= 32767;i++){ Inlut[i+1] = (int)(i/2 + 16384); } for (int i=32768;i<= 49151;i++){ Inlut[i+1] = (int)(i/4 + 32768); } for (int i=49152;i<= 131071;i++){ Inlut[i+1] = (int)(i/8 + 49152); } } public byte[] convertInt2Bytes(int value) { byte[] buf = new byte[4]; buf[3] = (byte) ((value & 0xFF000000)>>24); buf[2] = (byte) ((value & 0x00FF0000)>>16); buf[1] = (byte) ((value & 0x0000FF00)>>8); buf[0] = (byte) (value & 0x000000FF); return buf; } public byte[] convertInt2UnShort(int value) { byte[] buf = new byte[2]; buf[1] = (byte) ((value & 0x0000FF00)>>8); buf[0] = (byte) (value & 0x000000FF); return buf; } }