显示图像数据的直方图

我有时需要以直方图的forms显示图像数据的表示。 我对访问图像数据的方式特别感兴趣。 我熟悉JFreeChart ,其中包括直方图支持,但我会考虑其他方法。

下面的示例使用几种技术来创建任意图像的RGB直方图:

  • Raster方法getSamples()BufferedImage提取每个颜色带的值。

  • HistogramDataset方法addSeries()将每个band的计数添加到dataset

  • StandardXYBarPainter替换ChartFactory默认值,如此处所示。

  • 自定义DefaultDrawingSupplier提供每个系列所需的颜色; 它包含半透明的颜色。

  • 这里讨论的VisibleAction的变体用于控制每个波段的可见度; 这里显示了使用ChartMouseListener的补充方法。

颜色直方图

 import java.awt.BorderLayout; import java.awt.Color; import java.awt.EventQueue; import java.awt.Paint; import java.awt.event.ActionEvent; import java.awt.image.BufferedImage; import java.awt.image.Raster; import java.io.IOException; import java.net.URL; import javax.imageio.ImageIO; import javax.swing.AbstractAction; import javax.swing.ImageIcon; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.DefaultDrawingSupplier; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.StandardXYBarPainter; import org.jfree.chart.renderer.xy.XYBarRenderer; import org.jfree.data.statistics.HistogramDataset; /** * @see https://stackoverflow.com/q/40537278/230513 * @see https://stackoverflow.com/q/11870416/230513 * @see https://stackoverflow.com/a/28519356/230513 */ public class Histogram { private static final int BINS = 256; private final BufferedImage image = getImage(); private HistogramDataset dataset; private XYBarRenderer renderer; private BufferedImage getImage() { try { return ImageIO.read(new URL( "http://i.imgur.com/kxXhIH1.jpg")); } catch (IOException e) { e.printStackTrace(System.err); } return null; } private ChartPanel createChartPanel() { // dataset dataset = new HistogramDataset(); Raster raster = image.getRaster(); final int w = image.getWidth(); final int h = image.getHeight(); double[] r = new double[w * h]; r = raster.getSamples(0, 0, w, h, 0, r); dataset.addSeries("Red", r, BINS); r = raster.getSamples(0, 0, w, h, 1, r); dataset.addSeries("Green", r, BINS); r = raster.getSamples(0, 0, w, h, 2, r); dataset.addSeries("Blue", r, BINS); // chart JFreeChart chart = ChartFactory.createHistogram("Histogram", "Value", "Count", dataset, PlotOrientation.VERTICAL, true, true, false); XYPlot plot = (XYPlot) chart.getPlot(); renderer = (XYBarRenderer) plot.getRenderer(); renderer.setBarPainter(new StandardXYBarPainter()); // translucent red, green & blue Paint[] paintArray = { new Color(0x80ff0000, true), new Color(0x8000ff00, true), new Color(0x800000ff, true) }; plot.setDrawingSupplier(new DefaultDrawingSupplier( paintArray, DefaultDrawingSupplier.DEFAULT_FILL_PAINT_SEQUENCE, DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE, DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE, DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE, DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE)); ChartPanel panel = new ChartPanel(chart); panel.setMouseWheelEnabled(true); return panel; } private JPanel createControlPanel() { JPanel panel = new JPanel(); panel.add(new JCheckBox(new VisibleAction(0))); panel.add(new JCheckBox(new VisibleAction(1))); panel.add(new JCheckBox(new VisibleAction(2))); return panel; } private class VisibleAction extends AbstractAction { private final int i; public VisibleAction(int i) { this.i = i; this.putValue(NAME, (String) dataset.getSeriesKey(i)); this.putValue(SELECTED_KEY, true); renderer.setSeriesVisible(i, true); } @Override public void actionPerformed(ActionEvent e) { renderer.setSeriesVisible(i, !renderer.getSeriesVisible(i)); } } private void display() { JFrame f = new JFrame("Histogram"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(createChartPanel()); f.add(createControlPanel(), BorderLayout.SOUTH); f.add(new JLabel(new ImageIcon(image)), BorderLayout.WEST); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } public static void main(String[] args) { EventQueue.invokeLater(() -> { new Histogram().display(); }); } } 

使用Chart2D库,下面的示例说明了一些替代方法。

  • ColorConvertOp用于将样本图像转换为灰度,如此处和此处所示。

  • 嵌套循环遍历BufferedImage的像素,调用getRGB()方法来提取每个像素的值; 相应的计数用于构建dataset

Chart2DHistogram

 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.GradientPaint; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.image.BufferedImage; import java.awt.image.ColorConvertOp; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.UIManager; import net.sourceforge.chart2d.Chart2DProperties; import net.sourceforge.chart2d.Dataset; import net.sourceforge.chart2d.GraphChart2DProperties; import net.sourceforge.chart2d.GraphProperties; import net.sourceforge.chart2d.LBChart2D; import net.sourceforge.chart2d.LegendProperties; import net.sourceforge.chart2d.MultiColorsProperties; import net.sourceforge.chart2d.Object2DProperties; /** @see https://stackoverflow.com/q/9964872/230513 */ public class Histogram extends JPanel { private BufferedImage image = getImage("OptionPane.warningIcon"); private BufferedImage gray = getGray(image); public Histogram() { JPanel panel = new JPanel(new GridLayout(0, 1)); panel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); panel.add(new JLabel(new ImageIcon(image))); panel.add(new JLabel(new ImageIcon(gray))); this.setLayout(new BorderLayout()); this.add(panel, BorderLayout.WEST); this.add(createChart(gray, 20), BorderLayout.CENTER); } private BufferedImage getImage(String name) { Icon icon = UIManager.getIcon(name); int w = icon.getIconWidth(); int h = icon.getIconHeight(); this.setPreferredSize(new Dimension(w, h)); BufferedImage i = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = (Graphics2D) i.getGraphics(); g2d.setPaint(new GradientPaint( 0, 0, Color.blue, w, h, Color.green, true)); g2d.fillRect(0, 0, w, h); icon.paintIcon(null, g2d, 0, 0); g2d.dispose(); return i; } private BufferedImage getGray(BufferedImage image) { BufferedImage g = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY); ColorConvertOp op = new ColorConvertOp( image.getColorModel().getColorSpace(), g.getColorModel().getColorSpace(), null); op.filter(image, g); return g; } private LBChart2D createChart(BufferedImage gray, int buckets) { // Chart2D configuration Object2DProperties object2DProps = new Object2DProperties(); object2DProps.setObjectTitleText("Gray Histogram"); Chart2DProperties chart2DProps = new Chart2DProperties(); chart2DProps.setChartDataLabelsPrecision(-1); LegendProperties legendProps = new LegendProperties(); String[] legendLabels = {"Gray"}; legendProps.setLegendLabelsTexts(legendLabels); GraphChart2DProperties graphChart2DProps = new GraphChart2DProperties(); graphChart2DProps.setLabelsAxisTitleText("Gray"); graphChart2DProps.setNumbersAxisTitleText("Count"); // Dataset String[] labelsAxisLabels = new String[buckets]; for (int i = 0; i < labelsAxisLabels.length; i++) { labelsAxisLabels[i] = String.valueOf(i * 256 / buckets); } graphChart2DProps.setLabelsAxisLabelsTexts(labelsAxisLabels); int[] counts = new int[buckets]; for (int r = 0; r < gray.getHeight(); r++) { for (int c = 0; c < gray.getWidth(); c++) { int v = (gray.getRGB(c, r) & 0xff) * buckets / 256; counts[v]++; } } Dataset dataset = new Dataset(1, counts.length, 1); for (int i = 0; i < counts.length; i++) { dataset.set(0, i, 0, counts[i]); } GraphProperties graphProps = new GraphProperties(); MultiColorsProperties multiColorsProps = new MultiColorsProperties(); LBChart2D chart2D = new LBChart2D(); chart2D.setObject2DProperties(object2DProps); chart2D.setChart2DProperties(chart2DProps); chart2D.setLegendProperties(legendProps); chart2D.setGraphChart2DProperties(graphChart2DProps); chart2D.addGraphProperties(graphProps); chart2D.addDataset(dataset); chart2D.addMultiColorsProperties(multiColorsProps); //Optional validation: Prints debug messages if invalid only. if (!chart2D.validate(false)) { chart2D.validate(true); } return chart2D; } private void display() { JFrame f = new JFrame("Histogram"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(this); f.pack(); f.setSize(640, 480); f.setLocationRelativeTo(null); f.setVisible(true); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new Histogram().display(); } }); } }