如何用Java案例实现图片直方图?

wen java案例 2

本文目录导读:

如何用Java案例实现图片直方图?

  1. 图片直方图计算和显示
  2. 命令行版本
  3. 使用方法
  4. 主要功能特点

我将为您提供一个完整的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

主要功能特点

  1. RGB三通道直方图:分别计算红、绿、蓝通道的直方图
  2. 灰度直方图:使用标准加权公式计算灰度值
  3. 可视化显示:图形界面显示原图和直方图
  4. 数据导出:支持导出为CSV格式,方便进一步分析
  5. 统计信息:显示平均值、峰值等统计信息

这个实现提供了完整的图片直方图分析和可视化功能,可以用于图像处理、计算机视觉等应用场景。

抱歉,评论功能暂时关闭!