有时我需要以直方图的形式显示图像数据的表示形式。我对访问图像数据的方式特别感兴趣。我熟悉JFreeChart,其中包括直方图支持,但我会考虑其他方法。
JFreeChart
下面的示例使用多种技术来创建任意图像的RGB直方图:
该Raster方法getSamples()从中提取每个色带的值BufferedImage。
Raster
getSamples()
该HistogramDataset方法addSeries()将每个频段的计数添加到dataset。
HistogramDataset
addSeries()
dataset
一个StandardXYBarPainter替换ChartFactory默认,如图所示这里。
StandardXYBarPainter
ChartFactory
定制DefaultDrawingSupplier提供每个系列所需的颜色;它包含半透明的颜色。
DefaultDrawingSupplier
一种变型VisibleAction,讨论在这里,用于控制每个带的可见性; 这里ChartMouseListener显示了一种补充方法。
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(); }); } }