本文目录导读:

我将为您提供一个完整的Java案例来实现图片直方图,这个案例将展示如何计算和绘制RGB三个通道的直方图。
图片直方图计算和显示
核心实现类
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class ImageHistogram {
// 直方图数据类
public static class HistogramData {
public int[] redHistogram = new int[256];
public int[] greenHistogram = new int[256];
public int[] blueHistogram = new int[256];
public int[] grayHistogram = new int[256];
}
// 计算图片直方图
public static HistogramData calculateHistogram(BufferedImage image) {
HistogramData data = new HistogramData();
int width = image.getWidth();
int height = image.getHeight();
// 遍历每个像素
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int rgb = image.getRGB(x, y);
// 提取RGB分量
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
// 增加对应通道的计数
data.redHistogram[red]++;
data.greenHistogram[green]++;
data.blueHistogram[blue]++;
// 计算灰度值 (标准加权公式)
int gray = (int)(0.299 * red + 0.587 * green + 0.114 * blue);
data.grayHistogram[gray]++;
}
}
return data;
}
// 绘制直方图
public static BufferedImage drawHistogram(HistogramData data, int width, int height) {
BufferedImage histogramImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = histogramImage.createGraphics();
// 设置背景为白色
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
// 找到各通道的最大值用于归一化
int maxRed = getMax(data.redHistogram);
int maxGreen = getMax(data.greenHistogram);
int maxBlue = getMax(data.blueHistogram);
// 直方图绘制参数
int margin = 40; // 边距
int graphWidth = width - 2 * margin;
int graphHeight = height - 2 * margin;
int barWidth = graphWidth / 256;
// 绘制坐标轴
g2d.setColor(Color.BLACK);
g2d.drawLine(margin, height - margin, width - margin, height - margin); // X轴
g2d.drawLine(margin, margin, margin, height - margin); // Y轴
// 绘制刻度标签
g2d.setFont(new Font("Arial", Font.PLAIN, 10));
g2d.drawString("0", margin - 5, height - margin + 15);
g2d.drawString("255", width - margin - 15, height - margin + 15);
// 绘制三个通道的直方图
drawChannelHistogram(g2d, data.redHistogram, Color.RED, margin, height - margin,
graphWidth, graphHeight, barWidth, maxRed);
drawChannelHistogram(g2d, data.greenHistogram, Color.GREEN, margin, height - margin,
graphWidth, graphHeight, barWidth, maxGreen);
drawChannelHistogram(g2d, data.blueHistogram, Color.BLUE, margin, height - margin,
graphWidth, graphHeight, barWidth, maxBlue);
// 添加图例
g2d.setFont(new Font("Arial", Font.BOLD, 12));
g2d.setColor(Color.RED);
g2d.drawString("R", margin + 10, margin + 20);
g2d.setColor(Color.GREEN);
g2d.drawString("G", margin + 30, margin + 20);
g2d.setColor(Color.BLUE);
g2d.drawString("B", margin + 50, margin + 20);
g2d.dispose();
return histogramImage;
}
// 绘制单个通道的直方图
private static void drawChannelHistogram(Graphics2D g2d, int[] histogram, Color color,
int xOrigin, int yOrigin, int graphWidth,
int graphHeight, int barWidth, int maxValue) {
g2d.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 100));
for (int i = 0; i < 256; i++) {
int barHeight = (int)((double)histogram[i] / maxValue * graphHeight);
int x = xOrigin + i * barWidth;
int y = yOrigin - barHeight;
g2d.fillRect(x, y, Math.max(1, barWidth - 1), Math.max(1, barHeight));
}
}
// 获取数组最大值
private static int getMax(int[] array) {
int max = array[0];
for (int value : array) {
if (value > max) {
max = value;
}
}
return max;
}
}
图形界面类
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class HistogramViewer extends JFrame {
private BufferedImage originalImage;
private BufferedImage histogramImage;
public HistogramViewer(BufferedImage image) {
this.originalImage = image;
// 计算直方图
ImageHistogram.HistogramData data = ImageHistogram.calculateHistogram(image);
// 绘制直方图
this.histogramImage = ImageHistogram.drawHistogram(data, 800, 400);
// 设置窗口
setTitle("图片直方图分析");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
// 创建显示面板
JPanel mainPanel = new JPanel(new GridLayout(1, 2));
// 原图面板
JPanel originalPanel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// 缩放显示原图
int width = Math.min(originalImage.getWidth(), 400);
int height = Math.min(originalImage.getHeight(), 400);
g.drawImage(originalImage, 0, 0, width, height, null);
}
};
originalPanel.setPreferredSize(new Dimension(400, 400));
originalPanel.setBorder(BorderFactory.createTitledBorder("原图"));
// 直方图面板
JPanel histogramPanel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(histogramImage, 0, 0, null);
}
};
histogramPanel.setPreferredSize(new Dimension(800, 400));
histogramPanel.setBorder(BorderFactory.createTitledBorder("直方图"));
// 添加面板到主面板
mainPanel.add(originalPanel);
mainPanel.add(histogramPanel);
add(mainPanel, BorderLayout.CENTER);
// 添加控制面板
JPanel controlPanel = new JPanel();
JButton saveButton = new JButton("保存直方图");
saveButton.addActionListener(e -> saveHistogram());
controlPanel.add(saveButton);
add(controlPanel, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null);
}
private void saveHistogram() {
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
try {
File outputFile = fileChooser.getSelectedFile();
if (!outputFile.getName().endsWith(".png")) {
outputFile = new File(outputFile.getAbsolutePath() + ".png");
}
ImageIO.write(histogramImage, "PNG", outputFile);
JOptionPane.showMessageDialog(this, "直方图保存成功!");
} catch (IOException ex) {
JOptionPane.showMessageDialog(this, "保存失败:" + ex.getMessage());
}
}
}
public static void main(String[] args) {
try {
// 加载图片(请替换为实际图片路径)
BufferedImage image = ImageIO.read(new File("test.jpg"));
// 创建并显示窗口
SwingUtilities.invokeLater(() -> {
HistogramViewer viewer = new HistogramViewer(image);
viewer.setVisible(true);
});
} catch (IOException e) {
System.err.println("图片加载失败:" + e.getMessage());
e.printStackTrace();
}
}
}
命令行版本
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
public class HistogramCalculator {
public static void main(String[] args) {
if (args.length < 1) {
System.out.println("用法: java HistogramCalculator <图片路径> [输出文件]");
return;
}
try {
// 加载图片
BufferedImage image = ImageIO.read(new File(args[0]));
// 计算直方图
ImageHistogram.HistogramData data = ImageHistogram.calculateHistogram(image);
// 输出到文件或控制台
if (args.length >= 2) {
exportToCSV(data, args[1]);
System.out.println("直方图数据已导出到: " + args[1]);
} else {
printHistogram(data);
}
// 显示统计信息
printStatistics(data, image.getWidth(), image.getHeight());
} catch (IOException e) {
System.err.println("错误: " + e.getMessage());
e.printStackTrace();
}
}
private static void printHistogram(ImageHistogram.HistogramData data) {
System.out.println("灰度直方图数据:");
System.out.println("灰度值\t计数");
for (int i = 0; i < 256; i++) {
if (data.grayHistogram[i] > 0) {
System.out.printf("%d\t%d\n", i, data.grayHistogram[i]);
}
}
}
private static void exportToCSV(ImageHistogram.HistogramData data, String filename) {
try (PrintWriter writer = new PrintWriter(new File(filename))) {
writer.println("灰度值,R,G,B");
for (int i = 0; i < 256; i++) {
writer.printf("%d,%d,%d,%d\n", i,
data.redHistogram[i],
data.greenHistogram[i],
data.blueHistogram[i]);
}
} catch (IOException e) {
System.err.println("导出失败: " + e.getMessage());
}
}
private static void printStatistics(ImageHistogram.HistogramData data, int width, int height) {
int totalPixels = width * height;
System.out.println("\n直方图统计信息:");
System.out.printf("图片大小: %d x %d = %d 像素\n", width, height, totalPixels);
// 计算各通道的平均值
double avgRed = calculateAverage(data.redHistogram, totalPixels);
double avgGreen = calculateAverage(data.greenHistogram, totalPixels);
double avgBlue = calculateAverage(data.blueHistogram, totalPixels);
System.out.printf("红色通道平均值: %.2f\n", avgRed);
System.out.printf("绿色通道平均值: %.2f\n", avgGreen);
System.out.printf("蓝色通道平均值: %.2f\n", avgBlue);
// 找到各通道最亮的点
int maxRedIndex = findMaxIndex(data.redHistogram);
int maxGreenIndex = findMaxIndex(data.greenHistogram);
int maxBlueIndex = findMaxIndex(data.blueHistogram);
System.out.printf("红色通道峰值: %d (灰度值)\n", maxRedIndex);
System.out.printf("绿色通道峰值: %d (灰度值)\n", maxGreenIndex);
System.out.printf("蓝色通道峰值: %d (灰度值)\n", maxBlueIndex);
}
private static double calculateAverage(int[] histogram, int totalPixels) {
long sum = 0;
for (int i = 0; i < 256; i++) {
sum += (long) i * histogram[i];
}
return (double) sum / totalPixels;
}
private static int findMaxIndex(int[] histogram) {
int maxIndex = 0;
int maxValue = histogram[0];
for (int i = 1; i < 256; i++) {
if (histogram[i] > maxValue) {
maxValue = histogram[i];
maxIndex = i;
}
}
return maxIndex;
}
}
使用方法
图形界面版本
# 编译 javac ImageHistogram.java HistogramViewer.java # 运行(需提供图片路径) java HistogramViewer
命令行版本
# 编译 javac ImageHistogram.java HistogramCalculator.java # 运行(导出CSV格式) java HistogramCalculator sample.jpg histogram_data.csv # 运行(仅显示到控制台) java HistogramCalculator sample.jpg
主要功能特点
- RGB三通道直方图:分别计算红、绿、蓝通道的直方图
- 灰度直方图:使用标准加权公式计算灰度值
- 可视化显示:图形界面显示原图和直方图
- 数据导出:支持导出为CSV格式,方便进一步分析
- 统计信息:显示平均值、峰值等统计信息
这个实现提供了完整的图片直方图分析和可视化功能,可以用于图像处理、计算机视觉等应用场景。