package AngioTool; import Utils.*; import Pixels.*; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.event.*; import java.io.File; import java.io.InputStream; import java.util.LinkedList; import javax.swing.*; import javax.swing.border.EmptyBorder; public class AngioToolGui2 extends JFrame implements ColorElement.Listener, ActionListener, FocusListener, KeyListener { final JButton btnLoadImage = new JButton(); final JButton btnStartBatch = new JButton(); final JButton btnHelp = new JButton(); final JLabel labelAnalysis = new JLabel(); final JCheckBox cbComputeLacunarity = new JCheckBox(); final JCheckBox cbComputeThickness = new JCheckBox(); final JLabel labelSkeletonizer = new JLabel(); final ButtonGroup groupSkeletonizer = new ButtonGroup(); final JRadioButton rbSkelFast = new JRadioButton(); final JRadioButton rbSkelThorough = new JRadioButton(); final NumberEntry elemMaxSkelIterations; final NumberEntry elemResizeInputs; final NumberEntry elemLinearScaleFactor; final NumberEntry elemRemoveParticles; final NumberEntry elemFillHoles; final NumberEntry elemMaxHoleLevelPercent; final NumberEntry elemMinBoxnessPercent; final NumberEntry elemMinAreaLengthRatio; final JCheckBox cbTransformColors = new JCheckBox(); final JLabel labelSaturationFactor = new JLabel(); final JLabel labelVoidColor = new JLabel(); final JLabel labelTargetColor = new JLabel(); final JLabel labelHueBrightness = new JLabel(); final JLabel labelBrightnessGraph = new JLabel(); final JLabel labelSatPercent = new JLabel(); final JLabel labelHbRatio = new JLabel(); final JTextField textSaturationFactor = new JTextField(); final ColorElement elemVoidColor; final ColorElement elemTargetColor; final JTextField textHueWeight = new JTextField(); final JTextField textBrightnessWeight = new JTextField(); final JTextField textBrightnessSegments = new JTextField(); final JLabel labelSigmas = new JLabel(); final JTextField textSigmas = new JTextField(); final JLabel labelIntensity = new JLabel(); final JTextField textMinIntensity = new JTextField(); final JTextField textMaxIntensity = new JTextField(); final JLabel labelOverlay = new JLabel(); final SizeColorEntry elemOutline; final SizeColorEntry elemBranches; final SizeColorEntry elemSkeleton; final SizeColorEntry elemConvexHull; final ButtonGroup groupImageRecolor = new ButtonGroup(); final JRadioButton rbImageOriginal = new JRadioButton(); final JRadioButton rbImageIsolated = new JRadioButton(); final JRadioButton rbImageGray = new JRadioButton(); final JButton btnReset = new JButton(); final JLabel labelMemory = new JLabel(); AnalyzerParameters latestAnalyzerParams = null; String defaultPath; public final LinkedList imagingWindows = new LinkedList<>(); byte[] helpHtmlData; public AngioToolGui2(AnalyzerParameters analyzerParams, String defaultPath) { super(AngioTool.TITLE); this.defaultPath = defaultPath; this.setIconImage(AngioTool.ATIcon.getImage()); initButton(btnLoadImage, AngioTool.ATFolder, "View"); initButton(btnStartBatch, AngioTool.ATBatch, "Batch"); initButton(btnHelp, AngioTool.ATHelp, "Help"); labelAnalysis.setText("Analysis"); Misc.setNewFontSizeOn(labelAnalysis, 20); labelSkeletonizer.setText("Skeletonizer:"); rbSkelFast.setText("Fast (Zha84)"); rbSkelFast.setSelected(analyzerParams.shouldUseFastSkeletonizer); rbSkelThorough.setText("Thorough (Lee94)"); rbSkelThorough.setSelected(!analyzerParams.shouldUseFastSkeletonizer); groupSkeletonizer.add(rbSkelFast); groupSkeletonizer.add(rbSkelThorough); cbComputeLacunarity.setText("Lacunarity"); cbComputeLacunarity.setSelected(analyzerParams.shouldComputeLacunarity); cbComputeThickness.setText("Thickness"); cbComputeThickness.setSelected(analyzerParams.shouldComputeThickness); elemMaxSkelIterations = new NumberEntry("Max Skeleton Steps:", analyzerParams.shouldCapSkelIterations, analyzerParams.maxSkelIterations, ""); elemResizeInputs = new NumberEntry("Resize Inputs to:", analyzerParams.shouldResizeImage, 100.0 * analyzerParams.resizingFactor, "%"); elemLinearScaleFactor = new NumberEntry("Measurement Scale:", analyzerParams.shouldApplyLinearScale, 100.0 * analyzerParams.linearScalingFactor, "%"); elemRemoveParticles = new NumberEntry("Remove Particles:", analyzerParams.shouldRemoveSmallParticles, analyzerParams.removeSmallParticlesThreshold, "px"); elemFillHoles = new NumberEntry("Fill Holes:", analyzerParams.shouldFillHoles, analyzerParams.fillHolesValue, "px"); elemMaxHoleLevelPercent = new NumberEntry("Max Hole Level:", analyzerParams.shouldFillBrightShapes, 100.0 * analyzerParams.brightShapeThresholdFactor, "%"); elemMinBoxnessPercent = new NumberEntry("Min Boxness:", analyzerParams.shouldApplyMinBoxness, 100.0 * analyzerParams.minBoxness, "%"); elemMinAreaLengthRatio = new NumberEntry("Min Length : Area:", analyzerParams.shouldApplyMinAreaLength, analyzerParams.minAreaLengthRatio, "1 :"); labelSigmas.setText("Vessel Diameters list"); textSigmas.setText(Misc.formatDoubleArray(analyzerParams.sigmas, "12")); textSigmas.setToolTipText("List of Sigmas (numbers)"); labelIntensity.setText("Vessel Intensity range"); textMinIntensity.setText("" + analyzerParams.thresholdLow); textMaxIntensity.setText("" + analyzerParams.thresholdHigh); labelOverlay.setText("Overlay"); Misc.setNewFontSizeOn(labelOverlay, 20); elemOutline = new SizeColorEntry("Outline:", analyzerParams.shouldDrawOutline, analyzerParams.outlineSize, analyzerParams.outlineColor); elemBranches = new SizeColorEntry("Branches:", analyzerParams.shouldDrawBranchPoints, analyzerParams.branchingPointsSize, analyzerParams.branchingPointsColor); elemSkeleton = new SizeColorEntry("Skeleton:", analyzerParams.shouldDrawSkeleton, analyzerParams.skeletonSize, analyzerParams.skeletonColor); elemConvexHull = new SizeColorEntry("Convex Hull:", analyzerParams.shouldDrawConvexHull, analyzerParams.convexHullSize, analyzerParams.convexHullColor); elemOutline.setColorChangeListener(this); elemBranches.setColorChangeListener(this); elemSkeleton.setColorChangeListener(this); elemConvexHull.setColorChangeListener(this); cbTransformColors.setText("Transform Colors"); cbTransformColors.setSelected(analyzerParams.shouldRemapColors); labelSaturationFactor.setText("Saturation"); labelVoidColor.setText("Off"); labelTargetColor.setText("Target"); labelHueBrightness.setText("Hue : Brightness"); labelBrightnessGraph.setText("Brightness Graph"); labelSatPercent.setText("%"); labelHbRatio.setText(":"); textSaturationFactor.setText(Misc.formatDouble(100.0 * analyzerParams.saturationFactor)); elemVoidColor = new ColorElement("Off Color", analyzerParams.voidRemapColor); elemTargetColor = new ColorElement("Target Color", analyzerParams.targetRemapColor); elemVoidColor.setColorChangeListener(this); elemTargetColor.setColorChangeListener(this); textHueWeight.setText(Misc.formatDouble(analyzerParams.hueTransformWeight)); textBrightnessWeight.setText(Misc.formatDouble(analyzerParams.brightnessTransformWeight)); textBrightnessSegments.setText(Misc.formatIntVecTwoPointArray(analyzerParams.brightnessLineSegments)); textSaturationFactor.setEnabled(analyzerParams.shouldRemapColors); textHueWeight.setEnabled(analyzerParams.shouldRemapColors); textBrightnessWeight.setEnabled(analyzerParams.shouldRemapColors); textBrightnessSegments.setEnabled(analyzerParams.shouldRemapColors); rbImageOriginal.setText("Keep Original Colors"); rbImageOriginal.setSelected(!analyzerParams.shouldIsolateBrightestChannelInOutput); rbImageIsolated.setText("Isolate Brightest Channel"); rbImageIsolated.setSelected(analyzerParams.shouldIsolateBrightestChannelInOutput && !analyzerParams.shouldExpandOutputToGrayScale); rbImageGray.setText("Convert to Grayscale"); rbImageGray.setSelected(analyzerParams.shouldIsolateBrightestChannelInOutput && analyzerParams.shouldExpandOutputToGrayScale); groupImageRecolor.add(rbImageOriginal); groupImageRecolor.add(rbImageIsolated); groupImageRecolor.add(rbImageGray); btnReset.setText("Reset To Defaults"); updateMemoryMonitor(); JPanel dialogPanel = new JPanel(); GroupLayout layout = new GroupLayout(dialogPanel); dialogPanel.setLayout(layout); dialogPanel.setBorder(new EmptyBorder(0, 2, 4, 2)); layout.setAutoCreateGaps(true); layout.setAutoCreateContainerGaps(true); arrangeUi(layout); int nComponents = dialogPanel.getComponentCount(); for (int i = 0; i < nComponents; i++) { Component elem = dialogPanel.getComponent(i); if (elem instanceof AbstractButton) ((AbstractButton)elem).addActionListener(this); else elem.addFocusListener(this); if (elem instanceof JTextField) elem.addKeyListener(this); } dialogPanel.addMouseListener(new MouseListener() { @Override public void mousePressed(MouseEvent evt) { maybeUpdateImagingWindows(); } @Override public void mouseClicked(MouseEvent evt) {} @Override public void mouseEntered(MouseEvent evt) {} @Override public void mouseExited(MouseEvent evt) {} @Override public void mouseReleased(MouseEvent evt) {} }); Container container = getContentPane(); container.add(dialogPanel); this.pack(); this.setDefaultCloseOperation(0); this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent evt) { ATPreferences.savePreferences(buildAnalyzerParamsFromUi(), AngioTool.PREFS_TXT); AngioToolGui2.this.setVisible(false); System.exit(0); } }); Dimension minSize = this.getPreferredSize(); this.setMinimumSize(minSize); this.setSize(new Dimension(minSize.width + 50, minSize.height + 10)); } void setAnalysisUi(AnalyzerParameters analyzerParams) { rbSkelFast.setSelected(analyzerParams.shouldUseFastSkeletonizer); rbSkelThorough.setSelected(!analyzerParams.shouldUseFastSkeletonizer); cbComputeLacunarity.setSelected(analyzerParams.shouldComputeLacunarity); cbComputeThickness.setSelected(analyzerParams.shouldComputeThickness); elemMaxSkelIterations.update(analyzerParams.shouldCapSkelIterations, analyzerParams.maxSkelIterations); elemResizeInputs.update(analyzerParams.shouldResizeImage, 100.0 * analyzerParams.resizingFactor); elemLinearScaleFactor.update(analyzerParams.shouldApplyLinearScale, 100.0 * analyzerParams.linearScalingFactor); elemRemoveParticles.update(analyzerParams.shouldRemoveSmallParticles, analyzerParams.removeSmallParticlesThreshold); elemFillHoles.update(analyzerParams.shouldFillHoles, analyzerParams.fillHolesValue); textSigmas.setText(Misc.formatDoubleArray(analyzerParams.sigmas, "12")); textMinIntensity.setText("" + analyzerParams.thresholdLow); textMaxIntensity.setText("" + analyzerParams.thresholdHigh); elemOutline.update(analyzerParams.shouldDrawOutline, analyzerParams.outlineSize, analyzerParams.outlineColor); elemBranches.update(analyzerParams.shouldDrawBranchPoints, analyzerParams.branchingPointsSize, analyzerParams.branchingPointsColor); elemSkeleton.update(analyzerParams.shouldDrawSkeleton, analyzerParams.skeletonSize, analyzerParams.skeletonColor); elemConvexHull.update(analyzerParams.shouldDrawConvexHull, analyzerParams.convexHullSize, analyzerParams.convexHullColor); elemMaxHoleLevelPercent.update(analyzerParams.shouldFillBrightShapes, 100.0 * analyzerParams.brightShapeThresholdFactor); elemMinBoxnessPercent.update(analyzerParams.shouldApplyMinBoxness, 100.0 * analyzerParams.minBoxness); elemMinAreaLengthRatio.update(analyzerParams.shouldApplyMinAreaLength, analyzerParams.minAreaLengthRatio); textSaturationFactor.setText(Misc.formatDouble(100.0 * analyzerParams.saturationFactor)); elemVoidColor.update(analyzerParams.voidRemapColor); elemTargetColor.update(analyzerParams.targetRemapColor); textHueWeight.setText(Misc.formatDouble(analyzerParams.hueTransformWeight)); textBrightnessWeight.setText(Misc.formatDouble(analyzerParams.brightnessTransformWeight)); textBrightnessSegments.setText(Misc.formatIntVecTwoPointArray(analyzerParams.brightnessLineSegments)); cbTransformColors.setSelected(analyzerParams.shouldRemapColors); textSaturationFactor.setEnabled(analyzerParams.shouldRemapColors); textHueWeight.setEnabled(analyzerParams.shouldRemapColors); textBrightnessWeight.setEnabled(analyzerParams.shouldRemapColors); textBrightnessSegments.setEnabled(analyzerParams.shouldRemapColors); rbImageOriginal.setSelected(!analyzerParams.shouldIsolateBrightestChannelInOutput); rbImageIsolated.setSelected(analyzerParams.shouldIsolateBrightestChannelInOutput && !analyzerParams.shouldExpandOutputToGrayScale); rbImageGray.setSelected(analyzerParams.shouldIsolateBrightestChannelInOutput && analyzerParams.shouldExpandOutputToGrayScale); maybeUpdateImagingWindows(); } private void initButton(JButton button, ImageIcon icon, String text) { button.setIcon(icon); button.setVerticalTextPosition(SwingConstants.BOTTOM); button.setHorizontalTextPosition(SwingConstants.CENTER); button.setText(text); } private void arrangeUi(GroupLayout layout) { layout.setHorizontalGroup(layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(btnLoadImage) .addComponent(btnStartBatch) .addGap(0, 0, Short.MAX_VALUE) .addComponent(btnHelp) ) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(labelAnalysis) .addGroup(elemFillHoles.addToSeqGroup(layout.createSequentialGroup())) .addGroup(elemRemoveParticles.addToSeqGroup(layout.createSequentialGroup())) .addGroup(elemMaxHoleLevelPercent.addToSeqGroup(layout.createSequentialGroup())) .addGroup(elemMinBoxnessPercent.addToSeqGroup(layout.createSequentialGroup())) .addGroup(elemMinAreaLengthRatio.addToSeqGroup(layout.createSequentialGroup())) ) .addGap(16, 16, Short.MAX_VALUE) .addGroup(layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(cbComputeLacunarity) .addGap(16) .addComponent(cbComputeThickness) ) .addGroup(layout.createSequentialGroup() .addGap(4) .addComponent(labelSkeletonizer) .addGroup(layout.createParallelGroup() .addComponent(rbSkelFast) .addComponent(rbSkelThorough) ) ) .addGroup(elemMaxSkelIterations.addToSeqGroup(layout.createSequentialGroup())) .addGroup(elemResizeInputs.addToSeqGroup(layout.createSequentialGroup())) .addGroup(elemLinearScaleFactor.addToSeqGroup(layout.createSequentialGroup())) ) ) .addGroup(layout.createSequentialGroup() .addComponent(cbTransformColors) .addGap(0, 0, Short.MAX_VALUE) .addGroup(layout.createParallelGroup() .addComponent(labelSaturationFactor) .addGroup(layout.createSequentialGroup() .addComponent(labelSatPercent) .addGap(4) .addComponent(textSaturationFactor, 0, 48, 48) ) ) .addGap(12) .addGroup( elemVoidColor.addWithWidth(layout.createParallelGroup().addComponent(labelVoidColor)) ) .addGap(12) .addGroup( elemTargetColor.addWithWidth(layout.createParallelGroup().addComponent(labelTargetColor)) ) .addGap(0, 0, Short.MAX_VALUE) .addGroup(layout.createParallelGroup() .addComponent(labelHueBrightness) .addGroup(layout.createSequentialGroup() .addComponent(textHueWeight, 0, 48, 48) .addGap(4) .addComponent(labelHbRatio) .addGap(4) .addComponent(textBrightnessWeight, 0, 48, 48) ) ) ) .addGroup(layout.createParallelGroup() .addComponent(labelBrightnessGraph) .addComponent(textBrightnessSegments, 0, 200, Short.MAX_VALUE) ) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(labelSigmas) .addComponent(textSigmas) ) .addGroup(layout.createParallelGroup() .addComponent(labelIntensity) .addGroup(layout.createSequentialGroup() .addComponent(textMinIntensity) .addComponent(textMaxIntensity) ) ) ) .addComponent(labelOverlay) .addGroup( Misc.arrangeParallelEntries( elemBranches, elemConvexHull, layout, Misc.arrangeParallelEntries( elemOutline, elemSkeleton, layout, layout.createSequentialGroup() ).addGap(20) ) ) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(btnReset) .addComponent(labelMemory) ) .addGap(0, 0, Short.MAX_VALUE) .addGroup(layout.createParallelGroup() .addComponent(rbImageOriginal) .addComponent(rbImageIsolated) .addComponent(rbImageGray) ) ) ); final int MIN_TEXT_HEIGHT = 18; final int TEXT_HEIGHT = 24; layout.setVerticalGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(btnLoadImage) .addComponent(btnStartBatch) .addComponent(btnHelp) ) .addGap(20) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(labelAnalysis) .addComponent(cbComputeLacunarity) .addComponent(cbComputeThickness) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addGroup(layout.createSequentialGroup() .addGroup(elemFillHoles.addToParaGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE))) .addGroup(elemRemoveParticles.addToParaGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE))) ) .addGroup(layout.createSequentialGroup() .addGap(0, 0, 16) .addComponent(labelSkeletonizer) .addGap(0, 0, 16) ) .addGroup(layout.createSequentialGroup() .addComponent(rbSkelFast) .addComponent(rbSkelThorough) ) ) .addGroup( elemMaxSkelIterations.addToParaGroup( elemMaxHoleLevelPercent.addToParaGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)) ) ) .addGroup( elemResizeInputs.addToParaGroup( elemMinBoxnessPercent.addToParaGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)) ) ) .addGroup( elemLinearScaleFactor.addToParaGroup( elemMinAreaLengthRatio.addToParaGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)) ) ) .addGap(12) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addGroup(layout.createSequentialGroup() .addGap(9) .addComponent(cbTransformColors) .addGap(9) ) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(labelSaturationFactor) .addComponent(labelVoidColor) .addComponent(labelTargetColor) .addComponent(labelHueBrightness) ) .addGroup( elemTargetColor.addWithHeight( elemVoidColor.addWithHeight( layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(labelSatPercent) .addComponent(textSaturationFactor, MIN_TEXT_HEIGHT, TEXT_HEIGHT, TEXT_HEIGHT) ) ) .addComponent(textHueWeight, MIN_TEXT_HEIGHT, TEXT_HEIGHT, TEXT_HEIGHT) .addComponent(labelHbRatio) .addComponent(textBrightnessWeight, MIN_TEXT_HEIGHT, TEXT_HEIGHT, TEXT_HEIGHT) ) ) ) .addComponent(labelBrightnessGraph) .addComponent(textBrightnessSegments, MIN_TEXT_HEIGHT, TEXT_HEIGHT, TEXT_HEIGHT) .addGap(12) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(labelSigmas) .addComponent(labelIntensity) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(textSigmas, MIN_TEXT_HEIGHT, TEXT_HEIGHT, TEXT_HEIGHT) .addComponent(textMinIntensity, MIN_TEXT_HEIGHT, TEXT_HEIGHT, TEXT_HEIGHT) .addComponent(textMaxIntensity, MIN_TEXT_HEIGHT, TEXT_HEIGHT, TEXT_HEIGHT) ) .addGap(20) .addComponent(labelOverlay) .addGap(12) .addGroup( elemBranches.addToParaGroup( elemOutline.addToParaGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)) ) ) .addGroup( elemConvexHull.addToParaGroup( elemSkeleton.addToParaGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)) ) ) .addGap(8) .addComponent(rbImageOriginal) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(btnReset) .addComponent(rbImageIsolated) ) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(labelMemory) .addComponent(rbImageGray) ) ); } @Override public void onColorChanged(ColorElement colorElem) { maybeUpdateImagingWindows(); } @Override public void actionPerformed(ActionEvent evt) { Object source = evt.getSource(); if (source == btnLoadImage) openImageThenImagingWindow(); else if (source == btnStartBatch) openBatchWindow(); else if (source == btnHelp) openHelpWindow(); else if (source == btnReset) setAnalysisUi(AnalyzerParameters.defaults()); else if (source == cbTransformColors) toggleTransformColors(); else maybeUpdateImagingWindows(); } @Override public void focusGained(FocusEvent evt) { // ... } @Override public void focusLost(FocusEvent evt) { maybeUpdateImagingWindows(); } @Override public void keyPressed(KeyEvent evt) { if (evt.getKeyCode() == KeyEvent.VK_ENTER) maybeUpdateImagingWindows(); } @Override public void keyReleased(KeyEvent evt) {} @Override public void keyTyped(KeyEvent evt) {} void openImageThenImagingWindow() { File imageFile = openImageFile(); if (imageFile == null) return; double resizeFactor = elemResizeInputs.cb.isSelected() ? elemResizeInputs.getValue() / 100.0 : 1.0; ArgbBuffer image = null; Exception error = null; try { image = ImageFile.acquireImageForAnalysis(imageFile.getAbsolutePath(), resizeFactor); } catch (Exception ex) { error = ex; } if (image == null) { Misc.showDialogBox( "Failed to analyze image", error != null ? Misc.buildDialogMessageFromException(error) : "Image file could not be read" ); return; } imagingWindows.add(new ImagingWindow(this, image, resizeFactor, imageFile, defaultPath).showDialog()); updateMemoryMonitor(); } void openBatchWindow() { BatchParameters batchParams = BatchParameters.defaults(); try { ATPreferences.loadPreferences(batchParams, AngioTool.class, AngioTool.BATCH_TXT); } catch (Exception ignored) {} new BatchWindow(this, batchParams).showDialog(); updateMemoryMonitor(); } void openHelpWindow() { if (helpHtmlData == null) { String boxnessUrl = getClass().getResource("/images/boxness-formula.png").toString(); try (InputStream in = getClass().getResourceAsStream("/manual.html")) { ByteVectorOutputStream vec = Misc.readFullyAsVector(in); this.helpHtmlData = vec.toString().replace("/images/boxness-formula.png", boxnessUrl).getBytes(); } catch (Exception ex) { Misc.showExceptionInDialogBox(ex); return; } } new HelpWindow(this, this.helpHtmlData).showDialog(); updateMemoryMonitor(); } File openImageFile() { JFileChooser fc = Misc.createFileChooser(); fc.setDialogTitle("Open Image to View/Analyze"); fc.setDialogType(JFileChooser.OPEN_DIALOG); fc.setCurrentDirectory(new File(defaultPath)); Misc.addImageFileFilters(fc); return fc.showOpenDialog(this) == 0 ? fc.getSelectedFile() : null; } void toggleTransformColors() { boolean enabled = cbTransformColors.isSelected(); textSaturationFactor.setEnabled(enabled); textHueWeight.setEnabled(enabled); textBrightnessWeight.setEnabled(enabled); textBrightnessSegments.setEnabled(enabled); maybeUpdateImagingWindows(); } void maybeUpdateImagingWindows() { AnalyzerParameters params = buildAnalyzerParamsFromUi(); if (latestAnalyzerParams != null && params.equals(latestAnalyzerParams)) { updateMemoryMonitor(); return; } latestAnalyzerParams = params; for (ImagingWindow iw : imagingWindows) iw.updateImage(params); updateMemoryMonitor(); } public void closeImagingWindow(ImagingWindow window) { window.release(); imagingWindows.remove(window); } public AnalyzerParameters buildAnalyzerParamsFromUi() { ButtonModel skelType = groupSkeletonizer.getSelection(); boolean shouldUseFastSkel = skelType == rbSkelFast.getModel(); ButtonModel recolorType = groupImageRecolor.getSelection(); boolean shouldIsolateChannel; boolean shouldExpandToGrayScale; if (recolorType == rbImageOriginal.getModel()) { shouldIsolateChannel = false; shouldExpandToGrayScale = false; } else if (recolorType == rbImageGray.getModel()) { shouldIsolateChannel = true; shouldExpandToGrayScale = true; } else { shouldIsolateChannel = true; shouldExpandToGrayScale = false; } return new AnalyzerParameters( elemResizeInputs.cb.isSelected(), elemResizeInputs.getValue() / 100.0, cbTransformColors.isSelected(), Misc.parseDouble(textHueWeight.getText(), 0.0), Misc.parseDouble(textBrightnessWeight.getText(), 0.0), elemTargetColor.color, elemVoidColor.color, Misc.parseDouble(textSaturationFactor.getText(), 100.0) / 100.0, Misc.getSomeInts(textBrightnessSegments.getText()), elemMaxHoleLevelPercent.cb.isSelected(), elemMaxHoleLevelPercent.getValue() / 100.0, elemMinBoxnessPercent.cb.isSelected(), elemMinBoxnessPercent.getValue() / 100.0, elemMinAreaLengthRatio.cb.isSelected(), elemMinAreaLengthRatio.getValue(), elemRemoveParticles.cb.isSelected(), elemRemoveParticles.getValue(), elemFillHoles.cb.isSelected(), elemFillHoles.getValue(), Misc.getSomeDoubles(textSigmas.getText()), Misc.parseInt(textMaxIntensity.getText(), 255), Misc.parseInt(textMinIntensity.getText(), 0), shouldUseFastSkel, elemMaxSkelIterations.cb.isSelected(), (int)elemMaxSkelIterations.getValue(), elemLinearScaleFactor.cb.isSelected(), elemLinearScaleFactor.getValue() / 100.0, elemOutline.cb.isSelected(), elemOutline.getColor(), elemOutline.getValue(), elemSkeleton.cb.isSelected(), elemSkeleton.getColor(), elemSkeleton.getValue(), elemBranches.cb.isSelected(), elemBranches.getColor(), elemBranches.getValue(), elemConvexHull.cb.isSelected(), elemConvexHull.getColor(), elemConvexHull.getValue(), shouldIsolateChannel, shouldExpandToGrayScale, cbComputeLacunarity.isSelected(), cbComputeThickness.isSelected() ); } public void updateMemoryMonitor() { Runtime rt = Runtime.getRuntime(); long maxMB = (rt.maxMemory() + (1L << 19)) >> 20L; long usedMB = (rt.totalMemory() - rt.freeMemory() + (1L << 19)) >> 20L; labelMemory.setText("Used MB: " + usedMB + " / " + maxMB); } }