在同一帧上重新计算直方图并使用 JFreechart 重新绘制

Re-calculating histogram on same frame and re-plot it using JFreechart

在我的主要项目中,我有一个 class,它使用 JFreeChart 在框架中绘制直方图。从该帧开始,我希望能够使用用户想要的 bin 数量重新绘制直方图。

为此,我添加了一个带有文本字段的菜单和一个用户可以在其中选择垃圾箱数量的按钮。当他按下按钮时,整个框架都会用新的 bins 数量重新填充。

我的问题是它不会被绘制,旧框架被处理掉但它没有绘制任何东西而是创建了一个空框架。我没有收到任何错误或异常,所以我不知道问题出在哪里。我怀疑它与 JChart class 或数据集有关,但我找不到任何关于究竟是什么不起作用的信息。

我已尝试从我的代码创建 MCVE 代码。来自三个名为:

的 tiff 图像
 "IMG_7911.CR2.R.TIFF", "IMG_7911.CR2.G.TIFF", "IMG_7911.CR2.B.TIFF"

(对于它们的外观问题无关紧要,它们可能都是相同的图像)我创建了一个直方图,其默认 bin 大小为 2^16=16384,16 位。然后我希望用户能够从菜单中更改大小。为此,我使用方法 "changeBinsSize" 和 "reDisplay":

 package mcve;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Paint;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JTextField;
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;

public class HistogramRAW {

private int BINS;
private Raster raster;//Load image
private String filename;
private RenderedImage image;

private JFreeChart chart; //Create histogram
private ChartPanel panel;
private HistogramDataset dataset;
private XYBarRenderer renderer;
private JMenuBar menuBar; //Menubar
private JMenu options;

private JTextField numBINS;
private JFrame f; //Frame

public HistogramRAW(String filename) {
    this.filename = filename;
    this.BINS = 16384;
}

private void getImage(String filename) {
    try {
        URL url = new URL(filename);
        final BufferedImage bi = ImageIO.read(url);
        raster=bi.getRaster();
        image=(RenderedImage)bi;

    } catch (IOException e) {
        e.printStackTrace(System.err);
        return;
    }
}

private ChartPanel createChartPanel() {
    // dataset
    dataset = new HistogramDataset();
    getImage(filename); //Put it here to get width and height from it
    final int w = image.getWidth();
    final int h = image.getHeight();

    double[] buffer = new double[w * h];

    //R
    buffer = raster.getSamples(0, 0, w, h, 0, buffer);
    dataset.addSeries("red", buffer, BINS);

    //G
    getImage(filename);
    buffer = raster.getSamples(0, 0, w, h, 0, buffer);
    dataset.addSeries("green", buffer, BINS);

    //B
    getImage(filename);
    buffer = raster.getSamples(0, 0, w, h, 0, buffer);
    dataset.addSeries("blue", buffer, BINS);

    //chart
    chart = ChartFactory.createHistogram("Histogram", "",
            "", dataset, PlotOrientation.VERTICAL, false, true, false);
    //Set colors
    XYPlot plot = (XYPlot) chart.getPlot();
    renderer = (XYBarRenderer) plot.getRenderer();
    renderer.setBarPainter(new StandardXYBarPainter());
    Paint[] paintArray = { // translucent red, green blue 
        new Color(0x800000ff, true),//blue
        new Color(0x8000ff00, true),//green1
        new Color(0x80ff0000, true)//red
    };
    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));

    //Create panel with chart
    panel = new ChartPanel(chart);
    panel.setMouseWheelEnabled(true);

    return panel;
}

private JMenuBar setMenuBar() {
    menuBar = new JMenuBar(); //Create Menubar

    options = new JMenu("Options"); //  menu.
    options.setMnemonic(KeyEvent.VK_O);
    menuBar.add(options);

    JPanel binsPanel = new JPanel(); //Change BINS size button
    numBINS = new JTextField("" + BINS);
    binsPanel.add(numBINS);
    JButton binsButton = new JButton("changeBins");
    binsButton.addActionListener(new MenuActionListener());
    binsPanel.add(binsButton);
    options.add(binsPanel);

    return menuBar;
}

public void display() throws CloneNotSupportedException {
    f = new JFrame("Histogram");
    f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    f.add(createChartPanel(), BorderLayout.CENTER);
    f.setJMenuBar(setMenuBar());
    f.pack();
    f.setLocationRelativeTo(null);
    f.setVisible(true);
}

public void reDisplay() throws CloneNotSupportedException {
    f.add(createChartPanel(), BorderLayout.CENTER);
    f.setJMenuBar(setMenuBar());
    f.pack();
    f.setLocationRelativeTo(null);
    f.setVisible(true);

}

public void changeBinsSize() {
    try {
        BINS = Integer.parseInt(numBINS.getText());
        f.removeAll();
        f.dispose();
        System.out.println("" + BINS);
        reDisplay();
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    try {
        HistogramRAW hist = new HistogramRAW("https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Wikipedia-logo-v2.svg/245px-Wikipedia-logo-v2.svg.png");
        hist.display();
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();

    }
}

private class MenuActionListener implements ActionListener {

    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("changeBins")) {
            changeBinsSize();
        }
    }
}
}

更新:我修改了代码以下载随机照片而不是 tiff,所有频道都是相同的照片。

有人能看出我做错了什么吗?我花了好几个小时想看看哪里出了问题,但我找不到任何东西。

您当前的 changeBinsSize() 实现尝试 替换 视图组件。相反,更新模型,监听视图将自行更新。

I tried to update the dataset, but I don't see any way of deleting series.

HistogramDataset adjusts the dataset's internal state as a function of the number of bins. As a result, you'll need to recreate the dataset from the original image samples, passing the new bin count as a parameter to addSeries(). Use the setDataset() method of XYPlot to replace the dataset, which will notify the listening plot to update itself. A complete example is shown addSeries()方法。