You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java实现RGB转HSI并生成Hue、Saturation、Intensity图像求助

问题:Java实现RGB转HSI并生成H、S、I单通道图像

我正在尝试用Java将RGB图像转换为HSI格式,希望生成三张图像:H-色调图像、S-饱和度图像、I-亮度图像。

我的代码

private void jButton_Convert_HSIActionPerformed(java.awt.event.ActionEvent evt) { 
    // TODO add your handling code here: 
    BufferedImage image = null; 
    BufferedImage processed_hue, processed_sat, processed_in; 
    try { 
        image = ImageIO.read(new File("C:\\Users\\ATH\\Desktop\\photo\\Rotate\\test_rotate_lena.png")); 
    } catch (IOException ex) { 
        System.out.println(ex.getMessage()); 
    } 
    int width = image.getWidth(); 
    int height = image.getHeight(); 
    processed_hue = new BufferedImage(width, height, image.getType()); 
    processed_sat = new BufferedImage(width, height, image.getType()); 
    processed_in = new BufferedImage(width, height, image.getType()); 
    for (int y = 0; y < width; y++) //thuc hien lap cho y chay tu o den chieu cao anh 
    { 
        for (int x = 0; x < height; x++) //thuc hien lap cho x chay tu 0 den chieu rong 
        { 
            Color c = new Color(image.getRGB(x, y)); 
            float h = 0; 
            float r, g, b, s, i, theta; 
            // RGB TO HSI CONVERSION 
            int red = c.getRed(); 
            int green = c.getGreen(); 
            int blue = c.getBlue(); 
            float total = red + green + blue; 
            r = red / total; 
            g = green / total; 
            b = blue / total; 
            System.out.println("normalize red " + r); 
            System.out.println(" red = " + red + " green = " + green + " blue = " + blue); 
            s = 1 - (3 * Math.min(r, Math.min(g, b))); 
            i = total / (3 * 255); 
            theta = (float) Math.acos((0.5 * ((r - g) + (r - b))) / Math.pow((((r - g) * (r - g)) + ((r - b) * (g - b))), 1 / 2)); 
            System.out.println(" theta " + theta); 
            if (b <= g) { 
                // h = ((1 / Math.cos((0.5 * (2 * r - g - b)) / (Math.sqrt(((r - g) * (r - g) + (r - b) * (g - b))))))); 
                h = theta; 
            } else { 
                h = (float) ((2 * Math.PI) - theta); 
            } 
            System.out.println("Intial hue = " + h + " saturation = " + s + " intensity = " + i); 
            float h1 = (float) (h * (180 / Math.PI)); //to change Radian to Degree - multiply 180/pi 
            float s1 = (s * 100); 
            float i1 = (i * 255); 
            System.out.println(" Hue = " + Math.round(h1) + " Saturation = " + Math.round(s1) + " Intensity = " + Math.round(i1)); 
            // hue 
            float HSV[] = new float[3]; 
            // Color.RGBtoHSB(red, green, blue, HSV); 
            processed_hue.setRGB(x, y, Color.getHSBColor(h1, HSV[1], HSV[2]).getRGB()); 
            // processed_sat.setRGB(x, y, Color.getHSBColor(HSV[0], s1, HSV[2]).getRGB()); 
            // processed_in.setRGB(x, y, Color.getHSBColor(HSV[0], HSV[1], i1).getRGB()); 
        } 
    } // end for loop 
    try { 
        // save images 
        ImageIO.write(processed_hue, "png", new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\hue_image.png")); 
        ImageIO.write(processed_sat, "png", new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\sat_image.png")); 
        ImageIO.write(processed_in, "png", new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\in_image.png")); 
    } catch (IOException ex) { 
        System.out.println(ex.getMessage()); 
    } 
    System.out.println("Image is saved in D drive: "); 
    /* try { 
        File sat_out1 = new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\sat_image.png"); 
        ImageIO.write(sat_image, "png", sat_out1); 
    } catch (IOException ex) { 
        System.out.println(ex.getMessage()); 
    } 
    System.out.println("Image is saved in D drive: "); 
    try { 
        File inten_out1 = new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\inten_image.png"); 
        ImageIO.write(inten_image, "png", inten_out1); 
    } catch (IOException ex) { 
        System.out.println(ex.getMessage()); 
    } 
    System.out.println("Image is saved in D drive: "); */ 
} 

恳请各位提供建议与帮助,我该如何正确获取H、S、I三张图像?


解决方案

我帮你梳理下代码里的问题,以及如何正确生成H、S、I三张单通道图像:

1. 核心问题分析

你的代码里存在几个关键问题,导致无法正确生成目标图像:

  • 循环变量颠倒:y应该遍历图像高度,x遍历宽度,你现在写反了,会导致图像处理错误甚至数组越界。
  • 边界情况未处理:当图像像素为纯黑(RGB全0)时,total=0会触发除以0的错误;当像素为灰度(RGB值相等)时,计算theta的分母为0,会导致Math.acos报错。
  • 图像生成逻辑错误:使用Color.getHSBColor生成的是彩色图像,而你需要的是单通道的H/S/I灰度图像(每个通道的值映射为灰度级)。

2. 修复后的完整代码

private void jButton_Convert_HSIActionPerformed(java.awt.event.ActionEvent evt) { 
    BufferedImage image = null; 
    BufferedImage processed_hue, processed_sat, processed_in; 
    try { 
        image = ImageIO.read(new File("C:\\Users\\ATH\\Desktop\\photo\\Rotate\\test_rotate_lena.png")); 
    } catch (IOException ex) { 
        System.err.println("读取图像失败: " + ex.getMessage()); 
        return; 
    } 

    int width = image.getWidth(); 
    int height = image.getHeight(); 
    processed_hue = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 
    processed_sat = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 
    processed_in = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 

    // 确保保存目录存在
    File outputDir = new File("C:\\Users\\ATH\\Desktop\\photo\\HSI\\");
    if (!outputDir.exists()) {
        outputDir.mkdirs();
    }

    // 修正循环:y遍历高度,x遍历宽度
    for (int y = 0; y < height; y++) { 
        for (int x = 0; x < width; x++) { 
            Color c = new Color(image.getRGB(x, y)); 
            float h = 0; 
            float r = 0, g = 0, b = 0, s = 0, i = 0, theta = 0; 

            int red = c.getRed(); 
            int green = c.getGreen(); 
            int blue = c.getBlue(); 
            float total = red + green + blue; 

            // 处理纯黑像素(避免除以0)
            if (total == 0) {
                s = 0;
                i = 0;
                h = 0;
            } else {
                // 归一化RGB到[0,1]范围
                r = red / total; 
                g = green / total; 
                b = blue / total; 

                // 计算饱和度S
                s = 1 - (3 * Math.min(r, Math.min(g, b))); 
                // 计算亮度I
                i = total / (3 * 255f); 

                // 计算theta,处理灰度像素(分母为0)
                float numerator = 0.5f * ((r - g) + (r - b));
                float denominator = (float) Math.sqrt(((r - g)*(r - g)) + ((r - b)*(g - b)));
                
                if (denominator == 0) {
                    theta = 0; // 灰度像素,色调无意义,设为0
                } else {
                    // 确保acos参数在[-1,1]之间,避免报错
                    float cosTheta = Math.max(-1f, Math.min(1f, numerator / denominator));
                    theta = (float) Math.acos(cosTheta);
                }

                // 计算色调H
                if (b <= g) { 
                    h = theta; 
                } else { 
                    h = (float) (2 * Math.PI - theta); 
                }
            }

            // 将H/S/I映射到0-255范围,用于生成灰度图像
            // H:弧度转0-255
            int hValue = (int) ((h / (2 * Math.PI)) * 255);
            // S:0-1转0-255
            int sValue = (int) (s * 255);
            // I:0-1转0-255
            int iValue = (int) (i * 255);

            // 设置灰度图像(R=G=B=通道值)
            processed_hue.setRGB(x, y, new Color(hValue, hValue, hValue).getRGB());
            processed_sat.setRGB(x, y, new Color(sValue, sValue, sValue).getRGB());
            processed_in.setRGB(x, y, new Color(iValue, iValue, iValue).getRGB());
        } 
    } 

    // 保存图像
    try { 
        ImageIO.write(processed_hue, "png", new File(outputDir, "hue_image.png")); 
        ImageIO.write(processed_sat, "png", new File(outputDir, "sat_image.png")); 
        ImageIO.write(processed_in, "png", new File(outputDir, "in_image.png")); 
        System.out.println("图像已成功保存到目标目录!");
    } catch (IOException ex) { 
        System.err.println("保存图像失败: " + ex.getMessage()); 
    } 
} 

3. 关键修复说明

  • 循环修正:把y的循环条件改为y < height,x改为x < width,确保遍历所有像素。
  • 边界处理:添加了纯黑像素和灰度像素的特殊处理,避免数学运算错误。
  • 图像生成逻辑:将H、S、I的值分别映射到0-255的灰度范围,生成单通道灰度图像(R=G=B),这才是你需要的H/S/I单通道可视化结果。
  • 目录创建:提前创建输出目录,避免因目录不存在导致保存失败。

内容的提问来源于stack exchange,提问作者Aye Thu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:19:07