我有时需要显示
image data in the form of a histogram的表示.我对访问图像数据的方式特别感兴趣.我熟悉JFreeChart,其中包括直方图支持,但我会考虑其他方法.
解决方法
下面的示例使用几种技术来创建任意图像的RGB直方图:
> Raster
方法getSamples()从BufferedImage中提取每个色带的值.
> HistogramDataset
方法addSeries()将每个波段的计数添加到数据集.
> A StandardXYBarPainter
替换ChartFactory默认值,如here所示.
>定制DefaultDrawingSupplier
提供每个系列所需的颜色;它包含半透明的颜色.
> here的变形here用于控制每个频带的可见度;使用ChartMouseListener的补充方法如here所示.
- 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,w,h,r);
- dataset.addSeries("Red",r,BINS);
- r = raster.getSamples(0,1,r);
- dataset.addSeries("Green",2,r);
- dataset.addSeries("Blue",BINS);
- // chart
- JFreeChart chart = ChartFactory.createHistogram("Histogram","Value","Count",dataset,PlotOrientation.VERTICAL,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,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();
- });
- }
- }