Manchmal muss ich eine Darstellung von image data in the form of a histogram anzeigen. Ich bin besonders daran interessiert, wie ich auf die Bilddaten zugreifen kann. Ich bin vertraut mit JFreeChart
, die Histogramm-Unterstützung enthält, aber ich würde andere Ansätze in Betracht ziehen.Anzeigen eines Histogramms der Bilddaten
Antwort
Das Beispiel verwendet unter mehreren Techniken ein RGB-Histogramm eines beliebigen Bildes zu erzeugen:
Die
Raster
VerfahrengetSamples()
die Werte jedes Farbband extrahiert aus demBufferedImage
.Die
HistogramDataset
Methode fügt die Zählungen jedes Bandes zudataset
hinzu.Eine
StandardXYBarPainter
ersetzt dieChartFactory
Standard, wie gezeigt here.Eine benutzerdefinierte
DefaultDrawingSupplier
liefert die für jede Serie erforderliche Farbe; es enthält durchscheinende Farben.Eine Variation von
VisibleAction
, diskutiert here, wird verwendet, um die Sichtbarkeit jedes Bandes zu kontrollieren; Ein komplementärer Ansatz unter Verwendung vonChartMouseListener
wird gezeigt 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, 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();
});
}
}
Mit der Chart2D
Bibliothek, zeigt das folgende Beispiel einige alternative Ansätze.
ColorConvertOp
A wird verwendet, um das Musterbild in Graustufen konvertiert, wie here und here gezeigt.Verschachtelte Schleifen durchlaufen die Pixel von
BufferedImage
und rufen die MethodegetRGB()
auf, um den Wert jedes Pixels zu extrahieren; die entsprechenden Zählungen werden verwendet, um diedataset
zu konstruieren.
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();
}
});
}
}
Für Amüsement, hier ist ein [Histogramm] (http://i.imgur.com/1aQdxsM.png) der (berüchtigten) [blau schwarz weiß Goldkleid] (http://www.wired.com/2015/02/science-one-agrees-color-dress/). – trashgod
Siehe auch dieses verwandte [Beispiel] (http://stackoverflow.com/q/40537278/230513). – trashgod