【问题标题】:Displaying a histogram of image data显示图像数据的直方图
【发布时间】:2015-04-15 15:51:58
【问题描述】:

我有时需要显示image data in the form of a histogram 的表示。我对访问图像数据的方法特别感兴趣。我熟悉 JFreeChart,它包括直方图支持,但我会考虑其他方法。

【问题讨论】:

    标签: java image swing histogram jfreechart


    【解决方案1】:

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

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

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

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

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

    • VisibleAction 的变体,讨论了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(
                    "https://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();
            });
        }
    }
    

    【讨论】:

    【解决方案2】:

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

    • ColorConvertOp用于将样图转为灰度图,如图herehere

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

    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();
                }
            });
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-02
      • 2017-01-02
      • 2013-08-08
      • 2018-02-08
      • 2013-01-18
      • 2015-08-19
      • 1970-01-01
      相关资源
      最近更新 更多