java 显示图像数据的直方图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28519355/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Displaying a histogram of image data
提问by trashgod
I sometimes need to display a representation of image data in the form of a histogram. I'm especially interested in ways to access the image data. I'm familiar with JFreeChart
, which includes histogram support, but I'd consider other approaches.
我有时需要以直方图的形式显示图像数据的表示。我对访问图像数据的方法特别感兴趣。我熟悉JFreeChart
,其中包括直方图支持,但我会考虑其他方法。
回答by trashgod
The example below uses several techniques to create an RGB histogram of an arbitrary image:
下面的示例使用多种技术来创建任意图像的 RGB 直方图:
The
Raster
methodgetSamples()
extracts the values of each color band from theBufferedImage
.The
HistogramDataset
methodaddSeries()
adds each band's counts to thedataset
.A
StandardXYBarPainter
replaces theChartFactory
default, as shown here.A custom
DefaultDrawingSupplier
supplies the color required for each series; it contains translucent colors.A variation of
VisibleAction
, discussed here, is used to control the visibility of each band; a complementary approach usingChartMouseListener
is shown here.
该
Raster
方法从 中getSamples()
提取每个色带的值BufferedImage
。该
HistogramDataset
方法addSeries()
将每个波段的计数添加到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();
});
}
}
回答by trashgod
Using the Chart2D
library, the example below illustrates some alternative approaches.
使用该Chart2D
库,下面的示例说明了一些替代方法。
A
ColorConvertOp
is used to convert the sample image to grayscale, as shown hereand here.Nested loops iterate over the pixels of the
BufferedImage
, invoking thegetRGB()
method to extract the value of each pixel; the corresponding counts are used to construct thedataset
.
A
ColorConvertOp
用于将示例图像转换为灰度,如此处和此处所示。嵌套循环遍历 的像素
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();
}
});
}
}