package fr.unistra.pelican.gui.MultiViews; import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.image.BufferedImage; import java.io.File; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.Hashtable; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.InputVerifier; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButtonMenuItem; import javax.swing.JSlider; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.miginfocom.swing.MigLayout; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.LogarithmicAxis; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.data.statistics.HistogramDataset; import fr.unistra.pelican.ByteImage; import fr.unistra.pelican.Image; import fr.unistra.pelican.IntegerImage; import fr.unistra.pelican.algorithms.histogram.HistogramCorrection.MultiBandPolicy; import fr.unistra.pelican.algorithms.io.ImageLoader; import fr.unistra.pelican.algorithms.io.ImageSave; import fr.unistra.pelican.algorithms.io.JavaImageSave; import fr.unistra.pelican.gui.FileChooserToolBox; import fr.unistra.pelican.gui.MultiViews.View.GammaModel; import fr.unistra.pelican.util.ArrayToolbox; import fr.unistra.pelican.util.IMath; import fr.unistra.pelican.util.Tools; /** * A JPanel especially designed for image display. * It displays an image according to a View object and proposes popup menu for controlling options of the view. * * @author Benjamin Perret */ public class ImagePanel extends JPanel implements ChangeListener, MouseListener, MouseWheelListener, MouseMotionListener, ActionListener, ViewPort{ private DecimalFormat df=new DecimalFormat("##.#####"); private String [] decimalFormats = new String[]{"#","00","#.##","0.##","0.00","#.####E0"}; private JComboBox decimalFormatComboBox = new JComboBox(decimalFormats); private View view; /** serialVersionUID */ private static final long serialVersionUID = 1L; /** * Ready to fight? */ boolean init=false; int lastWidth=getWidth(); int lastHeight=getHeight(); /** * The menu */ private JPopupMenu popup; private JMenuItem sendToClipBoard; private JMenuItem save; private JMenuItem save2; private JMenuItem fitInWindow; private JMenuItem restoreView; private JMenuItem refreshView; private JMenuItem pixelsStat; private JMenuItem changeDecimalFormat; private JCheckBoxMenuItem autoCorrect; private JTextFieldMenuItem autoCorrectLevel; private JCheckBoxMenuItem autoScale; private JCheckBoxMenuItem inverseGrayScale; private JMenuItem colourOptions; private JCheckBoxMenuItem lockFit; private JCheckBoxMenuItem center; private JMenu subMenuCorrection=new JMenu("MultiBand correction"); private JRadioButtonMenuItem correctIndep = new JRadioButtonMenuItem("Independent"); private JRadioButtonMenuItem correctMin = new JRadioButtonMenuItem("Min"); private JRadioButtonMenuItem correctMax = new JRadioButtonMenuItem("Max"); private JRadioButtonMenuItem correctMedian = new JRadioButtonMenuItem("Median"); private JRadioButtonMenuItem correctMean = new JRadioButtonMenuItem("Mean"); private JMenu subMenuGammaCompression=new JMenu("Gamma Compression"); private JRadioButtonMenuItem gammaNo = new JRadioButtonMenuItem("No Compression"); private JRadioButtonMenuItem gammaSimple = new JRadioButtonMenuItem("Simple"); private JRadioButtonMenuItem gammaSRGB = new JRadioButtonMenuItem("sRGB"); private JRadioButtonMenuItem gammaREC709 = new JRadioButtonMenuItem("REC.709"); /** * To change colour display options */ private ColourOptionEditor coe = null; /** * Builder */ public ImagePanel() { setLayout(null); setSize(400, 400); DecimalFormatSymbols dfs=df.getDecimalFormatSymbols(); dfs.setDecimalSeparator('.'); df.setDecimalFormatSymbols(dfs); this.addMouseListener(this); this.addMouseMotionListener(this); this.addMouseWheelListener(this); createPopUp(); } private void createPopUp() { popup = new JPopupMenu(); pixelsStat = new JMenuItem("Show Pixels Information"); pixelsStat.addActionListener(this); popup.add( pixelsStat); refreshView = new JMenuItem("Refresh"); refreshView.addActionListener(this); popup.add( refreshView); center = new JCheckBoxMenuItem("Follow Window"); center.setSelected(true); center.addActionListener(this); popup.add(center); fitInWindow = new JMenuItem("Fit In Window"); fitInWindow.addActionListener(this); popup.add(fitInWindow); lockFit= new JCheckBoxMenuItem("Lock fit in window"); lockFit.setSelected(false); lockFit.addActionListener(this); popup.add(lockFit); popup.add(new JPopupMenu.Separator()); decimalFormatComboBox.setEditable(true); changeDecimalFormat = new JMenuItem("Decimal Format " + df.toPattern()); changeDecimalFormat.addActionListener(this); popup.add( changeDecimalFormat); popup.add(new JPopupMenu.Separator()); autoScale = new JCheckBoxMenuItem("Contrast scaling"); autoScale.setSelected(true); autoScale.addActionListener(this); autoScale.setEnabled(false); popup.add(autoScale); autoCorrect = new JCheckBoxMenuItem("Contrast correction"); autoCorrect.setSelected(true); autoCorrect.addActionListener(this); popup.add(autoCorrect); //autoCorrectSubMenu=new JMenu("Correction options"); // popup.add(autoCorrectSubMenu); autoCorrectLevel = new JTextFieldMenuItem("Threshold","99"); autoCorrectLevel.addActionListener(this); popup.add(autoCorrectLevel); ButtonGroup myGroup = new ButtonGroup(); myGroup.add(correctIndep); myGroup.add(correctMin); myGroup.add(correctMax); myGroup.add(correctMedian); myGroup.add(correctMean); correctIndep.setSelected(true); subMenuCorrection.add(correctIndep); correctIndep.addActionListener(this); subMenuCorrection.add(correctMin); correctMin.addActionListener(this); subMenuCorrection.add(correctMax); correctMax.addActionListener(this); subMenuCorrection.add(correctMedian); correctMedian.addActionListener(this); subMenuCorrection.add(correctMean); correctMean.addActionListener(this); popup.add(subMenuCorrection); popup.add(new JPopupMenu.Separator()); ButtonGroup myGroup2 = new ButtonGroup(); myGroup2.add(gammaNo); myGroup2.add(gammaSimple); myGroup2.add(gammaSRGB); myGroup2.add(gammaREC709); gammaNo.setSelected(true); subMenuGammaCompression.add(gammaNo); gammaNo.addActionListener(this); subMenuGammaCompression.add(gammaSimple); gammaSimple.addActionListener(this); subMenuGammaCompression.add(gammaSRGB); gammaSRGB.addActionListener(this); subMenuGammaCompression.add(gammaREC709); gammaREC709.addActionListener(this); popup.add(subMenuGammaCompression); popup.add(new JPopupMenu.Separator()); inverseGrayScale = new JCheckBoxMenuItem("Inverse Gray Scale"); inverseGrayScale.setSelected(false); inverseGrayScale.addActionListener(this); inverseGrayScale.setEnabled(true); popup.add(inverseGrayScale); colourOptions = new JMenuItem("Colour propeties"); colourOptions.addActionListener(this); popup.add(colourOptions); restoreView = new JMenuItem("Restore View"); restoreView.addActionListener(this); popup.add(restoreView); popup.add(new JPopupMenu.Separator()); sendToClipBoard = new JMenuItem("Send View to Clipboard"); sendToClipBoard.addActionListener(this); popup.add(sendToClipBoard); save = new JMenuItem("Save Original Image"); save.addActionListener(this); popup.add(save); save2 = new JMenuItem("Save View"); save2.addActionListener(this); popup.add(save2); } /** * Set the image and/or the rectangle to display * @param img * @param r */ public void setImage(Image img) { if (img == null) { setView(null); } else { if (view == null) view = new View(this); view.setImage(img); setView(view); } repaint(); } /** * Set the image and/or the rectangle to display * @param img * @param r */ public View setImage(BufferedImage img) { if (img == null) { setView(null); } else { if (view == null) view = new View(this); view.setImage(img); setView(view); repaint(); } return view; } public void setView(View view) { if (this.view != null) {// this.view.setViewPort(null); this.view.removeChangeListener(this); this.view.setActive(false); } this.view = view; if (view != null) { view.addChangeListener(this); view.setViewPort(this); this.view.setActive(true); autoScale.setSelected(view.isScaleResult()); autoCorrect.setSelected(view.isAutoCorrect()); if (autoCorrect.isSelected()) autoScale.setEnabled(false); else autoScale.setEnabled(true); // autoCorrectSubMenu.setEnabled(autoCorrect.isSelected()); inverseGrayScale.setSelected(view.isInverseGrayScale()); switch(view.getMultiBandPolicyCorrection()) { case Independent: correctIndep.setSelected(true); break; case Min: correctMin.setSelected(true); break; case Max: correctMax.setSelected(true); break; case Mean: correctMean.setSelected(true); break; case Median: correctMedian.setSelected(true); break; } switch(view.getGammaModel()) { case No: gammaNo.setSelected(true); break; case Simple: gammaSimple.setSelected(true); break; case sRGB: gammaSRGB.setSelected(true); break; case REC709: gammaREC709.setSelected(true); break; } lockFit.setSelected(view.isAutoFitWindow()); center.setSelected(view.isFollowWindow()); autoCorrectLevel.setText("" + view.getAutoCorrectLevel() * 100.0); } repaint(); } private void drawHasch(Graphics2D g,int h, int w,Color c, double slope, double space) { double x1=0; double x2=0; double y1=0; double y2=0; for(x1=0;x1<=w;x1+=space) { } } @Override public void paint(Graphics g) { int w=getWidth(); int h=getHeight(); g.clearRect(0,0,w,h); //g.fillRect(0, 0, w, h); // g.setColor(Color.black); if (view != null) { if (lockFit.isSelected()) view.fitToWindow(); BufferedImage myimg = view.getDisplay(); if (myimg != null) { int xdim = myimg.getWidth(null); int ydim = myimg.getHeight(null); int finalx = (int) (view.getZoom() * xdim); int finaly = (int) (view.getZoom() * ydim); if (center.isSelected()) { if (init) { /* * if (lastHeight < h && lastWidth < w) { double f1 = * (double) (h) / (double) (lastHeight); double f2 = * (double) (w) / (double) (lastWidth); view.zoomOn(w / * 2, h / 2, Math.min(f1, f2)); * * } else if (lastHeight > h && lastWidth > w) { double * f1 = (double) (h) / (double) (lastHeight); double f2 * = (double) (w) / (double) (lastWidth); view.zoomOn(w * / 2, h / 2, Math.max(f1, f2)); * * } */ }/* * else if(lastHeight!= h && lastWidth== w ) { double * f1=(double)(h)/(double)(lastHeight); * * view.zoomOn(w/2, h/2, f1); * * }else if(lastHeight== h && lastWidth!= w ) { double * f2=(double)(w)/(double)(lastWidth); * * view.zoomOn(w/2, h/2, f2); } */ if (finalx < w) view.centerXToWindow(); else view.noBlanckX(); if (finaly < h) view.centerYToWindow(); else view.noBlanckY(); } // double fact=Math.min((double)getWidth()/(double)xdim, // (double)getHeight()/(double)ydim); // Graphics2D g2 = (Graphics2D)g; // AffineTransform xform = // AffineTransform.getScaleInstance(fact, // fact); // g2.drawImage(myimg, xform,null); // java.awt.Image op = myimg.getScaledInstance((int)(zoom*xdim), // (int)(zoom*ydim), java.awt.Image.SCALE_FAST); // g2.drawImage(myimg, 0, 0,(int)(fact*xdim),(int)(fact*ydim), // this); // g.drawImage(op,shiftX,shiftY,null); /*if (myimg.getTransparency() == BufferedImage.TRANSLUCENT) { g.setColor(Color.black); g.fillRect(view.getShiftX(), view.getShiftY(), finalx, finaly); }*/ g.drawImage(myimg, view.getShiftX(), view.getShiftY(), finalx, finaly, null); } lastHeight = h; lastWidth = w; init = true; } fireChangeEvent(); } public static ImagePanel createFrame(String title) { JFrame frame = new JFrame(); frame.setTitle(title); ImagePanel pan= new ImagePanel(); frame.add(pan); frame.setVisible(true); frame.setSize(400,400); return pan; } public void mouseClicked(MouseEvent e) { maybeShowPopup(e); } public void mouseEntered(MouseEvent e) { // TODO Auto-generated method stub } public void mouseExited(MouseEvent e) { // TODO Auto-generated method stub } private boolean hold1=false; public void mousePressed(MouseEvent e) { maybeShowPopup(e); if(e.getModifiers() == MouseEvent.BUTTON1_MASK) { px=e.getX(); py=e.getY(); hold1=true; setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR) ); } } public void mouseReleased(MouseEvent e) { maybeShowPopup(e); if(e.getModifiers() == MouseEvent.BUTTON1_MASK) { setCursor(Cursor.getDefaultCursor() ); hold1=false; } } public void mouseWheelMoved(MouseWheelEvent e) { //int onMask= MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON2_DOWN_MASK; double tick = e.getWheelRotation(); if(Math.abs(tick)>0) { if (view!=null && e.isAltDown())//(e.getModifiersEx() & onMask ) == onMask) { double l=view.getAutoCorrectLevel(); // why not? view.setAutoCorrectLevel(l+(1.001-l)*tick*tick*Math.signum(tick)/10.0); view.refresh(); } else if (view!=null && !lockFit.isSelected()) { if (tick < 0) view.zoomOn(e.getX(), e.getY(), tick *= -1.2); else view.zoomOut(e.getX(), e.getY(), tick *= 1.2); //repaint(); } } } public void mouseDragged(MouseEvent e) { if(view!=null && !lockFit.isSelected() && hold1) { int ppx,ppy; ppx=e.getX(); ppy=e.getY(); view.shiftX((ppx-px)); view.shiftY((ppy-py)); px=ppx; py=ppy; //repaint(); } } private int px,py; public void mouseMoved(MouseEvent e) { if (view != null) { int x = view.getAbsoluteXCoord(e.getX()); int y = view.getAbsoluteYCoord(e.getY()); Image im=view.getPersistentImage(); String masked=(im.isPresentXY(x, y))?"":"M"; if (im instanceof IntegerImage) { int[] pix = im.getVectorPixelXYZTInt(x, y, 0, 0); this.setToolTipText(masked + "[" + x + ";" + y + "]->" + ArrayToolbox.printString(pix)); } else if (im instanceof ByteImage) { int[] pix = im.getVectorPixelXYZTByte(x, y, 0, 0); this.setToolTipText(masked +"[" + x + ";" + y + "]->" + ArrayToolbox.printString(pix)); } else { double[] pix = im.getVectorPixelXYZTDouble(x, y, 0, 0); this.setToolTipText(masked +"[" + x + ";" + y + "]->" + ArrayToolbox.printString(pix, df)); } } } public static void main(String [] args) { //Image im=ImageLoader.exec("samples/lenna512.png"); Image im=ImageLoader.exec("samples/AstronomicalImagesFITS/img1-10.fits"); JFrame frame = new JFrame("Mouhaha"); ImagePanel panel=new ImagePanel(); panel.setImage(im); frame.add(panel); frame.setSize(400, 800); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } private void maybeShowPopup(MouseEvent e) { if (popup.isPopupTrigger(e)) { popup.show(e.getComponent(), e.getX(), e.getY()); autoCorrectLevel.setText(""+df.format(view.getAutoCorrectLevel())); Window window = SwingUtilities.windowForComponent(popup); if (window != null) { window.setFocusableWindowState(true); } popup.setFocusable(true); popup.requestFocus(); //KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent(popup); //textField.requestFocusInWindow(); } } private void save(Image im, File f){ try{ ImageSave.exec(im,f.getAbsolutePath()); } catch (Exception e) { JOptionPane.showMessageDialog(this, "Error while saving file : " +e, "VisuTool error", JOptionPane.ERROR_MESSAGE); } } public void actionPerformed(ActionEvent e) { Object source=e.getSource(); if(source instanceof JMenuItem) { JMenuItem item=(JMenuItem)e.getSource(); if(item==save) { File f = FileChooserToolBox.openSaveFileChooser((JFrame)this.getRootPane().getParent()); if(f!=null)save(view.getPersistentImage(),f); }else if(item==save2) { File f = FileChooserToolBox.openSaveFileChooser((JFrame)this.getRootPane().getParent()); // this is the funny conversion game between JavaImage->BufferedImage->PelicanImage if(f!=null){ int x=view.getImage().xdim; int y=view.getImage().ydim; save(View.bufferedImageTopelicanImage(JavaImageSave.toBufferedImage(view.getDisplay().getScaledInstance((int)(view.getZoom()*x), (int)(view.getZoom()*y), BufferedImage.SCALE_REPLICATE))),f); } }else if(item==sendToClipBoard) { // this is the funny conversion game between JavaImage->BufferedImage->PelicanImage int x=view.getImage().xdim; int y=view.getImage().ydim; ClipBoardImageTranserferable.copyImageToClipboard(JavaImageSave.toBufferedImage(view.getDisplay().getScaledInstance((int)(view.getZoom()*x), (int)(view.getZoom()*y), BufferedImage.SCALE_REPLICATE))); } else if (item== restoreView) { view.resetView(); // repaint(); }else if (item== autoCorrect) { view.setAutoCorrect(autoCorrect.isSelected()); if(autoCorrect.isSelected()) { subMenuCorrection.setEnabled(true); autoScale.setEnabled(false); autoScale.setSelected(true); autoCorrectLevel.setEnabled(true); } else { subMenuCorrection.setEnabled(false); autoScale.setEnabled(true); autoCorrectLevel.setEnabled(false); } repaint(); }else if (item== correctIndep) { if(correctIndep.isSelected()) { view.setMultiBandPolicyCorrection(MultiBandPolicy.Independent); repaint(); } }else if (item== correctMean) { if(correctMean.isSelected()) { view.setMultiBandPolicyCorrection(MultiBandPolicy.Mean); repaint(); } }else if (item== correctMax) { if(correctMax.isSelected()) { view.setMultiBandPolicyCorrection(MultiBandPolicy.Max); repaint(); } }else if (item== correctMin) { if(correctMin.isSelected()) { view.setMultiBandPolicyCorrection(MultiBandPolicy.Min); repaint(); } }else if (item== correctMedian) { if(correctMedian.isSelected()) { view.setMultiBandPolicyCorrection(MultiBandPolicy.Median); repaint(); } } else if (item== gammaNo) { if(gammaNo.isSelected()) { view.setGammaModel(GammaModel.No); repaint(); } }else if (item== gammaSimple) { if(gammaSimple.isSelected()) { view.setGammaModel(GammaModel.Simple); repaint(); } }else if (item== gammaSRGB) { if(gammaSRGB.isSelected()) { view.setGammaModel(GammaModel.sRGB); repaint(); } }else if (item== gammaREC709) { if(gammaREC709.isSelected()) { view.setGammaModel(GammaModel.REC709); repaint(); } }else if (item== autoScale) { view.setScaleResult(autoScale.isSelected()); repaint(); }else if (item== inverseGrayScale) { view.setInverseGrayScale(inverseGrayScale.isSelected()); repaint(); }else if (item== fitInWindow) { view.fitToWindow(); //repaint(); }else if (item== lockFit) { view.setAutoFitWindow(lockFit.isSelected()); //repaint(); }else if (item== center) { view.setFollowWindow(center.isSelected()); //repaint(); }else if (item== lockFit) { view.setAutoFitWindow(lockFit.isSelected()); //repaint(); }else if (item== refreshView) { view.refresh(); //repaint(); } else if (item== pixelsStat) { JOptionPane.showMessageDialog(this, IMath.printStatistics(view.getPersistentImage())); } else if (item == colourOptions) { if(coe==null) coe=new ColourOptionEditor(); coe.setVisible(true); }else if (item== changeDecimalFormat) { //decimalFormatComboBox.setSelectedIndex(0); JOptionPane.showMessageDialog(this,decimalFormatComboBox, "Give decimal format (Java DecimalFormat pattern) : ",JOptionPane.QUESTION_MESSAGE); Object res=decimalFormatComboBox.getSelectedItem(); if(res!=null && res instanceof String){ try{ df.applyPattern((String)res); changeDecimalFormat.setText("Decimal Format " + df.toPattern()); } catch (IllegalArgumentException ex){ JOptionPane.showMessageDialog(this,"Invalid decimal pattern, see javadoc DecimalFormat!"); } } } } else if (source instanceof JTextField) { JTextField text =(JTextField)(source); try { double v=Double.parseDouble(text.getText()); if(v<0.0 || v>1.0) { JOptionPane.showMessageDialog(this,"Value must be between 0 and 1!"); text.setText(""+df.format(view.getAutoCorrectLevel())); } else { view.setAutoCorrectLevel(v); repaint(); } } catch (NumberFormatException ex) { JOptionPane.showMessageDialog(this,"Hey dude! give me a number between 0 and 1!"); text.setText(""+view.getAutoCorrectLevel()); } } } /** * @return the view */ public View getView() { return view; } public void addPopUpOption(String optionName,JMenuItem ...item) { JMenu menu = new JMenu(optionName); for(JMenuItem i:item) menu.add(i); popup.add(new JPopupMenu.Separator()); popup.add(menu); } class ColourOptionEditor extends JFrame implements ChangeListener, ActionListener{ private JCheckBox coloured=new JCheckBox("Colour display"); private JPanel main; private JPanel bandSelectorPanel; private JPanel colourSelectorPanel; private JPanel thresholdPanel; private JSlider slider=new JSlider(SwingConstants.HORIZONTAL,0,0,0); private JComboBox colourR=new JComboBox(); private JComboBox colourG=new JComboBox(); private JComboBox colourB=new JComboBox(); private JCheckBox threshold = new JCheckBox("Threshold"); private JComboBox thresholdBand=new JComboBox(); private int thresholdMin=0; private int thresholdMax=1000; private int thresholdInitValue=(thresholdMax-thresholdMin)/2+thresholdMin; private double thresholdRange=thresholdMax-thresholdMin; private JSlider thresholdSlider=new JSlider(SwingConstants.HORIZONTAL,thresholdMin,thresholdMax,thresholdInitValue); private JLabel thresholdMinLabel=new JLabel("xxxxxxxxxxx"); private JLabel thresholdMaxLabel=new JLabel("xxxxxxxxxxx"); private double imageMin=0.0; private double imageMax=1.0; private ImagePanel histo; private int histoBins=255; private JTextField histoBinsField= new JTextField(5); private double [] histogram; private double [] histogramTicks; private JCheckBox histoLogX=new JCheckBox("Log Scale X axis"); private JCheckBox histoLogY=new JCheckBox("Log Scale Y axis"); public ColourOptionEditor(){ main = new JPanel(new MigLayout()); coloured.addChangeListener(this); bandSelectorPanel=getBandSelectorPanel(); colourSelectorPanel=getColourSelectorPanel(); thresholdPanel=getThresholdPanel(); main.add(thresholdPanel,"wrap"); main.add(coloured,"wrap"); this.add(main); this.setTitle("Colour options"); this.setResizable(false); this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); } private JPanel getBandSelectorPanel(){ JPanel pan=new JPanel(new MigLayout()); pan.setBorder(BorderFactory.createTitledBorder("Band selection")); pan.add(new JLabel("Band number: ")); slider.setMajorTickSpacing(1); slider.setMinorTickSpacing(1); slider.setPaintTicks(true); slider.setPaintLabels(true); slider.addChangeListener(this); slider.setSnapToTicks(true); pan.add(slider,"wrap"); return pan; } private JPanel getThresholdPanel(){ JPanel pan=new JPanel(new MigLayout()); histo=new ImagePanel(); histo.setPreferredSize(new Dimension(600,300)); pan.setBorder(BorderFactory.createTitledBorder("Threshold tool")); pan.add(threshold); pan.add(new JLabel("Band:")); pan.add(thresholdBand); thresholdBand.addActionListener(this); thresholdSlider.setEnabled(false); threshold.setSelected(false); Hashtable labelTable = new Hashtable(); labelTable.put( thresholdMin, thresholdMinLabel ); labelTable.put( thresholdMax, thresholdMaxLabel ); thresholdSlider.setLabelTable( labelTable ); //thresholdSlider.setMajorTickSpacing(1); //thresholdSlider.setMinorTickSpacing(1); thresholdSlider.setPaintTicks(false); thresholdSlider.setPaintLabels(true); thresholdSlider.addChangeListener(this); //thresholdSlider.setSnapToTicks(true); threshold.addActionListener(this); thresholdSlider.setPreferredSize(new Dimension(600,30)); pan.add(thresholdSlider,"wrap"); pan.add(histo,"span"); pan.add(new JLabel("Bins: ")); pan.add(histoBinsField); pan.add(histoLogX); pan.add(histoLogY); histoLogX.addActionListener(this); histoLogY.addActionListener(this); histoBinsField.setText(""+histoBins); histoBinsField.addActionListener(this); histoBinsField.setInputVerifier(new InputVerifier(){ @Override public boolean verify(JComponent input) { JTextField tf = (JTextField) input; try{ Integer.parseInt(tf.getText()); }catch (NumberFormatException e) { return false; } return true; } }); return pan; } private JPanel getColourSelectorPanel(){ JPanel pan=new JPanel(new MigLayout()); pan.setBorder(BorderFactory.createTitledBorder("Colour selection")); pan.add(new JLabel("Red Band: ")); pan.add(colourR,"wrap"); colourR.setEditable(false); colourR.addActionListener(this); pan.add(new JLabel("Green Band: ")); pan.add(colourG,"wrap"); colourG.setEditable(false); colourG.addActionListener(this); pan.add(new JLabel("Blue Band: ")); pan.add(colourB,"wrap"); colourB.setEditable(false); colourB.addActionListener(this); return pan; } private void setSliderProp(){ Image im = view.getPersistentImage(); Object o = thresholdBand.getSelectedItem(); if (o != null) { int band = (Integer) o; double[] op = IMath.getMinMax(im, band); imageMin = op[0]; imageMax = op[1]; thresholdMinLabel.setText(Tools.df.format(imageMin)); thresholdMaxLabel.setText(Tools.df.format(imageMax)); thresholdSlider.repaint(); // System.out.println("min " + imageMin + " max " +imageMax); thresholdSlider.setValue(fromDoubleToSlider(view .getThresholdValue(band))); //computeHistogram(band); setHisto(band); } } private void setDisplay() { if(coloured.isSelected()) { //main.remove(thresholdPanel); main.remove(bandSelectorPanel); main.add(colourSelectorPanel); } else { main.remove(colourSelectorPanel); main.add(bandSelectorPanel,"wrap"); //main.add(thresholdPanel); } this.pack(); //this.setSize(400, 400); } private void computeHistogram(int b) { if (histogram==null || histogram.length!=histoBins){ histogram = new double[histoBins]; histogramTicks=new double[histoBins]; } else for(int i=0;i<histogram.length;i++) histogram[i]=0; double binSize = (double) (imageMax - imageMin) / (double) histoBins; Image input=view.getPersistentImage(); for(int i=0;i<histoBins;i++) histogramTicks[i]=binSize*i+imageMin; for (int j = 0; j < input.getYDim(); j++) for (int i = 0; i < input.getXDim(); i++) { double val = input.getPixelXYBDouble(i,j,b); /* * Min max are performed to avoid approximation errors */ int bi=Math.max(0, Math.min((int) ((val-imageMin) / binSize), histoBins - 1)); //System.out.println("Val:" +(int) ((val-min) / binSize) + " Bin: " +bi); histogram[bi]++; } } private void setHisto(int band) { HistogramDataset dataset = new HistogramDataset(); Image im=view.getPersistentImage(); double[] value=new double[im.getNumberOfPresentPixel(band)]; if(histoLogX.isSelected()){ for(int i=band,a=0;i<im.size();i+=im.bdim) if(im.isPresent(i)) value[a++]=Math.log(im.getPixelDouble(i));} else{ for(int i=band,a=0;i<im.size();i+=im.bdim) if(im.isPresent(i)) value[a++]=im.getPixelDouble(i); } dataset.addSeries("H", value, histoBins); JFreeChart chart = ChartFactory.createHistogram("Histogram","Pixel value","Number of pixels",dataset,PlotOrientation.VERTICAL,false,false,false); if(histoLogY.isSelected()) { XYPlot plot = chart.getXYPlot(); //final NumberAxis domainAxis = new NumberAxis("x"); LogarithmicAxis rangeAxis = new LogarithmicAxis("Log(y)"); rangeAxis.setAllowNegativesFlag(true); // plot.setDomainAxis(domainAxis); plot.setRangeAxis(rangeAxis); } View v=histo.setImage(chart.createBufferedImage(histo.getWidth(), histo.getHeight())); v.setAutoCorrect(false); view.setScaleResult(false); view.setAutoFitWindow(true); } private int fromDoubleToSlider(double d) { return (int)((d-imageMin)/(imageMax-imageMin)*(thresholdMax-thresholdMin) + thresholdMin); } private double fromSliderToDouble(int i) { double v=i; return ((v-(double)thresholdMin)/(double)(thresholdRange)*(double)(imageMax-imageMin) + (double)imageMin); } private void setViewProperties() { coloured.setSelected(view.isColoured()); slider.setMaximum(view.getPersistentImage().bdim-1); slider.setValue(view.getDisplayedBand()); //bandList = new Integer[view.getPersistentImage().bdim]; colourR.removeAllItems(); colourG.removeAllItems(); colourB.removeAllItems(); thresholdBand.removeAllItems(); colourR.removeActionListener(this); colourG.removeActionListener(this); colourB.removeActionListener(this); thresholdBand.removeActionListener(this); for(int b=0;b<view.getPersistentImage().bdim;b++) { colourR.addItem(new Integer(b)); colourG.addItem(new Integer(b)); colourB.addItem(new Integer(b)); thresholdBand.addItem(new Integer(b)); } colourR.setSelectedIndex(view.getColourBandR()); colourG.setSelectedIndex(view.getColourBandG()); colourB.setSelectedIndex(view.getColourBandB()); thresholdBand.setSelectedIndex(view.getDisplayedBand()); colourR.addActionListener(this); colourG.addActionListener(this); colourB.addActionListener(this); thresholdBand.addActionListener(this); setSliderProp(); } public void setVisible(boolean flag) { super.setVisible(flag); if(flag==true){ setDisplay(); setViewProperties(); } } private boolean noInfiniteLoopEventsHistoBandSlider=true; private int lastSliderValue=-1; @Override public void stateChanged(ChangeEvent e) { Object source=e.getSource(); if(source == coloured) { view.setColoured(coloured.isSelected()); setDisplay(); } else if (source == slider) { if (lastSliderValue != slider.getValue()) { lastSliderValue = slider.getValue(); view.setDisplayedBand(slider.getValue()); if (noInfiniteLoopEventsHistoBandSlider) { int a = slider.getValue(); if (a >= 0 && a < thresholdBand.getItemCount()) { noInfiniteLoopEventsHistoBandSlider = false; thresholdBand.setSelectedIndex(a); } } else { noInfiniteLoopEventsHistoBandSlider = true; } } // setSliderProp(); }else if(source == thresholdSlider) { double v=fromSliderToDouble(thresholdSlider.getValue()); thresholdSlider.setToolTipText(""+v); //System.out.println("val " +v); view.setThresholdValue((Integer)thresholdBand.getSelectedItem(),v); } } @Override public void actionPerformed(ActionEvent e) { Object source=e.getSource(); if(view!=null){ if(source == colourR ) { Object o=colourR.getSelectedItem(); if(o!=null) view.setColourBandR((Integer)o); } else if(source == colourG) { Object o=colourG.getSelectedItem(); if(o!=null) view.setColourBandG((Integer)o); } else if(source == colourB) { Object o=colourB.getSelectedItem(); if(o!=null) view.setColourBandB((Integer)o); } else if (source==threshold) { thresholdSlider.setEnabled(threshold.isSelected()); view.setThreshold(threshold.isSelected()); } else if (source == thresholdBand) { if (noInfiniteLoopEventsHistoBandSlider) { int a = thresholdBand.getSelectedIndex(); if (a >= 0 && a <= slider.getMaximum()) { noInfiniteLoopEventsHistoBandSlider = false; slider.setValue(a); } } else {noInfiniteLoopEventsHistoBandSlider=true;} setSliderProp(); }else if (source==histoBinsField) { try{ int a=Integer.parseInt(histoBinsField.getText()); histoBins=a; }catch(NumberFormatException ef) { histoBinsField.setText(histoBins+""); } setSliderProp(); }else if (source==histoLogX || source == histoLogY) { setSliderProp(); } }} } /* *********************************** * Change event thrower */ private ArrayList<ChangeListener> listeners=new ArrayList<ChangeListener>(); public void addChangeListener(ChangeListener cl) { listeners.add(cl); } public void removeChangeListener(ChangeListener cl) { listeners.remove(cl); } public void fireChangeEvent() { ChangeEvent e = new ChangeEvent(this); for(ChangeListener cl:listeners) cl.stateChanged(e); } @Override public void stateChanged(ChangeEvent e) { if(e.getSource() instanceof View) repaint(); } }