teaching machines

CS 145 Lecture 39 – Volume Slicer

December 5, 2014 by . Filed under cs145, fall 2014, lectures.

Agenda

TODO

Code

Gif

A transverse iteration through the Visible Male dataset.

A transverse iteration through the Visible Male dataset.

Vector2D.java

package lecture1205;

public class Vector2D {
  public double x;
  private double y;
  private double length;
  
  public Vector2D() {
    System.out.println("ctor");
  }
  
  public Vector2D(double x, double y) {
    this.x = x;
    this.y = y;
    length = Math.hypot(x, y);
  }
  
  public double getLength() {
    return length;
  }
  
  public void setX(double newX) {
    x = newX;
    length = Math.hypot(x, y);
  }
  
  public static Vector2D Vector2D() {
    System.out.println("static");
    return null;
  }
  
  public static void main(String[] args) {
    Vector2D v = new Vector2D();
    
    Vector2D vv = new Vector2D(10, 20);
    System.out.println(vv.getLength());
    vv.x = Double.MAX_VALUE;
    System.out.println(vv.getLength());

  }
}

Volume.java

package lecture1205;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Volume {
  private int[][][] voxels;
  
  public Volume(String path) throws IOException {
    LEDataInputStream in = new LEDataInputStream(path);
    
    int width = in.readInt();
    int height = in.readInt();
    int depth = in.readInt();
    
    System.out.printf("%d %d %d", width, height, depth);
    
    voxels = new int[depth][height][width];
    for (int z = 0; z < depth; ++z) {
      for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
          voxels[z][y][x] = in.read();
        }
      }
    }
    
    in.close();
  }
  
  public int getWidth() {
    return voxels[0][0].length;
  }
  
  public int getHeight() {
    return voxels[0].length;
  }
  
  public int getDepth() {
    return voxels.length;
  }
  
  public int getVoxel(int x, int y, int z) {
    return voxels[z][y][x];
  }
}

TransferFunction.java

package lecture1205;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class TransferFunction {
  private BufferedImage colors;
  
  public TransferFunction(String path) throws IOException {
    colors = ImageIO.read(new File(path));
  }
  
  public int lookup(float proportion) {
    int i = (int) (proportion * (colors.getWidth() - 1));
    return colors.getRGB(i, 0);
  }
}

Renderer.java

package lecture1205;

import java.awt.image.BufferedImage;

public class Renderer {
  public static void transverse(Volume volume,
                                TransferFunction function,
                                String outPath) {
    GifSequenceWriter giffer = new GifSequenceWriter(outPath, 100, true);

    for (int y = 0; y < volume.getHeight(); ++y) {
      BufferedImage frame = new BufferedImage(volume.getWidth(), volume.getDepth(), BufferedImage.TYPE_INT_RGB);
      for (int z = 0; z < volume.getDepth(); ++z) {
        for (int x = 0; x < volume.getWidth(); ++x) {
          int intensity = volume.getVoxel(x, y, z);
          int color = function.lookup(intensity / 255.0f);
          frame.setRGB(x, z, color);
        }
      }
      giffer.appendFrame(frame);
    }

    giffer.close();
  }

  public static void coronal(Volume volume,
                             TransferFunction function,
                             String outPath) {
    GifSequenceWriter giffer = new GifSequenceWriter(outPath, 100, true);

    for (int z = 0; z < volume.getDepth(); ++z) {
      BufferedImage frame = new BufferedImage(volume.getWidth(), volume.getHeight(), BufferedImage.TYPE_INT_RGB);
      for (int y = 0; y < volume.getHeight(); ++y) {
        for (int x = 0; x < volume.getWidth(); ++x) {
          int density = volume.getVoxel(x, y, z);
          int color = function.lookup(density / 255.0f);
          frame.setRGB(x, y, color);
        }
      }
      giffer.appendFrame(frame);
    }

    giffer.close();
  }
}

LEDataInputStream.java

package lecture1205;

import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * A class for reading primitives from a file in little endian format. 
 */
public class LEDataInputStream {

  /** The underlying big endian file reader. */
  private DataInputStream in;
  
  /** A collection of bytes used for an endian switcharoo. */
  private byte[] bytes;
  
  /** An endian switcher. */
  private ByteBuffer buffer;
  
  /**
   * Create a new little endian file reader for the specified file.
   * 
   * @param file
   * Name of file to reader.
   * 
   * @throws FileNotFoundException
   */
  public LEDataInputStream(String file) throws FileNotFoundException {
    in = new DataInputStream(new FileInputStream(file));
    bytes = new byte[4];
    buffer = ByteBuffer.wrap(bytes);
    buffer.order(ByteOrder.LITTLE_ENDIAN);
  }
  
  /**
   * Read the next int from the file.
   * 
   * @return
   * Value read.
   * 
   * @throws IOException
   */
  public int readInt() throws IOException {
    in.read(bytes, 0, 4);
    return buffer.getInt(0);
  }
  
  /**
   * Read the next short from the file.
   * 
   * @return
   * Value read.
   * 
   * @throws IOException
   */
  public short readShort() throws IOException {
    in.read(bytes, 0, 2);
    return buffer.getShort(0);
  }
  
  /**
   * Read a sequence of bytes from the file. The number of bytes read is determined by the length of the array.
   * 
   * @param bytes
   * Array in which read bytes are stored.
   * 
   * @throws IOException
   */
  public void read(byte[] bytes) throws IOException {
    in.read(bytes);
  }
  
  public int read() throws IOException {
    return in.read();
  }
  
  /**
   * Read a sequence of shorts from the file. The number of shorts read is determined by the length of the array.
   *  
   * @param shorts
   * Array in which shorts are stored.
   * 
   * @throws IOException
   */
  public void read(short[] shorts) throws IOException {
    for (int i = 0; i < shorts.length; ++i) {
      shorts[i] = readShort();
    }
  }
  
  /**
   * Close the file.
   * 
   * @throws IOException
   */
  public void close() throws IOException {
    in.close();
  }
}

GifSequenceWriter.java

package lecture1205;

// 
//  GifSequenceWriter.java
//  
//  Created by Elliot Kroo on 2009-04-25.
//
// This work is licensed under the Creative Commons Attribution 3.0 Unported
// License. To view a copy of this license, visit
// http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative
// Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.

import javax.imageio.*;
import javax.imageio.metadata.*;
import javax.imageio.stream.*;
import java.awt.image.*;
import java.io.*;
import java.util.Iterator;

public class GifSequenceWriter {
  protected ImageWriter gifWriter;
  protected ImageWriteParam imageWriteParam;
  protected IIOMetadata imageMetaData;
  protected ImageOutputStream outputStream;

  /**
   * Creates a new GifSequenceWriter
   * 
   * @param outputStream
   * the ImageOutputStream to be written to
   * @param imageType
   * one of the imageTypes specified in BufferedImage
   * @param timeBetweenFramesMS
   * the time between frames in miliseconds
   * @param loopContinuously
   * wether the gif should loop repeatedly
   * @throws IIOException
   * if no gif ImageWriters are found
   *
   * @author Elliot Kroo (elliot[at]kroo[dot]net)
   */
  public GifSequenceWriter(String outputPath,
                           int timeBetweenFramesMS,
                           boolean loopContinuously) {
    try {
      // my method to create a writer
      gifWriter = getWriter();
      imageWriteParam = gifWriter.getDefaultWriteParam();
      ImageTypeSpecifier imageTypeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);

      imageMetaData = gifWriter.getDefaultImageMetadata(imageTypeSpecifier, imageWriteParam);

      String metaFormatName = imageMetaData.getNativeMetadataFormatName();

      IIOMetadataNode root = (IIOMetadataNode) imageMetaData.getAsTree(metaFormatName);

      IIOMetadataNode graphicsControlExtensionNode = getNode(root, "GraphicControlExtension");

      graphicsControlExtensionNode.setAttribute("disposalMethod", "none");
      graphicsControlExtensionNode.setAttribute("userInputFlag", "FALSE");
      graphicsControlExtensionNode.setAttribute("transparentColorFlag", "FALSE");
      graphicsControlExtensionNode.setAttribute("delayTime", Integer.toString(timeBetweenFramesMS / 10));
      graphicsControlExtensionNode.setAttribute("transparentColorIndex", "0");

      IIOMetadataNode commentsNode = getNode(root, "CommentExtensions");
      commentsNode.setAttribute("CommentExtension", "Created by MAH");

      IIOMetadataNode appEntensionsNode = getNode(root, "ApplicationExtensions");

      IIOMetadataNode child = new IIOMetadataNode("ApplicationExtension");

      child.setAttribute("applicationID", "NETSCAPE");
      child.setAttribute("authenticationCode", "2.0");

      int loop = loopContinuously ? 0 : 1;

      child.setUserObject(new byte[]{
        0x1,
        (byte) (loop & 0xFF),
        (byte) ((loop >> 8) & 0xFF)
      });
      appEntensionsNode.appendChild(child);

      imageMetaData.setFromTree(metaFormatName, root);

      outputStream = new FileImageOutputStream(new File(outputPath));
      gifWriter.setOutput(outputStream);
      gifWriter.prepareWriteSequence(null);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  public void appendFrame(BufferedImage img) {
    try {
      gifWriter.writeToSequence(new IIOImage(img, null, imageMetaData), imageWriteParam);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Close this GifSequenceWriter object. This does not close the underlying
   * stream, just finishes off the GIF.
   */
  public void close() {
    try {
      gifWriter.endWriteSequence();
      outputStream.close();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Returns the first available GIF ImageWriter using
   * ImageIO.getImageWritersBySuffix("gif").
   * 
   * @return a GIF ImageWriter object
   * @throws IIOException
   * if no GIF image writers are returned
   */
  private static ImageWriter getWriter() throws IIOException {
    try {
      Iterator<ImageWriter> iter = ImageIO.getImageWritersBySuffix("gif");
      if (!iter.hasNext()) {
        throw new IIOException("No GIF Image Writers Exist");
      } else {
        return iter.next();
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * Returns an existing child node, or creates and returns a new child node (if
   * the requested node does not exist).
   * 
   * @param rootNode
   * the <tt>IIOMetadataNode</tt> to search for the child node.
   * @param nodeName
   * the name of the child node.
   * 
   * @return the child node, if found or a new node created with the given name.
   */
  private static IIOMetadataNode getNode(IIOMetadataNode rootNode,
                                         String nodeName) {
    int nNodes = rootNode.getLength();
    for (int i = 0; i < nNodes; i++) {
      if (rootNode.item(i).getNodeName().compareToIgnoreCase(nodeName) == 0) {
        return ((IIOMetadataNode) rootNode.item(i));
      }
    }
    IIOMetadataNode node = new IIOMetadataNode(nodeName);
    rootNode.appendChild(node);
    return node;
  }
}

Haiku

on assigning responsibility:
Do I milk the cow?
Or do I decow the milk?
I’m split half and half