本文目录导读:

我将为您提供一个完整的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格式,方便进一步分析
- 统计信息:显示平均值、峰值等统计信息
这个实现提供了完整的图片直方图分析和可视化功能,可以用于图像处理、计算机视觉等应用场景。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播