/*
* 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.apps.gui;
import ij.ImagePlus;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.text.DefaultEditorKit;
import edu.stanford.rsl.conrad.data.numeric.Grid3D;
import edu.stanford.rsl.conrad.filtering.ImageFilteringTool;
import edu.stanford.rsl.conrad.io.FileProjectionSource;
import edu.stanford.rsl.conrad.io.ImagePlusProjectionDataSource;
import edu.stanford.rsl.conrad.pipeline.BufferedProjectionSink;
import edu.stanford.rsl.conrad.pipeline.ParallelImageFilterPipeliner;
import edu.stanford.rsl.conrad.pipeline.ProjectionSource;
import edu.stanford.rsl.conrad.reconstruction.ReconstructionFilter;
import edu.stanford.rsl.conrad.utils.CONRAD;
import edu.stanford.rsl.conrad.utils.Configuration;
import edu.stanford.rsl.conrad.utils.DicomConfigurationUpdater;
import edu.stanford.rsl.conrad.utils.DoubleArrayUtil;
import edu.stanford.rsl.conrad.utils.FileUtil;
import edu.stanford.rsl.conrad.utils.GUIUtil;
import edu.stanford.rsl.conrad.utils.ImageUtil;
import edu.stanford.rsl.conrad.utils.RegKeys;
/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
public class ReconstructionPipelineFrame extends JFrame implements ActionListener, UpdateableGUI {
/**
*
*/
private static final long serialVersionUID = -2788658929679662808L;
private JLabel jLabel1;
private JTextField jProjectionsTextField;
private JPanel jPanel1;
private JButton jLoadDataButton;
private JButton jEditConfigurationButton;
private JButton jEditPipelineButton;
private JButton jChooseBackprojector;
private JLabel jPipelineLabel;
private JButton jReconstructButton;
private JButton jProjectionDataChooseButton;
private JLabel jProjectionsLabel;
private GUICompatibleObjectVisualizationPanel sinkPanel;
private BufferedProjectionSink sink;
private boolean debug = false;
private ConfigurePipelineFrame pipelineFrame = null;
private ConfigurationFrame configFrame = null;
private ParallelImageFilterPipeliner filteringPipeline;
private Clip soundClip = null;
public ReconstructionPipelineFrame() {
sink = Configuration.getGlobalConfiguration().getSink();
initGUI();
updateGUI();
// Load the sound file and setup playback
if (Configuration.getGlobalConfiguration().getRegistry().get(RegKeys.SOUND_FILE) != null) {
String name = Configuration.getGlobalConfiguration().getRegistry().get(RegKeys.SOUND_FILE);
if (name.isEmpty())
return;
AudioInputStream as = null;
try {
File in = new File(name);
as = AudioSystem.getAudioInputStream(in);
} catch (Exception ex) {
System.out.println("Failed to load sound file " + name);
return;
}
DataLine.Info info = new DataLine.Info(Clip.class, as.getFormat());
if (!AudioSystem.isLineSupported(info)) {
System.out.println("Audio output is not supported for this format");
return;
}
try {
soundClip = (Clip)AudioSystem.getLine(info);
soundClip.open(as);
} catch (Exception ex) {
soundClip = null;
System.out.println("Failed to setup sound playback (sound card probably busy)");
return;
}
}
}
public void updateGUI(){
sinkPanel.updateGUI();
repaint();
}
/**
* Create an Edit menu to support cut/copy/paste.
*/
@SuppressWarnings("serial")
public JMenuBar createMenuBar () {
JMenuItem menuItem = null;
JMenuBar menuBar = new JMenuBar();
JMenu mainMenu = new JMenu("Configuration");
mainMenu.setMnemonic(KeyEvent.VK_C);
menuItem = new JMenuItem(new AbstractAction(){
public void actionPerformed(ActionEvent e) {
try {
String filename = FileUtil.myFileChoose(".xml", false);
Configuration.setGlobalConfiguration(Configuration.loadConfiguration(filename));
if (configFrame != null) configFrame.exit();
if (pipelineFrame != null) pipelineFrame.exit();
} catch (Exception e1) {
System.out.println(e1.getLocalizedMessage());
}
}
});
menuItem.setText("Load");
menuItem.setMnemonic(KeyEvent.VK_L);
mainMenu.add(menuItem);
menuItem = new JMenuItem(new AbstractAction(){
public void actionPerformed(ActionEvent e) {
try {
String filename = FileUtil.myFileChoose(".xml", true);
if (!filename.endsWith(".xml")) filename += ".xml";
Configuration.saveConfiguration(Configuration.getGlobalConfiguration(), filename);
Configuration.loadConfiguration(filename);
} catch (Exception e1) {
System.out.println(e1.getLocalizedMessage());
}
}
});
menuItem.setText("Save");
menuItem.setMnemonic(KeyEvent.VK_S);
mainMenu.add(menuItem);
menuBar.add(mainMenu);
mainMenu = new JMenu("Edit");
mainMenu.setMnemonic(KeyEvent.VK_E);
menuItem = new JMenuItem(new DefaultEditorKit.CutAction());
menuItem.setText("Cut");
menuItem.setMnemonic(KeyEvent.VK_T);
mainMenu.add(menuItem);
menuItem = new JMenuItem(new DefaultEditorKit.CopyAction());
menuItem.setText("Copy");
menuItem.setMnemonic(KeyEvent.VK_C);
mainMenu.add(menuItem);
menuItem = new JMenuItem(new DefaultEditorKit.PasteAction());
menuItem.setText("Paste");
menuItem.setMnemonic(KeyEvent.VK_P);
mainMenu.add(menuItem);
menuBar.add(mainMenu);
return menuBar;
}
private void initGUI() {
Configuration config = Configuration.getGlobalConfiguration();
try {
{
{
// Set Look & Feel
try {
javax.swing.UIManager
.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception e) {
//e.printStackTrace();
}
}
getContentPane().setBackground(Color.WHITE);
this.setSize(640, 480);
this.setTitle("Reconstruction Pipeline " + CONRAD.VersionString);
this.setJMenuBar(createMenuBar());
GridBagLayout thisLayout = new GridBagLayout();
thisLayout.rowWeights = new double[] {0.1, 0.1, 0.1, 0.1, 0.1 };
thisLayout.rowHeights = new int[] {50, 50, 50, 50, 7 };
thisLayout.columnWeights = new double[] { 0.1, 0.1, 0.1, 0.1,
0.1 };
thisLayout.columnWidths = new int[] { 7, 7, 223, 7, 7 };
getContentPane().setLayout(thisLayout);
{
jLabel1 = new JLabel();
getContentPane().add(jLabel1, new GridBagConstraints(1, 0, 3, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
jLabel1
.setText(CONRAD.CONRADDefinition);
}
jPanel1 = new JPanel();
jPanel1.setBorder(BorderFactory.createTitledBorder("Input"));
jPanel1.setBackground(Color.WHITE);
GridBagLayout jPanel1Layout = new GridBagLayout();
getContentPane().add(
jPanel1,
new GridBagConstraints(1, 1, 3, 1, 0.0, 0.0,
GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(0, 0,
0, 0), 0, 0));
jPanel1Layout.rowWeights = new double[] { 0.1, 0.1 };
jPanel1Layout.rowHeights = new int[] { 40, 20 };
jPanel1Layout.columnWeights = new double[] {0.1, 0.1, 0.1};
jPanel1Layout.columnWidths = new int[] {80, 80, 80};
jPanel1.setLayout(jPanel1Layout);
{
jProjectionsTextField = new JTextField();
jPanel1.add(
jProjectionsTextField,
new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.NORTH,
GridBagConstraints.HORIZONTAL, new Insets(
0, 0, 0, 0), 0, 0));
jProjectionsTextField.setText(config.getRecentFileOne());
jProjectionsTextField.addActionListener(this);
GUIUtil.enableDragAndDrop(jProjectionsTextField);
jProjectionsLabel = new JLabel();
jPanel1.add(
jProjectionsLabel,
new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.NORTH,
GridBagConstraints.NONE, new Insets(0, 0,
0, 0), 0, 0));
jProjectionsLabel.setText("Projection Data:");
jProjectionDataChooseButton = new JButton();
jPanel1.add(jProjectionDataChooseButton, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
jProjectionDataChooseButton.setText("Choose");
jProjectionDataChooseButton.addActionListener(this);
jLoadDataButton = new JButton();
jPanel1.add(jLoadDataButton, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
jLoadDataButton.setText("Use Current ImagePlus");
jLoadDataButton.addActionListener(this);
}
jPanel1 = new JPanel();
jPanel1.setBorder(BorderFactory.createTitledBorder("Processing"));
jPanel1.setBackground(Color.WHITE);
jPanel1Layout = new GridBagLayout();
getContentPane().add(
jPanel1,
new GridBagConstraints(1, 2, 3, 1, 0.0, 0.0,
GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(0, 0,
0, 0), 0, 0));
jPanel1Layout.rowWeights = new double[] { 0.1, 0.1, 0.1 };
jPanel1Layout.rowHeights = new int[] { 50, 0, 0 };
jPanel1Layout.columnWeights = new double[] {0.1, 0.1};
jPanel1Layout.columnWidths = new int[] {80, 80};
jPanel1.setLayout(jPanel1Layout);
{
{
jEditPipelineButton = new JButton();
jPanel1.add(jEditPipelineButton, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
jEditPipelineButton.setText("Edit Pipeline");
jEditPipelineButton.addActionListener(this);
}
{
jEditConfigurationButton = new JButton();
jPanel1.add(jEditConfigurationButton, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
jEditConfigurationButton.setText("Edit Configuration");
jEditConfigurationButton.addActionListener(this);
}
}
jPanel1 = new JPanel();
jPanel1.setBorder(BorderFactory.createTitledBorder("Output"));
jPanel1.setBackground(Color.WHITE);
jPanel1Layout = new GridBagLayout();
getContentPane().add(
jPanel1,
new GridBagConstraints(1, 3, 3, 1, 0.0, 0.0,
GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(0, 0,
0, 0), 0, 0));
jPanel1Layout.rowWeights = new double[] { 0.1, 0.1, 0.1 };
jPanel1Layout.rowHeights = new int[] { 30, 80, 0 };
jPanel1Layout.columnWeights = new double[] {0.1, 0.1, 0.1};
jPanel1Layout.columnWidths = new int[] {80, 80, 80};
jPanel1.setLayout(jPanel1Layout);
{
sinkPanel = new GUICompatibleObjectVisualizationPanel(sink);
jPanel1.add(sinkPanel, new GridBagConstraints(0, 1, 3, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
sinkPanel.setParentFrame(this);
jChooseBackprojector = new JButton();
jPanel1.add(jChooseBackprojector, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
jChooseBackprojector.setText("Choose Output");
jChooseBackprojector.addActionListener(this);
}
}
jPipelineLabel = new JLabel();
getContentPane().add(jPipelineLabel, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(30, 0, 0, 0), 0, 0));
jPipelineLabel.setText("Reconstruction Pipeline");
{
jReconstructButton = new JButton();
getContentPane().add(jReconstructButton, new GridBagConstraints(1, 4, 3, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
jReconstructButton.setText("Reconstruct");
jReconstructButton.addActionListener(this);
}
} catch (Exception e) {
e.printStackTrace();
}
}
ImagePlus volumePreview = null;
ProjectionSource pSource = null;
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source != null){
//jChooseBackprojector
if (source.equals(this.jProjectionDataChooseButton)){
try {
String file = FileUtil.myFileChoose("", false);
this.jProjectionsTextField.setText(file);
if (Configuration.getGlobalConfiguration().getImportFromDicomAutomatically()){
DicomConfigurationUpdater update = new DicomConfigurationUpdater();
Configuration config = Configuration.getGlobalConfiguration();
update.setConfig(config);
update.setFilename(this.jProjectionsTextField.getText());
update.readConfiguration();
config.setGeometry(Configuration.loadGeometrySource(config));
Configuration.setGlobalConfiguration(config);
}
} catch (Exception e1) {
// TODO Auto-generated catch block
//e1.printStackTrace();
}
}
if (source.equals(this.jEditPipelineButton)){
if (pipelineFrame == null){
pipelineFrame = new ConfigurePipelineFrame();
pipelineFrame.setParentFrame(this);
pipelineFrame.setVisible(true);
pipelineFrame.setLocation(CONRAD.getWindowTopCorner());
} else {
if (pipelineFrame.isExited()){
pipelineFrame = new ConfigurePipelineFrame();
pipelineFrame.setParentFrame(this);
pipelineFrame.setVisible(true);
} else {
if (! pipelineFrame.isVisible()) {
pipelineFrame.setVisible(true);
}
}
}
}
if (source.equals(this.jEditConfigurationButton)){
if (configFrame == null){
configFrame = new ConfigurationFrame();
configFrame.setParentFrame(this);
configFrame.setVisible(true);
configFrame.setLocation(CONRAD.getWindowTopCorner());
} else {
if (configFrame.isExited()){
configFrame = new ConfigurationFrame();
configFrame.setParentFrame(this);
configFrame.setVisible(true);
} else {
if (! configFrame.isVisible()) {
configFrame.setVisible(true);
}
}
}
}
if (source.equals(this.jLoadDataButton)){
pSource = new ImagePlusProjectionDataSource();
((ImagePlusProjectionDataSource)pSource).initStream(null);
}
if (source.equals(this.jChooseBackprojector)){
Configuration config = Configuration.getGlobalConfiguration();
BufferedProjectionSink [] sinks = BufferedProjectionSink.getProjectionDataSinks();
BufferedProjectionSink selected = (BufferedProjectionSink) JOptionPane.showInputDialog(this, "Please select the reconstruction algorithm: ", "Select Reconstruction Algorithm", JOptionPane.INFORMATION_MESSAGE, null, sinks, sink);
if (selected != null) {
sink = selected;
sink.setConfiguration(config);
sinkPanel.setVisualizedObject(sink);
config.setSink(sink);
}
updateGUI();
}
if (source.equals(this.jReconstructButton)){
if (pSource == null){
try {
pSource = FileProjectionSource.openProjectionStream(jProjectionsTextField.getText());
} catch (IOException e1) {
if (debug) e1.printStackTrace();
JOptionPane.showMessageDialog(this, "Could not open projection source.");
}
}
if (pSource != null){
if (sink.isConfigured()) {
ImageFilteringTool [] filters = Configuration.getGlobalConfiguration().getFilterPipeline();
boolean isConfigured = true;
boolean recoTest = false;
for (int i = 0; i < filters.length; i++){
if (!filters[i].isConfigured()) isConfigured = false;
if(filters[i] instanceof ReconstructionFilter) recoTest = true;
}
final boolean isReconstruction = recoTest;
if (isConfigured) {
volumePreview = ImageUtil.wrapGrid3D(sink.getProjectionVolume(), "Preview");
if (volumePreview != null) volumePreview.show();
filteringPipeline = new ParallelImageFilterPipeliner(pSource, filters, sink);
Thread thread = new Thread(new Runnable(){
public void run(){
long time = System.currentTimeMillis();
try {
filteringPipeline.project();
} catch (Exception e) {
e.printStackTrace();
}
Grid3D result = sink.getResult();
time = System.currentTimeMillis() - time;
if (volumePreview == null) {
volumePreview = ImageUtil.wrapGrid3D(result, "Result of " + pSource);
ImageUtil.applyConradImageCalibration(volumePreview, isReconstruction);
if (volumePreview != null){
volumePreview.show();
}
}
if (volumePreview != null){
File filename = new File(jProjectionsTextField.getText());
volumePreview.setTitle(filename.getName());
if (pSource instanceof ImagePlusProjectionDataSource){
ImagePlusProjectionDataSource s = (ImagePlusProjectionDataSource) pSource;
volumePreview.setTitle("Reconstruction of " + s.getTitle());
}
}
filteringPipeline = null;
pSource = null;
CONRAD.log("Reconstruction time (sec):" + time);
try {
sink = sink.getClass().newInstance();
sinkPanel.setVisualizedObject(sink);
updateGUI();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
DoubleArrayUtil.visualizeBufferedArrays("Current Weighting");
// Play the sound if so desired
if (soundClip != null) {
soundClip.setFramePosition(0);
soundClip.start();
}
}
});
thread.start();
} else {
JOptionPane.showMessageDialog(this, "Not all filters of the reconstruction pipeline are configured. Please correct this.");
}
} else {
JOptionPane.showMessageDialog(this, "Reconstruction Algorithm is not configured.");
}
}
}
updateGUI();
}
}
public static void main(String [] args){
CONRAD.setup();
ReconstructionPipelineFrame oscar = new ReconstructionPipelineFrame();
oscar.setVisible(true);
oscar.setLocation(CONRAD.getWindowTopCorner());
}
}