Saturday 14 December 2013

Private tag numbers available for use in DICOM

Private tags are typically just documented by a device manufacturer in the DICOM Conformance Statement for the product adding the private tags. The method for adding private tags was designed to prevent conflicts between manufacturers. When adding tags, you should develop in such away to prevent conflicts. Ie, to give an example, a typical DICOM tag is composed of a 2 byte group and a 2 byte element:
(gggg,eeee)
The group needs to be an odd number greater than 0008. Your private attributes are typically in a private block that have an associated private creator data element. The private creator is encoded as such:
(gggg,00bb)
where bb in the tag is an open private block in the DICOM object and has a value in the rage of 10-FF. This private block is where conflicts between vendors are dealt with. You must assign your private tags in the object to one of these blocks.
Finally, the private elements themselves are within the block:
(gggg,bbxx)
Where the block is encoded in the tag, and then the elements themselves are defined by xx. Your conformance statement should list your private identification code, the DICOM VR of the tag, the element number (xx) of the tag, along with a description of the tag so that other vendors can use the tag, if necessary.
If you want a more detailed explanation, it can be found in Part 5 of the DICOM Standard, starting at page 45.

Thursday 12 December 2013

Create image thumbnail in java using ImageJ API

For more information on how to implement Photos sharing website using Java, Spring, Tomcat, Imagej download Fotovault (opensource Photo sharing project) Fotovault - Photo Sharing Project
Below is the code example to create thumbnails in Java.

Download ImageJ jar from

http://rsbweb.nih.gov/ij/download.html

and include it in your classpath.

The below code example proportionately/evenly crops the image to make the image a perfect square and creates a thumbnail of 100 X 100 pixels.
cropAndResize method takes the fileAbsolutePath and Save as image suffix (thumbnail name suffix).


Dynamic Cylinder

When a BY_REFERENCE GeometryArray object is created, the user creates geometry arrays and populates those arrays with geometry data. There are no geometry arrays internal to the Geometry object no copy of the geometry data made. Instead the BY_REFERENCE GeometryArray object simply stores a reference to the user array(s) of geometry data.
There are two good reasons for using BY_REFERENCE GeometryArray:
  1. if the geometry data is dynamic
  2. if the geometry data requires too much memory
This program shows how to implement the dynamic geometry data by a BY_REFERENCE GeometryArray.

Image 

public class DynamicCylinder extends JFrame {
  private float height = 0.5f;
  private float radius = 0.02f;
  private int verticesNum = 40;
  private float[] vertices = new float[verticesNum * 3];
  private Shape3D cylinder=new Shape3D(createGeometry());
  
  private JTextField heightTxt=new JTextField("0.5",5);
  private JTextField radiusTxt=new JTextField("0.02",5);
  
  public DynamicCylinder() {
    ...
    
    // Prepare the control panel for changing the height and radius of 
    // the cylinder
    JPanel panel=new JPanel();
    panel.add(new JLabel("Height:"));
    panel.add(heightTxt);
    panel.add(new JLabel("Radius:"));
    panel.add(radiusTxt);
    JButton okBtn=new JButton("Ok");
    okBtn.addActionListener(new ActionListener(){
      public void actionPerformed(ActionEvent e) {
        setHeight(Float.parseFloat(heightTxt.getText()));
        setRadius(Float.parseFloat(radiusTxt.getText()));
      }
      
    });
    panel.add(okBtn);
    getContentPane().add(panel,BorderLayout.SOUTH);
  }

  public BranchGroup createSceneGraph() {
    BranchGroup objRoot = new BranchGroup();

    // Set the proper capabilities
    cylinder.setCapability(Shape3D.ALLOW_GEOMETRY_READ);
    
    objRoot.addChild(cylinder);

    return objRoot;
  }

  private Geometry createGeometry() {
    updateVertices();

    // Create the geometry by reference
    TriangleStripArray quadArray = new TriangleStripArray(verticesNum,
        GeometryArray.COORDINATES | GeometryArray.BY_REFERENCE,
        new int[] { verticesNum });
    quadArray.setCoordRefFloat(vertices);
    // Set the capabilities
    quadArray.setCapability(GeometryArray.ALLOW_REF_DATA_READ);
    quadArray.setCapability(GeometryArray.ALLOW_REF_DATA_WRITE);

    return quadArray;
  }
  
  private void updateVertices() {
      float perR = (float) (* Math.PI / (verticesNum / 1));      
      for (int i = 0; i < verticesNum; i += 2) {
        vertices[ (i + 13= vertices[i *
            3(float) (radius * Math.cos(i / * perR));
        vertices[ (i + 12= vertices[i * +
            2(float) (radius * Math.sin(i / * perR));
        vertices[i * 1= height;
        vertices[ (i + 110;
      }
    }
  
  public void setHeight(float height) {
      float oldHeight = this.height;
      this.height = height;

      // Update the geometry
      this.updateGeometry();
    }
  
  public void setRadius(float radius) {
      float oldRadius = this.radius;
      this.radius = radius;

      // Update the geometry
      this.updateGeometry();
    }
  
  private void updateGeometry() {
      GeometryArray geometryArray = (GeometryArray)cylinder.getGeometry();
      geometryArray.updateData(new GeometryUpdater(){
        public void updateData(Geometry geometry){
          updateVertices();
        }
      });
    }

  public static void main(String[] args) {
    ...
  }
}

ImageJ New Plugins

In a joint project, we work towards using ImageJ in the context of neuroanatomy. The people involved are:
  • Baker, Dean
  • Jenett, Arnim
  • Grübel, Kornelia
  • Heisenberg, Martin
  • Larkworthy, Tom
  • Longair, Mark
  • Schindelin, Johannes
  • Schmid, Benjamin

AmiraMesh Reader / Writer

In the Würzburg group, we work a lot with Amira, and we work a lot with ImageJ.
To make the work easier, we wrote plugins to read and write 3d stacks in the Amira Mesh format in ImageJ.

Amira Surface Viewer

Amira can write 3d surface files. These can be loaded and visualized in ImageJ with the ShowAmiraSurface plugin.

ROI Brush

Tom Larkworthy wrote the ROI Brush, a tool which does not paint, but instead (un)selects circular regions.

Delaunay / Voronoi diagram

Gabriel Landini had this on his wishlist...

Two Point Correlation

This plugin plots a correlation / distance graph. It was requested by Paul Stutzman, but I have not heard back from him.

Scrollable StackWindow

With this plugin, you can select the current slice with your mouse wheel.

Align Image

Use this plugin to align an image to a template image, by selecting a line in both images.

Moving Least Squares

Warp an image using a technique presented by Schaefer et al. in Image Deformation Using Moving Least Squares.

IsoSurface Extractor

This plugin makes an isosurface from an image stack. It displays the result in a 3d window (you can zoom, pan and rotate the surface), and optionally saves the result as a VRML.

3D Viewer

This plugin offers 3D visualisation of image s

Thursday 5 December 2013

How do I get the X and Y location of an image in a JScrollPane

enter image description here



Instead of adding the MouseListener to the scrollpane, try adding it to the scroll pane's view component (ie, the thing that the scroll pane is displaying)
The image in this example is 2560x1600
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestScrollPanePos {

    public static void main(String[] args) {
        new TestScrollPanePos();
    }

    public TestScrollPanePos() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(new TestPane()));
                frame.setSize(400, 400);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private BufferedImage bg;
        private Point point;

        public TestPane() {
            try {
                bg = ImageIO.read(new File("/path/to/image));
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            addMouseMotionListener(new MouseAdapter() {

                @Override
                public void mouseMoved(MouseEvent e) {
                    System.out.println(e.getPoint());
                    point = e.getPoint();
                    repaint();
                }

            });
        }

        @Override
        public Dimension getPreferredSize() {
            return bg == null ? new Dimension(200, 200) : new Dimension(bg.getWidth(), bg.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (bg != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                int x = (getWidth() - bg.getWidth()) / 2;
                int y = (getHeight()- bg.getHeight()) / 2;
                g2d.drawImage(bg, x, y, this);
                if (point != null) {
                    FontMetrics fm = g2d.getFontMetrics();
                    g2d.setColor(Color.BLACK);
                    g2d.drawString(point.x + "x" + point.y, point.x, point.y - fm.getHeight() + fm.getAscent());
                }
                g2d.dispose();
            }
        }
    }

}